2010-06-25 5 views
18

Можно ли переопределить поведение WCF DataContractSerializer по умолчанию, когда Serialize/DeSerialize сущности и вместо этого использовать JSON.NET?Как установить Json.Net в качестве сериализатора по умолчанию для службы REST WCF

У меня есть следующий контракт на обслуживание объекта City. По соображениям дизайна объект City имеет IsReference = true, и поэтому по умолчанию DataContractSerializer вызывает ошибки.

Для методов «GET» я могу справиться с ситуацией с помощью JsonConvert.DeserializeObject, но с методами «PUT, POST, DELETE» DataContractSerializer имеет приоритет и терпит неудачу, поскольку объекты IsReference не могут быть сериализованы.

Я нашел это Post для реализации IOperationBehavior и предоставления собственного Serializer, но я не знаю, как интегрировать Json.NET с этим. и я считаю, что для этого должен быть более прямой подход.

Буду признателен за любую помощь или руководство в отношении этого сценария или рекомендации другим подходам.

[ServiceContract] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed) 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
public class CityService 
{ 
    [Description("Get all Cities")] 
    [WebGet(UriTemplate = "")] 
    public Message Cities() 
    { 

    } 

    [Description("Allows the details of a single City to be updated.")] 
    [WebInvoke(UriTemplate = "{code}", Method = "PUT")] 
    public Message UpdateCity(string code, City city) 
    { 
    } 
} 

Большое спасибо

Hossam

ответ

19

Использование расширенных кодеров и сериализаторов (см. http://msdn.microsoft.com/en-us/library/ms733092.aspx) или другие методы расширения WCF, такие как использование DataContractSerializerOperationBehavior, очень интересно, но для вашей особой проблемы есть более простые способы решения.

Если вы уже используете Message типа для возврата результатов в использовании WCF4 вы можете сделать что-то вроде следующего:

public Message UpdateCity(string code, City city) 
{ 
    MyResponseDataClass message = CreateMyResponse(); 
    // use JSON.NET to serialize the response data 
    string myResponseBody = JsonConvert.Serialize(message); 
    return WebOperationContext.Current.CreateTextResponse (myResponseBody, 
       "application/json; charset=utf-8", 
       Encoding.UTF8); 
} 

В случае возникновения ошибок (как HttpStatusCode.Unauthorized или HttpStatusCode.Conflict) или в других ситуациях, когда вам необходимо установить код состояния HTTP (например, HttpStatusCode.Created), вы можете продолжать использовать WebOperationContext.Current.OutgoingResponse.StatusCode.

В качестве альтернативы вы можете также возвращать Stream (см http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx и http://msdn.microsoft.com/en-us/library/ms732038.aspx) вместо Message возвратить любые данные без дополнительной обработки по умолчанию с помощью Microsoft JSON сериализатором. В случае WCF4 вы можете использовать CreateStreamResponse (см. http://msdn.microsoft.com/en-us/library/dd782273.aspx) вместо CreateTextResponse. Не забудьте установить позицию потока в 0 после записи в потоке, если вы будете использовать эту технику для получения ответа.

+0

Олег, большое спасибо, он работает как шарм, возвращая тип Stream, он останавливает сериализатор Microsft. Мне известно о DataContractSerializerOperationBehavior, но мне требуется, чтобы мой собственный сериализатор из XmlObjectSerializer был непростой задачей. Ваше предложение намного проще и прямо, спасибо еще раз. – Hossam

+0

Как это десериализует входящий объект City? –

+1

@ Кристофер Стотт: Смотрите, например, http://msdn.microsoft.com/en-us/library/ms734675.aspx, начиная с «Чтения сообщений». – Oleg

1

Есть ли какая-то причина, почему вы хотите использовать библиотеку Json.NET специально. Если вы хотите вернуть JSON, почему бы просто не использовать свойство ResponseFormat из атрибутов WebGet и WebInvoke?

[WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)] 

Это должно быть в большинстве случаев. Какую версию WCF вы используете? Любая причина, по которой вы возвращаете тип сообщения, а не фактический тип?

+0

Это WCF4. В моей сети.config, мой имеет defaultOutgoingResponseFormat = "Json", поэтому мне не нужно украшать методы службы. По дизайну все мои объекты имеют [IsReference = true] и не могут быть сериализованы с помощью DataContractSerializer по умолчанию. Поэтому я должен использовать onther Serializer, например Json.net, который может обрабатывать объекты с [IsReference = true]. Я возвращаю тип сообщения, чтобы не получить свой ответ, сериализованный дважды, один раз json.net, а затем DataContractSerializer. Если я вернул тип actall, я бы получил недействительный json как «{\« Город »: \" Cairo \ "}" Thanx для вашего ответа. – Hossam

+0

Итак, это работает для вас, если вы не используете атрибут IsReference, но вы должны использовать его по дизайну по другой причине? –

+0

Исправить, IsReference - единственная проблема. Об этом сообщается во многих сообщениях. DataContractJsonSerializer не может сериализовать объекты, помеченные IsReference = true. Вот почему я ищу использовать другой Serializer. Many Thanks – Hossam

0

Определить его в службы веб-конфигурации на поведение услуг:

<endpointBehaviors> 
    <behavior name="restfulBehavior"> 
     <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" /> 
     <!--<enableWebScript />--> 
    </behavior> 
</endpointBehaviors> 

или в операции контракта вашего интерфейса