locked
Exposing Metadata through WCF Routing Service RRS feed

  • Question

  • Hello.

    I'm working on a project which has a WsHttp WCF 4 routing service that forwards requests to several services exposed to the router through net.tcp endpoints.

    I would like to expose service metadata through the routing service, so I created metadata exchange endpoints on the router that forward requests to the internal metadata exchange endpoints. This way I can call the mex endpoints through the routing address and generate proxies with svcutil.

    The problem is that the configuration files generated by svcutil expose the internal net.tcp endpoint addresses. 

    How can I enable WSDL publishing/proxy generation through a WCF routing service without exposing the final endpoints?

    Monday, January 31, 2011 5:20 PM

Answers

  • Well, currently the only idea in my mind is to provide a custom WSDL file. You should be able to get the WSDL file using the internal address by navigating to http://host/service.svc?wsdl, as well as its related xml schema files. Try to copy the content of those files, and modify the internal address to the routing service's address. Then host the WSDL/XSD files as static contents (similar to js and image files) on your web site.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    • Marked as answer by Yi-Lun Luo Wednesday, February 9, 2011 9:22 AM
    Wednesday, February 2, 2011 5:06 AM

All replies

  • Hello, can you post the configuration file? Actually you're unable to expose a metadata endpoint for a routing service (well, you can, but the generated WSDL file will not contain the actual service's contract information). I guess you're still pointing to the actual service's metadata, and that's why you can generate teh client proxy but the address points to the actual service instead of the routing service.

    I can't think of good workarounds. You may have to manually modify the address and binding in your client configuration file.


    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    Tuesday, February 1, 2011 3:07 AM
  • Yi-Lun, thanks for your reply.

    Well, yes, actually I am simply exposing the internal mex endpoints to the client through the routing service, so when the client application calls the metadata endpoint it is getting the same response as it would get if the internal endpoint was called directly. Can you think of a good way to expose the metadata without revealing the internal endpoints? 

    Thanks in advance. Here is the relevant portion of the broker config file:

    <?xml version="1.0"?>
    <configuration>  
        <system.serviceModel>
          <protocolMapping>
            <remove scheme="http" />
            <add scheme="http" binding="wsHttpBinding" />
          </protocolMapping>
          <client>
            <endpoint name="MyCompany.FirstServiceImplementation" address="net.tcp://localhost:62010/FirstServiceImplementation" binding="netTcpBinding" contract="*" />
            <endpoint name="MyCompany.FirstServiceImplementation.mex" address="net.tcp://localhost:62010/FirstServiceImplementation/mex" binding="mexTcpBinding" contract="*" />
            <endpoint name="MyCompany.SecondServiceImplementation" address="net.tcp://localhost:62010/SecondServiceImplementation" binding="netTcpBinding" contract="*" />
            <endpoint name="MyCompany.SecondServiceImplementation.mex" address="net.tcp://localhost:62010/SecondServiceImplementation/mex" binding="mexTcpBinding" contract="*" />
          </client>
          <services>
            <service name="System.ServiceModel.Routing.RoutingService">
              <host>
                <baseAddresses>
                  <add baseAddress="http://localhost/MyCompany.ServiceBroker/Broker.svc" />
                </baseAddresses>
              </host>
              <endpoint address="" binding="wsHttpBinding"
               name="brokerEndpoint" bindingNamespace="http://mycompany.com/broker"
               contract="System.ServiceModel.Routing.IRequestReplyRouter" behaviorConfiguration="routingServerBehavior" />
              <endpoint address="mex" binding="mexHttpBinding" bindingNamespace="http://mycompany.com/broker" name="servicesMexEndpoint" contract="System.ServiceModel.Routing.IRequestReplyRouter" />
            </service>
          </services>
          <routing>
            <filters>
              <filter name="MyCompany.FirstServiceImplementation" filterType="EndpointAddress" filterData="http://localhost/MyCompany.ServiceBroker/FirstService.svc"/>
              <filter name="MyCompany.FirstServiceImplementation.mex" filterType="EndpointAddress" filterData="http://localhost/MyCompany.ServiceBroker/FirstService.svc/mex"/>
              <filter name="MyCompany.SecondServiceImplementation" filterType="EndpointAddress" filterData="http://localhost/MyCompany.ServiceBroker/SecondService.svc"/>
              <filter name="MyCompany.SecondServiceImplementation.mex" filterType="EndpointAddress" filterData="http://localhost/MyCompany.ServiceBroker/SecondService.svc/mex"/>
            </filters>
            <filterTables>
              <filterTable name="DefaultFilterTable">
                <add filterName="MyCompany.FirstServiceImplementation" endpointName="MyCompany.FirstServiceImplementation" />
                <add filterName="MyCompany.FirstServiceImplementation.mex" endpointName="MyCompany.FirstServiceImplementation.mex" />
                <add filterName="MyCompany.SecondServiceImplementation" endpointName="MyCompany.SecondServiceImplementation" />
                <add filterName="MyCompany.SecondServiceImplementation.mex" endpointName="MyCompany.SecondServiceImplementation.mex" />
              </filterTable>
            </filterTables>
          </routing>      
          <behaviors>
            <serviceBehaviors>
              <behavior>
                <serviceMetadata httpGetEnabled="true"/>
                <routing filterTableName="DefaultFilterTable" />
                <serviceAuthorization serviceAuthorizationManagerType="MyCompany.MyAuthorizationManager, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
                <serviceErrorHandling />
              </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
              <behavior>
                <endpointErrorHandling />
              </behavior>
              <behavior name="routingServerBehavior">
                <incomingRequestsPerSecond />
                <incomingMsgSizePerSecond />
                <requestsExecutingPerSecond />
                <outgoingMsgSizePerSecond />
                <outgoingResponsesPerSecond />
                <messageLogging />
                <brokerServiceContext />
              </behavior>
            </endpointBehaviors>
          </behaviors>
          <extensions>
            <behaviorExtensions>
              <add name="endpointErrorHandling" type="MyCompany.Platform.Wcf.FaultHandling.ErrorHandlingEndpointExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="serviceErrorHandling" type="MyCompany.Platform.Wcf.FaultHandling.ErrorHandlingServiceExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="requestsExecutingPerSecond" type="MyCompany.ServiceModel.Behaviors.PerformanceCounters.RequestsExecutingExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="incomingRequestsPerSecond" type="MyCompany.ServiceModel.Behaviors.PerformanceCounters.IncomingRequestsPerSecondExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="incomingMsgSizePerSecond" type="MyCompany.ServiceModel.Behaviors.PerformanceCounters.IncomingMsgSizePerSecondExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="outgoingResponsesPerSecond" type="MyCompany.ServiceModel.Behaviors.PerformanceCounters.OutgoingResponsesPerSecondExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="outgoingMsgSizePerSecond" type="MyCompany.ServiceModel.Behaviors.PerformanceCounters.OutgoingMsgSizePerSecondExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="messageLogging" type="MyCompany.ServiceModel.Behaviors.MessageLogging.MessageLoggingExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
              <add name="brokerServiceContext" type="MyCompany.ServiceModel.Behaviors.ServiceContext.BrokerServiceContextExtensionElement, MyCompany, Version=4.5.0.0, Culture=neutral, PublicKeyToken=8ffa52167d0c9a3d" />
            </behaviorExtensions>
          </extensions>
          <serviceHostingEnvironment>
            <serviceActivations>
              <add service="System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" relativeAddress="FirstService.svc" />
              <add service="System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" relativeAddress="SecondService.svc" />
              <add service="System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" relativeAddress="Broker.svc" />
            </serviceActivations>
          </serviceHostingEnvironment>
        </system.serviceModel>
      </configuration>
    Tuesday, February 1, 2011 10:19 AM
  • Well, currently the only idea in my mind is to provide a custom WSDL file. You should be able to get the WSDL file using the internal address by navigating to http://host/service.svc?wsdl, as well as its related xml schema files. Try to copy the content of those files, and modify the internal address to the routing service's address. Then host the WSDL/XSD files as static contents (similar to js and image files) on your web site.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    • Marked as answer by Yi-Lun Luo Wednesday, February 9, 2011 9:22 AM
    Wednesday, February 2, 2011 5:06 AM
  • Even though technical side of the question, “how to expose service metadata via WCF Routing Service” sounds quite legitimate and harmless, on a conceptual level it raises three very serious counter-questions:

    1.       Why do you need metadata?

    2.       What kind of metadata you expect to receive from the Routing Service?

    3.       Do you really want to receive your service metadata from the Routing Service but not from other “available sources” (whatever these sources or endpoints are)?

    The first question is easy to answer - we need to enable consumers with the knowledge of the service metadata so that consumers can learn how to call our service (build client apps).

    The second question is a bit trickier. Yes, we want our consumers to learn about service metadata, but which exactly service our consumers need to learn about? Is it a “virtual” service that consumer apps are facing at the Routing Service endpoint, or is it a physical service that messages are routed to by the Routing Service? The answer is “virtual” service, of course. This is because client apps will be connecting to the Routing Service endpoints (so the metadata has to reference Routing Service endpoint addresses but not the physical services’). Also, Routing Service endpoints can be configured with policies different from the physical service policies (again metadata will be very different). And finally it is conceivable that “virtual” service can have even different actual contract (for example virtual service can have operation names different from physical service operations, or even less operations then in the physical service).

    And the third question is the most important. In real-life SOA solutions (and those based on services virtualization in particular, like where Routing Service is dropped in the picture) we want consumers to learn about services from the central Repository that governs all aspects of our SOA solution (including services metadata). If that Repository on top of everything else, can provide us (via HTTP GET or metadata endpoints) with the precise and accurate metadata of ALL services, including virtual services hosted on the Routing Service, then that’s all we need. Even better, Repository automatically constructs virtual services' metadata “on a fly” based on its knowledge of what and how Routing Service virtualizes.

    My final note is a suggestion to look at Nevatech’s Seninet platform (http://www.nevatech.com/overview.aspx) that actually ALL runs on top of WCF 4.0 Routing Service and does everything I discussed here plus much, much more.

    Friday, February 3, 2012 4:55 AM