After studying the manual of Visual C#, I'm starting to program a simple app for Windows 8. I'm using Visual Studio 2013 Express and .NET Framework 4.5.1. In the code I've written up to now, in the code-behind of a page I create a list of people:
private Dictionary<string, People> listPeople = new Dictionary<string, People>();
After this, I wish this list would fill a ComboBox control of another page. The solution I thought is to save the Dictionary<string, People> variable in roaming, and then use it where I need. In this way also would solve the problem of maintaining the list of people saved even when the app is terminated.
How can I do?
did you already try it like that?
var applicationData = Windows.Storage.ApplicationData.Current;
applicationData.RoamingSettings.Values["PeopleList"] = listPeople;
var applicationData = Windows.Storage.ApplicationData.Current;
var listPeople = (Dictionary<string, People>)applicationData.RoamingSettings.Values["PeopleList"];
The overwhelming advice is to serialize your setting as a string then set the value in Values (or save the values in the complex type individually).
But, I think that really ignores the fact that Values is a series of key-value pairs... If you want to support complex types, I think creating your own file in the roaming folder is a better idea. I've written a small helper class to accomplish this via JSON serialization:
public class ApplicationStorageHelper
{
private static readonly JsonSerializer jsonSerializer = JsonSerializer.Create();
public static async Task<bool> SaveData<T>(T data)
{
var file =
await ApplicationData.Current.RoamingFolder.CreateFileAsync("settings.dat", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (var outputStream = stream.GetOutputStreamAt(0))
{
using (var writer = new StreamWriter(outputStream.AsStreamForWrite()))
{
var jsonWriter = new JsonTextWriter(writer);
jsonSerializer.Serialize(jsonWriter, data);
return true;
}
}
}
}
public static async Task<T> LoadData<T>()
{
try
{
var file =
await ApplicationData.Current.RoamingFolder.GetFileAsync("settings.dat");
using (var inputStream = await file.OpenSequentialReadAsync())
{
using (var reader = new StreamReader(inputStream.AsStreamForRead()))
{
var jsonReader = new JsonTextReader(reader);
return jsonSerializer.Deserialize<T>(jsonReader);
}
}
}
catch (FileNotFoundException)
{
return default(T);
}
}
}
You'll have to reference JSON.Net from Nuget or some other way.
Related
Info and code:
I am designing a UI where the user can design an object to meet their needs. Afterwards, I want them to be able to click a button to download a file containing the JSON representation of this object. A jquery click listener will use ajax to hit the endpoint on the controller when the button is clicked. Currently, the endpoint looks like this:
// GET: api/Missions/DownloadMission?id
[HttpGet]
[Route("api/Missions/DownloadMission{id}")]
public IHttpActionResult DownloadMission(int id)
{
Mission toDownload = db.Missions.Find(id);
string json = JsonConvert.SerializeObject(toDownload);
}
As you can see, the mission object's Id is provided to controller, and the mission is grabbed from it. My problem is that I do not know how to convert the object into JSON in a way that I can then write said JSON into a file, and prompt the user to download it.
Things I have tried:
using (MemoryStream stream = new MemoryStream())
{
using (StreamWriter writer = new StreamWriter(stream))
{
while(missionJson.nex)
}
return File(stream, "text/plain");
}
//I tried playing around with this type of set up, but could still not get the intended results
byte[] bytes = System.IO.File.ReadAllBytes(data);
var output = new FileContentResult(bytes, "application/octet-stream");
output.FileDownloadName = "download.txt";
return output;
Mission toDownload = db.Missions.Find(id);
string fileName = #"~\Mission.txt";
try
{
if (File.Exists(fileName))
{
File.Delete(fileName);
}
using (FileStream fs = File.Create(fileName))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new JavaScriptDateTimeConverter());
serializer.NullValueHandling = NullValueHandling.Ignore;
using (StreamWriter sw = new StreamWriter(fileName))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, toDownload);
}
return File(fs, "Mission.txt");
}
}
catch (Exception Ex)
{
Console.WriteLine(Ex.ToString());
}
// In this case, "File()" isnt recognized, but this is probably the closest i've been
I have looked through questions such as this one
Problems:
Like I said earlier, I don't know how to go from object to Json to a file
basically all tutorials I can find online are very outdated, or require a filepath, presuming you are providing a pre-existing file, which I am not.
Like I said earlier, I don't know how to go from object to Json to a file
You can use the System.Text.Json namespace to serialize and deserialize JavaScript Object Notation (JSON).
string jsonString = JsonSerializer.Serialize(weatherForecast);
basically all tutorials I can find online are very outdated, or require a filepath, presuming you are providing a pre-existing file, which I am not.
You can return FileContentResult.
You can check the example below.
Code
[HttpGet("DownloadMission/{id}")]
public FileContentResult DownloadMission(int id)
{
Mission toDownload = new Mission { Id = 1, name = "test" };
string jsonString = JsonSerializer.Serialize(toDownload);
var fileName = "test.txt";
var mimeType = "text/plain";
var fileBytes = Encoding.ASCII.GetBytes(jsonString);
return new FileContentResult(fileBytes, mimeType)
{
FileDownloadName = fileName
};
}
Result
This could work for you:
[HttpGet]
[Route("api/Missions/DownloadMission{id}")]
public IHttpActionResult DownloadMission(int id)
{
var toDownload = db.Missions.Find(id);
// if you set this, the browser asks the user to save 'export.json'
HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=export.json");
// return content as json with your default json serializer settings
return new JsonResult(toDownload);
}
Like pointed out before, replace the IHttpActionResult with IActionResult, that's the right return type for ASP.NET Core.
I didn't try how it behaves with larger objects, maybe there is some optimization needed for that.
Alternatively you can also set the header in a more "fancy" way, that will properly escape your file name and gives you some additional properites to set.
HttpContext.Response.Headers.Add("Content-Disposition", new System.Net.Mime.ContentDisposition
{
FileName = "export.json",
Inline = false
}.ToString());
I am trying to process a very large amount of data (~1000 seperate files, each of them ~30 MB) in order to use as input to the training phase of a machine learning algorithm. Raw data files formatted with JSON and I deserialize them using JsonSerializer class of Json.NET. Towards the end of the program, Newtonsoft.Json.dll throwing 'OutOfMemoryException' error. Is there a way to reduce the data in memory, or do I have to change all of my approach (such as switching to a big data framework like Spark) to handle this problem?
public static List<T> DeserializeJsonFiles<T>(string path)
{
if (string.IsNullOrWhiteSpace(path))
return null;
var jsonObjects = new List<T>();
//var sw = new Stopwatch();
try
{
//sw.Start();
foreach (var filename in Directory.GetFiles(path))
{
using (var streamReader = new StreamReader(filename))
using (var jsonReader = new JsonTextReader(streamReader))
{
jsonReader.SupportMultipleContent = true;
var serializer = new JsonSerializer();
while (jsonReader.Read())
{
if (jsonReader.TokenType != JsonToken.StartObject)
continue;
var jsonObject = serializer.Deserialize<dynamic>(jsonReader);
var reducedObject = ApplyFiltering(jsonObject) //return null if the filtering conditions are not met
if (reducedObject == null)
continue;
jsonObject = reducedObject;
jsonObjects.Add(jsonObject);
}
}
}
//sw.Stop();
//Console.WriteLine($"Elapsed time: {sw.Elapsed}, Elapsed mili: {sw.ElapsedMilliseconds}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex}")
return null;
}
return jsonObjects;
}
Thanks.
It's not really a problem with Newtonsoft. You are reading all of these objects into one big list in memory. It gets to a point where you ask the JsonSerializer to create another object and it fails.
You need to return IEnumerable<T> from your method, yield return each object, and deal with them in the calling code without storing them in memory. That means iterating the IEnumerable<T>, processing each item, and writing to disk or wherever they need to end up.
I have an ObservableCollection <T>. I want to insert the various elements in it and then save the newly created file in LocalStorage. How can I do that?
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(Path.Combine(ApplicationData.Current.LocalFolder.Path, "Database.db"), true);
await conn.CreateTableAsync<Musei>();
var Dbase = Path.Combine(ApplicationData.Current.LocalFolder.Path, "Database.db");
var con = new SQLiteAsyncConnection(Dbase, true);
var query = await con.Table<Musei>().ToListAsync();
ObservableCollection<Musei> favMusei = new ObservableCollection<Musei>();
if (query.Count > 0)
{
favMusei.Clear();
foreach (Musei museifav in query)
{
favMusei.Add(museifav);
}
}
I'm using a json file to store in the memory. JSON is a light weight message exchange format and is widely used. You have to do some slight modifications in the code if you want some different file format.
Your collection would be serialized to the memory at the time of saving and has to be deserialized when reading it back from memory.
Add your own generic implementation of the collection. To create your situation i'm using a simple ObservableCollection<int>. And don't forget to initialize the collection to some meaningful values, here i'm using the default constructor initialization.
using System.Collections.ObjectModel;
using System.Runtime.Serialization.Json;
using Windows.Storage;
//Add your own generic implementation of the collection
//and make changes accordingly
private ObservableCollection<int> temp;
private string file = "temp.json";
private async void saveToFile()
{
//add your items to the collection
temp = new ObservableCollection<int>();
var jsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<int>));
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(file, CreationCollisionOption.ReplaceExisting))
{
jsonSerializer.WriteObject(stream, temp);
}
}
private async Task getFormFile()
{
var jsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<int>));
try
{
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(file))
{
temp = (ObservableCollection<int>)jsonSerializer.ReadObject(stream);
}
}
catch
{
//if some error is caught while reading data from the file then initializing
//the collection to default constructor instance is a good choice
//again it's your choice and may differ in your scenario
temp = new ObservableCollection<int>();
}
}
To add some functionality to the code you can also have an ensureDataLoaded() function which would ensure that the data has been read from the JSON file.
public async Task ensureDataLoaded()
{
if (temp.Count == 0)
await getFormFile();
return;
}
Before using the global variable temp (having the ObservableCollection) call the ensureDataLoaded function. It would avoid some unnecessary NullPointerExceptions.
I'm new to C# and Windows Phone developing, I need to do app for school project.
I have simple class, and I want to save it to have access later, on next start of application.
What is the best (and easiest) method to do that? Using file, database or some other application memory?
Here is my class:
public class Place
{
private string name;
private string description;
private int distance;
private bool enabled;
private GeoCoordinate coordinates;
}
I need to store multiple instances of class.
There is no "best" way to do it; it depends on how you're going to use it.
A simple way is to use serialization, to XML, JSON, binary or whatever you want. I personally like JSON, as it's very lightweight and easy to read for a human. You can use the JSON.NET library to serialize objects to JSON.
For instance, if you want to serialize a collection of Place to a file, you can do something like that:
static async Task SavePlacesAsync(ICollection<Place> places)
{
var serializer = new JsonSerializer();
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync("places.json", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenStreamForWriteAsync())
using (var writer = new StreamWriter(stream))
{
serializer.Serialize(writer, places);
}
}
And to read it back from the file:
static async Task<ICollection<Place>> LoadPlacesAsync()
{
try
{
var serializer = new JsonSerializer();
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync("places.json");
using (var stream = await file.OpenStreamForReadAsync())
using (var reader = new StreamReader(stream))
using (var jReader = new JsonTextReader(reader))
{
return serializer.Deserialize<ICollection<Place>>(jReader, places);
}
}
catch(FileNotFoundException)
{
return new List<Place>();
}
}
I think the easiest way to make persistent your object is to store them in a file. However this is not the best way due to the time spent in IO operations, low security, etc.
Here you have a nice example:
How to quickly save/load class instance to file
I'm charting into completely new territory on this one...
Currently, I am using Azure Mobile Services and a SQL Azure Database to store the data for my Windows Phone 8 application. Every time the application is launched, it pulls down all of the data from specific tables via some queries I've set up.
items = await phoneTable
.Where(PhoneItem => PhoneItem.Publish == true)
.OrderBy(PhoneItem => PhoneItem.FullName)
.ToCollectionAsync();
However, this isn't always a great practice. I'm trying to implement a way for the data to be saved to a XML file in the IsolatedStorage of the application when it has been loaded.
I've already gotten some code that I think should READ the IsolatedStorage and search for the XML file, but I'm not sure how to download the data and then write that to IsolatedStorage.
public static IEnumerable<Phones> GetSavedData()
{
IEnumerable<Phones> phones = new List<Phones>();
try
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
string offlineData = Path.Combine("WPTracker", "Offline");
string offlineDataFile = Path.Combine(offlineData, "phones.xml");
IsolatedStorageFileStream dataFile = null;
if (store.FileExists(offlineDataFile))
{
dataFile = store.OpenFile(offlineDataFile, FileMode.Open);
DataContractSerializer ser = new DataContractSerializer(typeof(IEnumerable<Phones>));
phones = (IEnumerable<Phones>)ser.ReadObject(dataFile);
dataFile.Close();
}
else
{
// Call RefreshPhoneItems();
}
}
}
catch (IsolatedStorageException)
{
}
return phones;
}
I'm using the AzureMobileServices SDK and Newtonsoft.Json to interact with the database. Any help would be greatly appreciated!
Don't use ToCollectionAsync in this case - it will return an object which is best used when binding to some UI control. Use ToListAsync instead, somewhat like the code below:
items = await phoneTable
.Where(PhoneItem => PhoneItem.Publish == true)
.OrderBy(PhoneItem => PhoneItem.FullName)
.ToListAsync();
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
string offlineData = Path.Combine("WPTracker", "Offline");
string offlineDataFile = Path.Combine(offlineData, "phones.xml");
IsolatedStorageFileStream dataFile = null;
dataFile = store.OpenFile(offlineDataFile, FileMode.Create);
DataContractSerializer ser = new DataContractSerializer(typeof(IEnumerable<Phones>));
ser.WriteObject(dataFile, items);
dataFile.Close();
}