Sunday, September 02, 2012

A Generic WCF Proxy Class

A couple of years ago, when I first started using WCF, it seemed like a real pain in the you-know-what to add Service References to my app in order to consume WCF Services. I wanted a base Proxy class that I could extend to be used for any kind of ServiceContract. The key to writing this class was the use of generics Here’s what I came up with, after much trial and error (be sure you have using System.ServiceModel and using System.ServiceModel.Channels):

public abstract class ProxyBase<T> where T : class
{
    #region Declarations
    public ChannelFactory<T> Factory = null;
    public T proxy { get; set; }
    public string EndpointName { get; set; }
    private string m_Certificate;
    public string Certificate
    {
        get { return this.m_Certificate; }
        set
        {
            try
            {
                this.m_Certificate = value;
                if (this.m_Certificate.IsNotNullOrEmpty() && Factory != null)
                {
                    EndpointIdentity Identity = EndpointIdentity.CreateDnsIdentity(this.m_Certificate);
                    if (Identity == null)
                        Console.WriteLine("Identity Is Null");
                    else
                    {
                        Uri AddressUri = Factory.Endpoint.Address.Uri;
                        Factory.Endpoint.Address = new EndpointAddress(AddressUri, Identity);

                        // not sure, but probably have to remove old EventHandler before recreating the 
                        // proxy and recreating the Channel.
                        ((ICommunicationObject)proxy).Faulted -= new EventHandler(ProxyBase_Faulted);
                        proxy = Factory.CreateChannel();
                        ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
                    }
                }
            }
            catch (Exception ex)
            {
                Factory = null;
                proxy = null;
            }
        }
    }
    #endregion

    #region Constructors
    public ProxyBase() { }
    public ProxyBase(string endpoint)
    {
        // not the best error-handling, but good enough for now
        // TODO - make error-handling better
        //        Already handling faulted channels, but now need to do something for bad addresses?
        //        Because I *think* a bad address will cause an exception in the creation of the Factory.
        try
        {
            this.EndpointName = endpoint;
            Factory = new ChannelFactory<T>(endpoint);
            proxy = Factory.CreateChannel();
            ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error in Proxy for {0}, Endpoint: {1}\r\n{2)", typeof(T).Name, endpoint, ex.Message);
            Factory = null;
            proxy = null;
        }
    }
    public ProxyBase(string endpoint, string address)
    {
        // not the best error-handling, but good enough for now
        // TODO - make error-handling better
        //        Already handling faulted channels, but now need to do something for bad addresses?
        //        Because I *think* a bad address will cause an exception in the creation of the Factory.
        try
        {
            this.EndpointName = endpoint;
            Factory = new ChannelFactory<T>(endpoint);
            Factory.Endpoint.Address = new EndpointAddress(address);
            proxy = Factory.CreateChannel();
            ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Proxy for {0}, Endpoint: {1}, Address: {2}\r\n{3}", typeof(T).Name, endpoint, address, ex.Message);
            Factory = null;
            proxy = null;
        }
    }
    #endregion

    #region Methods
    public void Close()
    {
        if (proxy != null)
            ((IChannel)proxy).Close();
        if (Factory != null)
            Factory.Close();
    }
    #endregion

    #region Events
    private void ProxyBase_Faulted(object sender, EventArgs e)
    {
        Console.WriteLine("Proxy for {0}\r\n{1}", typeof(T).Name, ((IChannel)proxy).State.ToString());
        ((ICommunicationObject)sender).Abort();
        proxy = Factory.CreateChannel();
    }
    #endregion
}

Seems pretty simple. Notice that it’s an abstract class. You must sub-class it in order to use it. OK, so how do we construct the sub-class? Very simple also. First, you must have a few Interfaces defined, as you would normally have for any WCF service. Here is what I’m going to use for my example:

[ServiceContract(Namespace = "http://MyCompany")]
public interface IMessageService
{
    [OperationContract(IsOneWay = true)]
    void ProcessMessage(IMessage message);
}

[ServiceContract(Namespace = "http://MyCompany")]
public interface ISynchronousMessageService
{
    [OperationContract]
    bool ProcessMessage(IMessage message);
}

public interface IMessage
{
    string MessageToSend { get; set; }
    string MessageReceived { get; set; }
}
public class MyMessage : IMessage
{
    public string MessageToSend { get; set; }
    public string MessageReceived { get; set; }
}

All WCF Services need to have a ServiceContract and OperationContract, so there they are. I’ve also got an interface defined for the Messages I’m going to send, plus a MyMessage class that implements that IMessage interface.

Next, here is what my sub-classed Proxies might look like:

public class SynchronousProxy : ProxyBase<ISynchronousMessageService>, ISynchronousMessageService, IDisposable
{
    #region Constructors
    public SynchronousProxy(string endpoint) : base(endpoint) { }
    public SynchronousProxy(string endpoint, string address) : base(endpoint, address) { }
    #endregion

    #region Methods
    public virtual bool ProcessMessage(IMessage message)
    {
        try
        {
            if (proxy != null)
                return proxy.ProcessMessage(message);
            else
                return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception, ProcessMessage\r\n{0}", ex.Message);
            return false;
        }
    }
    public void Dispose()
    {
        this.Close();
    }
    #endregion
}
public class Proxy : ProxyBase<IMessageService>, IMessageService, IDisposable
{
    #region Constructors
    public Proxy(string endpoint) : base(endpoint) { }
    public Proxy(string endpoint, string address) : base(endpoint, address) { }
    #endregion

    #region Methods
    public virtual void ProcessMessage(IMessage message)
    {
        try
        {
            if (proxy != null)
                proxy.ProcessMessage(message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception, ProcessMessage\r\n{0}", ex.Message);
        }
    }
    public void Dispose()
    {
        this.Close();
    }
    #endregion
}

And now, how do I actually use these proxy classes? You’d have the usual WCF stuff defined in the .config in the endpoint in the systemServiceModel tags:

  <system.serviceModel>
    <client>
      <endpoint name="MyEndpoint"
          address="net.tcp://MyComputer:666/MyMessageService"
          binding="netTcpBinding" bindingConfiguration="netTcpConfig"
          contract="MyApp.IMessageService"/>
    </client>
  </system.serviceModel>

And then in your code, you’d call the WCF service like this:

using (Proxy proxy = new Proxy("MyEndpoint"))
{
    MyMessage message = new MyMessage();
    message.MessageToSend = "MyTestMessage";
    proxy.ProcessMessage(message);
}

Wow, that’s pretty easy, isn’t it? No need to add ServiceReferences or anything like that. All you need to know are the Interfaces that the Services use and you’re good to go!