How to improve WCF client proxy based on CreateChannel (not generated from WSDL) in C# When invoking a Web Service from C# (where the external service might be WCF, ASMX, Java, etc. - you just don't know), it is common practice to point your modern development tool of choice (Visual Studio in my case) at the service's WSDL to generate a proxy class for calling the service. You can also create a proxy "by hand" using CreateChannel. This code review posting is to seek feedback on a simple proxy class built using CreateChannel. A couple of supporting classes are shown for completeness &amp; context.

Interface for Service &amp; Proxy:

This interface is also passsed to ChannelFactory.

public interface IService
{
   ServiceResponse DoSomething(ServiceRequest request);
}


Example usage:

var proxy = new ServiceProxy("http://123.45.67.89/foo");
var request = new ServiceRequest { Number = 33, Name = "Larry Bird" };
ServiceResponse response = proxy.DoSomething(request);


Code of interest:  - Any comments/improvements/feedback appreciated

For readers wondering about the use of factory.Abort in the finally block, see answer to this question. Regarding the following casting business (which appears twice): ((IClientChannel)service).Close(); see MSDN document on How To: Use the ChannelFactory which demonstrates its use. The two are hacks that appear to be related and date from early WCF/Indigo days.

public class ServiceProxy : IService
{
   public string EndpointUrl { get; set; }
   public ServiceProxy(string endpointUrl) { EndpointUrl = endpointUrl; }

   public ServiceResponse DoSomething(ServiceRequest request)
   {
      Contract.Requires(request != null);
      Contract.Requires(! String.IsNullOrEmpty(EndpointUrl));

      var endpointAddress = new EndpointAddress(EndpointUrl);
      ChannelFactory&lt;IService&gt; factory = null;
      IService service = null; 

      try
      {
         // Just picking a simple binding here to focus on other aspects
         Binding binding = new BasicHttpBinding();
#if DEBUG // boost timeouts, otherwise can cause lots of timeouts in the debugger
         binding.SendTimeout = binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
#endif
         factory = new ChannelFactory&lt;IService&gt;(binding);
         service = factory.CreateChannel(endpointAddress);
         if (service == null)
         {
             throw new CommunicationException(
                String.Format("Unable to connect to service at {0}", endpointUrl));
         }

         ServiceResponse response = service.DoSomething(request);
         ((IClientChannel)service).Close();

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

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


Supporting Objects (for completeness)

Not much of interest in ServiceRequest and ServiceResponse classes, other than this is the prevailing style of calling services - one object in, one object out.

public class ServiceRequest // stuff we send to the service
{
   public int Number { get; set; }
   public string Name { get; set; }
}

public class ServiceResponse // stuff we get back from the service
{
   public int SomeStat { get; set; }
   public string SomeString { get; set; }
}
Instead of wrapping the proxy creation in a concrete service proxy implementation, I'd write a concrete service factory instead which in turn uses the ChannelFactory. The service factory class could also use an interface for creation, so you can have multiple concrete factories.

http://en.wikipedia.org/wiki/Factory_pattern

That way your code can continue to depend on the interface only, and you can change the way the proxy is created without writing concrete proxies. You could also have a "local service factory" which doesn't go over the wire.

Usage would be something like this instead:

var service = ServiceFactory.Create("http://127.0.0.1/svc");
var result = service.DoSomething(request);
// if you need cleanup..
ServiceFactory.Release(service);