尽管设置了accept,但WCF服务在请求json时返回XML响应:application / json

时间:2016-03-23 21:00:31

标签: c# web-services wcf serialization

我有一个WCF服务,它返回一个看起来像这样的简单DTO:

    [DataContract]
[KnownType(typeof(TimeTriggerCreateResult))]
[KnownType(typeof(ScheduleCreateResult))]
public class TriggerCreateResult
{
    [DataMember(Order = 1)] public bool AlreadyExisted;
    [DataMember(Order = 2)] public int SchedulerId; // TODO: rename to ScheduleId
    [DataMember(Order = 3, EmitDefaultValue = false)] public int TriggerId;
    [DataMember(Order = 4)] public ScheduleType ScheduleType;

    public NewSchedule Schedule;
}
[DataContract]
public class TimeTriggerCreateResult : TriggerCreateResult
{
    public TimeTriggerCreateResult()
    {
        ScheduleType = ScheduleType.TimeTrigger;
    }

    public TimeTriggerDto TimeTrigger;
    [DataMember] public List<DateTuple> NextRun;
    public List<DateTuple> OlderRuns;
}
[Description("Create Schedule")]
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "schedules/create")]
        TriggerCreateResult CreateNewSchedule(ScheduleDto scheduleDto);
[DataContract]
public enum ScheduleType
{
    [EnumMember] NoTrigger = 0,
    [EnumMember] TimeTrigger = 1,
}

此服务在幕后执行了许多复杂的操作,但返回了一个带有其定义中提到的相应属性的DTO。

我使用标题中的以下key =&gt;值来使用此服务:accept:application/json但具有讽刺意味的是,当服务创建新计划时,我会收到 XML响应。这是第一次创建计划时,它返回XML响应。如果尝试再次创建相同的计划,那么我得到 JSON响应,即如果计划已经存在于数据库中。我们不会以不同的响应格式手动序列化。我们完全依赖于WCF的序列化/反序列化。

我尝试过像REST WCF service returns XML response but not JSON response这样的答案来追踪问题,但没有得到任何有用的信息。我浪费了两天完全尝试不同的组合,如:

  • KnownTypes(typeof(ScheduleType))添加到TriggerCreateResult DTO,以防这是序列化问题。但如果是序列化问题,它不会抛出异常吗?
  • 因为当数据库中已存在计划时它总是返回一个json,我尝试将AlreadyExisted设置为true,但这根本没有帮助。
  • 我可以屏蔽问题,并始终使用operationcontract声明的json中的RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json强制WebInvoke响应。此外,通过确保DTO中使用的所有枚举类型ScheduleType都使用DataContract属性进行修饰,并将其成员声明为EnumMember。但话说回来,即使响应是JSON 符合预期响应标头包含Content-Type: application/xml

但是我想知道在请求JSON格式时导致这种自动XML序列化的原因,即使没有遇到序列化异常。我知道这是因为我们尝试了其他问题中提到的日志记录和跟踪。它只是静默地给出了HTTP 200的响应,但当预期的是JSON时,返回XML数据而不是JSON数据。

这使得这个奇怪的是,这个服务总是在请求返回时返回JSON响应,但最近的更改引入了枚举属性ScheduleType,它被初始化为构造函数内的特定类型对应的DTO,TimeTriggerCreateResult内的示例,它被初始化为TimeTrigger。从那以后,它一直表现得很奇怪。此后服务的响应采用XML格式,当它创建了一个从未存在于DB中的新计划时,当发生这种情况时,bool AlreadyExisted将具有值false。但是如果再次执行相同的请求,那么它会返回一个JSON响应,但是AlreadyExisted,现在是true

示例xml响应:

enter image description here

我不是所有WCF的专家。所以,我想知道在请求JSON时,什么可能导致WCF序列化以静默方式返回XML。

我浪费了相当多的时间(约5-6小时),试图通过测试各种不同的设置来了解正在发生的事情。我不想为此进行web.config更改,因为这是受此魔法行为影响的唯一服务。但我无法理解这种相当不自然的现象。如果您有任何想法,请提供帮助。

2 个答案:

答案 0 :(得分:1)

我认为你需要添加

  <endpointBehaviors>
    <behavior name="endpointBehavior">
      <enableWebScript />
      <webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Json" />
    </behavior>
  </endpointBehaviors>

<system.serviceModel> <behaviors>部分

答案 1 :(得分:1)

如果您希望响应的格式基于请求的accept标头,则需要设置WebHttpEndpoint或WebHttpBehaviour的AutomaticFormatSelectionEnabled属性。

<system.serviceModel>
  <behaviors> 
    <endpointBehaviors> 
      <behavior> 
        <webHttp automaticFormatSelectionEnabled="true" /> 
      </behavior> 
    </endpointBehaviors>
  </behaviors> 
  <standardEndpoints>  
    <webHttpEndpoint> 
      <!-- the "" standard endpoint is used by WebServiceHost for auto creating a web endpoint. --> 
      <standardEndpoint name="" helpEnabled="true" />
    </webHttpEndpoint>
  </standardEndpoints> 
</system.serviceModel>

有关详细信息,请参阅MSDN。要使用的最佳格式是通过按顺序检查以下内容来确定

  1. 请求消息的Accept标头中的媒体类型。
  2. 请求消息的内容类型。
  3. 操作中的默认格式设置。
  4. WebHttpBehavior中的默认格式设置。