使用UriTemplate在WCF中组合SOAP / JSON / XML

时间:2021-02-22 15:22:33

I'm trying to build a generic web service interface using WCF, to allow 3rd party developers to hook into our software. After much struggling and reading (this question helped a lot), I finally got SOAP, JSON and XML (POX) working together.

我正在尝试使用WCF构建一个通用的Web服务接口,以允许第三方开发人员加入我们的软件。经过多次努力和阅读(这个问题帮了很多),我终于让SOAP,JSON和XML(POX)一起工作了。

To simplify, here's my code (to make this example simple, I'm not using interfaces -- I did try this both ways):

为了简化,这是我的代码(为了使这个例子简单,我没有使用接口 - 我确实尝试了这两种方式):

<ServiceContract()> _
Public Class TestService
    Public Sub New()
    End Sub

    <OperationContract()> _
    <WebGet()> _
    Public Function GetDate() As DateTime
        Return Now
    End Function


    '<WebGet(UriTemplate:="getdateoffset/{numDays}")> _
    <OperationContract()> _
    Public Function GetDateOffset(ByVal numDays As Integer) As DateTime
        Return Now.AddDays(numDays)
    End Function

End Class

and the web.config code:

和web.config代码:

<services>
  <service name="TestService" 
           behaviorConfiguration="TestServiceBehavior">
    <endpoint address="soap" binding="basicHttpBinding" contract="TestService"/>
    <endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="TestService"/>
    <endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="TestService"/>
    <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding" />
  </service>
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="jsonBehavior">
      <enableWebScript/>
    </behavior>
    <behavior name="poxBehavior">
      <webHttp />
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="TestServiceBehavior">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

This actually works -- I'm able to go to TestService.svc/xml/GetDate for xml, TestService.svc/json/GetDate for json, and point a SOAP client at TestService.svc?wsdl and have the SOAP queries work.

这实际上是有效的 - 我可以使用TestService.svc / xml / GetDate for xml,TestService.svc / json / GetDate for json,并将SOAP客户端指向TestService.svc?wsdl并让SOAP查询工作。

The part I'd like to fix is the queries. I have to use TestService.svc/xml/GetDateOffset?numDays=4 instead of TestService.svc/xml/GetDateOffset/4. If I specify the UriTemplate, I get the error:

我想解决的部分是查询。我必须使用TestService.svc / xml / GetDateOffset?numDays = 4而不是TestService.svc / xml / GetDateOffset / 4。如果我指定UriTemplate,我收到错误:

Endpoints using 'UriTemplate' cannot be used with 'System.ServiceModel.Description.WebScriptEnablingBehavior'.

使用'UriTemplate'的端点不能与'System.ServiceModel.Description.WebScriptEnablingBehavior'一起使用。

But of course without using <enableWebScript/>, JSON doesn't work.

但是当然不使用 ,JSON不起作用。

The only other thing I've seen that I think will work is making 3 different services (.svc files), that all implement an interface that specifies the contract, but in the classes specify different WebGet/WebInvoke attributes on each class. This seems like a lot of extra work, that frankly, I don't see why the framework doesn't handle for me. The implementation of the classes would all be the same, except for the attributes, which means over time it would be easy for bugs/changes to get fixed/done in one implementation but not the others, leading to inconsistent behaviour when using the JSON vs SOAP implementation for example.

我认为唯一可行的另一件事是制作3种不同的服务(.svc文件),它们都实现了一个指定契约的接口,但是在类中为每个类指定了不同的WebGet / WebInvoke属性。这似乎是很多额外的工作,坦率地说,我不明白为什么框架不适合我。除了属性之外,类的实现都是相同的,这意味着随着时间的推移,错误/更改很容易在一个实现中得到修复/完成而不是其他实现,导致使用JSON vs时行为不一致例如,SOAP实现。

Am I doing something wrong here? Am I taking a totally wrong approach and misusing WCF? Is there a better way to do this?

我在这里做错了吗?我采取了一种完全错误的方法并滥用WCF吗?有一个更好的方法吗?

With my experience doing web stuff, I think it should be possible for some kind of framework to handle this ... I even have an idea in my head of how to build it. It just seems like WCF is supposed to be doing this, and I don't really want to reinvent the wheel.

根据我在做网络的经验,我认为应该可以通过某种框架来处理这个......我甚至对如何构建它有一个想法。看起来WCF应该是这样做的,我真的不想重新发明*。

3 个解决方案

#1


27  

Actually <enableWebScript /> is not required for "pure" JSON support. The WebScriptEnablingBehavior is only required if you want to support ASP.NET AJAX. More often than not, if you're trying to work with standard script libraries, you don't want to enable this support for your services.

实际上,“纯”JSON支持不需要 。仅当您要支持ASP.NET AJAX时才需要WebScriptEnablingBehavior。通常,如果您尝试使用标准脚本库,则不希望为您的服务启用此支持。

Instead what you want to do for your JSON endpoint is just use the WebHttpBehavior and set the DefaultOutgoingResponseFormat="JSON". The problem is, in .NET 3.5, you cannot control this setting through config because WebHttpElement does not expose these properties for configuration. To work around this in 3.5 have supplied an implementation for what I call the EnhancedWebHttpElement here in this answer to another * question.

相反,您要为JSON端点做的只是使用WebHttpBehavior并设置DefaultOutgoingResponseFormat =“JSON”。问题是,在.NET 3.5中,您无法通过配置控制此设置,因为WebHttpElement不会公开这些属性以进行配置。为了解决另一个*问题,在3.5中为解决这个问题提供了一个我称之为EnhancedWebHttpElement的实现。

Luckily Microsoft realized this shortcoming and enabled configuration of all the WebHttpBehavior settings via the WebHttpElement in 4.0.

幸运的是,微软意识到了这个缺点,并通过4.0中的WebHttpElement启用了所有WebHttpBehavior设置的配置。

#2


4  

Drew's answer is spot on, but I think the question still stands. Is there a sane way of having JSON for AJAX () and the blessings of UriTemplate?

德鲁的回答很明显,但我认为问题仍然存在。是否有一种理智的方式来获得AJAX()的JSON和UriTemplate的祝福?

I think it is worth mentioning that JSON returned with is different than JSON generated with [WebGet(ResponseFormat=WebMessageFormat.Json)]. The former is wrapped around the the MS AJAX 'd' element e.g. {"d":[{...}]}.

我认为值得一提的是,返回的JSON与使用[WebGet(ResponseFormat = WebMessageFormat.Json)]生成的JSON不同。前者包裹在MS AJAX'd'元素周围,例如{ “d”:[{...}]}。

#3


0  

You have specified integer parameters in your operation. URI template does not work well with int parameters. Please change it to string , It will work.

您已在操作中指定了整数参数。 URI模板不适用于int参数。请将其更改为字符串,它会起作用。

I think you have to write your own QuerystringConverter to use int with URITemplate.

我认为你必须编写自己的QuerystringConverter来使用int和URITemplate。

#1


27  

Actually <enableWebScript /> is not required for "pure" JSON support. The WebScriptEnablingBehavior is only required if you want to support ASP.NET AJAX. More often than not, if you're trying to work with standard script libraries, you don't want to enable this support for your services.

实际上,“纯”JSON支持不需要 。仅当您要支持ASP.NET AJAX时才需要WebScriptEnablingBehavior。通常,如果您尝试使用标准脚本库,则不希望为您的服务启用此支持。

Instead what you want to do for your JSON endpoint is just use the WebHttpBehavior and set the DefaultOutgoingResponseFormat="JSON". The problem is, in .NET 3.5, you cannot control this setting through config because WebHttpElement does not expose these properties for configuration. To work around this in 3.5 have supplied an implementation for what I call the EnhancedWebHttpElement here in this answer to another * question.

相反,您要为JSON端点做的只是使用WebHttpBehavior并设置DefaultOutgoingResponseFormat =“JSON”。问题是,在.NET 3.5中,您无法通过配置控制此设置,因为WebHttpElement不会公开这些属性以进行配置。为了解决另一个*问题,在3.5中为解决这个问题提供了一个我称之为EnhancedWebHttpElement的实现。

Luckily Microsoft realized this shortcoming and enabled configuration of all the WebHttpBehavior settings via the WebHttpElement in 4.0.

幸运的是,微软意识到了这个缺点,并通过4.0中的WebHttpElement启用了所有WebHttpBehavior设置的配置。

#2


4  

Drew's answer is spot on, but I think the question still stands. Is there a sane way of having JSON for AJAX () and the blessings of UriTemplate?

德鲁的回答很明显,但我认为问题仍然存在。是否有一种理智的方式来获得AJAX()的JSON和UriTemplate的祝福?

I think it is worth mentioning that JSON returned with is different than JSON generated with [WebGet(ResponseFormat=WebMessageFormat.Json)]. The former is wrapped around the the MS AJAX 'd' element e.g. {"d":[{...}]}.

我认为值得一提的是,返回的JSON与使用[WebGet(ResponseFormat = WebMessageFormat.Json)]生成的JSON不同。前者包裹在MS AJAX'd'元素周围,例如{ “d”:[{...}]}。

#3


0  

You have specified integer parameters in your operation. URI template does not work well with int parameters. Please change it to string , It will work.

您已在操作中指定了整数参数。 URI模板不适用于int参数。请将其更改为字符串,它会起作用。

I think you have to write your own QuerystringConverter to use int with URITemplate.

我认为你必须编写自己的QuerystringConverter来使用int和URITemplate。