Как передать данные из веб-приложения vaadin в приложение C # GUI - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть веб-приложение в Vaadin Framework 8. У меня есть приложение Windows GUI в C #.Приложение GUI использует компонент WebBrowser для отображения веб-приложения.WebBrowser компонент внутренне использует ядро ​​IE11 через ActiveX.Я могу успешно загрузить и отобразить веб-приложение в компоненте браузера приложения GUI.

Мне нужно передать данные из веб-приложения в приложение GUI.В веб-приложении загружено много строк на стороне сервера, только немногие отображаются в сетке.Я хочу передать все данные из веб-приложения в приложение GUI в каком-либо формате (CSV или JSON).

Я пробовал некоторые подходы, но мне это не удалось.

[Подход 1]

Webapp: присоедините загружаемый ресурс (csv) к Link с заранее заданным идентификатором, используя FileDownloader.Загрузка по клику мыши работает нормально, всплывающее диалоговое окно сохранения файла и данные успешно загружаются.

Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
FileDownloader downloader = new FileDownloader(resource);
downloader.extend(link);

Page.getCurrent().getJavaScript().addFunction("test", new JavaScriptFunction() {
     @Override
     public void call(JsonArray arguments) {
         Page.getCurrent().getJavaScript()
             .execute("document.getElementById('myId').click()");
    }
});

Приложение для графического интерфейса пользователя: вызывает событие onClick для ссылки и захватывает событие WebBrowser.FileDownload, захватывает событие WebBrowser.Navigate.Мне не удалось вызвать событие onClick из C #, используя:

HtmlElement el = webBrowser.Document.GetElementById("myId");
el.RaiseEvent("onClick");
el.InvokeMember("click");
webBrowser.Document.InvokeScript("document.getElementById('myId').click();", null);
webBrowser.Document.InvokeScript("test", null);

Результат: WebBrowser.FileDownload событие не работает (запускается, но не может захватить URL-адрес или данные), событие захвата WebBrowser.Navigate работает частично(может видеть URL ресурса, но не может загрузить данные, используя byte[] b = new WebClient().DownloadData(e.Url);).

[Подход 2]

Аналогично подходу 1. Я попытался получить URL-адрес ресурса, установить прямой URL-адрес на Link и загрузить ресурс в c # по прямой ссылке.Я могу создать тот же URL ресурса, который используется браузером для загрузки данных, когда пользователь щелкает ссылку.

Расширенный загрузчик файлов, в котором хранятся ресурс, ключ и соединитель:

public class ExtendedFileDownloader extends FileDownloader {
    private String myKey;
    private Resource myResource;
    private ClientConnector myConnector;

    public ExtendedFileDownloader(StreamResource resource, ClientConnector connector) {
        super(resource);
        myConnector = connector;
    }

    @Override
    protected void setResource(String key, Resource resource) {
        super.setResource(key, resource);
        myKey = key;
        myResource = resource;
    }

    public String getResourceUrl() {
        ResourceReference ref =
            ResourceReference.create(
                myResource,
                (myConnector != null) ? myConnector : this,
                myKey);
        String url = ref.getURL();
        return url;
    }
}

В представлении:

// fix app://path... urls to /<base-path>/path urls
private String fixResourceReferenceUrl(String resourceReferenceUrl) {
    String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
    String uiBaseUrl = ui.getUiRootPath();
    String fixedUrl = uiBaseUrl + "/" + resourceReferencePath;
    return fixedUrl;
}

Link link2 = new Link("Data2");
link2.setId("myId2");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource, this);
String fixedResourceUrl = fixResourceReferenceUrl(downloader.getResourceUrl());
link2.setResource(new ExternalResource(fixedResourceUrl));    

Результат: невозможно загрузить данные по этой ссылке, ошибка сервера 410 или ошибки NotFound.

Есть идеи?Любые другие подходы, чтобы попробовать?

1 Ответ

0 голосов
/ 27 сентября 2018

Я наконец-то решил проблему.Решение очень близко к подходу 2. URL ресурса передается в элементе с пользовательским атрибутом.C # WebClient необходимо установить файлы cookie из заголовков HTTP WebBrowser и Referer.Данные могут быть успешно загружены приложением C #.

Атрибут элемента в веб-приложении vaadin можно установить с помощью Vaadin-addon Атрибуты .

Файлы cookie в приложении C # можно получить с помощьюЭто решение .

// Fix resource urls begining with app://
public String fixResourceReferenceUrl(String resourceReferenceUrl) {
    try {
        String uiRootPath = UI.getCurrent().getUiRootPath();
        URI location = Page.getCurrent().getLocation();
        String appLocation = new URIBuilder()
                .setScheme(location.getScheme())
                .setHost(location.getHost())
                .setPort(location.getPort())
                .setPath(uiRootPath)
                .build()
                .toString();
        String resourceReferencePath = resourceReferenceUrl.replace("app://", "");
        String fixedUrl = appLocation + "/" + resourceReferencePath;
        return fixedUrl;
    }
    catch (Exception e) {
        return null;
    }
}

В поле зрения (с использованием ExtendedFileDownloader сверху):

Link link = new Link("Data");
link.setId("myId");
StreamResource resource = getMyResource(data);
ExtendedFileDownloader downloader = new ExtendedFileDownloader(resource);
downloader.extend(link);
Attribute attr = new Attribute("x-my-data", fixResourceReferenceUrl(downloader.getResourceUrl()));
attr.extend(link);
link.setVisible(true);

В приложении C #:

[DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetGetCookieEx(
    string url,
    string cookieName,
    StringBuilder cookieData,
    ref int size,
    Int32 dwFlags,
    IntPtr lpReserved);

private const Int32 InternetCookieHttponly = 0x2000;

public static String GetUriCookies(String uri)
{
    // Determine the size of the cookie
    int datasize = 8192 * 16;
    StringBuilder cookieData = new StringBuilder(datasize);
    if (!InternetGetCookieEx(uri, null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
    {
        if (datasize < 0)
            return null;
        // Allocate stringbuilder large enough to hold the cookie
        cookieData = new StringBuilder(datasize);
        if (!InternetGetCookieEx(
            uri,
            null, cookieData,
            ref datasize,
            InternetCookieHttponly,
            IntPtr.Zero))
            return null;
    }
    return cookieData.ToString();
}

private void button_Click(object sender, EventArgs e)
{
    HtmlElement el = webBrowser.Document.GetElementById("myId");
    String url = el.GetAttribute("x-my-data");
    String cookies = GetUriCookies(url);
    WebClient wc = new WebClient();
    wc.Headers.Add("Cookie", cookies);
    wc.Headers.Add("Referer", WEB_APP_URL); // url of webapp base path, http://myhost/MyUI
    byte[] data = wc.DownloadData(url);
}
...