C# 如何防止WCF服务进入故障状态?

C# 如何防止WCF服务进入故障状态?,c#,.net,wcf,msmq,C#,.net,Wcf,Msmq,我有一个WCF服务不应进入故障状态。如果出现异常,应记录该异常,并且服务应不间断地继续。该服务具有单向操作合约,正在从MSMQ读取消息 我的问题有两个: 这项服务似乎难以接受 异常/故障,因此我无法 调试它。我怎样得到服务 公开异常,以便 你能记录或处理它吗 服务是 之后进入故障状态 这个例外被接受了。怎么办 我阻止服务进入 进入故障状态 异常将导致代理出错。对此你无能为力:不要引起异常-p 我有点惊讶单向仍然会引起问题,但是对于一般的吞咽,有三个方面: 你在扔吗?还是例外?这很重要(应该是“错

我有一个WCF服务不应进入故障状态。如果出现异常,应记录该异常,并且服务应不间断地继续。该服务具有单向操作合约,正在从MSMQ读取消息

我的问题有两个:

  • 这项服务似乎难以接受 异常/故障,因此我无法 调试它。我怎样得到服务 公开异常,以便 你能记录或处理它吗
  • 服务是 之后进入故障状态 这个例外被接受了。怎么办 我阻止服务进入 进入故障状态

  • 异常将导致代理出错。对此你无能为力:不要引起异常-p

    我有点惊讶单向仍然会引起问题,但是对于一般的吞咽,有三个方面:

  • 你在扔吗?还是例外?这很重要(应该是“错误”)
  • 作为黑客,您可以启用调试异常消息-但请关闭它
  • 您是否正在“使用”服务对象?我刚刚谈到这个问题。。。基本上,您的“使用”可以接受异常。 3种选择:

    • 不要使用“使用”
    • 子类化代理并重写Dispose()
    • 按照博客的说法,把它包装起来

  • 大多数(如果不是所有的话)异常都可以在WCF跟踪()中看到,最好使用

    显然,这不是您应该在生产环境中全天运行的东西,但它有助于故障排除

    除此之外,请注意,根据您使用的会话模式,oneways可能不会作为真正的“fire and forget”运行。如果您为SessionMode.Allowed甚至SessionMode.Required配置了服务,则单向操作将以完全不是单向的方式运行(在netTcpBinding上使用单向时可以观察到这一点)。但是,坦率地说,我不知道这是否会改变您可以获得的异常类型,或者何时获得它们。但是,在任何情况下,如果请求根本无法发送,您都应该得到一个异常。好吧,当它在服务器端被成功地请求时,单向“结束”。因此,在此之前,存在(与WCF框架相关的)异常(想到序列化/反序列化)

    然后,使用上面提到的trace/traceviewer可以最好地看到这种与框架相关的异常(由于在请求/响应流中调用IErrorHandler的事实,即使IErrorHandler也无法获得所有异常)

    诀窍是您应该使用“using”,并且应该始终对引发异常的代理调用Abort()。这篇文章解释了这一切

    我们使用的服务类的灵感来自于包装服务调用的那篇文章。这是我的项目中的示例代码:

    ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
        proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID);
    );
    
    serviceheloper.Use(
    proxy=>seasonCodeBindingSource.DataSource=proxy.GetSeasonCodes(brandID);
    );
    
    这是ServiceHelper的代码,从文章中稍作修改。到目前为止,它为我们提供了非常好的服务

    using System;
    using System.ServiceModel;
    
    namespace Sportina.EnterpriseSystem.Client.Framework.Helpers
    {
        public delegate void UseServiceDelegate<TServiceProxy>(TServiceProxy proxy);
    
        public static class ServiceHelper<TServiceClient, TServiceInterface> where TServiceClient : ClientBase<TServiceInterface>, new() where TServiceInterface : class
        {
            public static void Use(UseServiceDelegate<TServiceClient> codeBlock)
            {
                TServiceClient proxy = null;
                bool success = false;
                try
                {
                    proxy = new TServiceClient();               
                    codeBlock(proxy);
                    proxy.Close();
                    success = true;
                }
                catch (Exception ex)
                {
                    Common.Logger.Log.Fatal("Service error: " + ex);                                
                    throw;
                }
                finally
                {
                    if (!success && proxy != null)
                        proxy.Abort();
                }
            }
        }
    }
    
    使用系统;
    使用System.ServiceModel;
    命名空间Sportina.EnterpriseSystem.Client.Framework.Helpers
    {
    公共委托无效UseServiceDelegate(TServiceProxy代理);
    公共静态类ServiceHelper,其中TServiceClient:ClientBase,new(),其中TServiceInterface:class
    {
    公共静态无效使用(UseServiceDelegate代码块)
    {
    TServiceClient proxy=null;
    布尔成功=假;
    尝试
    {
    proxy=新的TServiceClient();
    代码块(代理);
    proxy.Close();
    成功=真实;
    }
    捕获(例外情况除外)
    {
    Common.Logger.Log.Fatal(“服务错误:+ex”);
    投掷;
    }
    最后
    {
    如果(!success&&proxy!=null)
    proxy.Abort();
    }
    }
    }
    }
    
    我遇到了一个问题,在接收超时异常后,通道仍处于故障状态。这将导致任何后续连接都无法使用该服务

    对我来说,从故障状态恢复服务的修复方法是处理通信通道的故障事件:

     channelFactory = new ChannelFactory<IService>(endpoint);
     channelFactory.Faulted += OnChannelFaulted;
     var channel = channelFactory.CreateChannel();
    

    注意:我是通过代码运行WCF配置,而不是在Web.config中使用绑定。

    通常WCF服务托管在ServiceHost中,如果WCF服务失败,则唯一的选择是终止WCF服务并启动新的服务

    ServiceHost有一个事件触发器“Faulted”,该触发器在WCF服务失败时激活:

    ServiceHost host = new ServiceHost(new Service.MyService());
    host.Faulted += new EventHandler(host_faulted);
    host.Open();
    
    可以获取导致故障的异常,但需要做更多的工作:

    public class ErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
    
        }
    
        public bool HandleError(Exception error)
        {
            Console.WriteLine("exception");
            return false;
        }
    }
    
    public class ErrorServiceBehavior : IServiceBehavior
    {
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
    
        }
    
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
    
        }
    
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            ErrorHandler handler = new ErrorHandler();
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(handler);
            }
        }
    }
    
    ServiceHost host = new ServiceHost(new Service.MyService());
    host.Faulted += new EventHandler(host_faulted);
    host.Description.Behaviors.Add(new ErrorServiceBehavior());
    host.Open();
    
    公共类ErrorHandler:IErrorHandler
    {
    public void providefaulture(异常错误,消息版本,ref消息错误)
    {
    }
    公共布尔句柄错误(异常错误)
    {
    控制台写入线(“例外”);
    返回false;
    }
    }
    公共类ErrorServiceBehavior:IServiceBehavior
    {
    公共无效验证(ServiceDescription ServiceDescription,ServiceHostBase ServiceHostBase)
    {
    }
    public void AddBindingParameters(ServiceDescription ServiceDescription、ServiceHostBase ServiceHostBase、集合终结点、BindingParameterCollection bindingParameters)
    {
    }
    公共无效ApplyDispatchBehavior(ServiceDescription ServiceDescription,ServiceHostBase ServiceHostBase)
    {
    ErrorHandler=新的ErrorHandler();
    foreach(serviceHostBase.ChannelDispatchers中的ChannelDispatcher)
    {
    dispatcher.ErrorHandlers.Add(处理程序);
    }
    }
    }
    ServiceHost主机=新的ServiceHost(new Service.MyService());
    host.Faulted+=新的EventHandler(host\u Faulted);
    host.Description.Behaviors.Add(新的ErrorServiceBehavior());
    host.Open();
    

    学分

    关于如何
    public class ErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
    
        }
    
        public bool HandleError(Exception error)
        {
            Console.WriteLine("exception");
            return false;
        }
    }
    
    public class ErrorServiceBehavior : IServiceBehavior
    {
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
    
        }
    
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
    
        }
    
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            ErrorHandler handler = new ErrorHandler();
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(handler);
            }
        }
    }
    
    ServiceHost host = new ServiceHost(new Service.MyService());
    host.Faulted += new EventHandler(host_faulted);
    host.Description.Behaviors.Add(new ErrorServiceBehavior());
    host.Open();