如何在客户端代码中拦截来自WCF服务的HTTP响应代码

时间:2019-12-19 17:46:24

标签: c# asp.net-core asp.net-core-2.2

因此,我们有这个“代理”应用程序,它既是针对Angular应用程序的服务,又是使用WCF服务的客户端。

来自UI的请求调用了代理webApi,后者又调用了WCF(实际上是多个源,但可以简化为一个基础服务)。 WCF服务可能崩溃,并因此返回非OK HTTP状态代码。 WCF服务是第三方,因此绝对没有办法对其进行更改。

我们想在代理应用程序中拦截它,但是我们不能。 我尝试过制作中间件,过滤器属性,异常处理程序以及消息检查器的自定义行为。没运气。 enter image description here

发生的情况是,基础服务崩溃后,它将导致代理应用程序中出现异常。 我们的异常处理程序中间件捕获了此错误,但是我们无权访问WCF服务返回的HTTP状态代码。 只有异常消息可以指出发生了什么问题,但是我们不想依靠解析文本消息。 这是异常消息的一个示例> “远程服务器返回了意外的响应:(405)不允许使用方法。”

我还尝试调用自己创建的基础webApi-只是为了了解在拦截基础响应HTTP状态代码时WCF调用和webApi调用之间是否存在差异。 相同但不同:) 看起来像是在正确的位置挂上HTTP堆栈管道?!

因此,调试代理应用程序时,我们会遇到以下情况:

  1. 已收到来自用户界面的请求
  2. 代理致电WCF服务 另一个请求
  3. WCF服务以非OK状态代码响应(例如 405等)
  4. 立即在代理应用中抛出异常
  5. middelware异常处理程序可以很好地捕获异常-但是 无法访问wcf响应HTTP状态代码

在下面的代码中注意我的评论;)

控制器:

    [WcfErrorHandling]
    public async Task<PersonCivilIdentifierLookupResponse1> GetKRAsync(
          PersonCivilIdentifierLookupRequest lookupRequest)
    {
        if (lookupRequest == null)
        {
            throw new ArgumentNullException(nameof(lookupRequest));
        }

        PersonCivilIdentifierLookup lookup = new PersonCivilIdentifierLookup
           { PersonCivilIdentifierLookupRequest = lookupRequest };

        var binding = new WSHttpBinding();
        var endpoint = CreateEndpoint("***");   // URI for the underlying service removed


        var channelFactory = new ChannelFactory<MethodsPortType>(binding, endpoint);
        var behavior = new MessageInspectorBehavior(new MessageInspector());

        channelFactory.Endpoint.EndpointBehaviors.Add(behavior);
        var client = channelFactory.CreateChannel();

        // originally just used auto-generated client, but in order to add custom behavior
        // i created custom client via channelFactory above
        //using (var client = new MethodsPortTypeClient(binding, endpoint))
        {
            var response = await client.PersonCivilIdentifierLookupAsync(
                new PersonCivilIdentifierLookupRequest1(lookup));

            return response;
        }
    }

消息检查器:

public class MessageInspector : IClientMessageInspector
{
    int _statusCode;

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // will never go here when WCF service returns anything other that HTTP status code 200
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        return null;
    }
}

属性:

// seams to be totally ignored, or the exception is thrown before execution gets here
public class WcfErrorHandlingAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext context)
    {
        var statusCode = context.HttpContext.Response.StatusCode;
        base.OnResultExecuted(context);
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        base.OnResultExecuting(context);
    }
}

中间件异常处理程序:

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (FaultException fault)
        {

        }
        catch (Exception ex)
        {
            var logger = LogManager.GetCurrentClassLogger();
            LogUtils.AddPropertiesToLogger(logger, httpContext);
            logger.Error(ex);
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    private Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        var feature = context.Features.Get<IExceptionHandlerPathFeature>();
        var x = feature?.Error;

        return context.Response.WriteAsync(new ErrorDetails()
        {
            StatusCode = context.Response.StatusCode,
            Message = ex?.Message
        }.ToString());
    }
}

启动:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // tried the UseStatusCodePages as shown below
        // but it's not intercepting the response from WCF service before exception is thrown
        //app.UseStatusCodePages(builder =>
        //{
        //    builder.Run(async context =>
        //    {
        //        var response = context.Response;
        //        var statusCode = response.StatusCode;
        //        var headers = response.Headers.ToDictionary(x => x.Key, x => x.Value.ToString());

        //        if (statusCode > 299)
        //        {
        //            await Task.FromException(new ApiException("KR Service har returned an error", statusCode, response.ToString(), headers, null));
        //        }
        //    });
        //});

        app.ConfigureExceptionHandler();
        app.UseMvc();
    }

在传统的.NET Framework中,我想我们可以创建一个从WebHttpBehavior继承并使用WebHttpBinding的行为类,但是在Core中它们已经消失了。

NB。我们使用Core 2.2(可能会在不久的将来升级,但我看不到Core 3.0 / 3.1可以解决此问题!?)

0 个答案:

没有答案