Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

Exposing a WCF Service With Multiple Bindings and Endpoints

Posted by Keith Elder | Posted in .Net, WCF | Posted on 17-01-2008

Windows Communication Foundation (henceforth abbreviated as WCF) supports multiple bindings that allows developers to expose their services in a variety of ways.  What this means is a developer can create a service once and then expose it to support net.tcp:// or http:// and various versions of http:// (Soap1.1, Soap1.2, WS*, JSON, etc).  This can be useful if a service crosses boundaries between intranet and extranet applications for example.  This article walks through the steps to configure a service to support multiple bindings with Visual Studio 2008 and the .Net 3.5 framework.  For those that want to jump directly to the sample solution it can be found at the end of this article.

Setting Up The Test Solution

Below you will find the steps used to create the sample solution.  I’ll explain a few WCF concepts along the way but probably not all of them.  I will however link to relevant documentation where applicable.  To get started, within Visual Studio 2008 create a new WCF Service Application project.  This template can be found within the web section of Visual Studio 2008 as seen here.

image

After the project is initialized modify it so it contains four files, note this will require deleting the default files:  IMyService.cs, Service.cs, Service.svc, and Web.Config.  Once you have cleaned up the default template, it should look like this:

image

Creating Our Service Contract
The IMyService.cs file will contain our service contract.   In old ASMX services, in order to expose a method as a service one would attribute the method with the attribute of [WebMethod].  In WCF, everything is tied to a Service Contract.   By defining our service contract as an interface, any class that implements that interface can be exposed as a WCF service.  In order to achieve this a ServiceContract attribute will be placed on the interface and an OperationContract attribute will be placed on the method we want to expose for our service.  Our interface is going to be simple and will just contain one method to add two numbers.  Here is the sample.

[ServiceContract(Namespace="http://keithelder.net/Learn/WCF")]

    public interface IMyService

    {

        [OperationContract]

        int AddTwoNumbers(int x, int y);

    }

Implementing The Contract
The Service.cs file will contain the implementation of the IMyService interface.  Again, since we defined our contract as an interface our service class doesn’t need or have any attributes on it.  Here is the code:

    public class Service : IMyService
{
public int AddTwoNumbers(int x, int y)
{
return x + y;
}
}

Creating The Service Host
The file Service.svc will provide the endpoint for our URL that will be exposed by IIS.   Within this file, we only need one line which identifies the class that contains our service using the ServiceHost directive.  Here is the code for this file.

<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.Service" CodeBehind="Service.cs" %>

Now that we have the contract specified and implemented along with an endpoint to host the service everything from here on out is just configuration.  This is the beauty of WCF.   How we want the service to be exposed is stored within the web.config file.  There a lot of options in WCF and those just learning WCF are typically overwhelmed at the amount of options.  Luckily Microsoft has a tool to help us along.  The upside to this approach is we do not have to code how our service is secured as we did in older ASMX services.

Setting Up Basic Http Binding

Before we add multiple bindings to our single service, let’s focus on adding one binding.  In order to configure our service we are going to use the Microsoft Service Configuration Editor.  This editor allows us to configure our WCF service and can be launched right from Visual Studio.  To launch the editor, right click on the web.config file.  An option should be in the menu that says “Edit WCF Configuration”.  If it doesn’t don’t worry, sometimes, Visual Studio doesn’t pickup this option.  A trick is to go to the tools menu in Visual Studio and select the editor from there.  After the editor is launched it will then show up in the menu when you right click the web.config file.

For this example I have removed everything from the web.config file before launching so I can configure the service completely from scratch.  Opening the web.config with the editor shows a blank configuration as follows.

image

Follow the steps to initialize the configuration.

Step 1
Make sure your solution builds.

Step 2
Click “Create a New Service” in the right panel of the editor.

Step 3
Browse to the bin directory and select the WcfService1.dll (if the file doesn’t show up, go back to step 1)

image

Double click this file and select your service implementation.

image

Step 4
The service type should be displayed on the previous screen.  Press Next->.

Step 5
Select the contract.  This should automatically be selected to WcfService1.IMyService.  Press Next->.

Step 6
Since we are using IIS to host our service select the HTTP option for the communication mode.

image 

Step 7
Select the basic web services interoperability.  We’ll come back later on and add advance web services interoperability.

image

Step 8
Delete the “http://” from the address field.  Since we are developing we don’t know which port this will get assigned as of yet.
image

Press Next->.  A dialog will appear.  Select Yes.

image

Press Finish on the next screen.

At this point we have an almost configured service.  If you drill down into the Services folder within the tool down to the end point the configuration should look something like this.

image

Step 9
Let’s clean up our configuration.  In the screen shot above in the configuration section.  Give this endpoint a name of “Basic”.  This will let us know later on this endpoint is our BasicHttpBinding configuration which supports the SOAP1.1 protocol.

Step 10
Click on the “Services” folder in the editor.

image

Step 11
Next to the binding configuration there is a link that says “Click to Create”.  Click this link to create a binding configuration.  While this isn’t necessary in all instances it is a good practice to have a binding configuration.  This gives you more control over how your binding is configured and is a good practice to initialize early on.

Clicking this link will create a new binding.  In the name field under the configuration section, give it a name of “Basic”.  The defaults for this example are fine.

image

Note:  Clicking on the Security tab in the above screen the Mode should be set to None. 

At this point you should be able to save your configuration and press F5 in Visual Studio to launch your service in debug mode.  You should be presented with a web page that looks like the following:

image

Exposing Our Service’s WSDL

Unlike previous ASMX services, the WSDL (web service definition language) for WCF services is not automatically generated.  The previous image even tells us that “Metadata publishing for this service is currently disabled.”.  This is because we haven’t configured our service to expose any meta data about it.  To expose a WSDL for a service we need to configure our service to provide meta information.  Note:  The mexHttpBinding is also used to share meta information about a service.  While the name isn’t very “gump” it stands for Meta Data Exchange.  To get started configuring the service to expose the WSDL follow the following steps.

Step 1
Under the Advanced folder in the editor, select the “Service Behaviors”.

image

Click the “New Service Behavior Configuration” link in the right pane.

Step 2
Name the behavior “ServiceBehavior”.  In the bottom section press the add button and select the “serviceMetaData” option and press Add.

image

The end result should look like the following.

image

Step 3
Under the “Service Behaviors” folder, select the newly created “ServiceBehavior” option and then the “serviceMetadata” option underneath that.  In the right pane change the HttpGetEnabled to True.

image

Step 4
Select the service under the Services folder and apply the new service behavior to the service.

image

Step 5
Save the configuration and reload the service in the browser.  The page should be changed to the following:

image

Clicking on the link should display the WSDL for the service.

At this point our service is configured to support the SOAP1.1 protocol through the BasicHttpBinding and is also exposing the WSDL for the service. What if we want to also expose the service with the SOAP1.2 protocol and support secure and non-secure messages?  No problem.  We can expose the service all of those ways without touching any code only the configuration.

Adding More Bindings and Endpoints To Our Service

Now that we have the basic binding working let’s expose two additional endpoints for our service which support the WS* protocol but are configured differently.  We’ll expose a plain SOAP1.2 protocol message using the wsHttpBinding that is a plain message as well as a secured message using the wsHttpBinding.

Step 1
Under the Services folder select the EndPoints folder for the service and add a new service endpoint.  Give it a name of WsPlain.  This endpoint will serve as a standard SOAP1.2 message that isn’t encrypted.  Change the binding to wsHttpBinding.  In the address field, copy the address from your browser.  In my case, my project used the address of http://localhost:5606/Service.svc.  Paste this into the address field and add /WsPlain to the end of it so it looks like the following:

http://localhost:5606/Service.svc/WsPlain 

Each binding for each endpoint has to have a separate address.  Doing it this way allows us to keep our one service file and offer it up in various configurations.  In the contract option browse to the DLL in the bin directory and select the contract used previously.  The end result should look similar to this:

image

Step 2
Just as we did previously, click on the Services folder and create a binding configuration for this endpoint.  Refer to step 10 and 11 above.

Provide a name of WsPlain for the new binding.  In the security tab change the mode to “None” and set all other options to false or none.  This is setting up our binding so there is no security on our message.  By default the binding is configured to be secure.

image

The final settings for the WsPlain endpoint should be similar to this.

image

Step 3
To configure a secure binding using wsHttpBinding follow these same steps above but leave the default values in the security tab of the binding configuration.  Call this end point and binding WsSecured.  The new endpoint should look like this:

image

That’s it, our service is now configured three different ways and is configured to support SOAP1.1, SOAP1.2 and WS*.  Pretty cool huh?

Testing Our Service

Now that our service is configured with three different bindings, let’s look at the messages as they go back and forth across the wire.  In order to do this we are going to borrow knowledge from a previous article I did called “How to Get Around WCF’s Lack of a Preview Web Page and Viewing WCF Messages“.  From this article we are going to borrow the MessageViewerInspector class and build a small windows application to view our messages.

If you are still following along, add a new project of type Windows Application to the existing solution and then copy the MessageViewerInspector class from the referenced article and add it to the project.

If you have been following along you may have noticed that we only have one WSDL.  The WSDL contains all of our endpoints.  Even though we have three endpoints, we still only have one WSDL.  In testing with some third party clients my experience has been that clients only generate proxies for the endpoints they understand.  Add a service reference to the service to the windows application.

For the user interface I decided to use several split panels and create a three panel layout.  Here is what it looks like.

image

The idea is simple.  When I click on each button I want it to invoke my service and then display the request and response messages the service is using.  To do this I created one service method called CallService which is passed the end point name the service is to invoke.

        private void CallService(string endPoint)
{
MessageViewerInspector inspector = new MessageViewerInspector();

ServiceReference1.MyServiceClient proxy = new WindowsFormsApplication1.ServiceReference1.MyServiceClient(endPoint);

proxy.Endpoint.Behaviors.Add(inspector);
proxy.AddTwoNumbers(12332, 12323);
proxy.Close();

richTextBox1.Text = inspector.RequestMessage;
richTextBox2.Text = inspector.ResponseMessage;
}

The endpoint is the name of the endpoint we specified in our configuration.  For example to invoke the secure wsHttpBinding it is called like this.

CallService("WsSecured");

The first thing created is create the inspector so messages can be viewed coming in and out of the proxy class.  Once the proxy method is called we can then grab the messages and put them into the RichTextBox control on the form.  Here are screen shots of each call to the service.

BasicHttpBinding – SOAP1.1

image

WsHttpBinding – SOAP1.2 Plain / Unsecured

image

WsHttpBinding – SOAP1.2 Secured

image

Conclusion

WCF services are powerful as you have just seen.  It is possible to expose a single service in more ways than just one.  This allows developers to support things like net.tcp binary messages and SOAP messages from the same service.  If you are an enterprise developer supporting multiple clients this is a blessing since it means .Net consumers of your service can use TCP while other consumers use WS*.  The nice thing is the developer doesn’t have to code it, just declaratively express how he wants the service configured. 

Download Sample Solution:

Like this article? kick it on DotNetKicks.com

  • Excellent entry! It’s always nice when you can not only be informed, but also entertained!

  • Pantgovind2

    Good article 

  • Very good steps. thanks for demonstrating.

  • Charitha Ratnayaka

    It’s really nice. Well written. Thanks

  • Hemant1906

    Came across same error.  mexHttpBinding was present in web.config. Ultimately it turn out that namespace was changed in code. Updating web.config with correct namespace in endpoint configuration fixed the issue.

  • lewis

    excellent!! i always mess up my web config…. this helped me clean it out…!!

  • Marker

    The file Service.svc will provide the endpoint for our URL that will be exposed by IIS.   Within this file, we only need one line which identifies the class that contains our service using the ServiceHostdirective.  Here is the code for this file.
    Mary-Louise Parker

  • Venkat

    I’m getting this error while I running my service from IIS. Error message is ” When
    ‘system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled’ is
    set to true in configuration, the endpoints are required to specify a relative
    address. If you are specifying a relative listen URI on the endpoint, then the
    address can be absolute. To fix this problem, specify a relative uri for
    endpoint ‘http://192.168.0.118/Caliculator/ClsArthematic.svc/Basic’ “. What can I do to remove this error?

  • Vmorisetty

    I’m getting this error while I running my service from IIS. Error message is ” When
    ‘system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled’ is
    set to true in configuration, the endpoints are required to specify a relative
    address. If you are specifying a relative listen URI on the endpoint, then the
    address can be absolute. To fix this problem, specify a relative uri for
    endpoint ‘http://192.168.0.118/Caliculator/ClsArthematic.svc/Basic’ “. What can I do to remove this error?

  • Banaja

    Its really a nice article that I was looking for.It gave me a clear Idea in different bindings and their implementations

    Thank U so much for this post.

  • Anonymous

    I’ve never run into this issue myself. Try letting any and every thing through in the client access file and go from there. ——————————

  • Akhil Raj

    Excellent articles and thanks for nice solution. But can you guid me to solve my issue regarding this?

    I created multiple bindings and run successfully. I can access the service in silverlight application using basic endpoint. But i got the error as cross domain policy issue. But if i remove multiple i can run because i have the client access policy and cross domain xmls in the service application.

    But what need to be changed in the client access policy to give permission to subfolder serices?
    eg : http://localhost/MyApp/Service1.svc/Basic

  • Getting all sorrts of errors: The first one was this:

    When ‘system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled’ is set to true in configuration, the endpoints are required to specify a relative address.

    to fix that I changed the uri to relative, after which I got this:

    the communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

    Server stack trace:    at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen()   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

    Exception rethrown at [0]:    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)   at IService.GetData(Int32 value)   at ServiceClient.GetData(Int32 value)

  • This sounds to me like you don’t have SSL enabled for the transport in the basic binding security element. See this for more info on how that is configured.

    msdn.microsoft.com/en-us/library/ms731334.aspx

  • Thanks for the great information. I’m at a point where I have my service running internally using basicHttpBinding. We have a central web service server that serves both internal and external (DMZ) calls. I need my service to use both http: (internal calls) and https: (DMZ calls). I keep coming up with the following error when I call the service with a https:
    “The provided URI scheme ‘https’ is invalid; expected ‘http’.
    Parameter name: context.ListenUriBaseAddress”

    Any help would be greatly appreciated.

  • “It Depends” is the answer. Are you passing data that shouldn’t be viewed during transport? If not, then no, SSL isn’t something you need. If the answer is yes, then SSL is at least the minimum transport security you will want to use. There are other higher levels of security that WCF can provide where the message itself can be encrypted so it cannot be viewed over transport even without SSL. SSL is the easiest to get started with.

    -Keith

  • Anonymous

    Great article! Helped out alot! BTW: If I have an endpoint that has a wsHttpBinding…do I need to use SSL to secure the service? I was reading your comments and MSPress’s Windows Communication Foundation Step by Step and it sounds as though as long as I use this binding type…I should not need to use SSL. Is this right?

  • Anonymous

    Great Article . I have a problem here. I created a WCF service and hosted on ASP.NET application. I wan’t service to be access on internet. I have created following end point and custombinding. I ‘m unable to cess serive through internet, I ‘m able to access on intranet. Can some help?






    /security>

  • Anonymous

    Great Article . I have a problem here. I created a WCF service and hosted on ASO.NET application. I wan’t service to be access on internet. I have created following end point and custombinding. I ‘m unable to cess serive through internet, I ‘m able to access on intranet. Can some help?









  • Anonymous

    Good article…. U have concentrated much on the beginners … of WCF service

  • Anonymous

    Awesome!!!

  • Anonymous

    1. Create a new contract. IMyService2 that has a method “int AddThreeNumbers(int x, int y,int z)”

    2. Add it to your implementation
    public class Service : IMyService,IMyService2

    3. How do you expose that new contract?

    I got as far as copying one of the endpoints and setting the contract to the new one.
    Needless to say the server got an internal error when I did that. Having all the Contracts point to the same interface makes the server work.

    Thanks
    Herb

  • You need IIS7.

  • I get an error if I host this on a production server that has multiple http bindings in IIS 6.0, such as http://www.mydomain.com and domain.com.

    Of course these multiple bindings are necessary on a public server, but how do you get around the error saying multiple http bindings are not allowed?

    Thanks.

  • Anonymous

    Very well written post.

    I have also written a WCF service which had 2 bindings, basicHttp and netTcp. The basicHttp was for an endpoint exposed over the net while the netTcp endpoint was for internal use. One tool I found that was very useful in testing both bindings is WCFStorm, http://www.wcfstorm.com. You might want to have a look at it.

  • Nitin,

    Create a wcf application project, reference your wcf library and simply configure your service config to expose the service with the binding you want. Then publish the application to IIS.

    -Keith

  • Anonymous

    Hi ,
    Article is so gud. I Create one wcf Syndication Service Library using 3.5 framework, I have also one web application now if i add this library with website solution and run the application wcfService automativally host but now i want host it on webserver.Please help me if u have any idea regarding thAT.
    Thanks in advance.

  • @John

    Sure you can expose a WSDL without IIS. If you are self hosting you can still expose the WSDL. If you are self hosting a netTcpBinding then you use the mexTcpBinding:

    msdn.microsoft.com/en-us/library/aa967279.aspx#

    If you are self hosting HTTP then it is the same as you normally do it.

    -Keith

  • Anonymous

    Nice article. Is WSDL only possible when hosted under IIS? I have a WCF service hosted in a windows service and I have exposed a mex endpoint, but the guy writing the client wants to be able to see my WSDL and I can’t figure out how to point him at it since there is no .svc for me to do a /svc?WSDL

    Thanks, John

  • @Jeebu

    The URL of the service could be anything. This request is like saying, “My car is broke, can you tell me what is wrong with it?”

    Sorry, no one is going to be able to help you. One thing you can try is running a program like “netstat” from the command line. This will tell you a lot that is going on network wise on your machine.

    -Keith

  • @san

    Look at the line of code:

    MessageViewerInspector inspector = new MessageViewerInspector();

    The message viewer inspector is what can allow you to view the messages going in and out. Download the example above to see how it works. Good luck.

  • Anonymous

    how to view the SOAP request and reply at the Service host ?
    thanks!

  • @Nagin

    Sure, but I tend to think of these as seperate services. If you built the service correctly it should be easy to re-use what you’ve done but having one service calling another means you have tightly coupled the one service which means any changes to one affect the other. Not good.

  • After reading this post, I have some understanding on WCF (while I am a beginner)

    However,

    My Scenario is

    I already have a WebService hosted in a Secured Environment which canot be accessed directly via Http. Can I create another WCF service to expose the existing WebService to the Internet ?

    Please help.

  • Anonymous

    Hi keith. As always, very good article. I want to know if it’s possible to know (on service code implementation) from which endpoint the request arrived. Is it possible ? I want to give a different treatment to the requests depending on which was the endpoint used.

    Thanks in advance !

  • Anonymous

    Nice article. Helped me getting my first wcf ready.
    svcutil.exe http://localhost/wcfservice/interface.svc /out: proxy.cs

    Here we are talking about one single service contract implementation, let’s say IService1.cs

    I wonder if we keep creating separate .svc for each of such 10-15 contracts/implementations.
    And also create 10-15 such proxy classes.

    And add all of these .cs files in my client application. There should be some better way to architect this.

  • Anonymous

    Hi, I have already a WCF hosted in Windows Service. I try to use AJAs Autocompleted control and this extender needs to use web service. My question is : Is there a way that a can add svc point to the current WCF service?

    Thanks
    HANK

  • @Anthony

    It will if you instruct it to. Look at your binding configuration.

  • Anonymous

    I was just wondering about the SOAP 1.2 Secured example.
    This encrypts the header but not the body message


    http://keithelder.net/Learn/WCF“>
    24655

    doesnt wsHttpBinding encrypt the body part as well?

  • Anonymous

    Thank you very much for your reply. I did download your sample solution; the only difference is mine is in VB.net. Also, vs2005 does not have reference System.linq . Does it have to be in vs2008?

  • I suggest downloading the sample solution and doing a comparison.

  • Anonymous

    I have the same class MessageViewInspector as you do.

  • Anonymous

    P.S. I am doing this in vs2005

  • Anonymous

    I am trying to do the same thing as you did. But I have problem at :
    proxy.Endpoint.Behaviors.Add(inspector) , it errored out “Unable to cast object of type ‘AcftStatusService.MessageViewerInspector’ to type ‘System.ServiceModel.Description.IEndpointBehavior’.”
    What did I miss?

    Thanks a lot in advance.

  • Anonymous

    Nice article, but when I traied to add a TCP endpoint using the same basic steps, I get the error “The provided URI scheme ‘http’ is invalid; expected ‘net.tcp’.
    Parameter name: context.ListenUriBaseAddress”.

    So what am I missing?

  • @RF

    Sorry I haven’t done anything with the PollingDuplex binding.

    @lp
    Yes you can host for internal and external but you don’t want them to be placed on the same server obviously for security reasons. The whole point of WCF is all of the configuration settings are stored in the config file so you would deploy one service into your DMZ exposed via an HTTP binding and then behind the DMZ in corporate you would deploy another service to be used for TCP. This isn’t really a hard WCF question but more of a security question. Bottom line is yes, it is easy. Hope that helps.

  • Anonymous

    Hi,
    The article is great. But I would like to know if we can host the WCF with the TCP and the HTTP bindings, as in a case when I want my WCF service to be accesible both in the intranet (thro TCP) and extranet (HTTP). If thats possible, how can the above example be tweaked for that?

    Thanks,
    LP

  • Anonymous

    Hello,

    I am currently developing a wcf service using the new PollingDuplex for a silverlight client. I would like to combine both the duplex method, but still use the simple request response via BasicHttpBinding. The reason I would like to do this is so I can push data to the client when the data is changed, but the client can easily request the data using the standard “proxy.method()” approach. Do you know if combining the 2 is possible?

  • Anonymous

    Very good explanation…

  • Anonymous

    Explained Beautifully.