Question

I have two projects, one is a set of WCF services (let's call P1) and the other is a standard web application (P2).

As a start, we have consumed P1 services in P2 as SOAP services and everything went fine. Later we noticed that in all of our project deployments, we are hosting both P1 & P2 on the same server. So we thought why should we keep it like this - meaning: Why should we serialize/de-serialize the request/response every time for every method when it is running in the same server. So we made a decision to use P1 as standard project library reference in P2.

We had to make a lot of modifications because the proxy class name changes and having to remove the client "close" method after each call. Now, we have a new deployment that will requires P1 to be on a different server than P2, which we can change, and we have to consume P1 again as WCF service - meaning tons of changes all over the P2 and ending by having the serialization overhead on all of other deployments!

The question is, is there any way to make such a dynamic reference to P1, so no coding is required regardless the deployment is on 1 or 2 servers?

Was it helpful?

Solution

It is possible to make a WCF service run local( project reference ) or as a service based on some key on the web.config. I did the following example but I didnt test it but I have done exactly similar thing before

Add key in the web config say serviceMode="local/service"

Then say you have wcf service interface

    [ServiceContract]
    public class ICalculator
    {
         [OperationContract]
        int Add(int x, int y);
    }

implementation

  public class Calculator
   {
      public int Add(int x, y)
      {
        return x+y;
      }
}

///Now in your web application

you will have

   public LocalProxy:ICalculator //this will use direct instance of the Calculator Service
   {
      private ICalculator _calculator

      public  LocalProxy(ICalculator calculator)
      {
        _calculator =calculator;
      }

      public int Add(int x, int y)
      {
         return _calculator.Add(x,y);
      }

}




 public class RemoteProxy:ICalculator  ///This will be real wcf proxy

    {


       public int Add (int x,int y)
       {

          var endpointAddress = new EndpointAddress(EndpointUrl);
           ChannelFactory<ICalculator> factory = null;
           ICalculator calculator ;

          try
          {
             // Just picking a simple binding here to focus on other aspects
             Binding binding = new BasicHttpBinding();

             factory = new ChannelFactory<ICalculator>(binding);
             calculator= factory.CreateChannel(endpointAddress);
             if (calculator== null)
             {
                 throw new CommunicationException(
                    String.Format("Unable to connect to service at {0}", endpointUrl));
             }

             int sum= calculator.Add(x,y);
             ((IClientChannel)calculator).Close();

             calculator = null;
             factory.Close();
             factory = null;

             return sum;
          }
          finally
          {
             if (calculator!= null) ((IClientChannel)calculator).Close();
             if (factory != null) factory.Abort();
          }
       }

    }

Now how you use it

 ICalculator _calculatorProxy;

    //get the web config key here, you may use strategy pattern to select between the two proxies


     if(key=="local)
    {
     _calculator= new LocalProxy(new Calculator)
    }
    else
    {
     _calculator= new RemoteProxy();
    }


    //then 
     _calculator.Add(3,5);

Note: Define your interfaces and data contracts in a separate assembly so that you can share it with the web application that needs wcf run as a service.

OTHER TIPS

All your components in P2 which consume services from P1 should only consume the service interface (i.e. IMyService, ISomeOtherService). They should not care whether it is a local instance or a proxy and neither should they close the connection.

The easiest (imho) to realize this is by using dependency injection through an IoC like Castle Windsor (it's the only one I'm vaguely familiar with but there are several others out there). The container will be responsible to provide instances of the service interfaces. You can provide different implementations and configure the container at runtime with the appropriate one (WCF service or local instance). The container will also be responsible for disposing of the service components once they are not required anymore (i.e. calling Close() on the WCF proxies and doing nothing for the others).

It's a big topic so I'd suggest you search the internet for some of the keywords - there is lot of material out there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top