Замена устаревшей системы и создание нового серверного кода с помощью ServiceStack + настраиваемая сериализация - PullRequest
4 голосов
/ 13 марта 2012

У нас есть устаревший код сервера, от которого мы хотим отказаться и разработать новый, используя ServiceStack. Существующие клиенты не пишутся в .Net. Мы вообще не планируем использовать .Net на стороне клиента.

Обмен данными между клиентом и сервером осуществляется с использованием XML и JSON - на данный момент JSON используется только в качестве формата возврата для ответа (только для некоторых доступных служб). Формат XML был определен, когда первая версия серверного решения была создана пару лет назад. Мы не хотим его менять.

Как мы используем ServiceStack для создания новых веб-сервисов RESTful, которые будут сериализовывать и десериализовывать данные в формат, который был разработан в прошлом (обратите внимание, что клиенты не будут записываться в C # /. Net). Нам нужно контролировать и сериализацию, и десериализацию. Возможно ли использовать DTO и при этом контролировать, как эти объекты сериализуются / десериализуются?

1 Ответ

5 голосов
/ 13 марта 2012

Добавление пользовательской логики через фильтры запросов / ответов

См. Фильтры запросов и ответов , чтобы узнать, как добавить пользовательскую логику до и после вызова вашей службы.Лучше всего добавлять эти фильтры через атрибуты фильтра запросов / ответов , поскольку они позволяют помечать только те службы, которым нужны эти фильтры.

Проблема с фильтром запросовпроисходит ли это после десериализации в запрос DTO, что слишком поздно, чтобы добавить собственную логику десериализации.Чтобы обойти это, вы можете зарегистрировать настраиваемый механизм связывания запросов в вашем AppHost с помощью:

base.RegisterRequestBinder<MyRequest>(httpReq => ... requestDto);

Это дает вам доступ к объекту IHttpRequest и позволяет самостоятельно добавлять собственную логику десериализации.Другой вариант - указать ServiceStack не пытаться десериализовать сам запрос и вместо этого ввести HttpRequest InputStream, чтобы можно было самостоятельно десериализовать запрос:

public class Hello : IRequiresRequestStream {
    Stream RequestStream { get; set; }
}

Оба эти примера объяснены в сериализации ServiceStack иДесериализация вики-страница.

Регистрация собственного пользовательского типа носителя

Еще один вариант, позволяющий возвращать DTO со строгим типом, но изменить вывод для определенных запросов можно сделать, добавивновый пользовательский тип носителя, как описано в примере Northwind VCard Custom типа носителя , например:

public static void Register(IAppHost appHost)
{
    appHost.ContentTypeFilters.Register( "text/x-vcard", SerializeToStream,  DeserializeFromStream);
}

...    

public static void SerializeToStream(IRequestContext requestContext, object response, Stream stream)
{
    var customerDetailsResponse = response as CustomerDetailsResponse;
    using (var sw = new StreamWriter(stream))
    {
        if (customerDetailsResponse != null)
        {
            WriteCustomer(sw, customerDetailsResponse.Customer);
        }
        var customers = response as CustomersResponse;
        if (customers != null)
        {
            customers.Customers.ForEach(x => WriteCustomer(sw, x));
        }
    }
}

Это хороший вариант, если вы можете подключить пользовательские ответы XML под другим контентомВведите, например, application / v-xml , чтобы он не конфликтовал с существующим форматом / конечной точкой XML.Используя ContentType выше, ваш HTTP-клиент может вызвать эту пользовательскую реализацию с ? Format = v-xml или с помощью заголовка HTTP: Accept: application / v-xml .

Если вы хотите переопределить встроенный XML ContentType, вы все еще можете, но я рекомендую вернуться к исходной реализации XmlSerializer для методов SerializeStream и DeserializeStream, если это не один из устаревших форматов, которые вы должны поддерживать.

Обход ServiceStack и выполнение с использованием собственного настраиваемого IHttpHandler

Другой вариант - полностью обойти ServiceStack и вместо этого обработать запрос в собственном настраиваемом обработчике IHttpRequest, зарегистрировав его в конфигурации ServiceStack в вашем AppHost:

 SetConfig(new EndpointHostConfig { 
    RawHttpHandlers = {
      httpReq => return IsLegacyMatch(httpReq) ? new LegacyXmlHandler() : null 
    }
 });

Возвращение ненулевое (т. Е. Любой обработчик) обходит ServiceStack.

...