Edited at

SoapCoreを使って同一URLでsoap1.1とsoap1.2リクエストを処理する

More than 1 year has passed since last update.


始めに

ASP.NET CoreにおけるSOAPリクエスト処理ミドルウェアのSoapCoreが、0.9.7よりsoap1.2リクエストの処理が可能になった。

しかし、同一URLでsoap1.1と1.2を受ける場合、そのままでは両方解析ということはできないので、やり方を書いておく。

SoapCore自体の解説は、以前書いた記事 "ASP.NET CoreでHTTP SOAPリクエストを処理する"を参照のこと。


やり方


SoapCoreでSOAP 1.2を処理する方法

UseSoapEndPointの第二引数で、どのような通信方式を使用するか等を指定するので、以下のようにする。

// using System.ServiceModel;

// using System.ServiceModel.Channels;
// using SoapCore;

// soap1.1を使いたい場合は、第二引数にBasicHttpBindingをnewすればOK
var transportBinding = new HttpTransportBindingElement();
var textEncodingBinding = new TextMessageEncodingBindingElement(MessageVersion.Soap12WSAddressing10, Encoding.UTF8);
var customBinding = new CustomBinding(transportBinding, textEncodingBinding);
app.UseSoapEndpoint<T>("/Service.svc", customBinding, SoapSerializer.DataContractSerializer);

それぞれHttpTransportBindingが、通信プロトコルの決定、TextMessageEncodingBindingElementが、メッセージフォーマットの決定となる。そして、この二つを合わせて、CustomBindingを作る。これ自体はWCFの話になるので、詳しく知りたければWCF公式ドキュメントを参照のこと。


問題点

ここで問題は、TextMessageEncodingBindingElementが一度に一種類しか設定できないことにある。

よって、素直にUseSoapEndpointを使用した場合は、soap1.1あるいはsoap1.2のどちらかしか受け取れないということになる。


解決策

Startup内で以下のようにする。

// using Microsoft.AspNetCore.Builder;

// using System.ServiceModel;
// using System.ServiceModel.Channels;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseWhen(ctx => ctx.Request.Headers.ContainsKey("SOAPAction"), app2 =>
{
app2.UseSoapEndpoint<TestService>("/Service.svc", new BasicHttpBinding(), SoapSerializer.DataContractSerializer);
});
app.UseWhen(ctx => !ctx.Request.Headers.ContainsKey("SOAPAction"), app2 =>
{
var transportBinding = new HttpTransportBindingElement();
var textEncodingBinding = new TextMessageEncodingBindingElement(MessageVersion.Soap12WSAddressing10, System.Text.Encoding.UTF8);
app2.UseSoapEndpoint<TestService>("/Service.svc", new CustomBinding(transportBinding, textEncodingBinding), SoapSerializer.DataContractSerializer);
});
}

要はUseWhen(Func<HttpContext, bool>, Action<IApplicationBuilder>)を使って、分岐すれば良い、という事になる。

判定部分にどのような基準を置くかという事になるが、HTTPヘッダを用いた方法はいくつかある。

ボディはミドルウェア内部で使用するので触ることはできないことに注意。

判定方法
1.1
1.2

SOAPActionの有無

Content-Typeのmedia type
text/xml
application/soap+xml

Content-Typeのaction要素の有無

この辺りはクライアントの動作仕様によるところが大きいので、唯一解は無い。

参考リンクは以下