ServiceStack 4 Cookbook
上QQ阅读APP看书,第一时间看更新

Overriding serialization of request object types

ServiceStack's fast serialization of requests and responses is at the center of how its clients and services interact. Sometimes, however, there might be a need to have your request objects structured differently on the server than the client. In this recipe, we will cover how this can be handled within the ServiceStack framework.

Getting ready

First, we'll need a project with ServiceStack references to be up and running. To do this, please see Creating a ServiceStack solution with VisualStudio and NuGet in Appendix A, Getting Started.

Although ServiceStack has a simple way of aliasing properties for a request object, sometimes there might be more control needed around how your request-and-response objects serialize and deserialize.

Note

In this recipe, we are looking at only JSON serialization; some of these concepts can be converted into the other formats ServiceStack supports, such as JSV and CSV.

How to do it…

So, in this example, we are migrating from an old system, and we have to support the old clients, which only accept a very specific naming convention in their JSON payload, and beyond the URLs they hit, we are unable to change how they consume the responses from the server. So, one way we might handle this is having another host that reuses our code from the main project, but control how some of the domain objects are serialized, as follows:

public override void Configure(Funq.Container container)
{
    //Configuration code...
    JsConfig<Place>.RawSerializeFn = (place) =>
{
      return place.SerializeForOldClient();
};
}

public static class PlaceSerializer
{
    public static bool HasCountryInName(this Place place)
    {
        //If comma, client expects a country name
        return place.Name.Contains(',');
    }

    public static string SerializeForOldClient(this Place place)
    {
        if (place.HasCountryInName())
        {
            string[] nameCountry = place.Name.Split(',');
            return "{\"0_Name\":\"" + nameCountry[0].Trim() + "\",\"1_CountryName\":\"" + nameCountry[1].Trim() + "\",\"2_Description\":\"" + place.Description + "\"}";
        }

        return "{\"0_Name\":\"" + place.Name + "\",\"1_Description\":\"" + place.Description + "\"}";
    }
}

Another requirement for this old client might be that the service must return all names in capitalized text. Due to a matching routine, we no longer have the ability to change. A delegate for a different method is used for this kind of modification. Here's how this can be done:

JsConfig<Place>.RawSerializeFn = (place) =>
{
    place = JsConfig<Place>.OnSerializingFn(place);
    return place.SerializeForOldClient();
};
JsConfig<Place>.OnSerializingFn = (place) =>
{
    place.Name = place.Name.ToUpper();
    return place;
};
How to do it…

How it works…

The JsConfig object is a part of ServiceStack. This means that text that is responsible for all the JSON serialization. The generic T passed is used to isolate the functions you register to apply only to the type specified. Once registered, any serialization or deserialization performed on the specified type will run your registered functions.

The previously used serialize examples also have deserialize counterparts, which are used to convert back to the typed object on the request to your services. So, if your client was also responsible for updating data, you might consider using OnDeserializedFn and/or RawDeserializeFn to handle these requirements.