Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

How to Use a WCF Service without Adding a Service Reference or Proxy

4.78/5 (16 votes)
28 Jun 2012CPOL5 min read 221.2K   3.2K  
Shows how you can loosely couple your WCF service.

Introduction

In one of my recent interviews, I was asked about how to use a WCF Service without Adding a Service Reference or Proxy in an ASP.NET project. At that time I only knew to do it by adding a service reference from Visual Studio or using svcutil.exe to generate a proxy class. I did not have an answer at that time (of course I passed the interview). But after sometime I figured out the solution, this solution might benefit others.

Background

Say for example you are working on a website project and you are using a WCF service to get data or for other reasons and your client’s requirements change so rapidly; to accommodate a new requirement, you might need to add a new function in your WCF service but you can’t afford to add a new service reference or regenerate the proxy class or stop your application and restart again. But what if I tell you without going through all of this, you can still modify a WCF Service to add a new function and you don’t need to interrupt your running application.

Using the code

Let us understand this solution in detail. There are two ways you can create an ASP.NET user interface project in Visual Studio. You create an ASP.NET Web Application or ASP.NET Website. There are plenty of articles out on the internet about ASP.NET Web Application vs. ASP.NET Website, so I am not go in to much details, but just know that websites are dynamically compiled and the source is distributed with them and Web Applications can be compiled into a single DLL and deployed. So there are pros and cons when using an ASP.NET Web Application or ASP.NET Web Site. The solution I am recommending here is only going to work with an ASP.NET Website and while you will come to know why it only works with an ASP.NET Website. So let us get started…

  1. We are going to create three different projects: ISampleService, WCFSampleService and SampleServiceHost.
    1. ISampleService: we will keep all Interfaces separate in this project.
    2. WCFSampleService: we will define all functions that our service will expose.
    3. SampleServiceHost: this will host our WCFSampleService.
  2. Create a blank solution SampleServiceSolution and add a WCF Service Library project ISampleService to it. Once the project is created, delete the Service1.cs and App.config files from it, because we just want interfaces in this project.
  3. Image 1

    Following is the code for IService1. We will define a Service Contract. For the purposes of this article, I am going to have just a simple Service Contract GetMessage and later we will add more Service contracts to IService1.

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    namespace SampleService
    {
        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            string GetMessage();  
        }
    }
  4. Add a second WCF Service Library project WCFSampleService to the solution SampleServiceSolution. Once the project is created, delete the IService1.cs and App.config files from it. Add a Reference ISampleService to it.
  5. [Note: both projects use the namespace SampleService.]

    Image 2

    Following is the code for Service1. Now we will implement the Service Contract that we defined in IService1.

    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    namespace SampleService
    {
        public class Service1 : IService1
        {
            public string GetMessage()
            {
                return "Hello World";
            }
        }
    }
  6. Since our WCFSampleService is ready, now we are going to create a host application to host this service. For this article's purpose we are going to host our service on IIS and for that we are going to create a new Website project SampleServiceHost and add to it to SampleServiceSolution. It gets a little tricky here, I am going to show you step by step.
  7. In Visual Studio, right click on SampleServiceSolution, click Add, click New Web Site.

    Image 3

    Select project template WCF Service, click OK.

    Image 4

    This will create a WCF Service Website SampleServiceHost in the SampleServiceSolution solution. We already have created our WCFSampleService in a separate project. We will refer to it in Service.svc. We will delete the IService.cs and Service.cs files from the App_Code folder. Right click SampleServiceHost, Add Reference WCFSampleService to it.

    Image 5

    Open the Service.svc file from SampleServiceHost and modify it so it looks like this:

    ASP.NET
    <%@ ServiceHost Language="C#" Debug="true" Service="SampleService.Service1""%>

    Now check to see how we did it so far, let us set SampleServiceHost as the startup project and the Service.svc file to set as the Startup Page and then run SampleServiceHost.

    If everything is OK, your screen should look like:

    Image 6

    Now let us modify our Web.Config of SampleServiceHost as follows. You can modify your System.ServiceModel section according to your project needs.

    Such as your binding, your endpoint address, etc.

    XML
    //
    // Web.Config of SampleServiceHost 
    //
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <system.web>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>
      <system.serviceModel>
        <bindings>
          <basicHttpBinding>
            <binding name="BasicHttpBinding_IService1" closeTimeout="00:01:00" 
                  openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
                  allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
                  maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
                  messageEncoding="Text" textEncoding="utf-8" 
                  transferMode="Buffered" useDefaultWebProxy="true">
              <readerQuotas maxDepth="32" maxStringContentLength="8192" 
                 maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <security mode="None">
                <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
                <message clientCredentialType="UserName" algorithmSuite="Default" />
              </security>
            </binding>
          </basicHttpBinding>
        </bindings>
        <services>
          <service behaviorConfiguration="mexBehavior" name="EnterpriseService.Service1">
            <endpoint address="http://localhost/SampleService/Service.svc" 
               binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" 
               contract="EnterpriseService.IService1" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
            <behavior name="mexBehavior">
              <serviceMetadata httpGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <defaultDocument>
          <files>
            <add value="Service.svc" />
          </files>
        </defaultDocument>
      </system.webServer>
    </configuration>

Now it is time to deploy our SampleServiceHost website on IIS, so it will be available to the outside world. I deployed mine on http://localhost/SampleService/Service.svc on IIS.

Once you deploy SampleServiceHost, it is time to test our WCFSampleService. We are going create a separate Web site project TestClientForSampleService. Add Reference ISampleService to it.

Image 7

Next we are going to modify the Web.Config of the TestClientForSampleService Website as follows:

XML
//
// modify Web.Config of TestClientForSampleService
// add servicemodel section
//
<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService1" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost/SampleService/Service.svc"
          binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
          contract="SampleService.IService1" name="BasicHttpBinding_IService1" />
    </client>
</system.serviceModel>

Next we are going create a ServiceClient class under the App_Code folder as follows:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel;
using System.Configuration;

public class ServiceClient<T> : ClientBase<T> where T : class
{
    private bool _disposed = false;
    public ServiceClient()
        : base(typeof(T).FullName)
    {
    }
    public ServiceClient(string endpointConfigurationName)
        : base(endpointConfigurationName)
    {
    }
    public T Proxy
    {
        get { return this.Channel; }
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                if (this.State == CommunicationState.Faulted)
                {
                    base.Abort();
                }
                else
                {
                    try
                    {
                        base.Close();
                    }
                    catch
                    {
                        base.Abort();
                    }
                }
                _disposed = true;
            }
        }
    }
}

Next we are going to add two ASP.NET Labels on default.aspx as follows:

ASP.NET
<%@ Page Title="Home Page" Language="C#" 
    MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeFile="Default.aspx.cs" Inherits="_Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Welcome to ASP.NET!
    </h2>
    <div>
        <asp:Label ID="Label1" runat="server" /><br />
        <asp:Label ID="Label2" runat="server" /><br />
    </div>
</asp:Content>

Next in code-behind, Default.aspx.cs page on the Page_Load event, we are going to use our ServiceClient class to call our WCFSampleService.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using SampleService;
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        using (ServiceClient<IService1> ServiceClient = new ServiceClient<IService1>("BasicHttpBinding_IService1"))
        {
            this.Label1.Text = ServiceClient.Proxy.GetMessage();
        }
    }
}

Now it is time to run our TestClientForSampleService Website. Your screen should look like this.

Image 8

Now the real magic comes here, say for example if my client wants me to add a new function that displays a customer’s address, all I need to do is modify my ISampleService to add a new service contract and modify my WCFSampleService to add a new function that implements a new service contract. In my TestClientForSampleService website, I don’t need to add a ISampleService reference again, that is because the TestClientForSampleService website automatically gets a changed referenced DLL, thus without modifying the ISampleService reference to it, I still get a new function available to my TestClientForSampleService Website.

So let us modify ISampleService to add a new service contract GetAddress as follows and then build the project.

C#
namespace SampleService
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetMessage();
        [OperationContract]
        string GetAddress();  
    }
}

Modify WCFSampleService to implement a new service contract and then build the project:

C#
namespace SampleService
{
    public class Service1 : IService1
    {
        public string GetMessage()
        {
            return "Hello World";
        }
        public string GetAddress()
        {
            return "123 New Street, New York, NY 12345";
        }
    }
}

Finally build the SampleServiceHost project. Next build the TestClientForSampleService project, you don’t need to change the ISampleService reference to it. Then modify the default.aspx.cs file of the TestClientForSampleService website as follows:

C#
protected void Page_Load(object sender, EventArgs e)
{
    using (ServiceClient<IService1> ServiceClient = 
           new ServiceClient<IService1>("BasicHttpBinding_IService1"))
    {
        this.Label1.Text = ServiceClient.Proxy.GetMessage();
        //once you have done the build inteli sense 
            //will automatically gets the new function
        this.Label2.Text = ServiceClient.Proxy.GetAddress();
    }
}

Points of Interest

What I have tried to do here is to show you how you can loosely couple your WCF service.

History

  • 1 June 2012: First version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)