WCF服务mex及服务端点访问返回400错误排查求助
我参考微软官方文档创建了一个简单的WCF服务,暴露两个端点:
- 服务端点(/CalculationService);
- 元数据端点(/mex)。
该服务已在控制台应用中成功托管,可通过浏览器访问服务baseAddress及baseAddress?wsdl,但访问/mex和/CalculationService端点时均返回400错误,请问问题出在哪里?
托管应用代码
static void Main(string[] args) { // Step 1 of the address configuration procedure: Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/ServiceModelSamples/Service/"); // Step 2 of the hosting procedure: Create ServiceHost ServiceHost selfHost = new ServiceHost(typeof(Service1), baseAddress); try { // Step 3 of the hosting procedure: Add a service endpoint. // Step 4 of the hosting procedure: Enable metadata exchange. ServiceMetadataBehavior smb = selfHost.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (smb == null) smb = new ServiceMetadataBehavior(); //ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; selfHost.Description.Behaviors.Add(smb); selfHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, new BasicHttpBinding(), "mex"); // Step 5 of the hosting procedure: Start (and then stop) the service. selfHost.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "CalculatorService"); selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } }
WCF服务web.config配置
<?xml version="1.0"?> <configuration> <appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> </appSettings> <system.web> <compilation debug="true" targetFramework="4.6.1" /> <httpRuntime targetFramework="4.6.1"/> </system.web> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the values below to false before deployment --> <!--<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>--> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <!--<protocolMapping> <add binding="basicHttpsBinding" scheme="https" /> </protocolMapping>--> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <!-- To browse web app root directory during debugging, set the value below to true. Set to false before deployment to avoid disclosing web app folder information. --> <directoryBrowse enabled="true"/> </system.webServer> </configuration>
给你梳理几个核心问题点,都是控制台自托管WCF时容易踩的坑:
1. Mex端点绑定错误
你给Mex元数据端点用了BasicHttpBinding,这是完全错误的!Mex端点必须使用专门的元数据绑定,比如MetadataExchangeHttpBinding(对应HTTP场景)或者MetadataExchangeHttpsBinding(对应HTTPS场景)。普通的业务绑定不支持元数据交换的协议格式,直接用它配置Mex端点必然返回400错误。
2. 服务端点的浏览器访问误区
WCF的WSHttpBinding是SOAP服务端点,它默认只处理SOAP协议的POST请求,而浏览器发起的是HTTP GET请求,两者协议不匹配,所以直接在浏览器访问/CalculatorService会返回400错误——这是WCF的设计行为,不是bug。你需要用SOAP客户端(比如Visual Studio自带的WCF测试客户端、Postman构造SOAP请求)来调用这个端点。
3. 控制台托管时web.config无效
注意:你是用控制台应用自托管WCF服务,此时WCF服务项目里的web.config完全不起作用!控制台自托管的配置优先级是:代码硬编码配置 > 控制台应用自身的app.config,和服务项目的web.config没有任何关系。你之前在web.config里注释的serviceMetadata配置对当前托管的服务没有影响,所有配置都要在控制台代码或它的app.config里设置。
修正后的托管代码
把Mex端点的绑定改成MetadataExchangeHttpBinding,调整后的代码如下:
static void Main(string[] args) { Uri baseAddress = new Uri("http://localhost:8000/ServiceModelSamples/Service/"); ServiceHost selfHost = new ServiceHost(typeof(Service1), baseAddress); try { ServiceMetadataBehavior smb = selfHost.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (smb == null) smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; selfHost.Description.Behaviors.Add(smb); // 替换为元数据专用绑定 selfHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); selfHost.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "CalculatorService"); selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.ReadLine(); selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } }
验证方式
- Mex端点:现在可以用
svcutil.exe工具或者WCF测试客户端访问http://localhost:8000/ServiceModelSamples/Service/mex,能正常获取元数据,不会再返回400错误。 - 服务端点:打开Visual Studio的WCF测试客户端,添加服务地址
http://localhost:8000/ServiceModelSamples/Service/,就能看到IService1的方法并进行调用测试。
如果想让服务端点支持浏览器GET请求测试,可以给服务添加WebHttpBinding并配置WebHttpBehavior,不过这属于REST风格的WCF,和当前的SOAP服务模式不同,可根据需求选择是否调整。
内容的提问来源于stack exchange,提问作者Amey Deshpande

