WCF服务合同和错误处理

时间:2014-11-17 17:11:33

标签: c# wcf soap fault

我正在尝试托管一个可以用作代理/网关的服务,以通用的方式调用各种其他服务。该服务将采用标识要调用的服务的参数以及它简单地传递给“实现”的有效负载字符串。 “网关”负责外部客户端的身份验证,并将用户身份和其他“上下文”信息提供给“实现”。

我希望外部客户端提供无效请求以获取指示错误的错误。但由于“网关”服务不知道请求(或响应)应该是什么样子,因此必须依赖“真实”服务来提供可靠地指示“错误请求”的响应。还需要提供错误消息(人们可读的描述请求的错误)。在某些情况下,“实现”具有自己的授权逻辑,所以类似地它也必须能够指示“未授权”,我认为具有状态403的HttpException可以很好地表示。

所有实现者都将用.net编写为WCF服务。

我认为我可以通过指定服务合同来逃避并让实现抛出HttpException,状态代码为400或403,以便将错误信息提供回“网关” - 没有必要指定错误合同(isn)有一些通用的SOAP错误,这不至少允许错误代码和消息字符串??)。

现在我试图建立一个POC。请求有效并且实现正常返回的“正常”情况可以正常工作。但是当出现问题时,我无法看到任何获取错误信息的方法。

在用于测试一个服务实现的控制台应用程序中:

private string GetResponse(string req)
{
    try
    {
        using (var proxy = new MapperProxy())
        {
            return proxy.Map(null, req);
        }
    }
    catch (FaultException fe)
    {
        int status = GetStatus(fe);
        switch (status)
        {
            case 400:
                return "400 BAD REQUEST - " + fe.Message;

            case 403:
                return "403 FORBIDDEN - " + fe.Message;

            default:
                return "501 INTERNAL SERVER ERROR";
        }
    }
    catch (Exception ex)
    {
        return "Exception caught: " + ex.ToString();
    }
}

假设WCF服务抛出了状态代码为400的HttpException。(服务实现配置为“包含故障中的异常详细信息”。)如何实现GetStatus(FaultException ex)?

1 个答案:

答案 0 :(得分:0)

我找到了答案。我可以通过让实现者抛出指示FaultCode和消息的SoapFaultException来使用泛型SOAP错误。我应该设置Action和属性来指示它是客户端还是服务器故障,但是这样做:

服务器端:

public string Map(MapperContext context, string payLoad)
{
    string verb = GetFirstWord(payLoad).ToUpper();

    switch (verb)
    {
        case "ECHO":
            return payLoad.Substring(verb.Length).TrimStart();

        case "COP":
            throw new FaultException("Only cops may use this service.", new FaultCode("FORBIDDEN"));

        case "BUG":
            throw new NullReferenceException();
    }

    throw new FaultException("Invalid request; first word must be 'ECHO', 'COP' or 'BUG'.", new FaultCode("BAD REQUEST"));
}

private string GetFirstWord(string request)
{
    for (int i = 0; i < request.Length; i++)
    {
        if (char.IsWhiteSpace(request[i]))
        {
            return request.Substring(0, i);
        }
    }

    return request;
}

修改后的客户端(我的控制台应用程序来测试它):

private string GetResponse(string req)
{
    try
    {
        using (var proxy = new MapperProxy())
        {
            return proxy.Map(null, req);
        }
    }
    catch (FaultException fe)
    {
        switch (fe.Code.Name)
        {
            case "BAD REQUEST":
                return "400 BAD REQUEST - " + fe.Message;

            case "FORBIDDEN":
                return "403 FORBIDDEN - " + fe.Message;

            default:
                return "501 INTERNAL SERVER ERROR: " + fe.Message;
        }
    }
    catch (Exception ex)
    {
        return "Exception caught: " + ex.ToString();
    }
}

我认为这对我的目的来说已经足够了。