Would like to make this solution as a generic solution wherein instead of Person object, GetJSON Method should accept the generic type which is has the DataContract attribute. Can anybody explain how to go about doing it.
Here is the base code
namespace TestDataContractJsonSerializer
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Json;
public class Program
{
public static void Main(string[] args)
{
List<Person> persons = new List<Person> { new Person("Person1"), new Person("Person2") };
var strJSON = from p in persons select GetJSON(p);
Console.WriteLine("In JSON Format: ");
foreach (string str in strJSON)
{
Console.WriteLine(" {0}", str);
}
Console.ReadKey();
}
private static string GetJSON(Person p)
{
if (p != null)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Person));
dataContractJsonSerializer.WriteObject(stream, p);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
return string.Empty;
}
}
[DataContract]
public class Person
{
public Person(string name)
{
this.Name = name;
}
[DataMember]
public string Name { get; private set; }
}
}
It would look something like this in the very basic case. You'd probably need to add some special casing and/or error handling, for instance if the type T is not serializable.
private static string GetJSON<T>(T objToSerialize)
{
if (objToSerialize != null)
{
MemoryStream stream = new MemoryStream();
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(objToSerialize.GetType());
dataContractJsonSerializer.WriteObject(stream, objToSerialize);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
return string.Empty;
}
Related
I need to fill a form with inputs in Xamarin, and send them to my API page.
I already tried sending the data in "Postman" and it saved it correctly, but I would like to know how to send it from Xamarin.
Attention, I can read the data correctly from the application.
public class FuelPurchase
{
public int id { get; set; }
public string date{ get; set; }
public int vueltametal { get; set; }
public int amount{ get; set; }
public string station{ get; set; }
public string location{ get; set; }
}
And the form you create in Xamarin is this.
<Label Text="Fuel Purchase"/>
<Label Text="Fecha">
<DatePicker x:Name="Date"/>
<Label Text="Station"/>
<Entry x:Name="Station"/>
<Label Text="Location"/>
<Entry x:Name="Location"/>
<Label Text="Amount"/>
<Entry x:Name="amount" Keyboard="Numeric"/>
Here is a static class that I use for API's. You can change the url to match yours if you only have one. Make sure to step through it and check that all of your "/"'s are in the right spot!
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using NGJS = System.Text.Json;
using System.Threading.Tasks;
namespace TestBCS
{
public class RestService
{
readonly HttpClient client;
public RestService()
{
client = new HttpClient(new HttpClientHandler
{
Proxy = null,
UseProxy = false
});
}
#region GET
public async Task<object> RefreshDataAsync(string url, string qs)
{
Uri uri = new Uri(string.Format(url, qs));
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
return await NGJS.JsonSerializer.DeserializeAsync<object>(stream);
}
}
//Error Handling here
return null;
}
#endregion
#region POST
static void SerializeJsonIntoStream(object value, Stream stream)
{
using (var sw = new StreamWriter(stream, new UTF8Encoding(false), 1024, true))
using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None })
{
var js = new JsonSerializer();
js.Serialize(jtw, value);
jtw.Flush();
}
}
HttpContent CreateHttpContent(object content)
{
HttpContent httpContent = null;
if (content != null)
{
var ms = new MemoryStream();
SerializeJsonIntoStream(content, ms);
ms.Seek(0, SeekOrigin.Begin);
httpContent = new StreamContent(ms);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
return httpContent;
}
public async Task PostStreamAsync(string url, object content)
{
string Url = url;
using (var client = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Post, Url))
using (var httpContent = CreateHttpContent(content))
{
request.Content = httpContent;
using (var response = await client
.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
Debug.WriteLine("Successfully Sent");
}
}
}
#endregion
}
}
I am new to servicestack and am really enjoying it, however I can not for the life of me figure of why this is occuring.
I have mapped it as ROUTES.Add<images>("/Images"); in the APPHOST.cs
I use Rest Console(chrome plugin) to test and POST the following JSON:
(I know it is not and actual base64 encoding).
Any thoughts would be appreciated.
// Testing JSON
{"base64Encoding":"asdasdasdasd"}
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ServiceStack.ServiceInterface;
using RewoServiceLayer.RequestDTOs;
using System.Data.Entity;
using ServiceStack.ServiceInterface.ServiceModel;
using ServiceStack.Configuration;
using ServiceStack.Common;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface.Auth;
using ServiceStack.WebHost.Endpoints;
using System.IO;
using System.Web.Hosting;
namespace Blah.Services
{
public class ImageResponse
{
public images image { get; set; }
public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized
}
public class ImageRequest
{
public String base64Encoding;
}
public class ImageService : Service
{
//Give me something that looks like this:
//"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABG4...YII=";
public ImageResponse Post(ImageRequest request)
{
String base64EncodingImg = request.base64Encoding;
using (var db = new BlahDB())
{
//save to db
images imgToSave = new images();
//get base64
string base64 = base64EncodingImg.Substring(base64EncodingImg.IndexOf(',') + 1);
base64 = base64.Trim('\0');
byte[] imgBinData = Convert.FromBase64String(base64);
//get the
imgToSave.image_type = base64EncodingImg.Substring(0,base64EncodingImg.IndexOf(','));
db.images.Add(imgToSave);
db.SaveChanges();
//then save string contents to disk using ID
imgToSave.image_disk_loc = getPathFromImage(imgToSave);
writeByteArrToDisk(imgBinData, imgToSave.image_disk_loc);
db.SaveChanges();
ImageResponse imgResponse = new ImageResponse();
imgResponse.image = imgToSave;
return imgResponse;
}
}
private Boolean writeByteArrToDisk(byte[] toWrite, String path)
{
try
{
File.WriteAllBytes(path, toWrite);
return true;
}
catch (Exception e)
{
return false;
}
}
private String getAbsolutePathToImagesFolder()
{
return HostingEnvironment.MapPath(#"~/App_Data/UploadedImages");
}
private String getPathFromImage(images imgModel)
{
if (imgModel.image_disk_loc.IsNullOrEmpty())
{
return getAbsolutePathToImagesFolder() + imgModel.image_id;
}
else
{
return imgModel.image_disk_loc;
}
}
}
}
I am getting the following error and it does not hit the Post Method when I debug:
{
"responseStatus": {
"errorCode": "NullReferenceException",
"message": "Object reference not set to an instance of an object.",
"stackTrace": " at ServiceStack.WebHost.Endpoints.Utils.FilterAttributeCache.GetRequestFilterAttributes(Type requestDtoType)\r\n at ServiceStack.WebHost.Endpoints.EndpointHost.ApplyRequestFilters(IHttpRequest httpReq, IHttpResponse httpRes, Object requestDto)\r\n at ServiceStack.WebHost.Endpoints.RestHandler.ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, String operationName)"
}
}
I can't see your images class but I think you need to change
ROUTES.Add<images>("/Images");
To
ROUTES.Add<ImageRequest>("/Images")
since the Post on your ImageService is looking for a request of type ImageRequest.
This may be very simple but i am not finding a way to read query string value in my WCF rest service. I tried the following but no joy
HttpContext.Current.Request.QueryString["name"]
Something like this should work for you. You need to use the UriTemplate. The following is the WCF service
[ServiceContract]
interface IPing
{
[OperationContract]
[WebInvoke(Method="POST", UriTemplate="stuff?n={name}&q={quantity}")]
void AddStuff(string name, string quantity, Stream data);
}
class PingService : IPing
{
public void AddStuff(string name, string quantity, Stream data)
{
Console.WriteLine("{0} : {1}", name, quantity);
Console.WriteLine("Data ...");
using (StreamReader sr = new StreamReader(data))
{
Console.WriteLine(sr.ReadToEnd());
}
}
}
And the client
static void Main(string[] args)
{
WebRequest req = WebRequest.Create("http://localhost:9000/ping/stuff?n=rich&q=20");
req.Method = "POST";
req.ContentType = "text/html";
using (StreamWriter sw = new StreamWriter(req.GetRequestStream()))
{
sw.WriteLine("Hello");
}
req.GetResponse();
}
I use the RedisConnection Set method to set the byte array but how do i get the data? The get returns a wrapped byte array?
Links:
http://code.google.com/p/booksleeve/
http://code.google.com/p/protobuf-net/
This works but it doesn't feel right:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BookSleeve;
using ProtoBuf;
using System.IO;
namespace RedisTest001
{
[ProtoContract, Serializable]
public class Price
{
private string _ticker;
private double _value;
public Price()
{
}
public Price(string ticker, double value)
{
_ticker = ticker;
_value = value;
}
[ProtoMember(1)]
public string Ticker
{
get { return _ticker; }
set { _ticker = value; }
}
[ProtoMember(2)]
public double Value
{
get { return _value; }
set { _value = value; }
}
}
class Program
{
static void Main(string[] args)
{
using (var conn = new RedisConnection("localhost"))
{
Price p = new Price("IBM", 101.55);
byte[] raw;
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<Price>(ms,p);
raw = ms.ToArray();
}
conn.Open();
conn.Set(1, p.Ticker, raw);
var tb = conn.Get(1,"IBM");
var str = conn.Wait(tb);
Price p2 = Serializer.Deserialize<Price>(new MemoryStream(str));
}
}
}
}
More info:
public static class pex
{
public static byte[] ToBArray<T>(this T o)
{
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<T>(ms, o);
return ms.ToArray();
}
}
}
class Program
{
static void Main(string[] args)
{
Random RandomClass = new Random();
using (var conn = new RedisConnection("localhost"))
{
conn.Open();
for (int i = 0; i < 500000; i++)
{
Price p = new Price("IBM", RandomClass.Next(0, 1000));
conn.AddToSet(2, "PRICE.IBM", p.ToBArray());
}
That is entirely correct. "Get" (BookSleeve) returns a deferred byte[]. You have correctly used Wait to get the actual byte[], then used a MemoryStream over this byte[] to call Deserialize via protobuf-net.
All good.
If you make it clear any steps that you find ugly, I might be able to be more specific, but:
BookSleeve is entirely async via Task, hence the need for either Wait or ContinueWith to access the byte[]
protobuf-net is entirely Stream-based, hence the need for MemoryStream to sit on top of a byte[]
Of course, if you add a generic utility method (maybe an extension method) you only need to write it once.
And with the addition if a wrapper class (for some tracking/sliding-expiry) and a L1 cache (Redis as L2), this is pretty much exacty how we use it at stackoverflow.
One note: the connection is thread safe and intended to be massively shared; don't do a connection per operation.
I've been playing a little with the MongoDB Bson serializer, using the following piece of code:
class Program
{
public class myValue
{
public int Id = 0;
public string Label = "";
}
public class myValueMap : Dictionary<string, myValue>
{
}
public class myProdData
{
public myValueMap Mapping { get; set; }
}
public class mySystemPosition
{
public string Text { get; set; }
public myProdData ProdData { get; set; }
}
static void Main(string[] args)
{
BsonClassMap.RegisterClassMap<mySystemPosition>();
BsonClassMap.RegisterClassMap<myProdData>();
BsonClassMap.RegisterClassMap<myValueMap>();
BsonClassMap.RegisterClassMap<myValue>();
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new myValueMap()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var bson = o.ToBson();
var text = Encoding.ASCII.GetString(bson);
}
}
however I don't seem to be able to get the myProdData.Mapping serialized....
Do I need to configure the MongoDB Bson serializer in a special way, to make this work?
You no need to use BsonClassMap.RegisterClassMap if you no need custom serializtion(documentation).
All your classes will be desirialzied according to default rules.
Also i am changed your example a little bit to get it work(i've replaces myValueMap class with Dictionary):
public class myProdData
{
public Dictionary<string, myValue> Mapping { get; set; }
}
static void Main(string[] args)
{
var o = new mySystemPosition()
{
ProdData = new myProdData()
{
Mapping = new Dictionary<string, myValue>()
{
{"123", new myValue() {Id = 1, Label = "Item1"}},
{"345", new myValue() {Id = 2, Label = "Item2"}},
}
}
};
var json = o.ToJson();
Console.WriteLine(json);
Console.ReadKey();
}
Here is console output(just well formatted):
{
"Text":null,
"ProdData":{
"Mapping":{
"123":{
"_id":1,
"Label":"Item1"
},
"345":{
"_id":2,
"Label":"Item2"
}
}
}
}
You can test your serializtion using ToJson() extention method, in order to view that all correct and after that use ToBson() if need.
The problem is that myValueMap derives from Dictionary. That results in a class that the AutoMap method can't handle.
I recommend you just use the Dictionary directly, as Andrew did in his reply.
Ufortunately the myValueMap is an object that I can't easily change, however it turns out, that's pretty easy to create your own (de)serializer....
public class myValueMapSerializer : IBsonSerializer
{
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, System.Type actualType, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var res = new myValueMap();
var ser = new DictionarySerializer<string, myValue>();
var dic = (Dictionary<string, myValue>)ser.Deserialize(bsonReader, typeof(Dictionary<string, myValue>), options);
foreach (var item in dic)
{
res.Add(item.Key, item.Value);
}
return res;
}
public object Deserialize(Bson.IO.BsonReader bsonReader, System.Type nominalType, IBsonSerializationOptions options)
{
throw new Exception("Not implemented");
}
public bool GetDocumentId(object document, out object id, out IIdGenerator idGenerator)
{
id = null;
idGenerator = null;
return false;
}
public void Serialize(Bson.IO.BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
if (nominalType != typeof(myValueMap)) throw new ArgumentException("Cannot serialize anything but myValueMap");
var ser = new DictionarySerializer<string, myValue>();
ser.Serialize(bsonWriter, typeof(DictionarySerializer<string, myValue>), value, options);
}
public void SetDocumentId(object document, object id)
{
return;
}
}