WPF ClickOnce full trust issue (related to separate AppDomain?) - wpf

I'm working on creating a clickonce install for my application.
I have ClickOnce security settings enabled with full trust in the Security tab if the project properties. I publish to a network drive and run the install. The install is successful but when I run the application I get this error:
I have the Pos for .Net code running in a separate AppDomain (due to its issues with .net 4's default security policy). It runs fine on my local system without clickonce. My application uses Prism, so I had to modify the manifest to include the dynamically loaded modules. It's somehow related to my AppDomain I create not having full trust.
This is how I create the AppDomain
AppDomainSetup currentAppDomainSetup = AppDomain.CurrentDomain.SetupInformation;
AppDomainSetup newAppDomainSetup = new AppDomainSetup()
{
ApplicationBase = currentAppDomainSetup.ApplicationBase,
LoaderOptimization = currentAppDomainSetup.LoaderOptimization,
ConfigurationFile = currentAppDomainSetup.ConfigurationFile,
PrivateBinPath = #"Modules" // need to set this so that the new AppDomain can see the prism modules
};
newAppDomainSetup.SetCompatibilitySwitches(new[] { "NetFx40_LegacySecurityPolicy" }); // required for POS for .Net to function properly
_posAppDomain = AppDomain.CreateDomain("POS Hardware AppDomain", null, newAppDomainSetup);
// Error happens on the following line. Note that type T is always in same assembly that AppDomain was created in.
T hardware = (T)PosAppDomain.CreateInstanceFromAndUnwrap(Assembly.GetAssembly(typeof(T)).Location, typeof(T).FullName);
Is there a security setting that I'm missing?
I think I'm getting closer. The AppDomain I create runs in full trust when I run without clickonce, but when I run it with clickonce it doesn't run in full trust.... so now I'm trying to figure out how to get it in full trust.

Figured it out
I had to add the Evidence and PermissionSet ...
Evidence evidence = new Evidence();
evidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
PermissionSet ps = SecurityManager.GetStandardSandbox(evidence);
AppDomainSetup currentAppDomainSetup = AppDomain.CurrentDomain.SetupInformation;
AppDomainSetup newAppDomainSetup = new AppDomainSetup()
{
ApplicationBase = currentAppDomainSetup.ApplicationBase,
LoaderOptimization = currentAppDomainSetup.LoaderOptimization,
ConfigurationFile = currentAppDomainSetup.ConfigurationFile,
PrivateBinPath = #"Modules" // need to set this so that the new AppDomain can see the prism modules
};
newAppDomainSetup.SetCompatibilitySwitches(new[] { "NetFx40_LegacySecurityPolicy" }); // required for POS for .Net to function properly

Related

WebView2 Fixed Version not working when binaries stored on network share

I want to save the Fixed Version binaries on a network share path, but the WebView2 does not display the web page and does not throw an error.
I set the BrowserExecutableFolder path in the form designer:
CoreWebView2CreationProperties1.BrowserExecutableFolder = "j:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64\"
CoreWebView2CreationProperties1.Language = Nothing
CoreWebView2CreationProperties1.UserDataFolder = Nothing
Me.WebView21.CreationProperties = CoreWebView2CreationProperties1
Me.WebView21.DefaultBackgroundColor = System.Drawing.Color.White
Me.WebView21.Dock = System.Windows.Forms.DockStyle.Fill
Me.WebView21.Location = New System.Drawing.Point(0, 25)
Me.WebView21.Name = "WebView21"
Me.WebView21.Size = New System.Drawing.Size(800, 425)
Me.WebView21.TabIndex = 6
Me.WebView21.ZoomFactor = 1.0R
Setting to a UNC path, doesn't work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "\UNCFile1\private\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
Setting to the mapped drive, doesn't work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "j:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
This will work -
CoreWebView2CreationProperties1.BrowserExecutableFolder = "C:\Utilities\Microsoft.WebView2.FixedVersionRuntime.90.0.818.66.x64"
We run the application from a network share path instead of deploying to each users work station and would like to also store the fixed version binaries in the same network share path. Is there a way to make this work?
This is a known issue, according to Microsoft.
It seems WebView2's sandbox environement does not work (yet?) when launched from a network storage.
As an workarround, may disable sandbox using the additional browser arguments or set the environement variable WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS as --no-sandbox before webview initialization.
Sample code in Delphi:
SetEnvironmentVariable('WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS', '--no-sandbox');
EdgeBrowser.BrowserExecutableFolder := '\\unc\path\or\network\drive';
EdgeBrowser.CreateWebView;
Note, this might be a security risk in case if you will access untrusted websites.

WPF Click-Once deployment promoting from stage to production

I've a WPF Application that actually uses a Web server for downloading the app and execute it on the client... I've also created a staging enviorment for that application when I put the release as soon as new features are added / bug fixed.
I've not found a reasonable way of promoting from staging to production since the app.config is hashed... so I can't change my pointments (DB/Services) editing it...
My actual way is publishing for staging, increasing of 1 the publish version and publishing for production...but this is quite frustrating.... since I've to do twice the work...any sugeestion?
Thanks
Our team encountered the same situation a year ago. We've solved the situation by following this steps:
Determine the latest ClickOnce application version;
Removing the *.deploy extensions;
Making the necessary *.config file changes;
Updating the manifest file (*.manifest) by using 'Mage.exe' and your certificate (see also: MSDN);
Update the deployment manifest (*.application) in the application version directory and in the root directory, again by using 'Mage.exe';
Adding back the *.deploy extensions.
Hereby a short code sample for calling Mage, really not that complicated though.
// Compose the arguments to start the Mage tool.
string arguments = string.Format(
#"-update ""{0}"" -appmanifest ""{1}"" -certfile ""{2}""",
deploymentManifestFile.FullName,
applicationManifestFile.FullName,
_certificateFile);
// Add password to the list of arguments if necessary.
arguments += !string.IsNullOrEmpty(_certificateFilePassword) ? string.Format(" -pwd {0}", _certificateFilePassword) : null;
// Start the Mage process and wait it out.
ProcessStartInfo startInfo = new ProcessStartInfo(_mageToolPath, arguments);
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
Process mageProcess = Process.Start(startInfo);
mageProcess.WaitForExit();
// Show all output of the Mage tool to the current console.
string output = mageProcess.StandardOutput.ReadToEnd();
// Determine the update of the manifest was a success.
bool isSuccesfullyConfigured = output.ToLower().Contains("successfully signed");

Not able to deploy database on App Harbor

I am trying to deploy an instance which is getting the following build error on App Harbor
Build FAILED.
"D:\temp\gcp22bmp.ggi\input\src\ShareBill.sln" (default target) (1) ->
"D:\temp\gcp22bmp.ggi\input\src\Sharebill.Database\Sharebill.Database.dbproj" (default target) (5) ->
D:\temp\gcp22bmp.ggi\input\src\packages\TeamData\Microsoft.Data.Schema.SqlTasks.targets(5,3): error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\TeamData\Microsoft.Data.Schema.TSqlTasks.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk. [D:\temp\gcp22bmp.ggi\input\src\Sharebill.Database\Sharebill.Database.dbproj]
0 Warning(s)
1 Error(s)
I know this is because the sql targets that are generally present here - C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\TeamData
are not present on the deployment server.
What should I do to deploy the data base now? Is there any other way to deploy the database. I have not used code first in EF, but I still want to have db migrations automatically applied.
I am assuming that if i get the db project running it would automatically find the schema differences and apply the changes to the database.
I host a project on AppHarbor and use FluentMigrator to deploy my database changes.
It is really easy to implement, just follow the documentation you can use their fluent interface or even just use it to execute sql.
As an example I run the following from my Application_Start of my Global.asax.cs - just put you migrations in the same assembly as the NOP MigrationMarker class:
const string connectionString = #"Data Source=localhost, 1433;Initial Catalog=testdb;Integrated Security=SSPI;";
Announcer announcer = new TextWriterAnnouncer(s => System.Diagnostics.Debug.WriteLine(s));
announcer.ShowSql = true;
var assembly = Assembly.GetAssembly(typeof(MigrationMarker));
var migrationContext = new RunnerContext(announcer);
var options = new ProcessorOptions
{
PreviewOnly = false, // set to true to see the SQL
Timeout = 60
};
var factory = new SqlServer2008ProcessorFactory();
var processor = factory.Create(connectionString, announcer, options);
var runner = new MigrationRunner(assembly, migrationContext, processor);
runner.MigrateUp(true);

Is it possible to launch a Silverlight 4 OOB application from a web page? [duplicate]

This question already has an answer here:
Launch Silverlight Out-of-Browser from browser post-installation
(1 answer)
Closed 2 years ago.
I'm planning to build a download manager application and would like to be able to launch the application when a user clicks a button the site. The application would obviously already need to be installed on the client machine.
There are a few reasons why this needs to be written using Silverlight, but they're not really relevant to the question. I only mention it so that people don't suggest that I use another technology.
Doing a bit of a mash up from two other posts [1] and [2].
But of course this will only work for Windows not Mac. There you will have to fallback to the #michael-s-scherotter style solution.
private void Button_Click(object sender, RoutedEventArgs e)
{
if (Application.Current.HasElevatedPermissions && System.Windows.Interop.ComAutomationFactory.IsAvailable)
{
string run = "\""%ProgramFiles%\\Microsoft Silverlight\\sllauncher.exe"\" /emulate:"Silverface.xap" /origin:\"http://www.silverlight.net/content/samples/apps/facebookclient/ClientBin/Silverface.xap\" /overwrite";
dynamic cmd = ComAutomationFactory.CreateObject("WScript.Shell");
cmd.Run(run, 1, true);
}
}
Yes. Here is an example:
http://www.silverlight.net/content/samples/apps/facebookclient/sfcquickinstall.aspx
I found a trick that launches the installed silverlight OOB from the silverlight app in-browser. Both applications should be singed and have the elevated trust.
When a user installs the silverlight OOB App first time, retrive the path and argument values from the shortcut file of the OOB app on desktop. (ref: How I can use Shell32.dll in Silverlight OOB) If you know the the path and argument values, you can launch the OOB app using Com Object.
Send the retrive the path and argument values to the silverlight App in-browser. (ref: http://msdn.microsoft.com/en-us/library/dd833063(v=vs.95).aspx)
Store the path and argument values in a cookie.
Now, the silverlight app in-browser is able to launch the silverlight OOB using the path and argument values in the cookie.
using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))
{
shell.Run(launchPath);
}
I hope this trick is useful to you :)
It is possible if you agree to install the app each time the user clicks on it.
You also should set the app to require elevated trust in its OOB settings.
Just uninstall the app on startup (for example, in main window constructor):
if (Application.Current.HasElevatedPermissions && Application.Current.InstallState == InstallState.Installed)
{
string launcherPath = string.Empty;
using (dynamic shell = AutomationFactory.CreateObject("Shell.Application"))
{
string launcher64 = #"C:\Program Files (x86)\Microsoft Silverlight";
string launcher32 = #"C:\Program Files\Microsoft Silverlight";
dynamic folder64 = shell.NameSpace(launcher64);
if (folder64 != null)
{
launcherPath = launcher64;
}
else
{
dynamic folder32 = shell.NameSpace(launcher32);
if (folder32 != null)
{
launcherPath = launcher32;
}
}
}
using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))
{
var origin = Application.Current.Host.Source.OriginalString;
var launchCmd = string.Format(#"""{0}\sllauncher.exe"" /uninstall /origin:""{1}""", launcherPath, origin);
shell.Run(launchCmd);
}
}
(the code for uninstall was taken from this post: http://www.wintellect.com/blogs/sloscialo/programmatically-uninstalling-silverlight-out-of-browser-application)

Will Prism OnDemand module loading work in an OOB scenerio?

Should the loading of OnDemand Prism modules work in an OOB scenerio? If so, I cannot seem to make it work. Everything is currently working in browser without any problems. Specifically I:
register my modules in code:
protected override IModuleCatalog GetModuleCatalog() {
var catalog = new ModuleCatalog();
Uri source;
if( Application.Current.IsRunningOutOfBrowser ) {
source = IsolatedStorageSettings.ApplicationSettings[SOURCEURI] as Uri;
}
else {
var src = Application.Current.Host.Source.ToString();
src = src.Substring( 0, src.LastIndexOf( '/' ) + 1 );
source = new Uri( src );
IsolatedStorageSettings.ApplicationSettings[SOURCEURI] = source;
IsolatedStorageSettings.ApplicationSettings.Save();
}
if( source != null ) {
var mod2 = new ModuleInfo { InitializationMode = InitializationMode.OnDemand,
ModuleName = ModuleNames.mod2,
ModuleType = "mod2.Module, mod2.Directory, '1.0.0.0', Culture=neutral, PublicKeyToken=null" ),
Ref = ( new Uri( source, "mod2.xap" )).AbsoluteUri };
catalog.AddModule( mod2 );
}
// per Jeremy Likeness - did not help.
Application.Current.RootVisual = new Grid();
return ( catalog );
}
later request for the module to be loaded is made:
mModuleManager.LoadModule( ModuleNames.mod2 );
and wait for a response to an event published during the initialization of that loaded module.
The module appears to never be loaded, and when the application is running under the debugger there will be a message box that states that the web server returned a 'not found' error. I can take the requesting url for the module and enter it into Firefox and download the module with no problem.
I have not been able to find any reference to this actually being workable, but it seems as though it should. The most I have found on the subject is a blog entry by Jeremy Likeness, which covers loading modules in MEF, but applying his knowledge here did not help.
The server is localhost (I have heard it mentioned that this might cause problems). The server has a clientaccesspolicy.xml file - although I don't expect that is needed.
I am using the client stack and register it during app construction:
WebRequest.RegisterPrefix( Current.Host.Source.GetComponents( UriComponents.SchemeAndServer, UriFormat.UriEscaped ), WebRequestCreator.ClientHttp );
Followup questions:
Can all of the xaps be installed to the client desktop in some manner - or only the main application xap? specify them in appmanifest.xml somehow??
Is it worth it make this work if only the application.xap is installed and the rest of the xaps must be downloaded anyway?
Once I worked on a similar scenario. The trick is having the modules stored in isolated storage and use a module loader that reads from isolated storage when working offline.
This is because otherwise, you can't get download the modules that are in a different .xap file than the Shell.
Thanks,
Damian
It is possible to hook custom module loaders into Prism if you're willing to tweak the Prism source and build it yourself. I was actually able to get this to work pretty easily - in our app, I look on disk first for the module, and if it's not found, I fall back to loading it from the server via a third-party commercial HTTP stack that supports client certificates.
To do this, download the Prism source code, and locate the Microsoft.Practices.Composite.Modularity.XapModuleTypeLoader class. This class uses another Prism class, Microsoft.Practices.Composite.Modularity.FileDownloader, to download the .xap content; but it instantiates it directly, giving you no chance to inject your own or whatever.
So - in XapModuleTypeLoader, I added a static property to set the type of the downloader:
public static Type DownloaderType { get; set; }
Then I modified the CreateDownloader() method to use the type specified above in preference to the default one:
protected virtual IFileDownloader CreateDownloader() {
if (_downloader == null) {
if (DownloaderType == null) {
_downloader = new FileDownloader();
} else {
_downloader = (IFileDownloader)Activator.CreateInstance(DownloaderType);
}
}
return _downloader;
}
When my app starts up, I set the property to my own downloader type:
XapModuleTypeLoader.DownloaderType = typeof(LocalFileDownloader);
Voila - now Prism calls your code to load its modules.
I can send you my LocalFileDownloader class as well as the class it falls back to to load the .xap from the web if you're interested... I suspect though that if you look at Prism's FileDownloader class you'll see that it's simple enough.
With regard to your other questions, the clientaccesspolicy.xml file is probably not needed if the URL the app is installed under is the same one you're talking to, or if you're in elevated trust.
The .xaps can definitely be pre-installed on the client, but it's a bit of work. What we did was write a launcher app that is a standalone .NET 2.0 desktop app. It downloads the main .xap plus certain modules* (checking for updates and downloading only as needed), then uninstalls/reinstalls the app if necessary, then launches the app. The last two are done via sllauncher.exe, which is installed as part of Silverlight. Here's a good intro to that: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx.
Assuming you're running under elevated trust, it should also be possible to pre-fetch the module .xaps from within the SL client, but before they're actually requested due to user action. You'd just need to put them in a folder under My Documents somewhere, and then use the custom module loading approach described above to pull them from there.
*In our case, our main .xap is 2/3 of the application. The rest of our .xaps are small, so we download them on-the-fly, with the exception of some .xaps we created as containers for third-party components. We don't expect to update those very often, so we pre-install them.

Resources