如何在Asp.net Core项目中使用SoapCore在项目路径文件夹中公开wsdl

问题描述:

您的项目由Asp.net Core编写,可以部署Rest API。但是,您的客户想与肥皂进行交流。如何进行改进

Your project, written with Asp.net Core, makes deploying Rest API. However, your customer wanted to communicate with soap. How to make an improvement

SoapCore 已经为我们做了很多事情来支持这种情况。我们将逐步更改应用于Asp.net Core项目。

SoapCore has already done many things for us to support this situation. We apply step-by-step changes to our Asp.net Core project.

在Startup.cs中首先:

First in Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            try
            {
                services.AddSoapServiceOperationTuner(new MyServiceOperationTuner());

                services.Configure<XApiSettings>(options =>
                {
                    options.baseurl = XApiOptions[nameof(XApi.baseurl)];
                    options.accesstokenroute = XApiOptions[nameof(XApi.accesstokenroute)];
                    options.secret = XApiOptions[nameof(XApi.secret)];
                    options.secretkey = XApiOptions[nameof(XApi.secretkey)];
                    options.grant_type = XApiOptions[nameof(XApi.grant_type)];
                    options.username = XApiOptions[nameof(XApi.username)];
                    options.password = XApiOptions[nameof(XApi.password)];
                });


                services.AddSoapCore();
                services.AddSingleton<IRESAdapterService>(new RESAdapterService(
                    Xcontroller: new XApiController(
                        services.BuildServiceProvider().GetRequiredService<IOptions<XApi>>(),
                        _corendonLogger
                        )));
                services.AddSoapExceptionTransformer((ex) => ex.Message);
            }
            catch (Exception ex)
            {
                Log.Logger.Error("ConfigureServices Message: " + ex.Message);
            }
        }

如果您希望从根目录访问应用程序目录在您部署的地址,您可以直接输入路径'/'或将其命名为'/ XX'

If you want your application to be accessible from the root directory at the address you deploy, you can type path '/' directly or name it as '/ XX'

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ApplicationContext dbContext)
    {
        try
        {
            app.UseSoapEndpoint<IRESAdapterService>(path: "/", binding: new BasicHttpBinding(), SoapSerializer.XmlSerializer);
        }
    }

对于在服务器上处理的请求方面,以xml格式发送的数据通常为null。我们需要对SoapCore进行以下改进,以便服务器可以解决请求。

In the case of requests that are handled on the server side, data sent as xml will normally be null. We need to make the following improvement in SoapCore so that the server can resolve the request.

public class MyServiceOperationTuner : IServiceOperationTuner
    {
        public void Tune(HttpContext httpContext, object serviceInstance, SoapCore.OperationDescription operation)
        {
            RESAdapterService service = serviceInstance as RESAdapterService;
            service.SetHttpRequest = httpContext.Request;
        }
    }

此外,该接口可以满足传入请求并重定向到我们的控制器的服务应如下所示

In addition, the interface to meet the incoming requests and services to make redirects to our controller should write as follows

[ServiceContract]
    public interface IRESAdapterService
    {
        [OperationContract]
        [XmlSerializerFormat(SupportFaults = true)]
        Task<OTA_AirAvailRS> getAvailability([FromBody]HttpRequestMessage req);
        [OperationContract]
        Task<OTA_AirPriceRS> pricing([FromBody]HttpRequestMessage req);
    }

        public class RESAdapterService : IRESAdapterService
        {
            XApiController _controller;
            public HttpRequest SetHttpRequest { get; set; }
            public RESAdapterService(XApiController XApi)
            {
                _controller = XApi;
            }

            public Task<MyRequesterClass> Method1([FromBody]HttpRequestMessage req)
            {
                return _controller.Method1(SetHttpRequest);
            }

            public Task<MyDiffRequesterClass> Method2([FromBody]HttpRequestMessage req)
            {
                return _controller. Method2(SetHttpRequest);
            }
        }

控制器正在捕获来自Request对象的请求,但是;现在,在这种情况下,Request对象必须通过路由器服务才能获得null的未来。因此,我们可以实现如下读取XML的代码

The controller was catching requests from the Request object, but; now the Request object has to get through the router service for the future of null in this context. Therefore we can implement the code that reads XML as follows

 Stream reqBody = Request?.Body;
        if (Request == null)
            reqBody = (MyRequesterClass as HttpRequest).Body;

让我们来到客户端,编写一个简单的框架控制台项目

Let's come to the client side, write a simple framework console project

通常,我们提供wsdl visual studio通过添加代理可以创建和遍历的部分来添加引用。 (推荐的情况)但是在我的情况下,我决定在webclient上发布xml,因为我使用的是用户证书,而且我不知道要发送的对象类型。以下是示例用法:

Normally we offer wsdl visual studio add references by adding the portion of the proxy can create and walk. (Recommended case) But in my case I decided to post xml with webclient because I use a user certificate and I don't know the type of object to send. Sample use below:

static string xml = " <ReqObj xmlns='http://tempuri.org/'>"
                + "</ ReqObj >";

        static string wrapbody = @"<?xml version=""1.0"" encoding=""utf-8""?>
                    <soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" 
                        xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 
                        xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
                        <soap:Body>
                           #
                        </soap:Body>
                    </soap:Envelope>";

        public static async Task<string> CreateSoapEnvelope()
        {
            HttpResponseMessage response = await PostXmlRequest("https://localhostorliveaddress.com");
            string content = await response.Content.ReadAsStringAsync();

            return content;
        }

        public static async Task<HttpResponseMessage> PostXmlRequest(string baseUrl)
        {
            X509Certificate2 clientCert = new X509Certificate2(@"D:\ccer\xxx.pfx", "password");
            //X509Certificate2 clientCert = GetClientCertificate();
            WebRequestHandler requestHandler = new WebRequestHandler();
            requestHandler.ClientCertificates.Add(clientCert);

            using (var httpClient = new HttpClient(requestHandler))
            {
                string wrpXmlContent = wrapbody.Replace("#", xml);
                var httpContent = new StringContent(wrpXmlContent, Encoding.UTF8, "text/xml");
                httpContent.Headers.Add("SOAPAction", "https://localhostorliveaddress.com/method1");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));

                return await httpClient.PostAsync(baseUrl, httpContent);
            }
        }

从我的用户个人存储中获取客户端证书

Getting Client certificate from My User Personel Store

private static X509Certificate2 GetClientCertificate()
    {
        X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        try
        {
            userCaStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
            X509Certificate2Collection findResult = certificatesInStore.
                Find(X509FindType.FindBySubjectName, "XRootCertificateOnMyUserPersonelStore", true);
            X509Certificate2 clientCertificate = null;

            if (findResult.Count == 1)
            {
                clientCertificate = findResult[0];
            }
            else
            {
                throw new Exception("Unable to locate the correct client certificate.");
            }
            return clientCertificate;
        }
        catch
        {
            throw;
        }
        finally
        {
            userCaStore.Close();
        }
    }