如何捕获 WCF 中的所有异常但包括自定义数据?

How to catch all exceptions in WCF but include custom data?

我正在处理一个使用多个 WCF 调用来执行过程的项目。第一个调用 returns 一个唯一的 ID (Guid),以下所有调用都必须提供该 ID。服务器端,每个调用都与该唯一 ID 一起记录,以便可以观察单个过程的过程 (假设客户端可以同时开始其中的几个过程,并且它们是线程安全的).

客户端示例如下所示:

string clientName = GetClientName();
Guid uniqueId = wcfClient.Begin(clientName);
object data = wcfClient.GetData(clientName, uniqueId);

object processedData = ProcessDataLocally(data);

bool success = wcfClient.confirmDataValidity(clientName, uniqueId, processedData);

// ...

wcfClient.End(clientName, uniqueId);

如果服务器端出现问题,我也希望使用为出错的调用提供的 uniqueId 将其记录下来。为此,我使服务的所有方法都使用如下函数:

private T DoProcess<T>(Guid uniqueId, Func<T> process)
{
    try
    {
        return process();
    }
    catch(Exception ex)
    {
        Log(ex, uniqueId);

        throw; // or throw the same thing every time, if the client
               // shouldn't know the details
    }
}

public object GetData(string clientName, Guid uniqueId)
{
    return DoProcess(uniqueId, () =>
    {
        object data;

        // Generate data

        return data;
    });
}

但是,这样做似乎并不能捕获所有可能的错误(例如,如果连接超时)。

我阅读了有关实现 IErrorHandler 接口并将其附加到服务的信息。虽然这似乎捕获了所有错误,但似乎没有办法将信息传递给它,除了异常,例如 uniqueId。因此无法记录 ID。

是否可以捕获所有异常并包含已传递给抛出异常的方法的数据?

连接超时等异常不会到达服务,因此无法在服务端捕获。

话虽如此,您可以使用 IExtension 向当前的 OperationContext 添加额外的信息。基本模式是这样的:

public class OperationContextExtension : IExtension<OperationContext>
{
    private readonly Dictionary<string, object> extraInfo;

    public OperationContextExtension ()
    {
        extraInfo = new Dictionary<string, object>();
    }

    public static OperationContextExtension Current
    {
        get
        {
            OperationContextExtension c = OperationContext.Current.Extensions.Find<OperationContextExtension>();
            if (c == null)
            {
                c = new OperationContextExtension ();
                OperationContext.Current.Extensions.Add(c);
            }
            return c;
        }
    }

    public Dictionary<string, object> Extras
    {
        get { return extraInfo; }
    }

    public void Attach(OperationContext owner) { }

    public void Detach(OperationContext owner) { }
}

然后在 IErrorHandler 实现中使用 class :

class FaultErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return false;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
      Guid ID = OperationContextExtension.Current.Extras["uniqueId"] as Guid;

      LogIt(error.ToString() + ID);
    }
}

然后在GetData

public object GetData(string clientName, Guid uniqueId)
{
    OperationContextExtension.Current.Extras["uniqueId"] = uniqueId;
    return DoProcess(uniqueId, () =>
    {
        object data;

        // Generate data

        return data;
    });
}