自托管WCF 4.5 WsHttpBinding - > 400错误回应

时间:2013-06-17 16:10:09

标签: wcf .net-4.5

我是自托管WCF WSHttpBinding绑定服务。在运行时,我无法获得服务呼叫的任何变化。你能诊断出这个问题吗?

地址栏中的基本GET(多个浏览器)因400 Bad Request而失败。使用GETPOST 'dataType': 'json''dataType': 'jsonp'的$ .ajax也是如此。我试过基地址的变化。包含或省略WebInvokeAttribute并没有什么不同。 HTTP方法是否匹配或不匹配并没有什么不同。

将服务端点设置为较窄的路径,然后浏览到该端点外部的路径会导致错误(关于不允许的方法)。在没有jsonp的情况下使用ajax中的GET会因为预期的跨站点脚本保护而失败,但我可以避免这种情况。

(这个问题在网上有一百万个版本。有些版本似乎已经解决,但答案没有帮助。其他版本尚未解决。这与其中任何一个都不完全相同。)

WCF跟踪总是指示:“从网络收到的XML存在问题。”与“消息的主体无法读取,因为它是空的”作为内部异常 - 即使是GET请求,其中应该没有正文(对吗?)。即使我尝试使用''或'{}'的json数据POST,我仍然会出现此错误。

此代码示例主要来自:http://msdn.microsoft.com/en-us/library/ms730935.aspx,.Net 4.5 WCF示例。该示例比必要的大,我必须添加binding.HostNameComparisonMode = HostNameComparisonMode.Exact;,以便Windows允许它在没有完全管理权限的情况下运行。我也玩过相对url(现在为空)来测试。

运行此命令并将浏览器指向http://localhost:8000/正在为MEX / WSDL广告提供服务。这告诉我web服务正在运行,我正在浏览到正确的端点(至少加上或减去服务前缀),并且Windows防火墙或权限不会干扰进程在端口上打开或提供服务的能力。然而http://localhost:8000/Ping只得到400。

如果我没记错的话(可能不是这样),旧版本的WCF和.NET不允许或不支持自托管的类似Web的协议。我相信这已经改变了。同样,MEX数据的提供与我想要提供的自定义内容并没有什么不同 - 它只是来自同一过程中的不同位置。

sdb.IncludeExceptionDetailInFaults = true;似乎没有任何有用的效果。

using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;

namespace WCFWebHost
{
    static class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8000/");

            ServiceHost selfHost = new ServiceHost(typeof(EchoService), baseAddress);

            try
            {
                var binding = new WSHttpBinding();
                binding.HostNameComparisonMode = HostNameComparisonMode.Exact;

                selfHost.AddServiceEndpoint(typeof(IEcho), binding, "");

                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                selfHost.Description.Behaviors.Add(smb);

                var sdb = selfHost.Description.Behaviors.Find<ServiceDebugBehavior>();
                sdb.IncludeExceptionDetailInFaults = true;

                selfHost.Open();

                Console.WriteLine("Open and waiting.");
                Console.ReadKey(true);

                selfHost.Close();
            }
            catch (CommunicationException ce)
            {
                Console.WriteLine("An exception occurred: {0}", ce.Message);
                selfHost.Abort();
            }
        }
    }

    [ServiceContract(Namespace = "http://echo")]
    public interface IEcho
    {
        [OperationContract]
        [WebInvoke(
            Method = "GET",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            UriTemplate = "Ping")]
        void Ping();
    }

    public class EchoService : IEcho
    {
        public void Ping()
        {
        }
    }
}

web配置添加了traces.svc配置:

<system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.ServiceModel"
              switchValue="Verbose, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData="C:\Users\...\Traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

===

对我来说似乎很奇怪的是,跟踪的异常似乎来自错误报告本身。跟踪中的此错误是否隐藏了有关原始故障的更好信息?或者我只是在读错了?

<Exception>
<ExceptionType>System.ServiceModel.ProtocolException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>There is a problem with the XML that was received from the network. See inner exception for more details.</Message>
<StackTrace>
at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.ExceptionToTraceString(Exception exception, Int32 maxTraceStringLength)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetSerializedPayload(Object source, TraceRecord traceRecord, Exception exception, Boolean getServiceReference)
at System.Runtime.TraceCore.ThrowingException(EtwDiagnosticTrace trace, String param0, String param1, Exception exception)
at System.Runtime.ExceptionTrace.TraceException[TException](TException exception, String eventSource)
at System.Runtime.ExceptionTrace.AsError(Exception exception)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result)
at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult..ctor(ReplyChannelAcceptor acceptor, Action dequeuedCallback, HttpPipeline pipeline, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()
at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.SharedHttpTransportManager.EnqueueContext(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.IOCompleted(ListenerAsyncResult asyncResult, UInt32 errorCode, UInt32 numBytes)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.ServiceModel.ProtocolException: There is a problem with the XML that was received from the network. See inner exception for more details. ---&gt; System.Xml.XmlException: The body of the message cannot be read because it is empty.
   --- End of inner exception stack trace ---</ExceptionString>
<InnerException>
<Exception>
<ExceptionType>System.Xml.XmlException, System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The body of the message cannot be read because it is empty.</Message>
<StackTrace>
at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetInnerException(Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.ExceptionToTraceString(Exception exception, Int32 maxTraceStringLength)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetSerializedPayload(Object source, TraceRecord traceRecord, Exception exception, Boolean getServiceReference)
at System.Runtime.TraceCore.ThrowingException(EtwDiagnosticTrace trace, String param0, String param1, Exception exception)
at System.Runtime.ExceptionTrace.TraceException[TException](TException exception, String eventSource)
at System.Runtime.ExceptionTrace.AsError(Exception exception)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result)
at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult..ctor(ReplyChannelAcceptor acceptor, Action dequeuedCallback, HttpPipeline pipeline, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()
at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.SharedHttpTransportManager.EnqueueContext(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.IOCompleted(ListenerAsyncResult asyncResult, UInt32 errorCode, UInt32 numBytes)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.Xml.XmlException: The body of the message cannot be read because it is empty.</ExceptionString>
</Exception>
</InnerException>
</Exception>

2 个答案:

答案 0 :(得分:1)

WSHttpBinding创建基于soap的绑定。您无法通过导航到URL来访问此端点。您可以通过创建服务代理或使用wcftestclient(用于测试)来访问此绑定。如果您正在寻找开发REST端点,请使用webHttpBinding而不是wsHttpBinding。

Here是关于如何开发基于REST的服务的快速示例。 Here是一篇文章,描述了webHttpBinding&amp; amp;的wsHttpBinding。

答案 1 :(得分:0)

调用使用WSHttp绑定公开的WCF服务

web.config设置

<services> <service name="MyWcfService.MyService"> <endpoint address="jh" binding="wsHttpBinding" bindingConfiguration="NoSecurity" contract="MyWcfService.IMyService" /> </service> </services>

html page

     //SOAP request generated in order to call the Service method
     var whRequest ="<s:Envelope xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" +
                      "<s:Header>" +
                      "<a:Action s:mustUnderstand=\"1\">http://tempuri.org/IMyService/GetData</a:Action>" +
                      "<a:MessageID>urn:uuid:7fdde7b6-64c8-4402-9af1-cc848f15888f</a:MessageID>" +
                      "<a:ReplyTo>" +
                      "<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>" +
                      "</a:ReplyTo>" +
                      "<a:To s:mustUnderstand=\"1\">http://localhost:1415/MyService.svc/jh</a:To>" +
                      "</s:Header>" +
                      "<s:Body>" +
                      "<GetData xmlns=\"http://tempuri.org/\">"+
                      "<value>9</value>"+
                      "</GetData>" +
                      "</s:Body>" +
                      "</s:Envelope>";

      $(document).ready(function () {
          $("#btnWCFWSHttp").click(function () {
              $.ajax({
                  type: "POST",
                  url: "http://localhost:1415/MyService.svc/jh/",
                  data: whRequest,
                  timeout: 10000,
                  contentType: "application/soap+xml",
                  dataType: "xml",
                  async: false,
                  success: function (data, status, xhr) {
                      $(data).find("GetDataResponse").each(function () {
                          alert($(this).find("GetDataResult").text());
                        });
                  },
                  error: function (xhr, status, error) {
                      alert(error);

                  }
              });
          });
      });