ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

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.cs


public 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.cs


public 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.cs


public 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.html

SOAPMiddleware.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 中注入 CalculatorService

public 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.Primitives
Install-Package System.Private.ServiceModel
Install-Package System.ServiceModel.Http

 

Program代码如下:


编写好以后,分别对应到目录使用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跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java异常了还会往下走吗_异常一个问题,请帮下忙:处理异常后,程序会继续往下运行吗...

import java.util.*;public class PrintBig{public static void main(String[] args){Scanner in new Scanner(System.in);int sum;int count0;System.out.println("输入10个整数");for(int i0;i<10;i){sum in.nextInt();try{Integer k new Integer(sum);}catc…

新闻发布项目——访问温馨提示

1.本项目开发的软件&#xff1a;MyEclipse10.0tomcat7.0sql servel2012 2.本项目所有的CSS下载地址&#xff1a;Jsp实现新闻发布系统的CSS界面 3.本项目所有的JS下载地址&#xff1a;Jsp实现新闻发布系统的JS界面 4.本项目所有的图片下载地址&#xff1a;Jsp实现新闻发布系统的…

Tomcat 使用apr优化

转载自 Tomcat 使用apr优化最近业务服务器出现了一些问题&#xff0c;Nginx傲娇了&#xff0c;准备把加Nginx插件上的一些处理逻辑扔到后端的Tomcat的业务处理里面去&#xff0c;考虑到tomcat目前本来就压力山大&#xff0c;所以弄了弄apr库来优化tomcat的并发能力。&#xf…

ASP.NET Core MVC 配置全局路由前缀

前言 大家好&#xff0c;今天给大家介绍一个 ASP.NET Core MVC 的一个新特性&#xff0c;给全局路由添加统一前缀。严格说其实不算是新特性&#xff0c;不过是Core MVC特有的。 应用背景 不知道大家在做 Web Api 应用程序的时候&#xff0c;有没有遇到过这种场景&#xff0c;就…

java jpa saveall方法优化_JPA批量插入(saveAll)

有时候要从第三方导入数据&#xff0c;一般量都比较大&#xff0c;除了方法用异步线程Async之外&#xff0c;如果每条记录都调用一次save显然对数据库压力很大。可以使用JPA的批量保存方法saveAll(Iterable entities)。由于JPA的批量保存和批量修改是同一个方法&#xff0c;所以…

js截取字符串的后几位数 省份证号*隐藏

js截取字符串的后几位数 代码如下&#xff1a; var str"abcdefghhhh";//截取后4位 str.substring(str.length-4)&#xff1b; js * 代替 var str ’331023187609300311‘&#xff1b; //18位省份证号 前三位显示中间10位有8个*代替后5位显示 331********00…

java 单一职责原则_设计模式之单一职责原则

对类来说&#xff0c;即一个类应用只负责一项职责&#xff0c;如类A负责两个不同的职责&#xff1a;职责1&#xff0c;职责2.当职责1需求变更时&#xff0c;可造成职责2执行错误&#xff0c;所以需要将类A的粒度分解为A1&#xff0c;A2.降低类的复杂度&#xff0c;一个类只负责…

TypeScript 2.0 正式发布

9 月 22 日&#xff0c;TypeScript 2.0 正式发布了。 TypeScript 是微软开发的开源的编程语言&#xff0c;主要负责人是 C# 之父 Anders Hejlsberg。 TypeScript 成功将 JavaScript 的潜能与静态类型结合了起来&#xff0c;而且编译为 JavaScript。编译时类型检查可以避免很多潜…

Tomcat server.xml配置示例

转载自 Tomcat server.xml配置示例几乎所有容器类型的应用都会包含一个名为 server.xml 的文件结构。基本上&#xff0c;其中的每个元数据或者配置都是容器完成初始化所需要的。正是由于这些内容都是可配置的&#xff0c;使得软件设计者或架构师可以在容器运行时或销毁时&am…

日志-周报-月报(2019年2月)

20190203 1.马氏距离找公式 2.ruby先不看吧&#xff0c;先java学着到联通没办法在写ruby 3.舔狗&#xff0c;ppt&#xff0c;进公司考智商&#xff0c;升职靠情商。 4.看德哥看了一天 5.没了 6.联通调岗做销售&#xff0c;华为不续签合同&#xff0c;ppt文化哪家都一样&a…

怎么用php配合js编写动态页面_JavaScript_JavaScript教程:用JS脚本实现Web页面信息交互范例,要实现动态交互,必须掌握有 - phpStudy...

要实现动态交互&#xff0c;必须掌握有关窗体对象(Form)和框架对象(Frames)更为复杂的知识。三、范例下面我们演示通过点击一个按钮(red)来改变窗口颜色&#xff0c;点击“调用动态按钮文档”调用一个动态按钮文档。test8_1.htm//原来的颜色document.bgColor"blue";d…

SignalR的性能监测与服务器的负载测试

前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测与服务器的负载测试 我们开发任何一个应用,他的性能监测是很重要的参考数据,关系着我们后期优化,更新,改动..等等... SignalR作为…

在Tomcat配置JNDI数据源的三种方式

转载自 在Tomcat配置JNDI数据源的三种方式在我过去工作的过程中,开发用服务器一般都是Tomcat&#xff0c;数据源的配置往往都是在applicationContext.xml中配置一个dataSource的bean&#xff0c;然后在部署时再修改JNDI配置。我猜是因为Tomcat的配置需要改配置文件&#xff0…

毕业设计word 表格标题 图表标题

图一模一样 生成目录 ************************************************************************************************************************* 生成表目录和图目录 *********************************************************************************************…

php打印 二维数组,PHP中遍历二维数组_以不同形式的输出操作实例

//定义二维索引数组$arr array(array("101","李军","男","1976-02-20","95033"),array("103","陆君","男","1974-06-03","95031"),array("105","匡明&q…

Ubuntu 16.04下ASP.NET Core+ MySql + Dapper在 Jexus、nginx 下的简单测试

一、环境及工具 1、服务器 VirtualBox5.1.4 安装 Ubuntu Server 16.04 amd64MySql Ver 14.14 Distrib 5.6.21Jexus 5.8.1nginx 1.10.0dotnet core 1.0.0-preview2-003121supervisor 3.2.1 2、开发环境 VS2015 Update 3DotNetCore.1.0.0-VS2015Tools.Preview2.0.1.exe 3、测试工…

jsp九大隐藏对象

转载自 jsp九大隐藏对象&#xfeff;&#xfeff;jsp内置对象&#xff08;隐藏对象&#xff09;&#xff1a;不加声明和创建就可以在jsp页面脚本中使用的成员对象。 内置对象类型作用域requestjavax.servlet.http.HttpServletRequestrequestresponsejavax.servlet.http.HttpS…

新闻发布项目——数据库脚本(直接导入即可)

数据库sql servel 2012版本&#xff0c;以下是脚本&#xff1a; USE [master] GO /****** Object: Database [newsDB] Script Date: 2016/11/24 19:48:46 ******/ CREATE DATABASE [newsDB]CONTAINMENT NONEON PRIMARY ( NAME NnewsDB, FILENAME NE:\第二期\第六本书使…

最新版Intellij IDEA视频教程 20170814

01课程介绍和软件安装.avi 02Intellij IDEA常用快捷键1132.avi 03Intellij IDEA安装Tomcat和Maven.avi 04Intellij IDEA使用Maven Helper插件分.avi 05Intellij IDEA中Git安装和使用.avi 06Intellij IDEA连接MySQL数据库.avi 07Intellij IDE使用GsonFormat转化json.avi …