Winforms WebView2 with fixed runtime not working from shared folder - c#

I'm using a fixed version of WebView2 runtime like described in WebView2 working without WebView2 Runtime.
When I save this fixed runtime folder on my local machine it works fine. But as soon as I try to access the exact same folder on a shared folder/server it does not work. Any ideas?
public Form1()
{
InitializeComponent();
this.InitWeb();
}
public async void InitWeb()
{
var webEnv = await CoreWebView2Environment.CreateAsync(#"\\SharedFolder\FixedVersionFolder", Path.GetTempPath());
//var webEnv = await CoreWebView2Environment.CreateAsync(#"C:\FixedVersionFolder", Path.GetTempPath());
await this.webView21.EnsureCoreWebView2Async(webEnv);
webView21.Source = new Uri("https://www.microsoft.com");
}
In this case the webview does not show but if I replace the webEnv init line with the commented one, which points to my local folder it works just fine. I have tried multiple shared folders including creating one on my computer and it does not work.

The solution that worked for me was setting the WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS to --no-sandbox before the initialization of webview. I'm aware that this can cause some security risk, so use at your own risk.
Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--no-sandbox");

Related

c# WebView2 user directory "Access Denied"

I am having issues with the .NET WebView2 control. I thought I had it fixed but it is not working. I have read numerous posts to no avail.
I have a WPF C# application that runs on a server. Various people log into the server via a web browser and run the app.
Within this app, I open up a WebView2 browser, setting the user data directory to a unique directory for each person.
When I set the user data directory and call EnsureCoreWebView2Async(), I get an error in the exception code "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).
Below is the code:
public static async void InitializeWebView(WebView2 browser, string path)
{
Directory.CreateDirectory(path);
browser.CreationProperties = new CoreWebView2CreationProperties()
{
UserDataFolder = path
};
try
{
await browser.EnsureCoreWebView2Async();
}
catch( Exception ex)
{
Log.LogString("Ensure error: " + ex.Message);
}
}
I have tried various things without success. What am I doing wrong? Any suggestions?
I'm not all that familiar with CoreWebView2CreationProperties, but according to the documentation.
Its main purpose is to be set to CreationProperties in order to
customize the environment used by a WebView2 during implicit
initialization...If you need complete control over the environment used by a WebView2 control then you'll need to initialize the control explicitly by creating your own environment with CreateAsync(String, String, CoreWebView2EnvironmentOptions) and passing it to EnsureCoreWebView2Async(CoreWebView2Environment) before you set the Source property to anything.
As mentioned in the documentation referenced above, implicit initialization occurs when the Source property is set and CoreWebView2 hasn't been explicitly initialized.
To explicitly initialize CoreWebView2, try the following:
public async Task InitializeCoreWebView2Async(WebView2 wv, string userDataFolder = null)
{
//initialize CoreWebView2
CoreWebView2EnvironmentOptions options = null;
CoreWebView2Environment cwv2Environment = null;
//it's recommended to create the userDataFolder in the same location
//that your other application data is stored (ie: in a folder in %APPDATA%)
//if not specified, we'll create a folder in %TEMP%
if (String.IsNullOrEmpty(userDataFolder))
userDataFolder = Path.Combine(Path.GetTempPath(), System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
//create WebView2 Environment using the installed or specified WebView2 Runtime version.
//cwv2Environment = await CoreWebView2Environment.CreateAsync(#"C:\Program Files (x86)\Microsoft\Edge Dev\Application\1.0.1054.31", userDataFolder, options);
cwv2Environment = await CoreWebView2Environment.CreateAsync(null, userDataFolder, options);
//initialize
await wv.EnsureCoreWebView2Async(cwv2Environment);
System.Diagnostics.Debug.WriteLine("UserDataFolder: " + userDataFolder);
}
Note: If one desires to explicitly initialize CoreWebView2, it must be done prior to setting the Source property for the WebView2 control.
Usage:
await InitializeCoreWebView2Async(webView21, Path.Combine(#"C:\Temp", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name));
Resources:
CoreWebView2 Class
CoreWebView2CreationProperties
CoreWebView2Environment Class
CoreWebView2Environment.CreateAsync
WebView2.EnsureCoreWebView2Async(CoreWebView2Environment) Method
Thank you for your continued help. Due to character limitations, I am responding to your questions in an Answer section. In response to your comments...
If the Source was being set prior to initialization, I would be getting a different error (which I have had in the past).
Here is the xaml for the WebView2 control:
<Wpf:WebView2 Name="Browser" Margin="20,20,20,20" CoreWebView2InitializationCompleted="Browser_CoreWebView2InitializationCompleted" />
As you can see, I am subscribed to the InitializationComplete event, which is not being called due to the error.
Here is the source for the form that hosts the WebView2 control:
private async void _DoIt()
{
try
{
var env = await CoreWebView2Environment.CreateAsync(null, Global._GetServerDataDirectory(_Person));
await Browser.EnsureCoreWebView2Async(env);
}
catch( Exception ex)
{
Log.LogString("DoIt error: " + ex.Message);
}
}
public PayPal(Person person)
{
InitializeComponent();
_Person = person;
_DoIt();
Log.LogString("After PayPal constructor");
}
It is erroring in _DoIt().
Okay, after many hours of trying to track this down, the end issue is that Thinfinity's VirtualUI product does not support an application using WebView2. This was my core issue and has been confirmed by the vendor.
Thank you once again for everyone's kind help with this.

WebView2 site not loading

I have downloaded and attached the FixedVersionRuntime.88.0.705.81.x64 for WebView2 and attached it to my project.
Using the following it should load the necessary page but when loading the WebView is not crashing but no page is loaded:
public async Task InitializeAsync()
{
string installPath = #"C:\Program Files (x86)\WebView2Runtime\Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x64\";
var webView2Environment = await CoreWebView2Environment.CreateAsync(installPath);
await browserControl.EnsureCoreWebView2Async(webView2Environment);
}
I am then setting the source after this:
await InitializeAsync();
me.Source = new Uri(((MainViewModel)this.DataContext).Config.DefaultURL);
When using the evergreen installer it worked fine but when moving to the fixed version it seems to not load correctly when deployed.
I've tested the following, which seems to work:
Download WebView2 Fixed Version
Example
Given:
WebView2 Fixed Version: Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x86.cab
Project folder: C:\Projects\WpfTestFixedVersion
Output folder: C:\Projects\WpfTestFixedVersion\WpfTestFixedVersion\bin\Debug
Project compiled using:
Configuration: Debug
Platform: Any CPU (Prefer 32-bit)
Extract files from .cab
Open a cmd window
cmd window
C:\Users\Test\Downloads> expand Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x86.cab -F:* "C:\Projects\WpfTestFixedVersion\WpfTestFixedVersion\bin\Debug"
Note: When using expand in the above command, the destination folder must already exist and the name must not end with '\'.
C:\Projects\WpfTestFixedVersion\WpfTestFixedVersion\bin\Debug
C:\Projects\WpfTestFixedVersion\WpfTestFixedVersion\bin\Debug\Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x86
Option 1:
InitializeAsync
public async Task InitializeAsync()
{
string installPath = #".\Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x86";
var webView2Environment = await CoreWebView2Environment.CreateAsync(installPath);
await browserControl.EnsureCoreWebView2Async(webView2Environment);
}
Option 2:
Note: This option allows one to specify the userDataFolder. If it's not specified, it uses the user's temp folder as the location for the userDataFolder.
InitializeAsync
public async Task InitializeAsync(WebView2 wv, string webCacheDir = "")
{
CoreWebView2EnvironmentOptions options = null;
string tempWebCacheDir = string.Empty;
CoreWebView2Environment webView2Environment = null;
//set value
tempWebCacheDir = webCacheDir;
if (String.IsNullOrEmpty(tempWebCacheDir))
{
//get fully-qualified path to user's temp folder
tempWebCacheDir = System.IO.Path.GetTempPath();
tempWebCacheDir = System.IO.Path.Combine(tempWebCacheDir, System.Guid.NewGuid().ToString("N"));
}
//use with WebView2 FixedVersionRuntime
webView2Environment = await CoreWebView2Environment.CreateAsync(#".\Microsoft.WebView2.FixedVersionRuntime.88.0.705.81.x86", tempWebCacheDir, options);
//webView2Environment = await CoreWebView2Environment.CreateAsync(#"C:\Program Files (x86)\Microsoft\Edge Dev\Application\90.0.810.1", tempWebCacheDir, options);
//webView2Environment = await CoreWebView2Environment.CreateAsync(null, tempWebCacheDir, options);
//wait for CoreWebView2 initialization
await wv.EnsureCoreWebView2Async(webView2Environment);
}
The answer by #user9938 is comprehensive. But please also note that the version of "WebView2Loader.dll" which is in use is very crucial. I had almost the same problem with "Microsoft.WebView2.FixedVersionRuntime.101.0.1210.39.x64" when I tried to use the WebView2 component in the MMC Snap-Ins with types of "HTMLView" or "FormView".
I just copied the abovementioned dll file (version 1.0.1248.0, size=157640 bytes) in a proper path that was accessible for the project (you could just put it beside your project output files first to test it) and then WebView2 browser started to function as expected. Microsoft error messages sometimes (at least in my case) was a little bit misleading and did not convey enough and to the point information.
I received "BadImageFormatException" that normally occurs when you mix platform targets (for example using a dll file compiled in X64 in an application that targeted for x86 or vice versa) or mix native code and .NET but that was not my problem at all. I hope this help one who may stuck in.

KnownFolders.GetFolderAsync never returns in .NET Core 5

I am using Uno Platform to make an app which access a specific folder inside the user's Documents library from a game (BeamNG.drive). I want the app to read all the mod files inside this folder to be able to edit and display them to users on startup. I installed the Nito.Mvvm.Async Package to help me bind everything to the UI.
Here's part of the method that loads the mod files from the Documents folder:
public static async Task<List<Mod>> GetModList()
{
StorageFolder documents = await KnownFolders.DocumentsLibrary.GetFolderAsync("BeamNG.drive");
IReadOnlyList<StorageFile> fileList = await documents.GetFilesAsync();
List<Mod> foundModsList = new();
foreach (StorageFile file in fileList)
{
//...
}
return foundModsList;
}
Here's the code on MainPage.xaml.cs inside the Shared project in my solution, based on code from this answer
public NotifyTask<ObservableCollection<Mod>> ModsData { get; }
public MainPage()
{
InitializeComponent();
ModsData = NotifyTask.Create(InitModData());
}
private static async Task<ObservableCollection<Mod>> InitModData()
{
return new(await ModManager.GetModList());
}
The GetModList() method is called, but the GetFolderAsync("BeamNG.drive") method never returns, and the app keeps running normally (not UI freezes or anything). If I add a breakpoint in that line, Visual Studio stops there normally. But if I press "Step Over", instead of continuing on that method, VS jumps to this line...
return new(await ModManager.GetModList());
...then this one:
ModsData = NotifyTask.Create(InitModData());
Using ConfigureAwait(false) in any of the calls using await doesn't help anything. I'm really not sure what is going on and I suspect that Nito.Mvvm.Async might have something to do with it (considering its last update was in 2017) but I'm really not sure.
From your question it seems this problem occurs under .NET 5 - meaning targeting WebAssembly or Skia targets of Uno Platform. Under Uno, the KnownFolders type is not yet supported, so accessing DocumentLibrary is not possible. If you want to have this supported, please file an issue on Uno Platform GitHub.
In case of UWP, to access the Documents library, you need to declare a special capability in app manifest (see Docs). However, it is a restricted capability and it is quite likely that if you utilize it, the app will not pass Microsoft Store certification. Instead, it is recommended to use FolderPicker instead and let the user decide on the location when files are stored, or to use ApplicationData.Current.LocalFolder to store the data for the app privately.

Saving image to a folder in IIS localhost

I have to save images to a folder located in "c:\inetpub\wwwroot\" and named as "UploadedImages". Here is my code:
public string SaveImage(string base64,int compno)
{
string res = "";
try
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64)))
{
using (Bitmap bm2 = new Bitmap(ms))
{
bm2.Save(Server.MapPath("~/UploadedImages/ID"+compno+".jpg"));
}
}
res = "done";
}
catch (Exception ex) {
res = ex.ToString();
}
return res;
}
but it throws "A generic error occured in GDI+ at System.Drawing.Image.Save" exception. What am I doing wrong? This code works fine when saving image locally as
bm2.Save("D:Embasy\UploadedImages\ID"+compno+".jpg"));
What changes do I need to make to save images in localhost directory?
Your not going to believe this -- the site running v1.1 had a virtual directory set-up which was mapped to the directory in which the image was saved to -- things worked fine.
The v2.0 site also had the same virtual directory name, but the physical path was different -- I changed the path to point to the same directory as the v1.0 site and now the code works.
So in short -- you were right about the "path must exist".
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
and kindly refer this link
http://msdn.microsoft.com/en-us/library/xs6ftd89.aspx
When you are using Server.Mappath
bm2.Save(Server.MapPath("~/UploadedImages/ID"+compno+".jpg"));
"~(tield)" : is point to project/application root folder c:\inetpub\wwwroot\yourproject
then find remaining your path /UploadedImages and then create ID1.jpg.
But your imagefolder "UploadImages" is exist in d: not in c:\inetpub\wwwroot\yourproject
if you want to exist your image folder in D: then you should to create
virtual directory and then you need to apply path as relevant
My problem actually was that every time i published website, I replaced the "UploadedImages" folder too and thus permissions were changed. So, i didnt replaced the folder again after changing its permissions and creating "everyone" group and giving full rights to it. Now code is working perfectly :)

MonoDroid evaluation System.UnauthorizedAccessException in Directory.CreateDirectory()

Scenario:
Start MonoDevelop
new Android Application
Replace button click delegate with
string fullPath = "/data/misc.mvvmcross.customermanagement/files/_Caches/Pictures.MvvmCross/";
if (System.IO.Directory.Exists(fullPath))
{
button.Text = "exists";
}
else
{
button.Text = "not found";
Directory.CreateDirectory(fullPath);
}
run and click the button.
Directory.CreateDirectory will fail with
System.UnauthorizedAccessException
Have tried creating a new emulator image with different API levels, but problem is still here
Any thoughts anyone?
Ok, Have created new Android Emulator image and used that.
Everything now works.
Solution:
Create a new android emulator image for the API level you want (don't forget Google API support)
I'm wondering if this is caused by some kind of assembly/package naming issue.
I've tested this code:
string fullPath = Path.Combine(FilesDir.Path, "_Caches2/Pictures.MvvmCross/2/");
if (System.IO.Directory.Exists(fullPath))
{
button.Text = "exists";
}
else
{
button.Text = fullPath;
Directory.CreateDirectory(fullPath);
}
...and it works fine in a 2.3.3 emulator.
The data folder pattern is: /data/ * package name * /files/
And it is correct (I think) for one package not to be able to access the data of another.
So I'm wondering if somehow your package names are wrong - check the manifest tab and the manifest.xml file for your application?

Categories

Resources