Serialization and Deserialization

Passing complex objects in the Query String​

ServiceStack uses the JSV-Format (JSON without quotes) to parse QueryStrings.

JSV lets you embed deep object graphs in QueryString as seen this example url:

https://test.servicestack.net/json/reply/StoreLogs?Loggers=[{Id:786,Devices:[{Id:5955,Type:Panel,
Channels:[{Name:Temperature,Value:58},{Name:Status,Value:On}]},
{Id:5956,Type:Tank,TimeStamp:1199303309,
Channels:[{Name:Volume,Value:10035},{Name:Status,Value:Full}]}]}]

If you want to change the default binding ServiceStack uses, you can register your own Custom Request Binder.

Custom Media Types​

ServiceStack serializes and deserializes your DTOs automatically. If you want to override the default serializers or you want to add a new format, you have to register your own Content-Type:

Register a custom format​

string contentType = "application/yourformat"; //To override JSON eg, write "application/json"
var serialize = (IRequest req, object response, Stream stream) => ...;
var deserialize = (Type type, Stream stream) => ...;

//In AppHost Configure method
//Pass two delegates for serialization and deserialization
this.ContentTypes.Register(contentType, serialize, deserialize);	

Encapsulate inside a plugin​

If you're looking to standardize on a custom implementation, it's recommended to wrap the registration inside a plugin.

E.g. here's how you can change ServiceStack to use .NET's XmlSerializer instead of its DataContractSerializer default:

public class XmlSerializerFormat : IPlugin
{
    public static void Serialize(IRequest req, object response, Stream stream)
    {
        var serializer = new XmlSerializer(response.GetType());
        serializer.Serialize(stream, response);
    }

    public static object Deserialize(Type type, Stream stream)
    {
        var serializer = new XmlSerializer(type.GetType());
        var obj = (Type) serializer.Deserialize(stream);
        return obj;
    }

    public void Register(IAppHost appHost)
    {
        appHost.ContentTypes.Register(MimeTypes.Xml, Serialize, Deserialize);
    }
}

Where it can then be easily registered as a regular plugin:

Plugins.Add(new XmlSerializerFormat());

Other ContentType Examples​

The Protobuf-format shows an example of registering a new format whilst the Northwind VCard Format shows an example of creating a custom media type in ServiceStack.

For reference see registration examples of ServiceStack's different Formats:

Async ContentTypes Formats​

The async registration APIs are for Content-Type Formats which perform Async I/O, most serialization formats don't except for HTML View Engines which can perform Async I/O when rendering views, which are all registered using the RegisterAsync APIs:

appHost.ContentTypes.RegisterAsync(MimeTypes.Html, SerializeToStreamAsync, null);
appHost.ContentTypes.RegisterAsync(MimeTypes.JsonReport, SerializeToStreamAsync, null);
appHost.ContentTypes.RegisterAsync(MimeTypes.MarkdownText, SerializeToStreamAsync, null);

Reading in and De-Serializing ad-hoc custom requests​

There are 2 ways to deserialize your own custom format, via attaching a custom request binder for a particular service or marking your service with IRequiresRequestStream which will skip auto-deserialization and inject the ASP.NET Request stream instead.

Create a custom request dto binder​

You can register custom binders in your AppHost by using the example below:

appHost.RegisterRequestBinder<MyRequest>(httpReq => ... requestDto);      // or:
appHost.RequestBinders.Add(typeof(MyRequest), httpReq => ... requestDto);

This gives you access to the IHttpRequest object letting you parse it manually so you can construct and return the strong-typed Request DTO manually which will be passed to the service instead.

Uploading Files​

You can access uploaded files independently of the Request DTO using Request.Files. e.g:

public object Post(MyFileUpload request)
{
    if (this.Request.Files.Length > 0)
    {
        var uploadedFile = base.Request.Files[0];
        uploadedFile.SaveTo(MyUploadsDirPath.CombineWith(file.FileName));
    }
    return HttpResult.Redirect("/");
}

ServiceStack's imgur.netcore.io example shows how to access the byte stream of multiple uploaded files, e.g:

public object Post(Upload request)
{
    foreach (var uploadedFile in base.Request.Files
       .Where(uploadedFile => uploadedFile.ContentLength > 0))
    {
        using (var ms = new MemoryStream())
        {
            uploadedFile.WriteTo(ms);
            WriteImage(ms);
        }
    }
    return HttpResult.Redirect("/");
}

Reading directly from the Request Stream​

Instead of registering a custom binder you can skip the serialization of the Request DTO, you can add the IRequiresRequestStream interface to directly retrieve the stream without populating the Request DTO.

//Request DTO
public class RawBytes : IRequiresRequestStream
{
    /// <summary>
    /// The raw Http Request Input Stream
    /// </summary>
    Stream RequestStream { get; set; }
}

Which tells ServiceStack to skip trying to deserialize the request so you can read in the raw HTTP Request body yourself, e.g:

public async Task<object> PostAsync(RawBytes request)
{
    byte[] bytes = await request.RequestStream.ReadFullyAsync();
    string text = bytes.FromUtf8Bytes(); //if text was sent
}

Buffering the Request and Response Streams​

ServiceStack's Request and Response stream are non-buffered (i.e. forward-only) by default. This can be changed at runtime using a PreRequestFilters to allow the Request Body and Response Output stream to be re-read multiple times should your Services need it:

appHost.PreRequestFilters.Add((httpReq, httpRes) => {
    httpReq.UseBufferedStream = true;  // Buffer Request Input
    httpRes.UseBufferedStream = true;  // Buffer Response Output
});

Which you'll then be able to re-read the Request Input Stream with:

string textBody = await httpReq.GetRawBodyAsync(); //read as string

ReadOnlySpan<byte> bytes = ((MemoryStream)httpReq.InputStream).GetBufferAsSpan(); //read as bytes

Raw SOAP Message​

You can access raw WCF Message when accessed with the SOAP endpoints in your Service with IHttpRequest.GetSoapMessage() extension method, e.g:

Message requestMsg = base.Request.GetSoapMessage();

To tell ServiceStack to skip Deserializing the SOAP request entirely, add the IRequiresSoapMessage interface to your Request DTO, e.g:

public class RawWcfMessage : IRequiresSoapMessage {
    public Message Message { get; set; }
}

public object Post(RawWcfMessage request) { 
    request.Message... //Raw WCF SOAP Message
}