为了让 WCF 服务与 JQuery 一起工作,我在操作合同上添加了一个 WebInvoke 属性来控制 JSON 序列化,如下所示:
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
有没有办法通过配置中的服务绑定来控制这种序列化,因为它限制了这个服务向不同的端点提供不同的序列化。
为了让 WCF 服务与 JQuery 一起工作,我在操作合同上添加了一个 WebInvoke 属性来控制 JSON 序列化,如下所示:
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
有没有办法通过配置中的服务绑定来控制这种序列化,因为它限制了这个服务向不同的端点提供不同的序列化。
我有一个不同的解决方案,它在 @Marc Gravell 的另一端工作:不是复制合同,而是从服务实现派生 2 个不同的类。这些只是类型别名;它们是必要的,因为 WCF 激活系统(至少在 IIS 上)不允许您在不同的 URL 激活相同的服务类型(我不确定 Gravell 的解决方案为什么没有遇到这个问题 - 我的错误当我尝试在同一站点的不同 URL 上激活相同的服务类时,得到的是“URI 的注册已经存在...”)。请注意,如果您想同时使用 pox 和 json 运行相同的服务,这只是一个问题。如果您只想控制响应格式,则不需要此解决方法。
我的解决方案背后的关键概念是为同一个服务使用 2 个不同的 URI,然后使用端点行为来设置默认的出站响应格式。您可以在这个问题中找到更多信息,该问题还涉及概念纯度问题:我们是否应该使用合约属性来指定属于网络协议的属性?我认为 Marc Gravell 对这个问题的看法本身是有效的,但它与 WCF 的原始概念不一致,其中合约应该从协议栈中抽象出来。但是端点行为不允许您指定所有与 REST 相关的属性,您必须使用 URI 模板和入站格式的属性。
REST 是否可以以不同的方式实现?尽管 WCF 的设计者在设计通用框架方面做得非常出色,但我认为他们没有看到 REST 的到来。有些东西,比如 URI 模板,似乎确实属于合同。
说够了!这是代码。首先是 web.config 文件。这就是魔法发生的地方。请注意,我在此示例中使用基于 WCF 4 配置的激活,但您也可以通过使用 2 个 svc 文件来表示 2 个 URI 来完成相同的操作。
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="StackOverflow.QuoteOfTheDayAsJson">
<endpoint binding="webHttpBinding" contract="StackOverflow.IQuoteOfTheDay"
behaviorConfiguration="jsonBehavior" />
</service>
<service name="StackOverflow.QuoteOfTheDayAsPox">
<endpoint binding="webHttpBinding" contract="StackOverflow.IQuoteOfTheDay"
behaviorConfiguration="poxBehavior" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp defaultOutgoingResponseFormat="Json" />
</behavior>
<behavior name="poxBehavior">
<webHttp defaultOutgoingResponseFormat="Xml"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false">
<serviceActivations>
<add relativeAddress="QuoteOfTheDayJson.svc"
service="StackOverflow.QuoteOfTheDayAsJson"/>
<add relativeAddress="QuoteOfTheDayPox.svc"
service="StackOverflow.QuoteOfTheDayAsPox"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
下面是代码,包括服务契约、服务实现和实现这项工作所必需的类型别名:
namespace StackOverflow
{
[DataContract]
public class Quotation
{
[DataMember]
public string Text { get; set; }
[DataMember]
public string Author { get; set; }
}
[ServiceContract]
public interface IQuoteOfTheDay
{
[OperationContract]
[WebInvoke(Method="GET", UriTemplate="GetTodaysQuote")]
Quotation GetTodaysQuote();
}
public class QuoteOfTheDayImp : IQuoteOfTheDay
{
public Quotation GetTodaysQuote()
{
return new Quotation()
{
Text = "Sometimes it's better to appologize for not asking permission",
Author = "Admiral Grace Murray Hopper"
};
}
}
/// <summary>
/// A type alias used for json activation
/// </summary>
public class QuoteOfTheDayAsJson : QuoteOfTheDayImp
{}
/// <summary>
/// A type alias used for pox activation
/// </summary>
public class QuoteOfTheDayAsPox : QuoteOfTheDayImp
{}
}
如果不是因为类型别名的必要性,我会说这是一个完整的解决方案。如果您不想同时支持多种格式,这是一个完整的解决方案。这优于多合约解决方案,因为只有一个合约,您不需要保持 2 个合约同步。