问题
Your project, written with Asp.net Core, makes deploying Rest API. However, your customer wanted to communicate with soap. How to make an improvement
回答1:
SoapCore has already done many things for us to support this situation. We apply step-by-step changes to our Asp.net Core project.
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);
}
}
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);
}
}
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);
}
}
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
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();
}
}
来源:https://stackoverflow.com/questions/57713742/how-to-use-soapcore-in-asp-net-core-project-for-exposing-wsdl-at-project-route-f