{"id":104874,"date":"2021-02-17T07:00:00","date_gmt":"2021-02-17T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104874"},"modified":"2021-02-17T06:26:40","modified_gmt":"2021-02-17T14:26:40","slug":"20210217-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210217-00\/?p=104874","title":{"rendered":"How can I return custom content for specific URLs requested by a Windows Runtime WebView?"},"content":{"rendered":"<p>If you&#8217;re using a Windows Runtime WebView control, you may want to return custom content when the page requests content from specific URIs.<\/p>\n<p>One scenario for this is that you want to block specific sites.<\/p>\n<p>Another scenario is that you have copied the contents of a site locally, and you want all intra-site navigations to be served from your local copy. This is a handy way of converting a Web-based site into an app that can run offline.<\/p>\n<p>Yet another scenario is that the site and your app are in cahoots, and the site makes queries to specific URIs, knowing that your app will intercept the request and inject custom results.<\/p>\n<p>Whatever the scenario, you can do this by using the <code>Web\u00adResource\u00adRequested<\/code> event. Start with <a href=\"https:\/\/github.com\/microsoft\/Windows-universal-samples\/blob\/08d7459c552fe1065d3fe195b3fe2a5d7ec3b567\/Samples\/XamlWebView\/\"> the WebView sample<\/a> and make these changes:<\/p>\n<pre><span style=\"color: blue;\">using Windows.Web.Http;<\/span>\r\n\r\n    public <a href=\"https:\/\/github.com\/microsoft\/Windows-universal-samples\/blob\/08d7459c552fe1065d3fe195b3fe2a5d7ec3b567\/Samples\/XamlWebView\/cs\/Scenario2_NavToString.xaml.cs#L25\">Scenario2_NavToString<\/a>()\r\n    {\r\n        this.InitializeComponent();\r\n        <span style=\"color: blue;\">WebViewControl.WebResourceRequested += OnResourceRequested;<\/span>\r\n    }\r\n\r\n    <span style=\"color: blue;\">Uri fakeUri = new Uri(\"http:\/\/example.com\/fakeme\");\r\n\r\n    void OnResourceRequested(WebView sender,\r\n             WebViewWebResourceRequestedEventArgs e)\r\n    {\r\n        if (e.Request.RequestUri == fakeUri)\r\n        {\r\n            var response = new HttpResponseMessage(HttpStatusCode.Ok);\r\n            response.Content = new HttpStringContent(\"Here is some fake content\");\r\n            e.Response = response;\r\n        }\r\n    }<\/span>\r\n<\/pre>\n<p>And edit the <code>html\/html_example.html<\/code> file to contain this:<\/p>\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    <span style=\"color: blue;\">&lt;button id=tryme&gt;Try me&lt;\/button&gt;&lt;div id=result&gt;&lt;\/div&gt;\r\n    &lt;script&gt;\r\ntryme.addEventListener('click', function(e) {\r\n    var xhr = new XMLHttpRequest();\r\n    xhr.open('GET', 'http:\/\/example.com\/fakeme', true);\r\n    xhr.onreadystatechange = function() {\r\n        if (xhr.readyState == XMLHttpRequest.DONE) {\r\n            result.innerText = `status: ${xhr.status}, content = ${xhr.responseText}`;\r\n        }\r\n    };\r\n    xhr.send();\r\n});\r\n&lt;\/script&gt;<\/span>\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>We change the web page content so it issues an <code>XMLHttpRequest<\/code> to the fake site <code>http:\/\/example.com\/fakeme<\/code> and prints the result.<\/p>\n<p>On the app side, we respond to the <code>Web\u00adResource\u00adRequested<\/code> event by seeing if the request is for our custom fake site. If so, then we construct a custom response that is consists of a string of fake content. (If not, then the event handler does nothing, and the request goes out over the wire.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Intercepting the attempts to contact the outside world.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-104874","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Intercepting the attempts to contact the outside world.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104874","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=104874"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104874\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=104874"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104874"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104874"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}