.Net WFC / Web服务异常处理设计模式 [英] .Net WFC/Web service exception handling design pattern

查看:181
本文介绍了.Net WFC / Web服务异常处理设计模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图提出一个简单易用的设计模式,用于在.net wcf服务(特别是启用了Silverlight的wcf服务)中进行错误处理。如果在服务方法中抛出异常,Silverlight应用程序会看到一个CommunicationException,表示远程服务器返回错误:NotFound --->,可能还有一个堆栈跟踪,这取决于您的设置,这完全没有用,告诉你实际的错误,通常真正的错误不是NotFound。

I'm trying to come up with a simple, easy to use design pattern for error handling in a .net wcf service (specifically a silverlight enabled wcf service). If an exception gets thrown in the service method the silverlight application will see a CommunicationException stating "The remote server returned an error: NotFound ---> " and possibly a stack trace depending in your settings, which is entirely not useful because it doesn't tell you the actual error, and usually the real error is not "NotFound".

阅读Web服务和wcf服务和异常,你需要扔肥皂/ wcf标准异常,如FaultException或SoapException。因此,对于wcf服务,您需要将每个方法包装在try catch中,捕获每个异常,将其包装在FaultException中并将其抛出。至少这是我的理解,如果我错了就纠正我。

Reading up on web services and wcf services and exceptions, You need to throw soap/wcf standard exceptions such as FaultException or SoapException. So for a wcf service you need to wrap each method in a try catch, catch each exception, wrap it in a FaultException and throw it. At least that is my understanding, correct me if I am wrong.

所以我创建了我的设计模式:

So I've created my design pattern:

[ServiceContract(Namespace = "http://MyTest")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataAccess
{
    /// <summary>
    /// Error class, handle converting an exception into a FaultException
    /// </summary>
    [DataContractAttribute]
    public class Error
    {
        private string strMessage_m;
        private string strStackTrace_m;

        public Error(Exception ex)
        {
            this.strMessage_m = ex.Message;
            this.strStackTrace_m = ex.StackTrace;
        }

        [DataMemberAttribute]
        public string Message
        {
            get { return this.strMessage_m; }
            set { this.strMessage_m = value; }
        }

        [DataMemberAttribute]
        public string StackTrace
        {
            get { return this.strStackTrace_m; }
            set { this.strStackTrace_m = value; }
        }

        //Convert an exception into a FaultException
        public static void Throw(Exception ex)
        {
            if (ex is FaultException)
            {
                throw ex;
            }
            else
            {
                throw new FaultException<Error>(new Error(ex));
            }
        }
    }

    [OperationContract]
    [FaultContract(typeof(Error))]
    public void TestException()
    {
        try
        {
            throw new Exception("test");
        }
        catch (Exception ex)
        {
            Error.Throw(ex);
        }
    }
}

简而言之,我还没有在我的silverlight应用程序中得到正确的错误。我检查AsyncCompletedEventArgs.Error对象,它仍然包含一个通用错误的CommunicationException对象。帮助我找到一个很好的简单设计模式,让我轻松地从服务中抛出正确的异常,并轻松抓住它在应用程序中。

So to make a long story short, I'm still not getting the correct error in my silverlight application. I inspect the AsyncCompletedEventArgs.Error object and it still contains a CommunicationException object with the generic error. Help me come up with a nice simple design pattern to allow me to easily throw the correct exception from the service, and easily catch it in the application.

推荐答案

好的,我看了一下IErrorHandler的想法。我不知道你可以这样做,它是完美的,因为它让你避免尝试抓住每一种方法。你可以在标准的网络服务中做到这一点吗?我以下列方式实现:

Ok, I looked into the IErrorHandler idea. I had no idea you could do it this way, and it's perfect because it lets you avoid try catches for every method. Can you do this in standard web services too? I implemented it the following way:

/// <summary>
/// Services can intercept errors, perform processing, and affect how errors are reported using the 
/// IErrorHandler interface. The interface has two methods that can be implemented: ProvideFault and
/// HandleError. The ProvideFault method allows you to add, modify, or suppress a fault message that 
/// is generated in response to an exception. The HandleError method allows error processing to take 
/// place in the event of an error and controls whether additional error handling can run.
/// 
/// To use this class, specify it as the type in the ErrorBehavior attribute constructor.
/// </summary>
public class ServiceErrorHandler : IErrorHandler
{
    /// <summary>
    /// Default constructor
    /// </summary>
    public ServiceErrorHandler()
    {
    }

    /// <summary>
    /// Specifies a url of the service
    /// </summary>
    /// <param name="strUrl"></param>
    public ServiceErrorHandler(string strUrl, bool bHandled)
    {
        this.strUrl_m = strUrl;
        this.bHandled_m = bHandled;
    }

    /// <summary>
    ///HandleError. Log an error, then allow the error to be handled as usual. 
    ///Return true if the error is considered as already handled
    /// </summary>
    /// <param name="error"></param>
    /// <returns></returns>
    public virtual bool HandleError(Exception exError)
    {
        System.Diagnostics.EventLog evt = new System.Diagnostics.EventLog("Application", ".", "My Application");
        evt.WriteEntry("Error at " + this.strUrl_m + ":\n" + exError.Message, System.Diagnostics.EventLogEntryType.Error);

        return this.bHandled_m;
    }

    /// <summary>
    ///Provide a fault. The Message fault parameter can be replaced, or set to
    ///null to suppress reporting a fault.
    /// </summary>
    /// <param name="error"></param>
    /// <param name="version"></param>
    /// <param name="msg"></param>
    public virtual void ProvideFault(Exception exError,
        System.ServiceModel.Channels.MessageVersion version,
        ref System.ServiceModel.Channels.Message msg)
    {
        //Any custom message here
        /*
        DataAccessFaultContract dafc = new DataAccessFaultContract(exError.Message);

        System.ServiceModel.FaultException fe = new System.ServiceModel.FaultException<DataAccessFaultContract>(dafc);
        System.ServiceModel.Channels.MessageFault fault = fe.CreateMessageFault();

        string ns = "http://www.example.com/services/FaultContracts/DataAccessFault";
        msg = System.ServiceModel.Channels.Message.CreateMessage(version, fault, ns);
        */
    }

    private string strUrl_m;
    /// <summary>
    /// Specifies a url of the service, displayed in the error log
    /// </summary>
    public string Url
    {
        get
        {
            return this.strUrl_m;
        }
    }

    private bool bHandled_m;
    /// <summary>
    /// Determines if the exception should be considered handled
    /// </summary>
    public bool Handled
    {
        get
        {
            return this.bHandled_m;
        }
    }
}

/// <summary>
/// The ErrorBehaviorAttribute exists as a mechanism to register an error handler with a service. 
/// This attribute takes a single type parameter. That type should implement the IErrorHandler 
/// interface and should have a public, empty constructor. The attribute then instantiates an 
/// instance of that error handler type and installs it into the service. It does this by 
/// implementing the IServiceBehavior interface and then using the ApplyDispatchBehavior 
/// method to add instances of the error handler to the service.
/// 
/// To use this class specify the attribute on your service class.
/// </summary>
public class ErrorBehaviorAttribute : Attribute, IServiceBehavior
{
    private Type typeErrorHandler_m;

    public ErrorBehaviorAttribute(Type typeErrorHandler)
    {
        this.typeErrorHandler_m = typeErrorHandler;
    }

    public ErrorBehaviorAttribute(Type typeErrorHandler, string strUrl, bool bHandled)
        : this(typeErrorHandler)
    {
        this.strUrl_m = strUrl;
        this.bHandled_m = bHandled;
    }

    public virtual void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
        return;
    }

    public virtual void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
    {
        return;
    }

    protected virtual IErrorHandler CreateTypeHandler()
    {
        IErrorHandler typeErrorHandler;

        try
        {
            typeErrorHandler = (IErrorHandler)Activator.CreateInstance(this.typeErrorHandler_m, this.strUrl_m, bHandled_m);
        }
        catch (MissingMethodException e)
        {
            throw new ArgumentException("The ErrorHandler type specified in the ErrorBehaviorAttribute constructor must have a public constructor with string parameter and bool parameter.", e);
        }
        catch (InvalidCastException e)
        {
            throw new ArgumentException("The ErrorHandler type specified in the ErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler.", e);
        }

        return typeErrorHandler;
    }

    public virtual void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
        IErrorHandler typeErrorHandler = this.CreateTypeHandler();            

        foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
            channelDispatcher.ErrorHandlers.Add(typeErrorHandler);
        }
    }

    private string strUrl_m;
    /// <summary>
    /// Specifies a url of the service, displayed in the error log
    /// </summary>
    public string Url
    {
        get
        {
            return this.strUrl_m;
        }
    }

    private bool bHandled_m;
    /// <summary>
    /// Determines if the ServiceErrorHandler will consider the exception handled
    /// </summary>
    public bool Handled
    {
        get
        {
            return this.bHandled_m;
        }
    }
}

服务:

[ServiceContract(Namespace = "http://example.come/test")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ErrorBehavior(typeof(ServiceErrorHandler),"ExceptonTest.svc",false)]
public class ExceptonTest
{
    [OperationContract]
    public void TestException()
    {   
        throw new Exception("this is a test!");
    }
}

这篇关于.Net WFC / Web服务异常处理设计模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆