迁移遗留SOAP项目:CoreWCF自定义HTTP状态码配置方法问询
CoreWCF 自定义HTTP状态码解决方案(兼容遗留SOAP服务)
针对你在CoreWCF中需要保留遗留SOAP服务自定义HTTP状态码的需求,以下是具体实现方案:
问题1:处理完成后返回HTTP 202状态码
CoreWCF托管在ASP.NET Core之上,可通过IHttpContextAccessor直接操作请求上下文修改响应状态码,避免IsOneWay=true的立即返回问题。
步骤1:注册IHttpContextAccessor服务
在Startup.cs的ConfigureServices方法中添加:
services.AddHttpContextAccessor();
步骤2:在服务类中注入并设置状态码
修改DemoService.cs,注入IHttpContextAccessor并在满足业务条件时设置状态码:
using CoreWCF; using Microsoft.AspNetCore.Http; using System.Net; namespace CoreWcf.Samples.Http { public class DemoService : IDemo { private readonly IHttpContextAccessor _httpContextAccessor; public DemoService(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public string DemoRequest(string tagid, string readerid, string datetime) { // 模拟业务场景:满足特定条件时返回202 if (tagid == "async-process") { _httpContextAccessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.Accepted; } return $"Received tagid: {tagid}; readerid: {readerid}; datetime: {datetime}"; } } }
问题2:SOAP Fault返回自定义HTTP状态码
通过实现CoreWCF的IErrorHandler接口捕获异常,修改HTTP状态码同时保留原SOAP Fault结构,确保客户端兼容。
步骤1:创建自定义ErrorHandler
using CoreWCF; using CoreWCF.Channels; using CoreWCF.Description; using CoreWCF.Dispatcher; using Microsoft.AspNetCore.Http; using System.Net; namespace CoreWcf.Samples.Http { public class CustomErrorHandler : IErrorHandler { private readonly IHttpContextAccessor _httpContextAccessor; public CustomErrorHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } // 指定需要处理的异常类型 public bool HandleError(Exception error) { return error is FaultException; } // 自定义Fault响应并设置HTTP状态码 public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { if (error is FaultException faultException) { // 根据Fault内容匹配自定义状态码 if (faultException.Message.Contains("Unknown Username or Incorrect Password")) { _httpContextAccessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; } else if (faultException.Message.Contains("Business Conflict")) { _httpContextAccessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; } // 保留原SOAP Fault结构,避免客户端解析失败 fault = Message.CreateMessage(version, faultException.CreateMessageFault(), faultException.Action); } } } // 服务行为:将ErrorHandler注册到服务宿主 public class CustomErrorHandlerBehavior : IServiceBehavior { private readonly IHttpContextAccessor _httpContextAccessor; public CustomErrorHandlerBehavior(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) { channelDispatcher.ErrorHandlers.Add(new CustomErrorHandler(_httpContextAccessor)); foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomErrorHandler(_httpContextAccessor)); } } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } } }
步骤2:在Startup.cs中注册ErrorHandler
修改Startup.cs的Configure方法,将自定义行为添加到服务宿主:
public void Configure(IApplicationBuilder app) { var wsHttpBindingWithCredential = new BasicHttpBinding(CoreWCF.Channels.BasicHttpSecurityMode.TransportWithMessageCredential); wsHttpBindingWithCredential.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; // 获取IHttpContextAccessor实例 var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>(); app.UseServiceModel(builder => { builder.AddService<DemoService>(serviceOptions => { serviceOptions.BaseAddresses.Add(new Uri($"http://localhost:{Program.HTTP_PORT}/DemoService")); serviceOptions.BaseAddresses.Add(new Uri($"https://localhost:{Program.HTTPS_PORT}/DemoService")); }) .AddServiceEndpoint<DemoService, IDemo>(wsHttpBindingWithCredential, "/wsHttpUserPassword", ep => { ep.Name = "AuthenticatedDemoEP"; }); // 注册自定义ErrorHandler和用户名验证器 builder.ConfigureServiceHostBase<DemoService>(host => { host.Description.Behaviors.Add(new CustomErrorHandlerBehavior(httpContextAccessor)); CustomUserNamePasswordValidator.AddToHost(host); }); var serviceMetadataBehavior = app.ApplicationServices.GetRequiredService<CoreWCF.Description.ServiceMetadataBehavior>(); serviceMetadataBehavior.HttpGetEnabled = serviceMetadataBehavior.HttpsGetEnabled = true; }); }
步骤3:抛自定义FaultException
在服务方法或验证器中抛出带特定消息的FaultException,即可触发对应状态码:
// 在DemoService中抛业务冲突异常 public string DemoRequest(string tagid, string readerid, string datetime) { if (tagid == "duplicate") { throw new FaultException("Business Conflict: Tag ID already exists"); } // ...其他逻辑 }
关键说明
- CoreWCF已移除
WebOperationContext,官方推荐通过IHttpContextAccessor操作ASP.NET Core上下文。 - 修改状态码时需保留SOAP响应的标准结构,确保原有客户端无需修改即可解析。
- 方案完全兼容遗留业务逻辑,同时符合CoreWCF的托管规范。
内容的提问来源于stack exchange,提问作者Dolph
相关产品推荐
相关产品推荐

