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

C# 如何在客户端代码中拦截来自WCF服务的HTTP响应代码,c#,asp.net-core,asp.net-core-2.2,C#,Asp.net Core,Asp.net Core 2.2,所以我们有了这个“代理”应用程序,它既是面向Angular应用程序的服务,也是使用WCF服务的客户端 来自UI的请求调用代理webApi,代理webApi再次调用WCF(实际上是多个源,但可以将其简化为一个底层服务)。 WCF服务可能会崩溃,从而返回非OK HTTP状态代码。 WCF服务是第三方,因此绝对没有办法改变它 我们希望在代理应用程序中拦截此消息,但遗憾的是,我们无法。 我已经尝试过使用消息检查器制作中间件、过滤器属性、异常处理程序以及自定义行为。不走运。 发生的情况是,一旦基础服务崩

所以我们有了这个“代理”应用程序,它既是面向Angular应用程序的服务,也是使用WCF服务的客户端

来自UI的请求调用代理webApi,代理webApi再次调用WCF(实际上是多个源,但可以将其简化为一个底层服务)。 WCF服务可能会崩溃,从而返回非OK HTTP状态代码。 WCF服务是第三方,因此绝对没有办法改变它

我们希望在代理应用程序中拦截此消息,但遗憾的是,我们无法。 我已经尝试过使用消息检查器制作中间件、过滤器属性、异常处理程序以及自定义行为。不走运。

发生的情况是,一旦基础服务崩溃,就会导致代理应用程序中出现异常。 我们的异常处理程序中间件捕捉到了这一点,但我们无法访问WCF服务返回的HTTP状态代码。 只有异常消息给出了出错原因的指示,但我们不希望依赖于解析文本消息。 这是异常消息>“远程服务器返回意外响应:(405)方法不允许”的示例

我还尝试调用我自己创建的底层webApi,只是想看看WCF调用和webApi调用在拦截底层响应HTTP状态代码时是否有任何区别。 相同但不同:) 看起来这是关于在正确的位置将钩子插入HTTP堆栈管道

因此,我们在调试代理应用程序时的体验如下:

  • 收到来自UI的请求
  • 代理对WCF服务进行调用 还有一个要求
  • WCF服务以非OK状态代码(如 405或其他)
  • 代理应用程序中立即引发异常
  • 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;
            }
        }
    
    属性:

    // 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());
        }
    }
    
    在传统的.NET框架中,我想我们可以创建一个继承自WebHttpBehavior的行为类,并使用WebHttpBinding,但它们在我的核心中消失了


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

    您有机会修改WCF代码吗?如果是,您可以创建和
    ErrorHandler
    ,并使用FaultContract包装状态代码错误,该协议在属性中公开该状态代码。不幸的是,WCF是第三方政府数据提供商,当其他几个系统使用该服务时,他们不可能更改它。如果有一个格式良好的soap消息,其中包含错误的定义等,那就太好了。无论我们做什么,都必须在我们自己的应用程序中进行。这个答案可能对你有帮助。它也应该适用于.net内核。
    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();
        }