Can't upgrade settings when updating a WPF Desktop Bridge Universal app - c#

My app is written in WPF C# and I export it as Universal app using MSIX Application Project straight from Visual Studio.
I just can't get the settings to persist between updates. I'm using the following code in the MainWindow_Loaded event:
Settings.Default.Upgrade();
Settings.Default.Save();
Settings.Default.Reload();
I tried keeping assembly information versions the same and just increment the version in the appx.manifest but it doesn't work.
I've noticed that each time the app updates it creates a new uniquely named parent settings folder (with a new hash every time) and the subfolder name is the version from the assembly. The folder structure is like this:
App.exe_Url_dfvfmfjs1qo33zsag1ay5w1s0rwg0u53/0.2.10.0/user.config
App.exe_Url_tazrvujdga5ujjarnahpkoscv5zbkgl0/0.2.10.0/user.config
I believe it might have to do with the fact that it keeps generating new hashes instead of just placing the new version as a subfolder and that's why Upgrade doesn't do anything.
The only information I've found so far is to use Settings.Default.Upgrade()
How am I supposed to transfer the old version settings to the new version when my universal desktop bridge app updates?

As far as I researched these settings do not transfer to UWP updates using Desktop Bridge. So I started using UWP's native ApplicationData.Settings
As a workaround I created 2 methods to update the newly created WPF settings using LocalSettings which is the UWP equivalent and vice versa. UWP's LocalSettings transfer on update. I call Update() when I save my WPF settings and I call Load() when the application starts. It works.
Here's the code, only caveat I've found so far is you should use the basic types as these methods will fail transferring something like a List<string> or a StringCollection, for that I'm using serialization, although you can always adapt them to do that too:
static class UWPSettings
{
public static void Update()
{
if (Startup.IsUniversalPlatform)
{
foreach (SettingsPropertyValue value in Properties.Settings.Default.PropertyValues)
{
ApplicationData.Current.LocalSettings.Values[value.Name] = value.PropertyValue;
}
}
}
public static void Load()
{
if (Startup.IsUniversalPlatform)
{
foreach (var setting in ApplicationData.Current.LocalSettings.Values)
{
foreach (SettingsPropertyValue s in Properties.Settings.Default.PropertyValues)
{
if (s.Name == setting.Key)
{
s.PropertyValue = setting.Value;
}
}
}
Properties.Settings.Default.Save();
}
}
}

Related

C#.NET 6.0 - Load Class Library from file if newer version

I'm new to using class libraries. I've started a rather large project for work which needs the ability to be a self-contained file (essentially just drop a .exe on a desktop and run it without prereqs). This means the current class libraries build inside the .exe and I'm unsure how to directly reference them - but the application knows of them and uses them.
I've so far coded the project with the separate class libraries, and it all works great, but I'm now at the part where I need to add the ability for this to load the contents of a file dynamically if the file is available and of a greater file version.
For example:
File.dll v1 is self-contained
File.dll v2 is added to C:\ProgramData\FileVersions (dynamicdLLPath)
Assembly fileDll;
private void LoadDynamicDLLs()
{
if (Directory.Exists(dynamicDLLPath))
{
string filePath = dynamicDLLPath + "File.dll";
if (File.Exists(filePath))
{
FileVersionInfo curfvi = FileVersionInfo.GetVersionInfo(myassembly.Location);
FileVersionInfo newfvi = FileVersionInfo.GetVersionInfo(filePath);
if (Convert.ToInt64(newfvi.FileVersion) > Convert.ToInt64(curfvi.FileVersion))
{
fileDll = Assembly.LoadFrom(filePath);
}
} else
{
fileDll = Assembly.GetAssembly(typeof(FileDLL));
}
}
}
(FileDLL in this instance is the namespace of the self-contained dll)
If this loads correctly, can I then just call all my methods/functions from the file assembly as;
fileDll.myMethod();
This is as far as I've gotten based on not changing any of the existing code base that works. I'd rather not go through 20,000 lines if there's a solution to simply integrate what I've already got using a local .dll class library.

Can I check available storage in the Device on Xamarin Forms?

I am trying to make an app that requires that I frequently send recorded data to a firebase. When network goes out or battery is about to die, I am saving all of the data that wasn't stored into firebase locally. However, to do this I require about 20 MB of data (my data is pretty big). That being said, I want to find a way to check the available storage (and the battery if possible) to give the user a warning. Is this possible using Xamarin Forms? Also, is there a way that I can make this solution universal (i.e. I don't need a separate piece of code for iOS vs. Android)? (I am new to Xamarin and C#)
Use the following code to check the free size of a device:
For iOS:
NSFileManager.DefaultManager.GetFileSystemAttributes (Environment.GetFolderPath (Environment.SpecialFolder.Personal)).FreeSize;
For Android:
var freeExternalStorage = Android.OS.Environment.ExternalStorageDirectory.UsableSpace;
There is no universal option, but you can wrap it an interface like so and implement it on each project:
public interface IStorage
{
double GetRemainingStorage();
}
It would be great if a feature like this could be added in Xamarin.Essentials - there was a request on GitHub but it never really made it.
If there are any issues with the code - please tell me.
Hope this helped,
Instructions
Create an interface in your shared project titled IStorage.
In your Android project create a class titled AndroidStorageManager (you can name it however you would like). Make it so it extends IStorage. The method GetRemainingStorage() should be of return type double.
public class AndroidStorageManager : IStorage
{
public double GetRemainingStorage()
{
var freeExternalStorage = Android.OS.Environment.ExternalStorageDirectory.UsableSpace;
return freeExternalStorage;
}
}
For iOS
Create a class in your iOS project titled iOSStorageManager which extends IStorage:
public class iOSStorageManager : IStorage
{
public double GetRemainingStorage()
{
return NSFileManager.DefaultManager.GetFileSystemAttributes(Environment.GetFolderPath(Environment.SpecialFolder.Personal)).FreeSize;
}
}
In your Android implementation - add the following code above the namespace:
[assembly: Xamarin.Forms.Dependency(
typeof(AndroidStorageManager))]
For iOS:
[assembly: Xamarin.Forms.Dependency(
typeof(iOSStorageManager))]
To get the storage:
IStorage storageManager = DependencyService.Get<IStorage>();
double remaining = storageManager.GetRemainingStorage();
Hope this clarified things.

Does the Visual Studio OneClick publisher change the byte array needed for RSA encryption?

I'm trying to publish a COM add-in for Word and need to have a license file. I'm using Rhino Licensing and the file has no issues during debugging, but when using OneClick to publish the add-in the license is reported as no longer valid. Here is the code for the class I'm using to check the license:
using System;
using System.IO;
using Rhino.Licensing;
namespace Services.Licensing
{
public class LicenseChecker
{
private static string PublicKeyPath;
private static string LicensePath;
public static bool LicenseIsValid(string licPath)
{
bool result = false;
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
String Root = Directory.GetCurrentDirectory();
PublicKeyPath = Root + #"\Licensing\publicKey.xml";
LicensePath = Root + #"\Licensing\license.xml"; //licPath;
// not working on INSTALL, runs fine in debug
try
{
var publicKey = File.ReadAllText(PublicKeyPath);
//Throws an exception if license has been modified
LicenseValidator validator = new LicenseValidator(publicKey, LicensePath);
validator.AssertValidLicense();
if (validator.ExpirationDate > DateTime.Now)
{
result = true;
}
}
catch
{ }
return result;
}
}
}
I'm trying to bundle the license with the exe I'll be giving to a small testing group to save the testers unnecessary trouble managing the license and public key. Currently I have the (valid) license file and public key as embedded resources, set to "copy always."
I'm having the same issue when the license is not bundled with the published exe, but the public key is. When both files are left outside of the solution, there seems to be no problem. Could publishing the solution be changing the byte array of the public key or the license?
I'm using .Net Framework 4.7.2 and Visual Studio 2019.
After a lot of toying, the broad answer seems to be no, ClickOnce publishing does not affect the byte array.
The error seems to be occurring because the ClickOnce is not copying XML files into the Application Files folder it creates at all.
After pulling the licenses into a desktop folder and having the program call them from there, another class that uses XML files to load list items would not initialize, leading me to put Try{} around all functions that use pre-made XML files in my program. Each of these functions returned the Catch{}. I'm assuming that ClickOnce is too simplistic an installer to be used if you are trying to include many/any resource files, especially if they are XML.

Take picture with Windows 10, WinRT

hope its something simple stupid, but I am spinning my wheels.
I have a Surface Pro 4, Windows 10 and using Visual Studio 2013 Professional.
Developing WPF using C# 4.5.
In summary, all I am trying to do a simple camera capture to save an image without resorting to other 3rd party libraries I have no control over. The rest of this post are details of other research findings that I HAVE looked into and tried working out and what has failed and what such message from the compiler.
Again, simple camera, capture picture, save to disk, but all the async-await options appear to throw compiler errors.
EDIT 1 SAMPLE CODE
Here is code from the WPF form. I do not even have any control in the form as I can not even get the 'await' to compile.
using System;
using Windows.Media.Capture;
using System.Windows;
namespace CameraCapture
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
JustDoIt();
}
private MediaCapture _mediaManager;
private async void JustDoIt()
{
//initialize mediacapture with default camera
_mediaManager = new MediaCapture();
await _mediaManager.InitializeAsync();
if (_mediaManager == null)
MessageBox.Show("Failed Initialize");
await _mediaManager.StartPreviewAsync();
}
}
}
And my project also has per other links researched from below, the dlls for
System.Runtime.dll and
System.Runtime.WindowsRuntime.dll
Compile error for each of the 'await'
Error 1 'await' requires that the type 'Windows.Foundation.IAsyncAction' have a suitable GetAwaiter method. Are you missing a using directive for 'System'?
and I have "using System;" as the first line. Is there some other "await" going on when using WinRT vs default System include?
END OF EDIT
I started with https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.capture.cameracaptureui.aspx
CameraCaptureUI class
I then found this link https://www.eternalcoding.com/?p=183
How to use specific WinRT API from Desktop apps
I tried going through all the steps as outlined and getting errors associated with
await ... have a suitable GetAwaiter method.
So, I looked up about asynch and await and came across
How and When to use `async` and `await`
how and when to use async and await.
So, I scrapped the first camera capture project, started a new, and did that version
that has simple thread.sleep delay to show the concept of asynch / await. That part works.
So now, I add back the reference to the project and manually edit to add the
<PropertyGroup>
<TargetPlatformVersion>8.0</TargetPlatformVersion>
</PropertyGroup>
to expose the References expose the Windows / Core per the first link and then getting access to the Windows.Media, Windows.Storage. I add in just the first little bit of code about the CameraCaptureUI and CaptureFileAsync as just a starting point such as...
private async void Camera1()
{
var cameraUi = new Windows.Media.Capture.CameraCaptureUI();
var capturedMedia = await cameraUi.CaptureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.Video);
if (capturedMedia == null)
return;
MessageBox.Show("Valid Camera");
}
and get a compile error about:
'await' requires that the type
'Windows.Foundation.IAsyncOperation'
have a suitable GetAwaiter method.
Are you missing a using directive for 'System'?
Also, back to the original Windows version attempt via
private async void Camera2()
{
CameraCaptureUI dialog = new CameraCaptureUI();
Windows.Foundation.Size aspectRatio = new Windows.Foundation.Size(16, 9);
dialog.PhotoSettings.CroppedAspectRatio = aspectRatio;
StorageFile file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (file == null)
return;
MessageBox.Show("Valid Storage File Captured");
}
I even have System.Runtime and System.RunTime.WindowsRuntime as references to the project but still fail on compile.
What am I missing. I know things change between different versions such as Windows 8.1 and Windows 10, and upgrades to features / libraries, but why await works one way, but not another.
For those scratching their heads as I did, I finally came across another post that had a missing link...
How can i import windows.media.capture in my WPF project?
The difference was the
<TargetPlatformVersion>8.1</TargetPlatformVersion>
instead of 8.0.
8.1 showed many of the individual .dll references of Foundation, Media, etc but not the single "Windows" dll.
Once changed to 8.1 and recognized the WINDOWS dll, all worked with respect to the media manager or CameraCaptureUI options.

Reading user settings from another application

I have a windows application that writes user settings using the method described here:
http://msdn.microsoft.com/en-us/library/bb397755(v=vs.110).aspx
These settings are saved to a file in the users directory e.g:
c:\users\{you name}\Local\{Company}\{product}\user.config
I need to access these settings in a companion console application. Is this possible, at the moment the settings return null when I try to access them from the console application.
The code itself will look something like this:
To save the settings in App1:
namespace Application1{
public class DemoSave{
public void DoWork(){
Application1.Properties.Settings.Default.CustomSettings.Title ="someValue";
Application1.Properties.Settings.Default.Save();
}
}
}
To read the settings in another app:
namespace Application2{
public class Demo{
public void DoWork(){
var title = Application1.Properties.Settings.Default.CustomSettings.Title;
}
}
}
In Application2 the Application1.Properties.Settings.Default.CustomSettings property is null.
Last time I did something similar, I had two projects in a solution (a windows service and a wpf application), and I had to reference the WPF app in the Win Service project to access it's settings (I assume you're talking about Namespace.Properties.Settings). It seems to have worked fine for me. In this case i had to set the access modifier on the settings to public though. I'm not sure if this is the best way, but it worked for me for something very small and insignificant.
Are you even sure your pointing at the right place when you modifies/read the settings files.
Because that might be why it doesn't work.

Categories

Resources