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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/315736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:53:35  来源:igfitidea点击:

How do I prevent a WCF service from enter a faulted state?

c#.netwcfmsmq

提问by Guy

I have a WCF Service that should not enter the faulted state. If there's an exception, it should be logged and the service should continue uninterrupted. The service has a one-way operation contract and is reading messages from an MSMQ.

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

My problems are twofold:

我的问题是双重的:

  1. The service appears to be swallowing an exception/fault so I am unable to debug it. How do I get the service to expose the exception so that I can log or handle it?
  2. The service is entering into a faulted state after this exception is swallowed. How do I prevent the service from entering into a faulted state?
  1. 该服务似乎正在吞下异常/故障,因此我无法对其进行调试。如何让服务公开异常以便我可以记录或处理它?
  2. 吞下此异常后,服务将进入故障状态。如何防止服务进入故障状态?

采纳答案by Christian.K

Most, if not all exceptions can be seen in the WCF Trace (Configuring Tracing) and the trace is best viewed with the Service Trace Viewer.

大多数(如果不是所有)异常都可以在 WCF 跟踪(配置跟踪)中看到,最好使用服务跟踪查看器查看跟踪

Obviously, this is not something you should have running all day in a production environment, but it helps in troubleshooting anyway.

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

Apart from that, note that oneways may not run as a true "fire and forget" depending on the SessionMode you use. If you have your service configured for SessionMode.Allowed or even SessionMode.Required, the oneway operation will run as if it was not oneway at all (this can be observed when using oneways over the netTcpBinding). To be frank, however, I don't know if that changes the type of exceptions you can get, or when you get them. However, in any case, you should get an exception if the request could not be send at all. AFAIK, the oneway "ends" when it is successfully enqued on the server side. So there is some place for (WCF framework related) exceptions until then (serialization/deserialization comes to mind).

除此之外,请注意,根据您使用的 SessionMode,oneways 可能不会作为真正的“即发即弃”运行。如果您为 SessionMode.Allowed 或什至 SessionMode.Required 配置了您的服务,则单向操作将运行,就好像它根本不是单向(这可以在通过 netTcpBinding 使用单向时观察到)。然而,坦率地说,我不知道这是否会改变您可以获得的异常类型,或者何时获得它们。但是,无论如何,如果根本无法发送请求,您应该得到一个异常。AFAIK,当它在服务器端成功排队时,单向“结束”。所以在此之前(WCF 框架相关的)异常有一些地方(想到序列化/反序列化)。

Then, such framework related exceptions are best seen (even an IErrorHandler doesn't get them all due to the fact when it is called in the request/response-flow) using the above mentioned trace / traceviewer.

然后,使用上面提到的跟踪/跟踪查看器可以最好地看到此类与框架相关的异常(即使 IErrorHandler 由于在请求/响应流中调用它时也没有得到它们)。

回答by Marc Gravell

Exceptions will fault the proxy. You can't AFAIK do much about that: don't cause exceptions ;-p

异常将导致代理出错。你不能 AFAIK 做太多:不要引起异常;-p

I'm a little surprised that one-way is still causing a problem, but for swallowing in general, there are 3 aspects:

我有点惊讶的是单向的仍然是造成问题,但对于吞咽中属L时,有3个方面:

  1. are you throwing faults? or exceptions? it matters (and should be "faults")
  2. as a hack, you can enable debug exception messages - but turn it off please!!!
  3. are you "using" the service object? I've just bloggedon this exact subject... basically, your "using" can swallow the exception. 3 options:

    • don't use "using"
    • subclass the proxy and override Dispose()
    • wrap it, as per the blog
  1. 你在犯错吗?还是例外?这很重要(并且应该是“错误”)
  2. 作为黑客,您可以启用调试异常消息 - 但请关闭它!!!
  3. 你在“使用”服务对象吗?我刚刚写了一篇关于这个确切主题的博客......基本上,你的“使用”可以吞下异常。3个选项:

    • 不要使用“使用”
    • 子类化代理并覆盖 Dispose()
    • 包装它,根据博客

回答by David Vidmar

About 2)...

关于 2)...

The trick is that you should use "using" and should always call Abort() on the proxy that threw an exception. The article WCF Gotchaexplains it all.

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

We use service class inspired by that article that wraps service calls. This is sample code from my project:

我们使用受包装服务调用的文章启发的服务类。这是我的项目中的示例代码:

ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
    proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID);
);

And this is the code of ServiceHelper, slightly modified from the article. So far it has served us really well.

这是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();
            }
        }
    }
}

回答by rjchicago

I had an issue where the Channel remained in a faulted state after a ReceiveTimeout exception. This would cause the service to be rendered unusable by any subsequent connections.

我遇到了一个问题,即 Channel 在 ReceiveTimeout 异常后仍处于故障状态。这将导致任何后续连接无法使用该服务。

The fix for recovering the service from the faulted state for me was to handle the Faulted event of the communication channel:

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

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

Then define OnChannelFaulted:

然后定义 OnChannelFaulted:

 void OnChannelFaulted(object sender, EventArgs e)
 {
     channelFactory.Abort();
 }

Note: I am running the WCF config via code versus using bindings in the Web.config's.

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

回答by Rolf Kristensen

Usually the WCF service is hosted in a ServiceHost, if the WCF-Service fails then the only option is to kill the WCF service and start a new one.

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

The ServiceHost has an event trigger "Faulted" that is activated when the WCF Service fails:

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

ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Open();

It is possible to get the exception causing the fault, but it requires a bit more work:

有可能获得导致故障的异常,但它需要更多的工作:

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();

Credits http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

学分http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

回答by David d C e Freitas

The official documentation on how to handle Faults is here:

关于如何处理故障的官方文档在这里:

with the main page being at Channel Model Overview

主页位于渠道模型概览

There's a nice state diagram showing how things happen:

有一个很好的状态图显示了事情是如何发生的:

enter image description here

在此处输入图片说明