开发者

How to get WCF services to return fault messages with an HTTP 200 response code?

开发者 https://www.devze.com 2023-02-10 20:56 出处:网络
We are trying to get our WCF services return to fault messages with an HTTP 200 response code to our Silverlight 4 clients following this article on MSDN. After spending most of the day fighting with

We are trying to get our WCF services return to fault messages with an HTTP 200 response code to our Silverlight 4 clients following this article on MSDN. After spending most of the day fighting with the configuration, debugging and searching relevant topics on SO, we still haven't got it working.

Here is our SilverlightFaultBehaviour class:

public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
        EndpointDispatcher endpointDispatcher)
    {
        SilverlightFaultMessageInspector inspector = 
        new SilverlightFaultMessageInspector();
        endpointDispatcher.DispatchRuntime
            .MessageInspectors.Add(inspector);
    }

    public class SilverlightFaultMessageInspector : IDispatchMessageInspector
    {
        public void BeforeSendReply(ref Message reply,
            object correlationState)
  开发者_JS百科      {
            if (reply.IsFault)
            {
                HttpResponseMessageProperty property = 
                    new HttpResponseMessageProperty();

                // Here the response code is changed to 200.
                property.StatusCode = System.Net.HttpStatusCode.OK;

                reply.Properties[HttpResponseMessageProperty.Name] = property;
            }
        }

        public object AfterReceiveRequest(ref Message request,
            IClientChannel channel, 
            InstanceContext instanceContext)
        {
            // Do nothing to the incoming message.
            return null;
        }
    }

    // The following methods are stubs and not relevant. 
    public void AddBindingParameters(ServiceEndpoint endpoint,
        BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, 
        ClientRuntime clientRuntime)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public override Type BehaviorType
    {
        get { return typeof(SilverlightFaultBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new SilverlightFaultBehavior();
    }
}

And here is the relevant snippet from our web.config:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior name="FooWebServiceBehaviour">
        <serviceDebug includeExceptionDetailInFaults="true" />
        <serviceMetadata httpGetEnabled="true" />
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="SilverlightFaultBehavior">
        <silverlightFaults />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <services>
    <service name="Foo.Web.Services.BarService" behaviorConfiguration="FooWebServiceBehaviour">
      <endpoint address="" binding="customBinding"
        bindingConfiguration="Foo.Web.Services.HttpBinding"
        contract="Foo.Web.Service.IBarService"
        behaviorConfiguration="SilverlightFaultBehavior" />
    </service>
  </services>
  <extensions>
    <behaviorExtensions>
      <add name="silverlightFaults"
        type="Foo.Web.Behavior.SilverlightFaultBehavior, Foo.WebBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
  </extensions>
</system.serviceModel>

The problem seems to be that the BeforeSendReply method is never called, and our clients still receive the useful "Not Found" error every time we throw a FaultException.

Is there something blatantly obvious that we are missing to get the services to return the response code we want?


This turned out to be an error in our web.config, we replaced the generated customBinding with basicHttpBinding on our endpoints and now things are working as expected.

Strange, when adding a "Silverlight-enabled WCF Service" gives you a default configuration that doesn't seem to work with Silverlight.


Or you could place following magic code snippet into your Silverlight form constructor and leave service SOAP compliant (returning stadard 500 for faults)

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);

I was amazed when it worked like a charm.


As originally suggested, using HTTP status to "communicate" faults is best practice. So if you can do that, you should.

As for your solution, I'm not familiar with the model described, but in base WCF you can just try/catch whatever, grab the outgoing response, and modify from there.

Something like this: (this changes a 400 to a 200)

try
{
    throw new WebFaultException(System.Net.HttpStatusCode.BadRequest);
}
catch(WebFaultException)
{
    WebOperationContext.Current.OutgoingResponse.StatusCode = 
                                                  System.Net.HttpStatusCode.OK;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消