65.9K
CodeProject 正在变化。 阅读更多。
Home

从 Silverlight 客户端检索 WebService 异常

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (9投票s)

2010年1月24日

公共领域

2分钟阅读

viewsIcon

39089

downloadIcon

364

本文介绍了如何通过创建 WCF 终结点行为来从 Web 服务检索异常到 Silverlight 客户端。

引言

默认情况下,在 WCF 服务中抛出的异常不会返回到 Silverlight 客户端,而且每个人都知道异常处理对于任何企业解决方案都至关重要,例如,通知用户发生故障或用于调试目的。

在编写本文之前,我搜索了很多关于如何从 Web 服务检索异常到 Silverlight 客户端的信息。大多数文章都讨论了实现一个自定义错误对象,该对象的属性填充了 Web 服务中的错误异常,并将该对象从 Web 服务传递到 Silverlight 客户端。虽然这可能是一个很好的解决方案,但这会在客户端检索异常消息时增加额外的开销。我们希望在这里直接从 e 事件处理程序中检索错误,如下所示

private void customerService_Completed(object sender, 
             GenerateErrorCompletedEventArgs e)
{
   if (e.Error == null)
   {
     myOutput.Text = "Sucess";
   }
   else
   {
     myOutput.Text = e.Error.Message.ToString();
   }
}

背景

默认情况下,WCF 服务会返回带有 HTTP 500 响应代码的错误消息。由于浏览器网络堆栈的限制,这些消息的正文在 Silverlight 中无法访问,因此,客户端无法读取错误消息。

为了覆盖此约束并使 Silverlight 客户端能够检索错误,关键是使 WCF 服务返回带有 HTTP 200 响应代码而不是 HTTP 500 响应代码的错误消息。此更改使 Silverlight 能够读取消息正文,并且还使同一服务的 WCF 客户端能够继续使用其正常的错误处理程序工作;因此,无需为现有客户端代码进行重构。

Using the Code

来自附加源代码中 *ServiceFaultBehavior.cs* 的 ServiceFaultBehavior 类实现了用于编写自定义终结点行为的 IEndpointBehavior 接口。主要实现是 ApplyDispatchBehavior 方法,该方法将 ServiceFaultMessageInspector 应用于 WCF 终结点行为。

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

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

   // 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 System.Type BehaviorType
   {
      get { return typeof(ServiceFaultBehavior); }
   }

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

ServiceFaultMessageInspector 类通过使用其 BeforeSendReply 方法,在回复为 Fault 时,将 HTTP 响应从 HTTP 500 更改为 HTTP 200。

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace Service
{

/// <summary>
/// Change reponse code from HTTP 500 to HTTP 200 works with 
/// <see "Service.ServiceFaultBehavior" />
/// </summary>
public class ServiceFaultMessageInspector : IDispatchMessageInspector
{
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
      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;
     }
}
}

配置

不要忘记配置 WCF 服务 *web.config* 中的 <system.serviceModel> 部分,以将新的 WCF 终结点行为应用于该服务。

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="serviceFaults" 
        type="Service.ServiceFaultBehavior, 
        Service, 
        Version=1.0.0.0, 
        Culture=neutral, 
        PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ServiceFaultBehavior">
          <serviceFaults/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="Service.CustomerServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <services>
      <service behaviorConfiguration="Service.CustomerServiceBehavior" 
      name="Service.CustomerService">
        <endpoint address="" behaviorConfiguration="ServiceFaultBehavior" 
        binding="basicHttpBinding" contract="Service.CustomerService"/>
        <!--<endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>-->
      </service>
    </services>
</system.serviceModel>

对此 WCF 服务进行修改后,访问此服务的 Silverlight 客户端将可以访问错误。

检索用于调试的错误

可以发送两种类型的 SOAP 错误:声明的和未声明的。 *声明的* SOAP 错误是指操作具有 FaultContractAttribute 属性,该属性指定自定义 SOAP 错误类型。这些 SOAP 错误用于生产中。 *未声明的* SOAP 错误未在操作的协定中指定。这些 SOAP 错误仅用于调试。

未声明的 SOAP 错误对于调试服务很有用。启用这些未定义的错误以传播从服务发送到客户端的错误消息中有关异常的完整信息很简单。这是通过将 <serviceDebug> 配置元素的 includeExceptionDetailInFaults 属性设置为 true 来完成的。

<serviceDebug includeExceptionDetailInFaults="true"/>
© . All rights reserved.