Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF IIS hosted service multiple Service Contracts implemented by a single service - how do I share uri between endpoints via config

I have a set of Service Contracts which split up my service interface into chunks of related functionality. I am currently implementing all contracts using a single service class (may want to split these later but for now the single service class suffices).

I am trying to use configure the endpoints using a config file (as opposed to via code). The problem is I get a ServiceActivationException because the two endpoints (one for each service contract) are trying to listen on the same uri. The exception details say that to achieve this the two endpoints must share the binding object, which makes sense but I can't figure out how to do this via config (I haven't tried doing this via code as I am hosting in IIS but I can imagine it being a simple exercise to configure in code).

The following is the config I am currently using (this is still dev so I'm not currently worried about security concerns etc. that some of these settings may expose):

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
  <service name="CDC.WebPortal.MidTier.MidTierAccessService"
           behaviorConfiguration="MidTierServiceBehaviour" >
    <endpoint address=""
              binding="webHttpBinding"
              bindingConfiguration="RestBindingConfiguration"
              contract="****************************.IProductService" />

    <endpoint address=""
              binding="webHttpBinding"
              bindingConfiguration="RestBindingConfiguration"
              contract="****************************.ICategoryService" />

    <endpoint address="mex" binding="mexHttpBinding"
              contract="IMetadataExchange" />

  </service>
</services>

<bindings>
  <webHttpBinding>
    <binding name="RestBindingConfiguration"
             maxReceivedMessageSize="104857600">
      <readerQuotas maxStringContentLength="104857600"/>
    </binding>
  </webHttpBinding>
</bindings>

<behaviors>
  <serviceBehaviors>
    <behavior name="MidTierServiceBehaviour">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>
</behaviors>

So my question is how do I share this binding between the two endpoints?

Comments in this SO question suggest I may not be able to do this, but I don't beleive that is correct.

UPDATE 1 According to this MS publication what I'm doing should be ok...

UPDATE2 Here is the svc file content if it helps:

<%@ ServiceHost Language="VB" Debug="true"
                Service="*********************.MidTierAccessService"
                Factory="Microsoft.ServiceModel.Web.WebServiceHost2Factory" %>

UPDATE 3 Here is the exception detail:

A binding instance has already been associated to listen URI '********************'. If two endpoints want to share the same ListenUri, they must also share the same binding object instance. The two conflicting endpoints were either specified in AddServiceEndpoint() calls, in a config file, or a combination of AddServiceEndpoint() and config.

UPDATE 4 Ok I missed this before, stating "You will need to use relative addresses when exposing more than one endpoint for a particular .svc service". The cause of this is something to do with the IIS virtual directory determining the base address of the service, can anyone explain this in a little more detail, i.e. why IIS needs relative addressing for each contract.

like image 457
Simon Fox Avatar asked Sep 25 '09 02:09

Simon Fox


People also ask

Can WCF service have multiple endpoints?

As demonstrated in the Multiple Endpoints sample, a service can host multiple endpoints, each with different addresses and possibly also different bindings. This sample shows that it is possible to host multiple endpoints at the same address.

How many endpoints can a WCF Service have?

The service configuration has been modified to define two endpoints that support the ICalculator contract, but each at a different address using a different binding.

Which part of the endpoint outlines what functionality the endpoint exposes to the client?

Contracts: The contract outlines what functionality the endpoint exposes to the client. A contract specifies: What operations can be called by a client.

What is meant by an endpoint in WCF services with its components?

WCF formalizes this relationship in the form of an endpoint. The endpoint is the fusion of the address, contract, and binding (see Figure 1-8). Every endpoint must have all three elements, and the host exposes the endpoint. Logically, the endpoint is the service's interface and is analogous to a CLR or COM interface.


1 Answers

To my knowledge, and I have been doing extensive work with WCF in the last month, you can not share the same exact URI for more than one endpoint. In WCF, a "service" is not defined by the implementation of a contract, but by the contract itself (which also follows WSDL and standard SOA practices.) Endpoints allow you to expose a single service via multiple protocols (and therefor different addresses), but you can not share different services on the same exact address. Logically that wouldn't work.

Assume the following scenario (which is what you are trying to accomplish):

IProductService exposed @ http://localhost/service
ICategoryService exposed @ http://localhost/service
IMetadataExchange exposed @ http://localhost/service/mex

It is easy enough to access the MEX endpoint...it has a unique URI. However, how do you access either of IProductService or ICategoryService? There is nothing that allows you to differentiate the two other than a URI. WCF has nothing that will allow it to route between messages that are supposed to go to IProductservice, and those that are supposed to go to ICategoryService. Since both use the same URI, you do indeed have a conflict. Every service CONTRACT must be exposed via a unique URI. Every endpoint that utilizes the same exact binding must use a distinct address.

There is a way to achieve what you need. The problem is message routing. WCF does not natively support message routing OOB, however it does provide the ability to implement your own message router. (Or, if you are willing to use beta tech, .NET 4.0 comes with a message router out of the box, based on the articles linked below, but with improved configurability.) Michele Bustamante, a veritable sorceress of WCF, has provided a complete implementation and article describing message routing at the following links:

http://msdn.microsoft.com/en-us/magazine/cc500646.aspx http://msdn.microsoft.com/en-us/magazine/cc546553.aspx

The general idea is that you set up a single service that listens on a single URI. This service uses wildcard dispatch to a single service operation, which then determines which unique URI to route each message to. You can make the determination any way you wish, however the simplest is via the request Action, assuming each action on your two interfaces, IProductService and ICategoryService, are globally unique. You will end up with more services, however...the router itself is a distinct WCF service that would need to be hosted just like any other.

like image 152
jrista Avatar answered Oct 19 '22 17:10

jrista