I am developing a reasonably complex process control background application on a Pi 3 (using c#, VC 2015). This is being developed and tested in a modular manner (display, user input, gpio extender boards, various types of sensors, relays, network comms, etc). Each module is built as a separate DLL and tested with its own background test app.
My problem is that I need to maintain a common set of data across all modules, particularly a set of application parameters. Also local storage as a cache for results and logging. So several different applications need to access this data during development - but only one at a time. Obviously in the final project, there will be a single application, so no problem.
I have been amazed to find that Win IoT does not seem to allow a simple file to be accessible to different applications. App Services and other inter-app communications all seem to be at the transaction level and not appropriate here. To build an app services facility to handle all I/o would be tedious(not ultimately required).
Does anyone have an idea as to how this situation could be managed sensibly, please?
Due to File access permissions of UWP app. Reading data from a file in local storage seems unreachable.
So, if you are willing to use a removable device(external storage) attached to the Raspberry Pi and store your application parameters in a file, like a text file, and read the data from your apps.
I test the following code(UWP app) on desktop and read data successfully from multi apps. I am sure that you can read data on Raspberry Pi from one app but I didn't test multi apps. You can have a try. If there is any concern please feel free let me know.
Task.Run( async () =>
{
var removableDevices = KnownFolders.RemovableDevices;
var externalDrives = await removableDevices.GetFoldersAsync();
var drive0 = externalDrives[0];
var testFolder = await drive0.GetFolderAsync("test");
var SharedDateFile = await testFolder.GetFileAsync("data.txt");
var data = await FileIO.ReadTextAsync(SharedDateFile);
System.Diagnostics.Debug.WriteLine(data);
});
In the app manifest, you need specify the Removable Storage capability and register at least one File Type Association declaration.
UPDATE:
Using publisher folder is the better solution. First, add the following extension in Package.appxmanifest:
<Extensions>
<Extension Category="windows.publisherCacheFolders">
<PublisherCacheFolders>
<Folder Name="Folder1"/>
</PublisherCacheFolders>
</Extension>
</Extensions>
Then write and read file like this:
//Write file
var folder = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("Folder1");
var file = await folder.CreateFileAsync("settings.txt", Windows.Storage.CreationCollisionOption.OpenIfExists);
await FileIO.WriteTextAsync(file,"Hello writen by app1");
//Read file
var folder = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("Folder1");
var file = await folder.GetFileAsync("settings.txt");
var text = await FileIO.ReadTextAsync(file);
System.Diagnostics.Debug.WriteLine(text);
Related
I am utilizing Syncfusion's PdfViewerControl and PdfLoadedDocument classes to generate thumbnail images of a PDF. However, once I moved the project to an Azure App Service, the PdfViewerControl is throwing an exception when being initialized. I am curious if it is attempting to use system memory and Azure is blocking this. Below is the method GenerateThumbnails I've created and the exception is being thrown when creating a new PdfViewerControl. If anyone has a work around for this or has experienced something similar when moving to Azure, any assistance would be greatly appreciated.
Along with that, if someone knows of another tool to create thumbnails from a PDF in this manner that'd be very helpful as well. Thanks!
Exception:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
Method:
public static List<Byte[]> GenerateThumbnails(Byte[] file)
{
Int32 resizedHeight;
Int32 resizedWidth;
List<Byte[]> thumbnails = new List<Byte[]>();
using (PdfViewerControl pdfViewerControl = new PdfViewerControl())
using (PdfLoadedDocument pdfLoadedDocument = new PdfLoadedDocument(file, true))
{
// The PDF Viewer Control must load the PDF from a PdfLoadedDocument, rather than directly from the filename because
// when loaded from the filename, it is not disposed correctly and causes a file lock.
pdfViewerControl.Load(pdfLoadedDocument);
for (Int32 i = 0; i < pdfViewerControl.PageCount; ++i)
{
using (Bitmap originalBitmap = pdfViewerControl.ExportAsImage(i))
{
if (pdfViewerControl.LoadedDocument.Pages[i].Size.Width > pdfViewerControl.LoadedDocument.Pages[i].Size.Height)
{
resizedHeight = (PdfUtility.TARGET_THUMBNAIL_WIDTH_LANDSCAPE * originalBitmap.Height) / originalBitmap.Width;
resizedWidth = PdfUtility.TARGET_THUMBNAIL_WIDTH_LANDSCAPE;
}
else
{
resizedHeight = PdfUtility.TARGET_THUMBNAIL_HEIGHT_PORTRAIT;
resizedWidth = (PdfUtility.TARGET_THUMBNAIL_HEIGHT_PORTRAIT * originalBitmap.Width) / originalBitmap.Height;
}
using (Bitmap resizedBitmap = new Bitmap(originalBitmap, new Size(resizedWidth, resizedHeight)))
using (MemoryStream memoryStream = new MemoryStream())
{
resizedBitmap.Save(memoryStream, ImageFormat.Jpeg);
thumbnails.Add(memoryStream.ToArray());
}
}
}
}
return thumbnails;
}
Update
Web App for Containers on Windows is now supported. This allows you to bring your own docker container that runs outside of the sandbox, so the restrictions described below won't affect your application.
There are restrictions in the sandbox that the app is running in that prevents certain API calls.
Here is a list of frameworks and scenarios that have been found to be
not be usable due to one or more of the restrictions above. It's
conceivable that some will be supported in the future as the sandbox
evolves.
PDF generators failing due to restriction mentioned above:
Syncfusion Siberix Spire.PDF The following PDF generators are
supported:
SQL Reporting framework: requires the site to run in Basic or higher
(note that this currently does not work in Functions apps in
Consumptions mode) EVOPDF: See
http://www.evopdf.com/azure-html-to-pdf-converter.aspx for vendor
solution Telerik reporting: requires the site to run in Basic or
higher. More info here Rotativa / wkhtmltopdf: requires the site to
run in Basic or higher. NReco PdfGenerator (wkhtmltopdf): requires
subscription plan Basic or higher Known issue for all PDF generators
based on wkhtmltopdf or phantomjs: custom fonts are not rendered
(system-installed font is used instead) because of sandbox GDI API
limitations that present even in VM-based Azure Apps plans (Basic or
higher).
Other scenarios that are not supported:
PhantomJS/Selenium: tries to connect to local address, and also uses
GDI+.
https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox
Im creating a web extension and porting from XUL. I used to be able to easily read files with
var dJsm = Components.utils.import("resource://gre/modules/Downloads.jsm").Downloads;
var tJsm = Components.utils.import("resource://gre/modules/Task.jsm").Task;
var fuJsm = Components.utils.import("resource://gre/modules/FileUtils.jsm").FileUtils;
var nsiPromptService = Components.classes["#mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
....
NetUtil.asyncFetch(file, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
return;
}
var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
var data = window.btoa(data);
var encoded_data_to_send_via_xmlhttp = encodeURIComponent(data);
...
});
This above will be deprecated.
I can use the downloads.download() to know what was the last download but I can NOT read the file and then get the equivalent for encoded_data_to_send_via_xmlhttp
Also in Firefox 57 onwards, means that I have to try to fake a user action by a button click or something, or upload a file.
Access to file:// URLs or reading files without any explicit user input
isnt there an easy way to read the last downloaded file?
The WebExtension API won't allow extensions to read local files anymore. You could let the extension get CORS privilege and read the content directly from the URL via fetch() or XMLHttpRequest() as blob and store directly to IndexedDB or memory, then encode and send to server. This comes with many restrictions and limitations such as to which origin you can read from and so forth.
Also, this would add potentially many unneeded steps. If the purpose is, as it seem to be in the question at the moment, to share the downloaded file with a server, I would instead suggest that you obtain the last DownloadItem object, extract the URL (.url) from that object and send the URL back to server.
This way the server can load directly from that URL (and encode it on server if needed). The network load will be about the same (a little less actually since there is no Base64 encoding involved which adds 33% to the size), and much less load on the client. The server would read the data as a binary/byte data stream; about the same as if the data was sent directly from the extension.
To obtain the last downloaded file you would do the following from a privileged script:
browser.downloads.search({
limit: 1,
orderBy: ["-startTime"]
})
.then(getLastDownload);
function getLastDownload(downloads) {
if (downloads.length) {
var url = downloads[0].url;
// ... send url to the server and let server fetch the data from it directly
}
}
According to this support mozilla question.
(2) Local file security
Firefox limits access from pages on web servers to pages on local disk or UNC paths. [...]).
Which solution ?
Use local-filesystem-links firefox addon (not tested)
and/or
run a small local webserver on client side, supposing server was run with sufficient privileges, you may finally access any local content via http:// (but still cannot with file:///)
I have a simple Xamarin Forms app. I've now got a simple POCO object (eg. User instance or an list of the most recent tweets or orders or whatever).
How can I store this object locally to the device? Lets imagine I serialize it as JSON.
Also, how secure is this data? Is it part of Keychains, etc? Auto backed up?
cheers!
You have a couple options.
SQLite. This option is cross-platform and works well if you have a lot of data. You get the added bonus of transaction support and async support as well. EDIT: In the past I suggested using SQLite.Net-PCL. Due to issues involving Android 7.0 support (and an apparent sunsetting of support) I now recommend making use of the project that was originally forked from: sqlite-net
Local storage. There's a great nuget that supports cross-platform storage. For more information see PCLStorage
There's also Application.Current.Properties implemented in Xamarin.Forms that allow simple Key-Value pairs of data.
I think you'll have to investigate and find out which route serves your needs best.
As far as security, that depends on where you put your data on each device. Android stores app data in a secure app folder by default (not all that secure if you're rooted). iOS has several different folders for data storage based on different needs. Read more here: iOS Data Storage
Another option is the Xamarin Forms settings plugin.
E.g. If you need to store a user instance, just serialize it to json when storing and deserialize it when reading.
Uses the native settings management
Android: SharedPreferences
iOS: NSUserDefaults
Windows Phone: IsolatedStorageSettings
Windows RT / UWP: ApplicationDataContainer
public User CurrentUser
{
get
{
User user = null;
var serializedUser = CrossSettings.Current.GetValueOrDefault<string>(UserKey);
if (serializedUser != null)
{
user = JsonConvert.DeserializeObject<User>(serializedUser);
}
return user;
}
set
{
CrossSettings.Current.AddOrUpdateValue(UserKey, JsonConvert.SerializeObject(value));
}
}
EDIT:
There is a new solution for this. Just use Xamarin.Essentials.
Preferences.Set(UserKey, JsonConvert.SerializeObject(value));
var user= JsonConvert.DeserializeObject<User>(Preferences.Get(UserKey, "default_value");
Please use Xamarin.Essentials
The Preferences class helps to store application preferences in a key/value store.
To save a value:
Preferences.Set("my_key", "my_value");
To get a value:
var myValue = Preferences.Get("my_key", "default_value");
If you want to store a simple value, such as a string, follow this Example code.
setting the value of the "totalSeats.Text" to the "SeatNumbers" key from page1
Application.Current.Properties["SeatNumbers"] = totalSeats.Text;
await Application.Current.SavePropertiesAsync();
then, you can simply get the value from any other page (page2)
var value = Application.Current.Properties["SeatNumbers"].ToString();
Additionally, you can set that value to another Label or Entry etc.
SeatNumbersEntry.Text = value;
If it's Key value(one value) data storage, follow below code
Application.Current.Properties["AppNumber"] = "123"
await Application.Current.SavePropertiesAsync();
Getting the same value
var value = Application.Current.Properties["AppNumber"];
I have an app that needs to include a links to a second app in the same phone.
If the app is not installed the link should point to the windows store to install it (that part is working fine).
But if the app is already installed the link should go straight to the app and open it. How can I do that?
The app has two versions one form WP7 and other from WP8. if the solution is different for them please point the difference.
Thanks for the help...
I believe a URI Association is what you want. You should be able to create a different association in your WP7 app and in your WP8 app, and handle them accordingly.
A URI association allows your app to automatically launch when another app launches a special URI.
Also note:
If you are interested only in launching your own apps, consider using
APIs from the Windows.Phone.Management.Deployment namespace. You can
use this API to check for other apps that you’ve published, and then
launch them if they’re installed.
You basically just need to update the WMAppManifest.xml file to include the URI Association and then listen for that URI. Example:
<Extensions>
<Protocol Name="contoso" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />
</Extensions>
Then you can use a custom URI Mapper to handle your association (full example in top link above):
public override Uri MapUri(Uri uri)
{
tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
// URI association launch for contoso.
if (tempUri.Contains("contoso:ShowProducts?CategoryID="))
{
// Get the category ID (after "CategoryID=").
int categoryIdIndex = tempUri.IndexOf("CategoryID=") + 11;
string categoryId = tempUri.Substring(categoryIdIndex);
// Map the show products request to ShowProducts.xaml
return new Uri("/ShowProducts.xaml?CategoryID=" + categoryId, UriKind.Relative);
}
// Otherwise perform normal launch.
return uri;
}
Hope this helps!
Is the secondary app one that you have created? If so, do something like this:
IEnumerable<Package> packages = InstallationManager.FindPackagesForCurrentPublisher();
foreach (Package package in packages)
{
if (package.Id.ProductId.ToString().ToLower() == "product id of secondary app")
{
//Launch the app
package.Launch();
}
}
Make sure that your publisher ids match in the WMAppManifest for both apps.
If this secondary app was published by someone else, you'll need to use a custom Uri schema. The app needs to have this feature added by the developer, you can't just launch any app.
I have Console application which submit messages to Azure queue. Now I am trying to migrate this application to Mobile, but met reference problem with CloudStorageAccount. It requires Windows dll version but mine is Mobile.
Do you guys have any idea how I can initialize CloudStorageAccount object alternative way?
public Initializator()
{
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
// for a console app, reading from App.config
configSetter(ConfigurationManager.ConnectionStrings[configName].ConnectionString);
});
CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("QueueStorage");
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
queueIn = queueClient.GetQueueReference("queuein");
queueOut = queueClient.GetQueueReference("queueout");
queueIn.CreateIfNotExist();
queueOut.CreateIfNotExist();
}
One of the easiest ways, in my opinion, to work with Windows Azure storage (tables, blobs, & queues) from Windows Phone is to use the Phone.Storage NuGet package (http://www.nuget.org/packages/Phone.Storage). This makes working with storage on the phone nearly identical to working with storage from a server (or console app).
Be sure to check out Wade Wegner's blog post at http://www.wadewegner.com/2011/11/nuget-packages-for-windows-azure-and-windows-phone-developers/ for some additional info on the NuGet packages.
There's also a Phone.Storage.Sample package that may be worth taking a look at.