4

ServiceStack を使用した簡単な API セットアップがあります。次のコードを使用して実行します。

namespace TheGuest.Test
{
    [DataContract]
    [Description("A sample web service.")]
    public class Greet
    {
        [DataMember]
        public string Name { get; set; }
    }

    [DataContract]
    public class GreetResponse
    {
        [DataMember]
        public string Result { get; set; }
    }

    /// <summary>
    /// An example of a very basic web service.
    /// </summary>
    public class GreetService : IService<Greet>
    {
        public object Execute(Greet request)
        {
            return new GreetResponse { Result = "Hello " + request.Name };
        }
    }

    public static class Constants
    {
        public const string DefaultNamespaceV1 = "http://my/custom/namespace";
    }

    public class MyAppHost : AppHostBase
    {
        // Tell Service Stack the name of your application and where to find your web services.
        public MyAppHost()
            : base("My Web Services", typeof(GreetService).Assembly)
        {
        }

        public override void Configure(Container container)
        {
            SetConfig(new EndpointHostConfig { WsdlServiceNamespace = Constants.DefaultNamespaceV1 });

            // Register user-defined REST-ful URLs.
            Routes
                .Add<Greet>("/hello")
                .Add<Greet>("/hello/{Name}")
                .Add<Greet>("/hello/{Name*}");
        }
    }

    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            new MyAppHost().Init();
        }
    }
}

AssemblyInfo.cs に次の行を追加します。

[assembly: ContractNamespace("http://my/custom/namespace", ClrNamespace = "TheGuest.Test")]

次の WSDL が生成されます。

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="Soap12" 
    targetNamespace="http://my/custom/namespace" 
    xmlns:svc="http://my/custom/namespace" 
    xmlns:tns="http://my/custom/namespace" 

    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" 
    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" 
    xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" 
    xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
    xmlns:wsa10="http://www.w3.org/2005/08/addressing" 
    xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex">

    <wsdl:types>
        <xs:schema xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="anyType" nillable="true" type="xs:anyType" />
  <xs:element name="anyURI" nillable="true" type="xs:anyURI" />
  <xs:element name="base64Binary" nillable="true" type="xs:base64Binary" />
  <xs:element name="boolean" nillable="true" type="xs:boolean" />
  <xs:element name="byte" nillable="true" type="xs:byte" />
  <xs:element name="dateTime" nillable="true" type="xs:dateTime" />
  <xs:element name="decimal" nillable="true" type="xs:decimal" />
  <xs:element name="double" nillable="true" type="xs:double" />
  <xs:element name="float" nillable="true" type="xs:float" />
  <xs:element name="int" nillable="true" type="xs:int" />
  <xs:element name="long" nillable="true" type="xs:long" />
  <xs:element name="QName" nillable="true" type="xs:QName" />
  <xs:element name="short" nillable="true" type="xs:short" />
  <xs:element name="string" nillable="true" type="xs:string" />
  <xs:element name="unsignedByte" nillable="true" type="xs:unsignedByte" />
  <xs:element name="unsignedInt" nillable="true" type="xs:unsignedInt" />
  <xs:element name="unsignedLong" nillable="true" type="xs:unsignedLong" />
  <xs:element name="unsignedShort" nillable="true" type="xs:unsignedShort" />
  <xs:element name="char" nillable="true" type="tns:char" />
  <xs:simpleType name="char">
    <xs:restriction base="xs:int" />
  </xs:simpleType>
  <xs:element name="duration" nillable="true" type="tns:duration" />
  <xs:simpleType name="duration">
    <xs:restriction base="xs:duration">
      <xs:pattern value="\-?P(\d*D)?(T(\d*H)?(\d*M)?(\d*(\.\d*)?S)?)?" />
      <xs:minInclusive value="-P10675199DT2H48M5.4775808S" />
      <xs:maxInclusive value="P10675199DT2H48M5.4775807S" />
    </xs:restriction>
  </xs:simpleType>
  <xs:element name="guid" nillable="true" type="tns:guid" />
  <xs:simpleType name="guid">
    <xs:restriction base="xs:string">
      <xs:pattern value="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" />
    </xs:restriction>
  </xs:simpleType>
  <xs:attribute name="FactoryType" type="xs:QName" />
  <xs:attribute name="Id" type="xs:ID" />
  <xs:attribute name="Ref" type="xs:IDREF" />
</xs:schema>
<xs:schema xmlns:tns="http://my/custom/namespace" elementFormDefault="qualified" targetNamespace="http://my/custom/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="Greet">
    <xs:sequence>
      <xs:element minOccurs="0" name="Name" nillable="true" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Greet" nillable="true" type="tns:Greet" />
</xs:schema>
    </wsdl:types>



    <wsdl:message name="GreetIn">
        <wsdl:part name="parameters" element="tns:Greet" />
    </wsdl:message>

    <wsdl:portType name="ISyncReply">

    </wsdl:portType>

    <wsdl:portType name="IOneWay">
    <wsdl:operation name="Greet">
        <wsdl:input message="svc:GreetIn" />
    </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="WSHttpBinding_ISyncReply" type="svc:ISyncReply">
        <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />

    </wsdl:binding>

    <wsdl:binding name="WSHttpBinding_IOneWay" type="svc:IOneWay">
        <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="Greet">
      <soap:operation soapAction="http://schemas.servicestack.net/types/Greet" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
    </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="SyncReply">
        <wsdl:port name="WSHttpBinding_ISyncReply" binding="svc:WSHttpBinding_ISyncReply">
            <soap:address location="http://localhost:50472/test/soap12" />
        </wsdl:port>
    </wsdl:service>

    <wsdl:service name="AsyncOneWay">
        <wsdl:port name="WSHttpBinding_IOneWay" binding="svc:WSHttpBinding_IOneWay">
            <soap:address location="http://localhost:50472/test/soap12" />
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

Visual Studio 2010 を介してこのサービスを追加すると、2 つのクライアントが取得されます。1 つは呼び出すことができるメソッドを持たない「SyncReplyClient」と呼ばれ、もう 1 つは「Greet」メソッドを持つ「OneWayClient」と呼ばれます。しかし、名前が示すように、応答が必要なので SyncReplyClient を使用したいと思います。

どうすればこれを達成できますか?

ちなみに、OneWayClient は ProtocolException をスローし、次のメッセージが表示されます。OneWayClient を使用したくないので、それほど気になりませんが、それでもなお奇妙です。

4

3 に答える 3

5

SOAP で使用するサービスを作成するときは、 SOAP の制限について必ずお読みください。つまり、単一の XSD/WSDL 名前空間を維持する必要があります。たとえば、AppConfig のデフォルトの WSDL 名前空間を次のように変更できます。

SetConfig(new EndpointHostConfig {
    WsdlServiceNamespace = "http://my.new.namespace.com/types",
});

これにより、生成された WSDL ページで使用される WSDL/XSD 名前空間が設定されます。[DataContract]また、各 DataContract に手動で指定することで実行できる各 DataContract の名前空間を指定して、このカスタム XSD 名前空間を DTO と一致させる必要があります。

[DataContract(Namespace="http://my.new.namespace.com/types")]

または指定を使用できます

 [assembly: ContractNamespace("http://my/custom/namespace", 
            ClrNamespace = "TheGuest.Test")] 

共有 C# 名前空間の下にある多数の DTO に設定します。

また、最近いくつかの変更が加えられました。新しい APIを追加し、さまざまな属性を追加して、サービスに注釈を付けることができるようにしました (/metadata および Api Docs/Swagger ページに表示されます)。これらの変更を考慮して、サービスを作成する新しい方法は次のとおりです。

[DataContract]
[Api("A sample web service.")]
public class Greet
{
    [DataMember]
    [ApiMember("The name of the person you wish to greet")]
    public string Name { get; set; }
}

[DataContract]
public class GreetResponse
{
    [DataMember]
    public string Result { get; set; }
}

public class GreetService : Service
{
    public GreetResponse Any(Greet request)
    {
        return new GreetResponse { Result = "Hello " + request.Name };
    }
}

サービス応答タイプが何であるかを ServiceStack に通知する

ServiceStack がサービスの応答タイプを判断するには、以下のヒントのいずれかを提供する必要があります。

強い型の戻り値の型を使用する

サービスは型を返すかobjectResponseDto型を返すことができます。例:

public class GreetService : Service
{
    //1. Using Object
    public object Any(Greet request)
    {
        return new GreetResponse { Result = "Hello " + request.Name };
    }

    //2. Above service with a strong response type
    public GreetResponse Any(Greet request)
    {
        return new GreetResponse { Result = "Hello " + request.Name };
    }
}

オプション 2) を使用する場合、ServiceStack はGreetResponseタイプを想定します。

IReturn マーカー インターフェイスを使用する

[DataContract]
public class Greet : IReturn<GreetResponse> { ... }

Marker インターフェイスを使用するもう 1 つの利点は、より簡潔なクライアント API を提供することです。

GreetResponse response = client.Send(new Greet { Name = "World!" });

Marker インターフェイスがなければ、クライアント API は次のようになります。

GreetResponse response = client.Send<GreetResponse>(new Greet { Name = "World!" });

typeof(RequestDto).Name + 'Response' 命名規則を使用する

サービスにobject応答タイプがあり、マーカー インターフェイスがない場合は、名前の{RequestDto}Response命名規則を使用して ServiceStack に応答タイプを伝えることができます。

注: ServiceStack が応答タイプを検出できるようにするには、要求 DTOと同じ名前空間に存在する必要があります。また、すべてのリクエストおよびレスポンス DTO には一意の名前を付ける必要があります。これにより、完全な名前空間ではなく、リクエスト DTOの名前だけで ServiceStack サービスを呼び出すことができます。

于 2012-12-24T00:21:37.873 に答える
2

サービスを参照してプロキシ クラスを生成する理由はありますか? (説明を求めて申し訳ありませんが、質問にコメントを投稿するのに十分な名声がありません。)

これが初めての ServiceStack サービスである場合は、それが WCF とは異なるパラダイムであることについて読む必要があります。ここに簡単な要約があります。

SS の優れた点は、プロキシを生成する必要がなく、リモート アクションを行う代わりにデータの転送に集中できることです。DTO を指定する DLL を用意するだけで、その DLL はサービス プロジェクトとクライアント プロジェクトの両方から参照されます。

これにより、組み込みのサービス クライアント (JSON/SOAP/etc) を使用してサービスと通信できます。違いを理解するには少し時間がかかりますが、ServiceStack の違い (特に Javascript やその他の C# 以外のクライアントからのサービスの呼び出しに関して) を理解したら、プロキシを再生成せずにサービス レイヤーをリファクタリングする必要があります。なぜそれが良いのかがわかります。

クライアント プロキシを生成する特別な必要があり、これで質問に答えられない場合は申し訳ありません。このリンクは、汎用クライアントを使用するのがいかに簡単かを示しています。SOAP 生成を行う特別な理由がない限り、このアプローチを取ることを強くお勧めします。

于 2012-10-18T05:54:04.993 に答える
1

見つけた!

ServiceStack の例を確認しましたが、動作しますが、私のプログラムは動作しません。

違いは、操作 (SayHello) と応答 (SayHelloResponse) が同じ名前空間 (My.Application.Operations と MyApplication.Responses) にないことです。

それらを同じ名前空間に配置すると、機能し、サービスは「OneWay」ではなく「SyncReply」になります。

于 2012-12-23T22:41:20.583 に答える