C# 如何在客户端代码中拦截来自WCF服务的HTTP响应代码
所以我们有了这个“代理”应用程序,它既是面向Angular应用程序的服务,也是使用WCF服务的客户端 来自UI的请求调用代理webApi,代理webApi再次调用WCF(实际上是多个源,但可以将其简化为一个底层服务)。 WCF服务可能会崩溃,从而返回非OK HTTP状态代码。 WCF服务是第三方,因此绝对没有办法改变它 我们希望在代理应用程序中拦截此消息,但遗憾的是,我们无法。 我已经尝试过使用消息检查器制作中间件、过滤器属性、异常处理程序以及自定义行为。不走运。 发生的情况是,一旦基础服务崩溃,就会导致代理应用程序中出现异常。 我们的异常处理程序中间件捕捉到了这一点,但我们无法访问WCF服务返回的HTTP状态代码。 只有异常消息给出了出错原因的指示,但我们不希望依赖于解析文本消息。 这是异常消息>“远程服务器返回意外响应:(405)方法不允许”的示例 我还尝试调用我自己创建的底层webApi,只是想看看WCF调用和webApi调用在拦截底层响应HTTP状态代码时是否有任何区别。 相同但不同:) 看起来这是关于在正确的位置将钩子插入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服务是第三方,因此绝对没有办法改变它 我们希望在代理应用程序中拦截此消息,但遗憾的是,我们无法。 我已经尝试过使用消息检查器制作中间件、过滤器属性、异常处理程序以及自定义行为。不走运。 发生的情况是,一旦基础服务崩
[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();
}