How to implement Custom Deserializer - restsharp

I have written a custom serializer and attached it to my RestClient. I am trying to also implement a custom deserializer as well. I noticed in my code that the serializer gets called when i added it to my client like so :RestClient Client = new RestClient(options).UseSerializer<CustomJsonSerializer>();
However, I am not sure what code to add to point to my custom deserializer and where to add it.
I am trying to call a method that essentially hijack's the response content, changes the string, and then sends the modified string back as the new response content to then be deserialized.
Where would i add the code to call my custom deserializer? What would the code snippet look like? And is it possible to even alter the response.content before the deserialization happens? And if so, how do i implement that?

The UseSerializer<T> expects T to be IRestSerializer, which has properties for ISerializer and IDeserializer. The Deserializer property needs to return your custom deserializer.
public interface IRestSerializer {
ISerializer Serializer { get; }
IDeserializer Deserializer { get; }
...

Related

ASP .NET - JSON Serializer not working on class instances

Anonymous objects are automatically serialized as expected when returned from controller action.
When returning class instance, http response contains only empty json body, why? Where is this documented?
Ok, I forgot to add default { get; set; } to the properties, this seems to be compulsory for the json serializer.

How do I create hypermedia links in custom serializer with Spring Data Rest

I have a abstract class and two implementations:
public abstract class Attribute {
// some properties
}
public class CustomAttribute extends Attribute{
private String property1;
}
public class DefaultAttribute extends Attribute{
private String property2;
}
There's another class, which includes these attributes:
public class Step{
private List<Attribute> attributes;
}
Now when Step gets serialized, the self link is missing. I need the self reference, since I want to update the attributes. According to the documentation, jackson needs a little help deciding which class to use. But that does not help, because I need to use both classes. So I build a custom serializer (and registered with a module) for Step and now I wonder how I can construct the link myself. I couldn't find anything in the Spring Data Rest docs regarding this. Since Spring Data Rest adds these links automatically, I think there might be a way to have the protocol/hostname/port information available in the JsonSerializer. How do I get the information in my custom serializer?
Ok, now I use the linkTo() function to get the hostname and port and I manually set the rest of the resource URL in my custom serializer.
final Link attributeLink = linkTo(CustomAttributeRepository.class)
.slash("/api")
.slash("customAttributes")
.slash(attribute.getIdentifier()).withSelfRel();
//#formatter:off
jsonGenerator.writeFieldName("_links");
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("self");
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("href", attributeLink.getHref());
jsonGenerator.writeEndObject();
jsonGenerator.writeEndObject();
//#formatter:on

Spring data REST content negotiation

I have an annotated RepositoryRestResource for domain objects whose fields also contain binary data (images.) The Spring Rest machinery will create nice RESTful links for these fields, but I would also like to introduce a handler that returns the bare binary when browsers send an "image/*" accept header.
I could overlay a controller on the same paths, but it's brittle and I'd rather write a strategy class for this.
Possible? Any idea where to plug it in the Spring plumbing?
TIA,
Edoardo
Using the #RepositoryRestController annotation "properly", you should be able to restrict the controller override to the "image/*" only.
Say you have a simple domain object model (getters/setters and a some annotations omitted...)
public class Item {
#Id
private String id;
private String name;
}
Let's override the controller for image/* only
#RepositoryRestController
#ResponseBody
public class ItemRepositoryRestController {
#Autowired
private ItemRepository repository;
#RequestMapping(value = "/items/{id}", method = RequestMethod.GET,
produces = "image/*")
public Item getItem(#PathVariable(value = "id") String id)
{
Item item = repository.findOne(id);
/* do some magic with your item */
return item;
}
Obviously, no image/* data is returned here - you'll actually get a 400 error - but you do only get to this controller if asking if accepting image/*, while going through the automagic Spring Rest Controller when not asking for image/* if and only if you use #RequestMapping at the method level.
I haven't been to the point where I return raw binary data, you may have to use the HttpServletResponse directly as shown here. Or perhaps you already have an answer for this since in your comment you mention having added another resource path already (in which case I'm interested in how you return the raw data).

Protobuf-net serializer for NEventStore 3+

Can anyone point me to a protobuf-net serializer for NEventStore 3.0?
I'm having trouble I think mainly due to the serialization in event store 3 wrapping the event body and headers in an EventMessage.
I'm not sure how to setup the custom serializer correctly.
This is entirely untested guesswork based on a very brief glance at github, but it looks like you want to use the wire-up API to specify a custom serializer, for example:
var store = Wireup.Init()
.UsingSqlPersistence("Name Of EventStore ConnectionString In Config File")
.InitializeStorageEngine()
.UsingCustomSerialization(mySerializer)
... etc
where mySerializer is an instance of a type that implements the ISerialize interface. It looks like this should work:
class ProtobufSerializer : EventStore.Serialization.ISerialize
{
public void Serialize<T>(Stream output, T graph)
{
ProtoBuf.Serializer.Serialize<T>(output, graph);
}
public T Deserialize<T>(Stream input)
{
return ProtoBuf.Serializer.Deserialize<T>(input);
}
}
(so obviously mySerializer here would be a new ProtobufSerializer())

How can I return json from my WCF rest service (.NET 4), using Json.Net, without it being a string, wrapped in quotes?

UPDATE 10/19/2010
I know I asked this question a while ago, but the workarounds shown in these answers are hardly satisfactory, and this is still a common problem for many. WCF just isn't flexible. I started my own open source C# library for creating REST services without WCF. Check restcake.net or rest.codeplex.com for info on said library.
END UPDATE
UPDATE 8/2/2012
ASP.NET Web API (previously WCF Web API, the replacement for REST WCF) uses Json.NET by default
END UPDATE
The DataContractJsonSerializer is unable to handle many scenarios that Json.Net handles just fine when properly configured (specifically, cycles).
A service method can either return a specific object type (in this case a DTO), in which case the DataContractJsonSerializer will be used, or I can have the method return a string, and do the serialization myself with Json.Net. The problem is that when I return a json string as opposed to an object, the json that is sent to the client is wrapped in quotes.
Using DataContractJsonSerializer, returning a specific object type, the response is:
{"Message":"Hello World"}
Using Json.Net to return a json string, the response is:
"{\"Message\":\"Hello World\"}"
I do not want to have to eval() or JSON.parse() the result on the client, which is what I would have to do if the json comes back as a string, wrapped in quotes. I realize that the behavior is correct; it's just not what I want/need. I need the raw json; the behavior when the service method's return type is an object, not a string.
So, how can I have my method return an object type, but not use the DataContractJsonSerializer? How can I tell it to use the Json.Net serializer instead?
Or, is there someway to directly write to the response stream? So I can just return the raw json myself? Without the wrapping quotes?
Here is my contrived example, for reference:
[DataContract]
public class SimpleMessage
{
[DataMember]
public string Message { get; set; }
}
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PersonService
{
// uses DataContractJsonSerializer
// returns {"Message":"Hello World"}
[WebGet(UriTemplate = "helloObject")]
public SimpleMessage SayHelloObject()
{
return new SimpleMessage("Hello World");
}
// uses Json.Net serialization, to return a json string
// returns "{\"Message\":\"Hello World\"}"
[WebGet(UriTemplate = "helloString")]
public string SayHelloString()
{
SimpleMessage message = new SimpleMessage() { Message = "Hello World" };
string json = JsonConvert.Serialize(message);
return json;
}
// I need a mix of the two. Return an object type, but use the Json.Net serializer.
}
I finally figured out a solution to this. It's not what I would have preferred (which would be to return the specific object type, and somehow instruct WCF to use a Json.Net serializer, instead of the DataContractJsonSerializer), but it is working great, and it's simple and clear.
Extending my contrived example using this new solution:
[WebGet(UriTemplate = "hello")]
public void SayHello()
{
SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
string json = JsonConvert.Serialize(message);
HttpContext.Current.Response.ContentType = "application/json; charset=utf-8";
HttpContext.Current.Response.Write(json);
}
Note the return type of void. We do not return anything, since it would be serialized with DataContractJsonSerializer. Instead, I write directly to the response output stream. Since the return type is void, the processing pipeline doesn't set the content-type to the default type of "application/json", so I set it explicitly.
Because this uses HttpContext, I'm guessing it will only work if you have [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] on your service class, since that will force requests to the service to go through the ASP.NET pipeline. Without the asp.net compatibility, the HttpContext will not be available, since wcf hosting is supposed to be host agnostic.
Using this method, the results look perfect in firebug for GET requests. Correct content-type, correct content length, and raw json, not wrapped in quotes. And, I'm getting the serialization I want using Json.Net. Best of both worlds.
I'm not 100% positive of what obstacles I might run into regarding deserialization, when my service methods have [DataContract] object types as input parameters. I'm assuming the DataContractJsonSerializer will be used for that too. Will cross that bridge when I come to it...if it creates a problem. It hasn't so far, with my simple DTOs.
UPDATE
See Oleg's answer (the UPDATE2 part). He changes the return type of the service method from void to System.ServiceModel.Channels.Message, and rather than using HttpContext.Current.Response.Write(), he uses:
return WebOperationContext.Current.CreateTextResponse (json,
"application/json; charset=utf-8", Encoding.UTF8);
Which is indeed a better solution. Thank you Oleg.
UPDATE 2
There is yet another way of accomplishing this. Change your service's return type from Message to Stream, and return this:
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));
I haven't done any specific tests, but it's possible that this would be a better choice for methods that could potentially return large amounts of data. I don't know if that matters for non-binary data though. Anyway, a thought.
It seems to me that you use not correct DataContractJsonSerializer. What is strange is: you don't define ResponseFormat = ResponseFormat.Json attribute for the public SimpleMessage SayHelloObject() method.
Moreover if you have {"Message":"Hello World"} in a string and display it in debugger it will be display as "{\"Message\":\"Hello World\"}", so exactly like you see string json = JsonConvert.Serialize(message); (Json.Net). So it seems to me that you have in both cases the same results.
To verify this use a client software which read the results. See some examples
JQuery ajax call to httpget webmethod (c#) not working
Can I return JSON from an .asmx Web Service if the ContentType is not JSON?
How do I build a JSON object to send to an AJAX WebService?
UPDATED: In your code you define method SayHelloString(). It's result are a string. If you call the method this string will be one more time JSON serialized. JSON serialization of the string {"Message":"Hello World"} is a quoted string (see http://www.json.org/ definition for not a object, but a string) or exactly string "{\"Message\":\"Hello World\"}". So everything is correct with both methods of your Web Service.
UPDATED 2: I am glad that my tip from "Update" part of my answer helped you to swich of the double JSON serialization.
Nevertheless I would recommend you to change a little the solution to stay more at the WCF concept.
If you want implement a custom encoding of the web responce in WCF (see http://msdn.microsoft.com/en-us/library/ms734675.aspx) your WCF method should better return Message instead of void:
[WebGet(UriTemplate = "hello")]
public Message SayHello()
{
SimpleMessage message = new SimpleMessage() {Message = "Hello World"};
string myResponseBody = JsonConvert.Serialize(message);
return WebOperationContext.Current.CreateTextResponse (myResponseBody,
"application/json; charset=utf-8",
Encoding.UTF8);
}
You can of cause use another Message formater: for example CreateStreamResponse (or some other see http://msdn.microsoft.com/en-us/library/system.servicemodel.web.weboperationcontext_methods(v=VS.100).aspx) instead of CreateTextResponse.
If you want to set some additional HTTP headers or Http status code (for example in case of some error) you can do this with this way:
OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse;
ctx.StatusCode = HttpStatusCode.BadRequest;
At the end I want repeat my question from a comment: could you explain why you want use Json.Net instead of DataContractJsonSerializer? Is it performance improvement? Do you need implement serialization of some data types like DateTime in other way as DataContractJsonSerializer do? Or the main reason of your choose of Json.Net is some other?