web-dev-qa-db-ja.com

.net CoreでSOAPサービスを呼び出す

.net 4.6.2コードをSOAPサービスを呼び出す。netコアプロジェクトに移植しています。新しいコードでは、C#を使用しています(設定上の理由により、今はなぜなのか思い出せません)。

しかし、次の例外が発生しています。

https://someurl.com/ws/Thing.pub.ws:Something へのHTTP応答の受信中にエラーが発生しました。これは、サービスエンドポイントバインディングがHTTPプロトコルを使用していないことが原因である可能性があります。これは、サーバーによって中断されたHTTP要求コンテキストが原因である可能性もあります(おそらくサービスのシャットダウンが原因です)。詳細については、サーバーログを参照してください。

それを投げているコードは

try
{
    var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

    var endpoint = new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService"));

    var thing= new TheEndpoint.AService_PortTypeClient(binding, endpoint);
    thing.ClientCredentials.UserName.UserName = "usrn";
    thing.ClientCredentials.UserName.Password = "passw";

    var response = await thing.getSomethingAsync("id").ConfigureAwait(false);

}
finally
{
    await thing.CloseAsync().ConfigureAwait(false);
}

サービスを呼び出して動作する古い構成に基づいて、このようなものです私は何が欠けていますか

<bindings>
  <basicHttpsBinding>
    <binding name="TheEndpoint_pub_ws_AService_Binder" closeTimeout="00:02:00"
        openTimeout="00:02:00" receiveTimeout="00:03:00" sendTimeout="00:03:00">
      <security mode="Transport">
        <transport clientCredentialType="Basic" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>
  </basicHttpsBinding>
</bindings>
<client>
  <endpoint address="https://someurl.com/ws/Thing.pub.ws:AService"
      binding="basicHttpsBinding" bindingConfiguration="TheEndpoint_pub_ws_AService_Binder"
      contract="TheEndpoint.AService_PortType" name="TheEndpoint_pub_ws_AService_Port" />
</client>

このオンラインで多くの情報を見つけることができません。あなたが私を助けることができることを願っています。

UPDATESixto Saezの提案に従って、エンドポイントにエラーを明らかにしてもらいました。

HTTP要求は、クライアント認証スキーム「基本」で許可されていません。サーバーから受信した認証ヘッダーは、 'Basic realm = "Integration Server"、encoding = "UTF-8"'でした。

何をすべきかを見つけ、成功した場合はここに結果を投稿しようとします。

更新2

さて、ここでこのコードを使用して新しい構文に移動しようとしました

ChannelFactory<IAService> factory = null;
IAService serviceProxy = null;
Binding binding = null;

try
{
   binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);

   factory = new ChannelFactory<IAService>(binding, new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));            
   factory.Credentials.UserName.UserName = "usrn";
   factory.Credentials.UserName.Password = "passw";

   serviceProxy = factory.CreateChannel();

   var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);

    factory.Close();
    ((ICommunicationObject)serviceProxy).Close();  
}
catch (MessageSecurityException ex)
{
    //error caught here
    throw;
}

しかし、私はまだ同じ(わずかに異なる)エラーを受け取ります。 「基本」ではなく「匿名」になり、最後に「、encoding = "UTF-8"がなくなりました。

HTTP要求は、クライアント認証スキーム「匿名」で許可されていません。サーバーから受信した認証ヘッダーは「Basic realm = "Integration Server"」でした。

問題は私の側にあるのか、サーバーにあるのか?

明らかに、私のSOAP "スキル"は現在、非常に不足していますが、この新しいアプローチで思いつかないすべての構成コンボを試してみました。誰かが私を正しい方向に向けてくれることを願っています。

20
Sturla

OKこの答えは、接続しようとしている人向けですWCFへサービス。netコアからプロジェクト。

新しい.net Core WCF構文/ライブラリを使用したmy問題の解決策を次に示します。

BasicHttpBinding basicHttpBinding = null;
EndpointAddress endpointAddress = null;
ChannelFactory<IAService> factory = null;
IAService serviceProxy = null;

try
{
    basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
    basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
    endpointAddress = new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService"));
    factory = new ChannelFactory<IAService>(basicHttpBinding, endpointAddress);

    factory.Credentials.UserName.UserName = "usrn";
    factory.Credentials.UserName.Password = "passw";
    serviceProxy = factory.CreateChannel();

    using (var scope = new OperationContextScope((IContextChannel)serviceProxy))
    {
        var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);
    }

    factory.Close();
    ((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
     throw;
}
catch (Exception ex)
{
    throw;
}
finally
{
    // *** ENSURE CLEANUP (this code is at the WCF GitHub page *** \\
    CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
}

UPDATE

上記のコードを使用して次の例外が発生しました

このOperationContextScopeは順不同で破棄されています。

これは 壊れている何か (または対処が必要)のようです。

だから、私はそれを機能させるために次のことをしなければなりませんでした(これに基づいて GitHub問題

basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

factory = new ChannelFactory<IAService_PortType>(basicHttpBinding, new EndpointAddress(new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));
factory.Credentials.UserName.UserName = "usern";
factory.Credentials.UserName.Password = "passw";
serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();
var opContext = new OperationContext((IClientChannel)serviceProxy);
var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
OperationContext.Current = opContext;

try
{
    var result = await serviceProxy.getSomethingAsync("id").ConfigureAwait(false);

    // cleanup
    factory.Close();
    ((ICommunicationObject)serviceProxy).Close();
}
finally
{
  // *** ENSURE CLEANUP *** \\
  CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
  OperationContext.Current = prevOpContext; // Or set to null if you didn't capture the previous context
}

ただし、要件はおそらく異なるでしょう。 WCFサービスへの接続に役立つリソースは次のとおりです。

テストは私を大いに助けてくれましたが、見つけるのが少し難しい場所でした(助けがありました、Zhenlanに感謝します 私のwcf githubの問題に答えます

23
Sturla

.NETコアからSOAPサービスを使用するために、プロジェクトUIから接続されたサービスを追加しても機能しません。

オプション1:dotnet-svcutil CLIを使用します。前提条件:VS 2017、バージョン15.5以降

  1. Developer Command Prompt VS 2017を起動します。
  2. App.csprojファイルに移動して、以下の参照を追加します。

    <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.9" />
    <PackageReference Include="System.ServiceModel.Http" Version="4.5.3" />
    </ItemGroup>
    <ItemGroup>
    <DotNetCliToolReference Include="dotnet-svcutil" Version="1.0.*" />
    </ItemGroup>
    
  3. ソリューションを再構築します。

  4. VSコマンドプロンプトからプロジェクトの場所にディレクトリを変更します。
  5. 実行コマンド:svcutil SOAP_URL?wsdl;例:example.com/test/testing?wsdlこれにより、プロジェクトに参照ファイルとoutput.configファイルが生成されます。
  6. .Net Coreにはapp.configまたはweb.configファイルはありませんが、output.configファイルはSOAPバインディングを提供します。

オプション2複数のSOAPサービスを参照する必要がある場合

  1. 新しいクラスライブラリプロジェクトを作成し、.Net Framework 4.5.1を使用します。NetFrameworkが最新の場合、契約から生成された参照ファイルが正しくないので、.Netフレームワークが重要です。
  2. [参照]を右クリックして、サービス参照を追加します。
  3. .Netコアプロジェクトからクラスライブラリプロジェクトを参照します。
4
Palash Roy

NTLMと.Net Coreで同じことをしようとしていて、いくつかの変数がどのように定義されているのか疑問に思っている人のために、コードを次のように明確にしました。

IAService_PortTypeは、 https://joshuachini.com/2017/07/13/calling-a-soap-service-from-asp-net-coreのガイドに従って作成したサービス参照です。 -or-net-core /

BasicHttpBinding basicHttpBinding = 
    new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
// Setting it to Transport will give an exception if the url is not https
basicHttpBinding.Security.Transport.ClientCredentialType = 
    HttpClientCredentialType.Ntlm;

ChannelFactory<IAService_PortType> factory = 
    new ChannelFactory<IAService_PortType>(basicHttpBinding, 
    new EndpointAddress(
        new Uri("https://someurl.com/ws/TheEndpoint.pub.ws:AService")));
factory.Credentials.Windows.ClientCredential.Domain = domain;
factory.Credentials.Windows.ClientCredential.UserName = user;
factory.Credentials.Windows.ClientCredential.Password = pass;
IAService_PortType serviceProxy = factory.CreateChannel();
((ICommunicationObject)serviceProxy).Open();

try
{
    var result = serviceProxy.getSomethingAsync("id").Result;

}
finally
{
    // cleanup
    factory.Close();
    ((ICommunicationObject)serviceProxy).Close();
}
2
C64

そのため、これを行う必要があり、 WCF Webサービス参照プロバイダーツール を使用しました。

ここにあるような回答によると、Bindings and Factories and Proxiesとのすべてのラウンドアバウトビジネスに対する明らかな必要性は奇妙なようでした。

簡単な公式の「HowTo」が見つからないので、要件に合わせてまとめたsimplestセットアップに関する調査結果を投稿しますダイジェスト認証の場合:

    ServiceName_PortClient client = new ServiceName_PortClient();
    //GetBindingForEndpoint returns a BasicHttpBinding
    var httpBinding = client.Endpoint.Binding as BasicHttpBinding;
    httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
    client.ClientCredentials.HttpDigest.ClientCredential = new NetworkCredential("Username", "Password", "Digest");
    var result = await client.GetResultAsync();

ここで、単に認証を行う必要がない場合:

    ServiceName_PortClient client = new ServiceName_PortClient();
    var result = await client.GetResultAsync();

十分なはずです。

ServiceName_PortClientクラスは、インポートツールによってそのように生成されました。ServiceNameは、インポートするサービスの名前です。

もちろん、次の行に沿って部分的なServiceName_PortClientクラスに設定を配置することは、インポートされたコードの精神にあるようです。

    public partial class ServiceName_PortClient
    {
        static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials)
        {
            var httpBinding = serviceEndpoint.Binding as BasicHttpBinding;
            httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
            clientCredentials.HttpDigest.ClientCredential = new NetworkCredential("Username", "Password", "Realm");
        }
    }
0
David