ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析
2016-09-23 07:22
1381 查看
ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析。本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host。因为WCF中不仅仅只是有SOAP, 它还包含很多如消息安全性,生成WSDL,双工信道,非HTTP传输等。ASP.NET Core 官方推荐大家使用RESTful Web API的解决方案提供网络服务。SOAP 即 Simple Object AccessProtocol 也就是简单对象访问协议。SOAP 呢,其指导理念是“唯一一个没有发明任何新技术的技术”,是一种用于访问 Web 服务的协议。因为 SOAP 基于XML 和 HTTP ,其通过XML 来实现消息描述,然后再通过 HTTP 实现消息传输。SOAP 是用于在应用程序之间进行通信的一种通信协议。因为是基于 XML 和HTTP 的,所以其独立于语言,独立于平台,并且因为 XML 的扩展性很好,所以基于 XML 的 SOAP 自然扩展性也不差。通过 SOAP 可以非常方便的解决互联网中消息互联互通的需求,其和其他的 Web 服务协议构建起 SOA 应用的技术基础。 下面来正式开始 ASP.NET Core 实现SOAP 服务端解析。
新建项目
首先新建一个ASP.NET Core Web Application -》 SOAPService 然后再模板里选择 Web API。然后我们再添加一个Class Library -》 CustomMiddleware实现
下面我们来实现功能,首先在类库项目中添加以下引用Install-Package Microsoft.AspNetCore.Http.Abstractions Install-Package System.ServiceModel.Primitives Install-Package System.Reflection.TypeExtensions Install-Package System.ComponentModel首先新建一个 ServiceDescription、ContractDescription和OperationDescription 类,这里需要注意的是ServiceDescription,ContractDescription和OperationDescription这里使用的是不能使用 System.ServiceModel.Description命名空间中的类型。它们是示例中简单的新类型。ServiceDescription.cspublic class ServiceDescription { public Type ServiceType { get; private set; } public IEnumerable<ContractDescription> Contracts { get; private set; } public IEnumerable<OperationDescription> Operations => Contracts.SelectMany(c => c.Operations); public ServiceDescription(Type serviceType) { ServiceType = serviceType; var contracts = new List<ContractDescription>(); foreach (var contractType in ServiceType.GetInterfaces()) { foreach (var serviceContract in contractType.GetTypeInfo().GetCustomAttributes<ServiceContractAttribute>()) { contracts.Add(new ContractDescription(this, contractType, serviceContract)); } } Contracts = contracts; } }
ContractDescription.cspublic class ContractDescription { public ServiceDescription Service { get; private set; } public string Name { get; private set; } public string Namespace { get; private set; } public Type ContractType { get; private set; } public IEnumerable<OperationDescription> Operations { get; private set; } public ContractDescription(ServiceDescription service, Type contractType, ServiceContractAttribute attribute) { Service = service; ContractType = contractType; Namespace = attribute.Namespace ?? "http://tempuri.org/"; // Namespace defaults to http://tempuri.org/ Name = attribute.Name ?? ContractType.Name; // Name defaults to the type name var operations = new List<OperationDescription>(); foreach (var operationMethodInfo in ContractType.GetTypeInfo().DeclaredMethods) { foreach (var operationContract in operationMethodInfo.GetCustomAttributes<OperationContractAttribute>()) { operations.Add(new OperationDescription(this, operationMethodInfo, operationContract)); } } Operations = operations; } }OperationDescription.cspublic class OperationDescription { public ContractDescription Contract { get; private set; } public string SoapAction { get; private set; } public string ReplyAction { get; private set; } public string Name { get; private set; } public MethodInfo DispatchMethod { get; private set; } public bool IsOneWay { get; private set; } public OperationDescription(ContractDescription contract, MethodInfo operationMethod, OperationContractAttribute contractAttribute) { Contract = contract; Name = contractAttribute.Name ?? operationMethod.Name; SoapAction = contractAttribute.Action ?? $"{contract.Namespace.TrimEnd('/')}/{contract.Name}/{Name}"; IsOneWay = contractAttribute.IsOneWay; ReplyAction = contractAttribute.ReplyAction; DispatchMethod = operationMethod; } } 添加完成后下面来新建一个中间件 SOAPMiddleware ,对于新建中间件可以参考我之前的文章:http://www.cnblogs.com/linezero/p/5529767.htmlSOAPMiddleware.cs 代码如下:public class SOAPMiddleware { private readonly RequestDelegate _next; private readonly Type _serviceType; private readonly string _endpointPath; private readonly MessageEncoder _messageEncoder; private readonly ServiceDescription _service; private IServiceProvider serviceProvider; public SOAPMiddleware(RequestDelegate next, Type serviceType, string path, MessageEncoder encoder,IServiceProvider _serviceProvider) { _next = next; _serviceType = serviceType; _endpointPath = path; _messageEncoder = encoder; _service = new ServiceDescription(serviceType); serviceProvider = _serviceProvider; } public async Task Invoke(HttpContext httpContext) { if (httpContext.Request.Path.Equals(_endpointPath, StringComparison.Ordinal)) { Message responseMessage; //读取Request请求信息 var requestMessage = _messageEncoder.ReadMessage(httpContext.Request.Body, 0x10000, httpContext.Request.ContentType); var soapAction = httpContext.Request.Headers["SOAPAction"].ToString().Trim('\"'); if (!string.IsNullOrEmpty(soapAction)) { requestMessage.Headers.Action = soapAction; } //获取操作 var operation = _service.Operations.Where(o => o.SoapAction.Equals(requestMessage.Headers.Action, StringComparison.Ordinal)).FirstOrDefault(); if (operation == null) { throw new InvalidOperationException($"No operation found for specified action: {requestMessage.Headers.Action}"); } //获取注入的服务 var serviceInstance = serviceProvider.GetService(_service.ServiceType); //获取操作的参数信息 var arguments = GetRequestArguments(requestMessage, operation); // 执行操作方法 var responseObject = operation.DispatchMethod.Invoke(serviceInstance, arguments.ToArray()); var resultName = operation.DispatchMethod.ReturnParameter.GetCustomAttribute<MessageParameterAttribute>()?.Name ?? operation.Name + "Result"; var bodyWriter = new ServiceBodyWriter(operation.Contract.Namespace, operation.Name + "Response", resultName, responseObject); responseMessage = Message.CreateMessage(_messageEncoder.MessageVersion, operation.ReplyAction, bodyWriter); httpContext.Response.ContentType = httpContext.Request.ContentType; httpContext.Response.Headers["SOAPAction"] = responseMessage.Headers.Action; _messageEncoder.WriteMessage(responseMessage, httpContext.Response.Body); } else { await _next(httpContext); } } private object[] GetRequestArguments(Message requestMessage, OperationDescription operation) { var parameters = operation.DispatchMethod.GetParameters(); var arguments = new List<object>(); // 反序列化请求包和对象 using (var xmlReader = requestMessage.GetReaderAtBodyContents()) { // 查找的操作数据的元素 xmlReader.ReadStartElement(operation.Name, operation.Contract.Namespace); for (int i = 0; i < parameters.Length; i++) { var parameterName = parameters[i].GetCustomAttribute<MessageParameterAttribute>()?.Name ?? parameters[i].Name; xmlReader.MoveToStartElement(parameterName, operation.Contract.Namespace); if (xmlReader.IsStartElement(parameterName, operation.Contract.Namespace)) { var serializer = new DataContractSerializer(parameters[i].ParameterType, parameterName, operation.Contract.Namespace); arguments.Add(serializer.ReadObject(xmlReader, verifyObjectName: true)); } } } return arguments.ToArray(); } } public static class SOAPMiddlewareExtensions { public static IApplicationBuilder UseSOAPMiddleware<T>(this IApplicationBuilder builder, string path, MessageEncoder encoder) { return builder.UseMiddleware<SOAPMiddleware>(typeof(T), path, encoder); } public static IApplicationBuilder UseSOAPMiddleware<T>(this IApplicationBuilder builder, string path, Binding binding) { var encoder = binding.CreateBindingElements().Find<MessageEncodingBindingElement>()?.CreateMessageEncoderFactory().Encoder; return builder.UseMiddleware<SOAPMiddleware>(typeof(T), path, encoder); } }这里对于输出的消息做了一个封装,以输出具有正确的元素名称的消息的主体。添加一个 ServiceBodyWriter 类。public class ServiceBodyWriter : BodyWriter { string ServiceNamespace; string EnvelopeName; string ResultName; object Result; public ServiceBodyWriter(string serviceNamespace, string envelopeName, string resultName, object result) : base(isBuffered: true) { ServiceNamespace = serviceNamespace; EnvelopeName = envelopeName; ResultName = resultName; Result = result; } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { writer.WriteStartElement(EnvelopeName, ServiceNamespace); var serializer = new DataContractSerializer(Result.GetType(), ResultName, ServiceNamespace); serializer.WriteObject(writer, Result); writer.WriteEndElement(); } }这里对于中间件整个就完成了。
服务端
在服务端使用,这里你也可以新建一个Web 项目。因为刚刚我们已经新建好了一个Web API项目,我们就直接拿来使用。首先添加 CustomMiddleware 引用在 SOAPService 中添加一个 CalculatorService 类这里我为了方便将接口契约也放在CalculatorService 中,你也可以新建一个接口。然后在 Startup.cs 的 ConfigureServices 中注入 CalculatorServicepublic void ConfigureServices(IServiceCollection services)
{ // Add framework services. services.AddMvc(); services.AddScoped<CalculatorService>(); }在Configure 方法中加入中间件public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); //加入一个/CalculatorService.svc 地址,绑定Http app.UseSOAPMiddleware<CalculatorService>("/CalculatorService.svc", new BasicHttpBinding()); app.UseMvc(); }这样就完成了服务端编写。
客户端
新建一个 Console Application -》SOAPClient添加如下引用:Install-Package System.ServiceModel.PrimitivesInstall-Package System.Private.ServiceModelInstall-Package System.ServiceModel.HttpProgram代码如下:编写好以后,分别对应到目录使用dotnet run执行程序。成功建立了连接,也有返回。也就实现SOAP 的解析。 示例代码GitHub:https://github.com/linezero/Blog/tree/master/SOAPService 参考文档:https://blogs.msdn.microsoft.com/dotnet/2016/09/19/custom-asp-net-core-middleware-example/原文地址:http://www.cnblogs.com/linezero/p/aspnetcoresoap.html.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
相关文章推荐
- ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- ASP.NET Core 开发-中间件(Middleware)
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
- ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”
- ASP.NET Core 中的SEO优化(1):中间件实现服务端静态化缓存
- 浅谈ASP.NET Core中间件实现分布式 Session
- ASP.NET Core 使用 URL Rewrite 中间件实现 HTTP 重定向到 HTTPS
- [转载]利用WCF共享ASP.NET session实现WCF服务端验证
- 利用WCF共享ASP.NET session实现WCF服务端验证
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- ASP.NET Core 2.0系列学习笔记-Middleware中间件
- ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面
- ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”
- 利用WCF共享ASP.NET session实现WCF服务端验证
- ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求
- ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构
- ASP.NET Core -中间件(Middleware)使用
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
- ASP.NET Core2利用Jwt技术在服务端实现对客户端的身份认证