class AppDataManager
{
public static async Task SaveAsync<T>(T data, string fileName)
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName,
CreationCollisionOption.GenerateUniqueName);
var stream = await file.OpenStreamForWriteAsync();
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(stream ,data);
await stream.FlushAsync();
}
public static async Task<T> RestoreAsync<T>(string fileNa me)
{
try
{
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
var instream = await file.OpenStreamForReadAsync();
var serializer = new DataContractSerializer(typeof(T));
return (T)serializer.ReadObject(instream);
}
catch (Exception)
{
return default(T);
}
}
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
await AskUserToLocalDataAsync();
if (useLocalData)
{
SomethingGoesHere = await AppDataManager.RestoreAsync<UserData>(fileName);
}
}
the code works fine, but it return only one Object, I want to write multiple objects and retrieve it as an observableCollection to bind it to a GridView. the GenerateUniqueName is to append multiple objects wright ?
how to store it ? and how to retrieve it ?
Create a class with a property that will hold your collection. Then serialize that class.
I would recommend creating a Collection class for your objects.
For example a Widget object:
[DataContract]
public class Widget
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Value { get; set; }
}
You could then make a WidgetCollection class:
[DataContract]
public class WidgetCollection
{
[DataMember]
public List<Widget> Widgets { get; set; }
}
You can serialize/deserialize the WidgetCollection and then foreach through and add to an ObservableCollection<Widget>.
Also, wrap your IDisposable objects (like IRandomAccessStream) in using statements so they get properly disposed.
Related
JIL json serializer does not serialize properties from derived class
Below are the code snippet:
public async Task WriteAsync(OutputFormatterWriteContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var response = context.HttpContext.Response; response.ContentType = "application/json";
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
{
Jil.JSON.Serialize(context.Object, writer);
await writer.FlushAsync();
}
}
1) Model Type:
public class BaseBOResponse
{
public string pk { get; set; }
}
public class PaymentTypeBOResponse : BaseBOResponse
{
public string description { get; set; }
public bool isSystem { get; set; }
public bool isActive { get; set; }
}
Here when i set something to BaseBOResponse's response property "pk", then JIL serializer eliminate this property.
Please suggest if you have any solution.
You have to tell Jil to include inherited properties as well:
Jil.JSON.Serialize(context.Object, writer, Jil.Options.IncludeInherited);
So here's what I am trying to do and what I have accomplished.
private static T _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = w.DownloadString(url);
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
This method (when called) is used like so:
var onlineornot = ("http://blah.com");
var chatters = _getjson<Rootobject>(onlineornot);
<Rootobject> being a class set up like this:
public class Rootobject
{
public _Links _links { get; set; }
public int chatter_count { get; set; }
public Chatters chatters { get; set; }
public Stream stream { get; set; }
public Stream game { get; set; }
public _Links2 _links2 { get; set; }
}
For the most part, it works but it causes my app to hang every time I call _getJson. I was wondering how I could use Async in this case, while maintaining the ability to get the properties from <Rootobject>.
The WebClient class has a DownloadStringAsync() method (doc) you can use.
Here is a brief blog post that shows how you can use async/await to prevent your UI from blocking.
ex:
private static async Task<T> _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = await w.DownloadStringTaskAsync(url);
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
public async void Button1_Click(...)
{
...
var onlineornot = ("http://example.com");
var chatters = await _getjson<Rootobject>(onlineornot);
...
}
Quick answer, use WebClient.DownloadStringAsync method: https://msdn.microsoft.com/en-us/library/ms144202(v=vs.110).aspx
Modify your code like this:
private static async Task<T> _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = await w.DownloadStringTaskAsync(new Uri(url));
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
Also, the key thing here is to make sure this is not executed on the main UI thread.
I'm trying to do qualification job for a work and have some problems with realization of code on Xamarin.
I have such classes and functions. They're working on console of c# but not in xamarin. I don't know what to do. They give only freeze on Xamarin.
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace radacode.ActionForm
{
class ListMaker
{
public static List<Country> GetCountryList()
{
List<Country> result=new List<Country>();
Task<string> task =GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
JObject vk = JObject.Parse(task.GetAwaiter().GetResult());
foreach (JObject jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
public static async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
override public string ToString()
{
return Title;
}
}
}
}
When using Xamarin Forms, it's best to use Portable Class Projects rather than Shared. In my opinion.
Also it's important that Statics are not used especially for calls that are async. Think of Async as to being similar to AsyncTask in JAVA. They're none blocking.
public class ListMaker
{
public List<Country> GetCountyList()
{
return GetCountryListAsync().Result;
}
private async Task<List<Country>> GetCountryListAsync()
{
var result = new List<Country>();
var task =
await GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
var vk = JObject.Parse(task);
foreach (var jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
private async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
public new string ToString()
{
return Title;
}
}
}
Now that you have your class, you can then create an instance of it and execute it.
NOTE:- the Async and Await in my example, or this one, is incorrect.
It should really bubble up to a parent class that has a property and a void in the class statement.
public async void TheLister()
{
var listMaker = new ListMaker();
var countryList = await listmaker.GetCountryListAsync();
// Do something with countryList
}
I got a fine working XMLSerializer for a sophisticated List of 3D models with many different elements. Now I want to serialize another List beside of that, that is saving only few Elements of it.
I just tried to bar some of them out with [XMLIgnore] but this causes problems in the deserialization of my other list.
Here's the Code of my (De)Serializer:
public void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) return;
var serializer = new XmlSerializer(serializableObject.GetType());
using (var stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, serializableObject);
}
}
public T DeserializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) return default(T);
var serializer = new XmlSerializer(typeof(T),overrides);
using (var stream = File.Open(fileName, FileMode.Open))
{
return (T)serializer.Deserialize(stream);
}
}
Maybe its an idea to clone my list, and to remove all the Elements I don't wish to save before Serialization?
You can use base derived relation to build your collection type where one ignore serialization and other override what you ignored.
[Serializable]
public abstract class BaseClass
{
[XmlIgnore]
public virtual bool BaseMember { get; set; }
}
[Serializable]
public class DerivedClass : BaseClass
{
public string DerivedMember { get; set; }
}
[Serializable]
public class XmlIgnore : BaseClass
{
// no XmlIgnore
public override bool BaseMember
{
get
{
return base.BaseMember;
}
set
{
base.BaseMember = value;
}
}
}
I am trying to use MessagePack to serialize an object that has a property of an interface type. When I call Pack, it throws SerializationException that says a serializer is not defined for the interface.
Code example:
namespace ConsoleApplication1
{
// interfaces and classes declaration
public interface IDummyInterface { }
public class DummyObject : IDummyInterface
{
public string Value { get; set; }
}
public class SmartObject
{
public string Name { get; set; }
IDummyInterface DummyOne { get; set; }
}
// in main
var mySmartObject = new SmartObject() { Name = "Yosy", DummyOne = new DummyObject() { Value = "Value"} };
using(var stream = new MemoryStream())
{
var serializer = MessagePackSerializer.Create<SmartObject>();
serializer.Pack(mySmartObject, stream); // => This code throws the exception
}
}
Can I tell MessagePack which serializer to use for IDummyInterface and tell it to act as DummyObject?
It seems to me you are using msgpack-cli. To make it work, basically there are two ways to do it.
1. Use MessagePackKnownTypeAttribute
This one is easy and straightforward.
public class SmartObject
{
public string Name { get; set; }
[MessagePackKnownType("d", typeof(DummyObject))]
public IDummyInterface DummyOne { get; set; } // Need to make this property public
}
2. Implement custom serializer
If you want a clean model class without reference to MsgPack library, you can do the following, but you need to figure out a way to serialize/deserialize SmartObject (efficiently).
public class SmartObjectSerializer : MessagePackSerializer<SmartObject>
{
public SmartObjectSerializer(SerializationContext ownerContext) : base(ownerContext)
{
}
protected override void PackToCore(Packer packer, SmartObject objectTree)
{
var str = ToString(objectTree); // TODO: Just an example
packer.Pack(str);
}
protected override SmartObject UnpackFromCore(Unpacker unpacker)
{
var str = unpacker.LastReadData.AsStringUtf8(); // TODO: Just an example
return new SmartObject
{
// TODO: Initialize based on str value
};
}
}
// In main
var context = new SerializationContext();
context.Serializers.RegisterOverride(new SmartObjectSerializer(context));
var serializer = MessagePackSerializer.Get<SmartObject>(context);
// The rest is the same
There are some sample codes you may be interested to take a look.
CustomSerializer
Polymorphism