WCF Webservice behind public reverse proxy - wcf

How can I correctly serve WSDL of a WCF webservice located in a private LAN from behind a reverse proxy listening on public IP?
I have an Apache webserver configured in reverse proxy mode which listens for requests on a public IP address and serves them from the internal IIS host. WCF webservice generates WSDL using the FQDN address of the LAN host which, of course, cannot be read by an internet web service client.
Is there any setting that can be configured in wcf application's web.config or in IIS in order to customize the WSDL generated containing host address and put public address instead?

Add the following attribute to your service class:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
This allows the service to be addressed by the client as https://... but the service can still be hosted on http://.....
See my answer on How to specify AddressFilterMode.Any declaratively for how to create an extension to allow AddressFilterMode.Any to be specified through configuration without requiring code attributes.
In the web.config of the service host, the endpoint element must have an absolute URL in the address attribute that is the public URL that will be used by the client. In the same endpoint element, set the listenUri attribute to the absolute URL on which the service host is listening.
The way I determine what the default absolute URI the host is listening on is to add a service reference in a client application which points the the physical server where the service is hosted. The web.config of the client will have an address for the service. I then copy that into the listenUri attribute in the hosts web.config.
In your service behavior configuration, add the element serviceMetaData with attribute httpGetEnabled=true
So you'll have something like this:
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<!-- ... -->
<services>
<service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
<endpoint listenUri="http://www.servicehost.com"
address="https://www.sslloadbalancer.com"
binding="someBinding"
contract="IMyServiceInterface" ... />
</service>
</services>
I am not sure if this works with message security or transport security. For this particular application, the credentials were passed as part of the DataContract so we had basicHttpBinding > security > mode=none. Since the transport is secure (to the ssl load balancer) there were no security issues.
It is also possible in to leave the listenUri attribute blank, however it must be present.
Unfortunately, there is a bug in WCF where the the base address of imported schemas in the WSDL have the listenUri base address rather than the public base address (the one configured using the address attribute of the endpoint). To work around that issue, you need to create an IWsdlExportExtension implementation which brings the imported schemas into the WSDL document directly and removes the imports.
An example of this is provided in this article on Inline XSD in WSDL with WCF. Additionally you can have the example class inherit from BehaviorExtensionElement and complete the two new methods with:
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(InlineXsdInWsdlBehavior)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New InlineXsdInWsdlBehavior()
End Function
This will allow you to add an extension behavior in the .config file and add the behavior using configuration rather than having to create a service factory.
Under the system.servicemodel configuration element add:
<behaviors>
<endpointBehaviors>
<behavior name="SSLLoadBalancerBehavior">
<flattenXsdImports/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!--The full assembly name must be specified in the type attribute as of WCF 3.5sp1-->
<add name="flattenXsdImports" type="Org.ServiceModel.Description.FlattenXsdImportsEndpointBehavior, Org.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
And then reference the new endpoint behavior in your endpoint configuration using the behaviorConfiguration attribute
<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">

I'm having similar issues, one of which was the resolution of public and server addresses. This solved that issue although I still have a couple authentication problems.
See: How to change HostName in WSDL for an IIS-hosted service? by Wenlong Dong
archive

See: Service Station WCF Addressing In Depth by Aaron Skonnard
archive link

Related

Few basic query regarding entries in config file for WCF service end as a wcf starter

i am very new in WCF world. i just download a code and saw the wcf service config file but confusion is occuring in my mind regarding entries in config file for WCF service due to my lack of knowledge.i go through some online article but still i have confusion.
here are my question
1) <service name="WCFService.Service"
when service name is required? can i omit the service name and if yes then what kind of problem may occur?
2) can i set any name to service name like abc.xyz or is there is some rule for assigning service name?
3) what is the use of base address? if one omit the base address then what can be problem.
when base address is required.according to below config entries there are two base addresses...why two base address is required. when people give more base addresses? just see the below 2 base address and tell me why people give two base address why not one...is there any specific reason?
4) there are two endpoints one is tcp and another is mex.
if i omit mex base address then service will not be discoverable? if yes that means no one can create proxy from VS IDE or svcutil....am i right.
5) if mex endpoint will be remove then how one can interact with the service....there must be some other way out. if so then tell me how one can interact with service as a client end.
6)
just see the above mex endpoint and tell me can we write mex endpoint url anything like
**net.tcp://localhost:1645/MyServer/mex** instead of ChatServer ??
actually wcf service hosted in win form project whose name is ChatServer. is this the reason that url becomes net.tcp://localhost:1645/ChatServer/mex?
i have seen many time people write mex end point like and here no url assign to address tag of mex endpoint....why?
when i should write the mex endpoint like above...please explain with example.
7) what is the meaning of /mex....net.tcp://localhost:1645/ChatServer/mex
/mex is mandatory and mex is fixed word?
8) now see tcp endpoint
tcp endpoint address has no url rather tcp the word has been assign to address property...why?
can't we assign any valid url to address filed of tcp endpoint??
9) the address field of tcp endpoint will always have the fixed word called "tcp" is it rule or convention.
10) if i need to add another endpoint called wsdualhttp binding then what i need to write in config file
11) suppose some one developing service which will be hosted in IIS but client can be another asp.net web apps and win apps then what he/she need to do?
then what url client should use to create proxy from VS ide? can anyone come with sample config entries.
12) how to write config file if i want that people can create proxy of my service using two url like....one is as sample net.tcp://localhost:1645/ChatServer/mex and another one
is http://localhost:1645/ChatServer/message.svc
i know my question are very basic but still i am not being able to sort these question.
also guide me how could i have strong knowledge for creating config file entries boldly.
is there any tool which will create right config entries for my service....i am is there any automated apps which will do it on behalf developer. thanks
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WCFService.Service" behaviorConfiguration="behaviorConfig">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:1645/ChatServer/"/>
<add baseAddress="http://localhost:1648/ChatServer/"/>
</baseAddresses>
</host>
<endpoint address="tcp"
binding="netTcpBinding"
bindingConfiguration="tcpBinding"
contract="ChatService.IChat"/>
<endpoint address="net.tcp://localhost:1645/ChatServer/mex"
binding="mexTcpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="behaviorConfig">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="tcpBinding"
maxBufferSize="67108864"
maxReceivedMessageSize="67108864"
maxBufferPoolSize="67108864"
transferMode="Buffered"
closeTimeout="00:00:10"
openTimeout="00:00:10"
receiveTimeout="00:20:00"
sendTimeout="00:01:00"
maxConnections="100">
<security mode="None">
</security>
<readerQuotas maxArrayLength="67108864"
maxBytesPerRead="67108864"
maxStringContentLength="67108864"/>
<reliableSession enabled="true" inactivityTimeout="00:20:00"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
MY Edited part start here
3) what common part you are talking about. what common part u have seen in my complete config file...please explain with example.
you said....If you omit base address, you need to specify common part multiple times every time. Multiple base address are required if endpoints are specified for multiple transport protocol
can u please make me understand with example what u have said for omit base address becoz the things not clear to me after reading ur answer for points 3
4) if i disable mex endpoints then how can i create wsdl with svcutil? if i give my service dll then client can decode the code and get my full source code.can u tell me more elaborately what u trying to say for the points 4
12) if i expose two url for consuming my service then asp.net client can create service proxy using tcp url like net.tcp://localhost:1645/ChatServer/mex ??
is there will be any problem for web client for using tcp binding. because tcp is state full but web is stateless...that is why i am asking is there will be any problem for web client for using tcp binding url net.tcp://localhost:1645/ChatServer/mex
13) in my example the mex endpoint look like
but many people create mex end point like
so tell me what is the difference between two mex end point....also tell me when one should go for 1ts mex endpoint and when people go for second mex endpoint
14) in my case if i would write mex end like
and tcp endpoint like
then what would be the result. my service would be discoverable or not.
what address i shoudl use to create service proxy in that case.
if possible please answer my question with mini sample for easy understanding because i am very new in WCF....thanks
Your answers one by one
Service name is always required. If you omit it in the configuration file, runtime error will occur related to malformed configuration file (with error indicating invalid service name). If you omit it from the code, it will form compile time error.
No. Service name should be corresponding to the type that is implementing the service (along with namespace). Check this answer for detail.
If multiple end points are defined (like service endpoint, and mex endpoint) with some common part, then common part can be specified in base address tag. Only differential part is then required in endpoint address attribute (usually "" for service endpoint and "mex" for mex endpoint) If you omit base address, you need to specify common part multiple times every time. Multiple base address are required if endpoints are specified for multiple transport protocol (ie different base address for http and net.tcp).
Example is here with and without baseaddress.
Common part is "net.tcp://localhost:1645/ChatServer"
If you omit mex endpoint, you need to provide the contract information offline to client. As you have mentioned service will not be discoverable. Thus you need to supply the service/data contract information (as WSDL/ library/ source file ) somehow to client application.
To create client, all you need is contracts and configuration. If mex is available, this information is gathered from mex endpoint. If mex is not available, this information must be made available offline. Example (sending contracts library and configuration by email).
Way out is to provide contract information offline (as mentioned in step 4)
Yes, but not recommended to avoid ambiguity.
No, "mex" is not fixed. It can be anything (as long as URL is valid). "mex" is just unsaid protocol/standard.
Endpoint address = baseAddress + address attribute.
In this case address (of tcp endpoint) = "net.tcp://localhost:1645/ChatServer/" + "tcp"
It is no convention. It could be anyting (as long as URL is valid).
Refer to the link for wsdualhttpbinding configuration. However not that since transport protocol is http, you need to provide full address. baseAddress will not be picked up. This is due to protocol mapping.
Client app (be it ASP.NET/console/win app/WPF/ any other) need to add WCF client configuration and proxy.
If is upto client to decide, which URL they want to use (provided they have access and they are aware). If you want to do it on server side, you may use Routing service feature (available in WCF 4.0 onwards).
I am not sure how web client uses tcp clients (Does security policy allows this?). What ever is the case, exposing two endpoints from server side has no issues on how client will access the endpoints.
13/14 code snippet not visible due to formatting issue.

IIS Hosted WCF Service schemaLocation Address Issue

I have a service hosted in IIS 7 on a separate web server in my local network. I have the service accessible on the Internet. One thing is bothering me and I can't solve it.
When I check the wsdl of the service, I see that the schemaLocation address is set to the machine name of the server and not the domain name the service is assigned to. I tried changing the baseAddress to the domain name but it doesn't change a thing. But when I change the baseAddress to the IP address of the server schemaLocation changes.
What do I need to configure so that the schemaLocation on the wsdl would use the domain name set for the service?
In your serviceMetadata tag, there is an attribute you can set called httpGetUrl, like this:
<behavior name="serviceBehavior">
<serviceMetaData httpGetEnabled="true" httpGetUrl="your-complete-url-here"/>
</behavior>
That will set it for you.
http://knowledgebaseworld.blogspot.co.uk/2010/06/domain-name-replaced-with-machine-name.html
Edit: There's also a httpsGetUrl to use if your service is secured (you didnt say)

Getting machine name in the svcutil when hosting WCF service

I have a domain/website(HTTR.abc.com) hosted in inetmgr in IIS in production servers.
I want to host a WCF service under the domain HTTR.abc.com
The web.config of my WCF service is as follows
<services>
<service behaviorConfiguration="HTTR.Business.HTTRContextServiceBehavior" name="HTTR.Business.HTTRContextService">
<endpoint address="http://machinename:83/GTYEBus/abcService.svc" binding="wsHttpBinding" contract="HTTR.Business.IHTTRContextService">
</endpoint>
</service>
</services>
When i run the URL
"http://HTTR.abc.com/GTYEBus/abcService.svc" the page shows properly but it is showing
WSDL file pointing to "http://machinename:83/GTYEBus/abcService.svc?WSDL"
I would want the page to show the WSDL with the same path as the .svc path, that is it should show as "http://HTTR.abc.com/GTYEBus/abcService.svc?WSDL" instead of
"http://machinename:83/GTYEBus/abcService.svc?WSDL"
I came across this one while tring to find a resolution to the same issue.
This ended up being a issue with the site not having a host name.
In IIS7.5, simply add in the host name into the host header on the binding. If it is https, the host header may be protected. You'll need to make the certificate become a pseudo wildcard cert by putting a * as the start of the certificates friendly name. Then the host name will be editable.
This link has a good description of the resolution in IIS6
In the serviceMetadata section of the web.config you can include the attribute externalMetadataLocation and refer it to the "http://httr.abc.com/GTYEBus/abcService.svc?wsdl" location. Example:
<serviceMetadata externalMetadataLocation="http://httr.abc.com/GTYEBus/abcService.svc?wsdl" />
Here is the MSDN reference on the serviceMetaData config section: http://msdn.microsoft.com/en-us/library/ms731317.aspx.
This does not require any additional IIS configuration and is much more scalable.
Hope this helps.

How to configure WCF service from code when hosted in IIS?

My WCF service exposes an https AND an http endpoint. Apart from the SSL they are identical. They map to the same code.
The ultimate intention is for external users to connect via https, internal users to use http.
In development this gives me a problem. Cassini, the development web server packaged in VS, hates SSL.
I'm wondering if I can configure the service from code, so when running under Cassini, I would not configure https.
Hence the question - How do I configure the service from code if it is IIS hosted? I'd be very happy with alternative answers on how I can persuade Cassini to NOT complain about the https part of the configuration.
"IIS will take care of spinning up the necessary ServiceHost based on your *.svc file - not a whole lot you can do about that, really."
Not too close to the truth. Exactly in the SVC file of your service there is attribute named Factory. Where you can specify the the class and the assebly where the class is located. This class may be your own descendant of Web|DataServiceHostFactory
So your svc markup would look like this
<%# ServiceHost
Language="C#"
Debug="true"
Service="name.space.myService"
CodeBehind="name.space.myService.svc.sc"
Factory = "name.space.WebServiceHostFactoryEx, assembly.name"
%>
The WebServiceHostFactory will be created for every service hit and will recreate your host the way you want it.
You will also need to inherith WebServiceHost and create it the way you need it with certain endpoins, behaviors, addresses, etc settings - whatever you like.
There is very nice post from Michele Bustamante here
EDIT: I figured out the above link is not working anymore, so here it is another one.
I am using this in IIS hosted enviroment for couple of services that are initialized same way.
When you're hosting in IIS, you're leaving a lot of care taking into the realm of IIS - you cannot really grab a hold of your service in this case.
IIS will take care of spinning up the necessary ServiceHost based on your *.svc file - not a whole lot you can do about that, really.
My solution would be different - externalize the <service> tag in your configuration file (web.config):
<system.serviceModel>
<services>
<service configSource="service.dev.config" />
</services>
</system.serviceModel>
In your dev environment, only expose the http endpoint - so your service.dev.config would look something like this:
<service name=".....">
<endpoint name="default"
address="....."
binding="basicHttpBinding" bindingConfiguration="insecure"
contract="......" />
</service>
Create a second service.prod.config which then contains both endpoints - http and https:
<service name=".....">
<endpoint name="default"
address="....."
binding="basicHttpBinding" bindingConfiguration="insecure"
contract="......" />
<endpoint name="secure"
address="....."
binding="basicHttpBinding" bindingConfiguration="secure"
contract="......" />
</service>
and reference that in your web.config on the deployment server.

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.
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.