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

Ham*_*RIM 1 soap wsdl client-certificates asp.net-core

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

Ham*_*RIM 7

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

首先在 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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

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

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

对于在服务器端处理的请求,以 xml 形式发送的数据通常为空。我们需要在SoapCore中进行以下改进,以便服务器能够解析请求。

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

另外,满足传入请求和服务重定向到我们的控制器的接口应该写成如下

[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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

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

 Stream reqBody = Request?.Body;
        if (Request == null)
            reqBody = (MyRequesterClass as HttpRequest).Body;
Run Code Online (Sandbox Code Playgroud)

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

通常我们通过添加代理可以创建和行走的部分来提供wsdl Visual Studio添加引用。(推荐案例)但就我而言,我决定使用 webclient 发布 xml,因为我使用用户证书并且不知道要发送的对象类型。使用示例如下:

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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

从我的用户个人商店获取客户端证书

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();
        }
    }
Run Code Online (Sandbox Code Playgroud)