1

I am planning to publish my Web Service so it can be used on outside network. The issue comes about is that the Web Admins do not want to make this web service external but want me to wrap a proxy around it and make the proxy external. I am not liking the proxy part due to than having to maintain versioning on both the Service and the Proxy. I was wondering if there is a simple way to do this, if you accessing the webservice using outside network (URL) to use SSL and request authentication but if you are using it in internal network (URL) to not request authentication or SSL. I tried having two endpoint configuration in webconfig one secure and one not secure but the problem is when you consume the webservice both bindings show and the client can choose one or the either. If anyone has done this differently or reccomends a different way let me know, usually I do one approach either all secure or all non secure but not different depending on network. Thanks much :)

Nick Manojlovic
  • 1,171
  • 10
  • 30
  • 49

1 Answers1

1

You'll be please to know that WCF has built-in support for your 'Proxy'. It is called the Routing Service and is available in WCF 4.0 and later.

You can configure it to route the internet calls for a certain service contract to the WCF service running in your intranet. It can even translate bindings so that your internal service using TCP bindings can be called by external customers using a HTTP binding that can pass through your firewall.

It only needs to know what contracts to route to where. So no need to update it when your contracts change...

See here for more info.

EDITED: The following example system.serviceModel node allows a client to add a service reference to the routed service. The trick is to let the routing service impose itself as the service(s) it is routing to. See the serviceActivations node for that. Note that this removes the need to have a .svc file.

Next we define two endpoint filters to redirect the requests for the service to the routed service and the requests for the mex endpoint (which exposes the metadata) to the mex endpoint of the routed service. See the filters node for that.

Last, we explicitly disable exposing the metadata of the routing service itself via http to force clients to use mex (which we are routing) for the discovery. See the serviceBehaviors node for that.

EDITED AGAIN: added solution for mex size limit

<system.serviceModel>
  <serviceHostingEnvironment>
    <serviceActivations>
      <!--Lets the routing service impose himself as Service.svc  (No .SVC file is needed!!!) -->
      <add service="System.ServiceModel.Routing.RoutingService" relativeAddress="Service.svc" />
    </serviceActivations>
  </serviceHostingEnvironment>
  <bindings>
    <wsHttpBinding>
      <!-- a mexHttpBinding is in fact a wsHttpBinding with security turned off -->
      <binding name="mexBinding" maxReceivedMessageSize="5000000">
        <security mode="None"/>
      </binding>
    </wsHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior >
        <!-- Use the filter table with the name 'Filters' defined below -->
        <routing routeOnHeadersOnly="false" filterTableName="Filters"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>
        <!-- Disable exposing metadata for this routing service to force discovery using mex -->
        <serviceMetadata httpGetEnabled="false"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <routing>
    <filters>
      <!-- Declare a routing filter that filters on endpoint Service.svc -->
      <filter name="WcfServiceFilter" filterType="EndpointAddress" filterData="http://localhost/ServiceRouter/Service.svc" />
      <!-- Declare a routing filter that filters on mex endpoint of Service.svc -->
      <filter name="WcfServiceFilter.mex" filterType="EndpointAddress" filterData="http://localhost/ServiceRouter/Service.svc/mex"/>
    </filters>
    <filterTables>
      <!-- Declare the routing table to use -->
      <filterTable name="Filters">
        <!-- requests that match the WcfServiceFilter (declared above) should be routed to the client endpoint WcfService -->
        <add filterName="WcfServiceFilter" endpointName="WcfService"/>
        <!-- requests that match the WcfServiceFilter.mex (declared above) should be routed to the client endpoint WcfService.mex -->
        <add filterName="WcfServiceFilter.mex" endpointName="WcfService.mex"/>
      </filterTable>
    </filterTables>
  </routing>
  <services>
    <!-- Declare our service instance and the endpoints it listens on -->
    <service name="System.ServiceModel.Routing.RoutingService">
      <!-- Declare the endpoints we listen on -->
      <endpoint name="WcfService" contract="System.ServiceModel.Routing.IRequestReplyRouter" binding="wsHttpBinding" />
      <endpoint name="WcfServiceFilter.mex" address="mex" contract="System.ServiceModel.Routing.IRequestReplyRouter" binding="mexHttpBinding" />
    </service>
  </services>
  <client>
    <!-- Define the client endpoint(s) to route messages to -->
    <endpoint name="WcfService" address="http://localhost/WcfService/Service.svc" binding="wsHttpBinding" contract="*" />
    <endpoint name="WcfService.mex" address="http://localhost/WcfService/Service.svc/mex" binding="wsHttpBinding" bindingConfiguration="mexBinding" contract="*" />
  </client>
</system.serviceModel>
Marc Selis
  • 833
  • 12
  • 17
  • I have read about Routing Service and tried some examples but it looks like it makes it complicated for the client to consume the service since you really cannot reference the service but a dummy proxy that is not clear of methods unless you specify the wsdl separately... Am I understanding that correctly? – Nick Manojlovic Jan 27 '14 at 21:13
  • The routing service is a transparant proxy, so your client doesn't need to know it is there. For more information on how to configure the routing service to expose metadata of services behind it, see the answers in [this thread](http://stackoverflow.com/questions/17476156/wcf-how-to-combine-several-services-into-single-wsdl/19890944#19890944) – Marc Selis Jan 28 '14 at 12:14
  • Awesome... I appreciate your help since this is the first time I am creating a Routing Service... I created a sample service and was able to get the Service metadata through 'Proxy'. Now when I try to link the 'Proxy' to our actual service it gives me an error. While stepping through the code I found out that it is having problems with some DataContracts which does not make any sense since there is nothing out of ordinary with them. If I delete the DataContract it works if I bring it back in it fails... How you experienced this before? Any ideas? – Nick Manojlovic Jan 29 '14 at 14:15
  • This is the error: There was an error downloading 'http://localhost/SericeRouter/RouterService.svc/MyService/_vti_bin/ListData.svc/$metadata'. The request failed with HTTP status 400: Bad Request. Metadata contains a reference that cannot be resolved: 'http://localhost/SericeRouter/RouterService.svc/MyService'. Metadata contains a reference that cannot be resolved: 'http://localhost/SericeRouter/RouterService.svc/MyService'. If the service is defined in the current solution, try building the solution and adding the service reference again. – Nick Manojlovic Jan 29 '14 at 14:17
  • By digging some more seems like there is a possibility of size limitation on WSDL that the Routing Service can produce? – Nick Manojlovic Jan 29 '14 at 17:32
  • I edited my answer to include a working sample config. – Marc Selis Jan 29 '14 at 19:58
  • I did exactly what you have there and I keep on getting an error that "The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element." – Nick Manojlovic Jan 30 '14 at 19:11
  • Is that error coming from your service, or from the routing service? If it is the second, you'll need to add a default wsHttpBinding and configure the maxReceivedMessage size. Select a value that is big enough to receive all possible response from the routed service, but is small enough not to blow up your memory resources. ' ' – Marc Selis Jan 30 '14 at 19:22
  • I updated my response to include a sample. Be warned: there are many examples available where that setting is set to its max value (2147483647) but that is a bad idea for a public service. If someone sends you a response of that size, you risk bringing your service down with a OutOfMemoryException, because it will effectively try to alloc that much of memory to buffer the response. – Marc Selis Jan 30 '14 at 19:27
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46459/discussion-between-nick-manojlovic-and-marc-selis) – Nick Manojlovic Jan 30 '14 at 20:25
  • 1
    Just for reference for future readers: after a long chat we cracked the mex size limit problem. I altered my sample config above to include the solution. – Marc Selis Jan 30 '14 at 22:35
  • Hey Marc, Are you familiar with Routing Service security - SSL or Transport Security? – Nick Manojlovic Jan 31 '14 at 16:27