1

I have a simple web app I would like to run in a WinUI app that can fetch external HTML content:

    private async fetchHtml() {
        const url = document.querySelector<HTMLInputElement>("#txt-url")!.value;
        const html = await fetch(url).then(r => r.text());
        document.querySelector<HTMLTextAreaElement>("#txt-html")!.value = html;
    }

Obviously this would hit a CORS error. I want to disable it but cannot find any way for WinUI3:

  • WebView2 in WinUI does not have EnsureCoreWebView2Async overload that takes CoreWebView2EnvironmentOptions so this answer does not help.

  • The URL is external URL so SetVirtualHostNameToFolderMapping suggested by this answer does not help as well.

  • I tried injecting my own CORS header but it does not work on fetch (WebResourceResponseReceived event is not fired only on fetch requests):

c.WebResourceResponseReceived += (_, e) =>
{
    var origin = e.Request.Headers.FirstOrDefault(q => q.Key == "Origin").Value;
    if (!string.IsNullOrEmpty(origin))
    {
        e.Response.Headers.AppendHeader("Access-Control-Allow-Origin",
            new Uri(e.Request.Uri).GetLeftPart(UriPartial.Authority));
        e.Response.Headers.AppendHeader("Access-Control-Allow-Methods", "*");
        e.Response.Headers.AppendHeader("Access-Control-Allow-Headers", "*");
    }
};
Luke Vo
  • 17,859
  • 21
  • 105
  • 181

1 Answers1

2

So it turns out you actually need to handle proxying the request in the WebResourceRequested event. WebResourceResponseReceived is triggered after the browser handles the request.

To proxy the request manually, you need to first set up a web resource requested filter.

// CoreWebView2WebResourceContext.XmlHttpRequest is triggered
// by fetches for some reason. This filter will listen for any URI.
this.webView.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.XmlHttpRequest);

Then you can set up a listener just like for WebResourceResponseReceived

this.webView.CoreWebView2.WebResourceRequested += this.CoreWebView2_WebResourceRequested;

So to proxy the request, you need to set up an HttpClient and handle the requests manually.

For example, this will proxy all requests, assuming httpClient is defined as an HttpClient:

private void CoreWebView2_WebResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
    HttpRequestMessage request = new(new HttpMethod(e.Request.Method), e.Request.Uri)
    {
        Content = new StreamContent(e.Request.Content)
    };

    foreach (KeyValuePair<string, string> header in e.Request.Headers)
    {
        // Copy base headers
        request.Headers.TryAddWithoutValidation(header.Key, header.Value);

        // Copy content headers
        request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
    }

    // Make the request
    HttpResponseMessage response = httpClient.Send(request);

    // Custom headers
    response.Headers.Add("Access-Control-Allow-Origin", "*");

    // Webview2 Response expecting headers in a string with following format:
    //   key: value
    //   header2: value
    List<string> headers = response.Headers.Select(h => $"{h.Key}: {string.Join(",", h.Value)}").ToList();

    // Create Webview2 response
    CoreWebView2WebResourceResponse webView2WebResourceResponse = this.webView.CoreWebView2.Environment.CreateWebResourceResponse(
        response.Content.ReadAsStream(),
        (int)response.StatusCode,
        response.ReasonPhrase,
        string.Join('\n', headers));

    e.Response = webView2WebResourceResponse;
}

NOTE

Should not use async methods when building out a response object. The COM layer does not respect threading.

BlueFrog
  • 1,147
  • 1
  • 7
  • 15
  • Thanks for the solution! I heard that they added [the option](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2471#issuecomment-1182657427) here but haven't got the chance to test it myself if you don't want setting up a proxy – Luke Vo Sep 25 '22 at 14:17
  • 1
    I typically disable web security, but there is something to be said for a custom proxy for requests if you need more rigid validation. – BlueFrog Sep 26 '22 at 14:36
  • This won't work for WinUI3, as you CANNOT use blocking sync method in main thread (which will be the thread calling the callback) – sz ppeter Aug 15 '23 at 03:34