让WCF支持Http调用
自己有一个项目是使用WCF写的,使用的是wsHttpBind,现在的新需求是要做Web版的,如果再写一套WebApi那工作量有点大了
WCF是可以使用Http进行访问的,只要在配置中开启了
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
</behavior>
</serviceBehaviors>
但因为是使用的wsHttpBind进行绑定,所以有一个问题,http在发送POST或GET请求时,需要将参数封闭成Soap式的XML信封形式,然后写入到请求正文中,大致如下
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body>
<!-- 请求方法名称 --> <Login xmlns="http://tempuri.org/" xmlns:a="http://schemas.datacontract.org/2004/07/PSerivce" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<!-- 请求参数 name --> <name>super</name>
<!-- 请求参数 pwd-->
<pwd>123456</pwd>
<!-- 复杂参数 person-->
<person xmlns:a="http://schemas.datacontract.org/2004/07/PublicModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:gender>boy</a:gender>
</person>
</Login>
</s:Body>
</s:Envelope>
上面的信封的意思就是我要 访问的方法是Login,有三个参数,name,pwd,以及一个自定义类型person,可以看到
封装成xml的形式很麻烦,特别是针对复杂类型,而wcf返回的正文也是一样的形式,很不好解析,而且在请求标头里还需要加一个自定义的SOAPAction属性,值为 "http://tempuri.org/IPublicSerivce/Login" (注意,引号也是必须的,该值的组成为 "命名空间/契约接口/方法名称"
换另一种更简单的方式
这是配置文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<!--配置WCF-->
<system.serviceModel>
<!--配置行为-->
<behaviors>
<!--终结点行为-->
<endpointBehaviors>
<!--配置一个web行为-->
<behavior name="WebBehavior">
<!--以下参数的释义
1.是否启用帮助页面
2.参数与响应的封装类型(此处为都封装)
3.默认的返回主体格式化(此处为返回json格式)
4.是否自动选择请示正文和响应正文的格式化(如果为true,则会先去找http请示标头上的Accept,
再找契约方法上有无 RequestFormat/ResponseFormat,如果没有,则找此配置中有无
defaultOutgoingResponseFormat
5.启用异常输出
-->
<webHttp helpEnabled="true"
defaultBodyStyle="Wrapped"
defaultOutgoingResponseFormat="Json"
automaticFormatSelectionEnabled="true"
faultExceptionEnabled="true"
/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<!--添加绑定-->
<bindings>
<!--添加web绑定-->
<webHttpBinding>
<!--是否启用跨域-->
<binding crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<!-- 我们手动添加 -->
<services>
<!--添加一个服务-->
<service name="PublicSerivce.PSerivce">
<!--绑定一个用来http访问的web终结点
注意该终结点的属性 address 因为这里绑了两个终结点
所以它们的路径不能一致,使用http调用的时候
此处的地址可能为 http://localhost:56599/pSerivcce.svc/SerivceWeb/请示的方法名称
-->
<endpoint address="SerivceWeb"
behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="PublicInterFace.IPublicSerivce" />
<!--绑定第二个终结点-->
<endpoint binding="basicHttpBinding"
contract="PublicInterFace.IPublicSerivce" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
配置好了文件后,在契约接口中应当打上WebGet或WebInvoke标记
WebGet:允许http以Get方式调用,但要指定UriTemplete(指定参数形式,一般来说不太常用,请参见 https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/feature-details/uritemplate-and-uritemplatetable
WebInovke:默认为POST请求,如果要使用Get,则设置其Method属性
以下为契约接口示例
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface IPublicSerivce
{
//这个标记还是可以使用以前的访问模式
[OperationContract]
//下面这个标记是允许使用http方式调用
//因为在配置文件中已经设置了默认的 requestMessageFormat,responseMessageFormat,BodyStyle,所以此处不用设置属性
//而UriTemplate未设置,则直接使用方法名称 (UriTemplate可以给方法指定别名)
[WebInvoke]
string GetErroMsg();
[OperationContract]
[WebInvoke]
bool Login(string name1, string pwd, out UserInfoModel userInfo);
[OperationContract]
[WebInvoke]
bool FindPartsForType(string name, out DataTable dt);
[OperationContract]
[WebInvoke]
bool FindTypeForPart(string name, out DataTable dt);
}
现在就OK了,现在我们就可以使用http调用wcf了,以下为POSTMAN的调用截图
示例为调用
FindTypeForPart
请求头

请求主体

响应

可以看到,请求和响应的时候都是json,但out参数datatable类型却输出的是xml,这个暂时我还不知道怎么弄成json的
另外特别注意
参数是自定义类型:
需要完整属性,不能是自动属性,否则返回的json中属性名称可能就不是你的预期了(自己试下就知道了)
另外如果是DateTime属性,最好换成DateTime?类型,而且此属性一定不能给其赋值 DateTime.MinValue,否则会进入两次调用,而且wcf会关闭连接导致获取不到响应(这个我也不知道为嘛)

浙公网安备 33010602011771号