Georg Georg - 22 days ago 13
C# Question

Loading page relative to local folder

I am trying to show a web page relative to the local folder in a UWP app. This means, I have the page itself as string, but assets (images, scripts) are located in the apps local folder.

I tried to use the

NavigateToString
method that as I understood should serve this task, in combination with the
Source
-property of a
WebView
control.

var baseUri = new Uri("ms-appdata:///local/");
WebView.Source = baseUri;
var page = ...;
WebView.NavigateToString(page);


However, this gives me the following error message when assigning the
Source
-property of the web view:

Exception thrown: 'System.ArgumentException' in App.exe
Additional information: Value does not fall within the expected range.


So apparently, using the local app folder for assets is not supported?

The app targets minimum Windows 10 Build 10586.

Does anybody know whether there is a useful workaround for this?

Edit: I tried to make a minimum example. In the following, I created a small test app that does nothing but loading a static html file from the local storage. As far as I can tell, this code exactly resembles the XamlWebView example but does raise an ArgumentException.

MainPage.xaml

<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<WebView Name="WebView" />
</Grid>
</Page>


MainPage.xaml.cs

using System;
using System.IO;
using Windows.Storage;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace App1
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();

Initialize();
}

private async void Initialize()
{
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("index.html", CreationCollisionOption.ReplaceExisting);
using (var sw = new StreamWriter(await file.OpenStreamForWriteAsync()))
{
sw.WriteLine("<html>");
sw.WriteLine("<body>");
sw.WriteLine("This is some text");
sw.WriteLine("</body>");
sw.WriteLine("</html>");
}

WebView.Navigate(new Uri("ms-appdata:///local/index.html"));
}
}
}


I do not even know where the difference to the sample is, can't find any.

Answer

WebView.Source property is ued to gets or sets the Uniform Resource Identifier (URI) source of the HTML content to display in the WebView control. We usually set the Source property in XAML. The XAML parser automatically converts the string to a Uri. The Source property can be set in code, but rather than doing so, we typically use one of the Navigate methods such as Navigate, NavigateToString and NavigateWithHttpRequestMessage method to load content in code.

And the URI you've used in your code is not a valid URI for WebView control, so you got a Value does not fall within the expected range. error. To load content from app’s local storage, we need to place the content in a subfolder under the local folder. Ref Remarks in WebView class:

To load uncompressed and unencrypted content from your app’s LocalFolder or TemporaryFolder data stores, use the Navigate method with a Uri that uses the ms-appdata scheme. The WebView support for this scheme requires you to place your content in a subfolder under the local or temporary folder. This enables navigation to URIs such as ms-appdata:///local/folder/file.html and ms-appdata:///temp/folder/file.html . (To load compressed or encrypted files, see NavigateToLocalStreamUri.)

Each of these first-level subfolders is isolated from the content in other first-level subfolders. For example, you can navigate to ms-appdata:///temp/folder1/file.html, but you can’t have a link in this file to ms-appdata:///temp/folder2/file.html. However, you can still link to HTML content in the app package using the ms-appx-web scheme, and to web content using the http and https URI schemes.

So when you use WebView.Navigate(new Uri("ms-appdata:///local/index.html"));, you still get the error as ms-appdata:///local/index.html is also not a valid URI for WebView.

Besides, although NavigateToString supports content with references to external files such as CSS, scripts, images, and fonts. But it only supports content in the app package using the ms-appx-web scheme, and web content using the http and https URI schemes. It can't work with assets located in the apps local folder. To achieve what you want you need to put these assets into a subfolder under the local folder and then also store the html string to a file under the same subfolder. in the html, you can use relative URI to reference these assets like what in my previous answer.