1

私は現在、Windows サービス (IIS ではない) でいくつかの WCF REST サービスを実行していますWebServiceHost。サービスごとに個別のインターフェイスとクラスを定義していますが、セルフホステッド ソリューションを作成するために一緒に使用する方法WebServiceHostを理解するのに問題がServiceEndpointあります。ServiceContracts

私が現在設定している方法はWebServiceHost、サービスを実装するクラスごとに新しいクラスを作成し、クラスの名前を URI の一部として使用し、残りの URI をインターフェイスで定義することです。

[ServiceContract]
public interface IEventsService
{
    [System.ServiceModel.OperationContract]
    [System.ServiceModel.Web.WebGet(UriTemplate = "EventType", ResponseFormat=WebMessageFormat.Json)]
    List<EventType> GetEventTypes();

    [System.ServiceModel.OperationContract]
    [System.ServiceModel.Web.WebGet(UriTemplate = "Event")]
    System.IO.Stream GetEventsAsStream();
 }

public class EventsService: IEventsService
{
     public List<EventType> GetEventTypes() { //code in here }
     public System.IO.Stream GetEventsAsStream() { // code in here }
}

サービスを作成するコードは次のようになります。

Type t = typeof(EventService);
Type interface = typeof(IEventService);

Uri newUri = new Uri(baseUri, "Events");
WebServicesHost host = new WebServiceHost(t, newUri);
Binding binding = New WebHttpBinding();
ServiceEndpoint ep = host.AddServiceEndpoint(interface, binding, newUri);

これはうまく機能し、各サービスのサービス エンドポイントが適切な URL に作成されます。

http://XXX.YYY.ZZZ:portnum/Events/EventType http://XXX.YYY.ZZZ:portnum/Events/Event

次に、別のサービス インターフェイスとサービス クラスについて繰り返します。Eventsただし、URLの を削除したいのですが、それをWebServiceHosts行って同じベース URL で複数を作成すると、エラーが発生します。

The ChannelDispatcher at 'http://localhost:8085/' with contract(s) '"IOtherService"' is unable to open its IChannelListener

内部例外:

"A registration already exists for URI 'http://localhost:8085/'."

とがどのようWebServiceHostに連携して ChannelListener を作成するかを理解しようとしています。ServiceEndpointServiceContract

WebServiceHostサービスを実装するクラスごとに個別に必要ですか? 複数のタイプを単一のタイプに登録する方法がわかりませんWebServiceHost

次に、インターフェイスを AddServceEndpoint メソッドに渡しています。メソッドがすべての OperationContract メンバーのオブジェクトをチェックして追加すると仮定します。問題は、どのクラスがどのインターフェイスにマップされるべきかを WebServiceHost がどのように認識するかです。

私が気に入っているのは、インターフェイスと実装クラスを分離しながら複数のサービスを実行する WCF 自己ホスト型サービスを作成する例です。

4

4 に答える 4

2

URI のアプローチについて再考することは、あなたにとって有益かもしれないと思います。Uri は一意のリソース識別子です。各エンドポイントは、「Events」と「OtherResource」という異なる種類のリソースの外部に公開しようとしていると言います。したがって、UriTemplates を少し変更する必要があります。

私はそうします:

[ServiceContract]
public interface IEventTypesService
{
    [OperationContract]
    [WebGet(UriTemplate = "", ResponseFormat=WebMessageFormat.Json)]
    IList<EventType> GetEventTypes();

    [OperationContract]
    [WebGet(UriTemplate = "{id}")]
    EventType GetEventType(string id);
}

[ServiceContract]
public interface IEventsService
{
    [OperationContract]
    [WebGet(UriTemplate = "")]
    Stream GetEventsAsStream();

    [OperationContract]
    [WebGet(UriTemplate = "{id}")]
    Event GetEvent(string id);
}

public class EventsService: IEventsService, IEventTypesService
{
     public IList<EventType> GetEventTypes() { //code in here }
     public EventType GetEventType(string id) { //code in here }
     public Stream GetEventsAsStream() { // code in here }
     public EventType GetEventType(string id) { // code in here }
}

Type t = typeof(EventService);
Type interface1 = typeof(IEventsService);
Type interface2 = typeof(IEventTypesService);

var baseUri = new Uri("http://localhost");
Uri eventsUri= new Uri(baseUri, "Events");
Uri eventTypesUri= new Uri(baseUri, "EventTypes");
WebServicesHost host = new WebServiceHost(t, baseUri);
Binding binding = New WebHttpBinding();
host.AddServiceEndpoint(interface1, binding, eventsUri);
host.AddServiceEndpoint(interface2, binding, eventTypesUri);

はい、その通りです。別のアドレスを使用する必要がありますが、実際には別のリソースです。それをよりよく理解するには、次を参照してください: RESTful API 設計best-practices-for-a-pragmatic-restful-api

最後に、同じアドレスを使用する方法がありますが、そのアプローチは少し奇妙です: 同じアドレスを使用する

于 2014-04-11T22:05:26.927 に答える
0

次の解決策:

  • 単一のオブジェクトが特定のエンドポイントを処理できるようにする
  • パスのどの部分も URI テンプレートにありません
  • すべてのサービスに同じポートを使用します

複数の WebServiceHost (要求を処理するオブジェクトごとに 1 つ) が必要です。もう 1 つの問題は、より深いエンドポイント (/events/2014 など) を追加すると、固有のパラメーターが必要になるか、URI テンプレートにパスの一部を含める必要があることです。

WebServiceHost は 1 つのもの (クラス) しかホストできませんが、そのオブジェクトは複数のインターフェイスを持ち、異なる URL で複数の異なる種類の要求を処理できます。異なる WebServiceHosts が同じ domain:port にバインドするにはどうすればよいですか? できないので、WebServiceHost は、リクエストを適切なオブジェクトにルーティングする基礎となる静的オブジェクトをラップしていると思います。これは技術的にあなたの質問に答えるものではありませんが、この実装により、あなたが望むことを正しく行うことができると思いますか?

Web サービスをホストするコンソール アプリ。

public class Program
{
    static void Main (string[] args)
    {
        var venueHost = new WebServiceHost (typeof (Venues));
        venueHost.AddServiceEndpoint (typeof (IVenues), new WebHttpBinding (), "http://localhost:12345/venues");
        venueHost.Open ();

        var eventHost = new WebServiceHost (typeof (Events));
        eventHost.AddServiceEndpoint (typeof (IEvents), new WebHttpBinding (), "http://localhost:12345/events");
        eventHost.Open ();

        while (true)
        {
            var k = Console.ReadKey ();
            if (k.KeyChar == 'q' || k.KeyChar == 'Q')
                break;
        }
    }
}

Venues クラスは IVenues を実装し、へのリクエストを処理します。http://localhost:12345/venues/

    [ServiceContract]
    public interface IVenues
    {
        [WebInvoke (Method = "GET", UriTemplate = "?id={id}")]
        string GetVenues (string id);
    }

    public class Venues : IVenues
    {
        public string GetVenues (string id)
        {
            return "This would contain venue data.";
        }
    }

Events クラスは IEvents を実装し、http://localhost:12345/events/

    [ServiceContract]
    public interface IEvents
    {
        [WebInvoke (Method = "GET", UriTemplate = "?venue={venue}")]
        string GetEvents (string venue);
    }

    public class Events : IEvents
    {
        public string GetEvents (string venue)
        {
            return "This would contain event data.";
        }
    }
于 2014-04-11T20:57:02.837 に答える