Wrap generated client with custom generated resurrecting client

Jan 22, 2010 at 11:02 AM

The idea here is to ensure client is not faulted before forwarding the call to it. If it is, we try to Abort() it and just new it with the same endpoint address and binding. 

I mean why do we need to deal with ChannelFactory while MRU caching is available in .net3.5sp1?

What you think?

 

    public class TodoListServiceResurrectingClient : ITodoListService
    {
        private TodoListServiceClient _client;
        private readonly object _sync = new object();

        public TodoListService(TodoListServiceClient client)
        {
            if (client == null) throw new InvalidOperationException("Resurrecting client needs instance of client to forward calls to.");
            _client = client;
        }

        private bool ClientRequiresResurrection
        {
            get { return _client.State == System.ServiceModel.CommunicationState.Faulted; }
        }

        private void EnsureClient()
        {
            if (this.ClientRequiresResurrection)
            {
                lock (_sync)
                {
                    if (this.ClientRequiresResurrection)
                    {
                        this.AbortClient();
                        _client = new TodoListServiceClient(_client.Endpoint.Binding, _client.Endpoint.Address);
                    }
                }
            }
            return _client;
        }

        private void AbortClient()
        {
            try { _client.Abort(); }
	        catch { }
        }

        public System.Collections.ObjectModel.ObservableCollection<TodoList.WpfClient.ServiceReference1.TodoItem> GetItems()
        {
            this.EnsureClient();
            return _client.GetItems();
        }

        public string CreateItem(TodoList.WpfClient.ServiceReference1.TodoItem item)
        {
            this.EnsureClient();
            return _client.CreateItem(item);
        }

        public void UpdateItem(TodoList.WpfClient.ServiceReference1.TodoItem item)
        {
            this.EnsureClient();
            _client.UpdateItem(item);
        }

        public void DeleteItem(string id)
        {  
            this.EnsureClient();
            _client.DeleteItem(id);
        }
    }

 

 

Coordinator
Jan 24, 2010 at 7:55 PM

The whole point is to prevent you from writing all the resurrection code from the business logic, because in a larger sample, there are potentially many places where you use the proxy and would need to a) check if the proxy is good, if not recreate, b) look out for timeouts, handle those with a retry to the same method, c) handle safe closing. Your code above only does one of these three things. Imagine in a much bigger sample the redundancy? Of course, if you don't mind putting that logic in your code, you are not obligated ot use a proxy wrapper.

As for MRU caching, it only works when you initialize the bindings from config, and if you don't modify credentials. So, if you don't use Windows security, or you programmatically initialize the proxy config, you are hosed.

Jan 25, 2010 at 5:46 AM

Thanks for explanation, Michele. I would not actualy dare to cover your solution with mine :)

The sample is a try to make use of MRU caching to simplify channel resurrection, but if I understand you correct, newing XServiceClient with binding and address is not working out.

Coordinator
Jan 25, 2010 at 2:00 PM

I would say the use of MRU and the use of this proxy wrapper are mutually exclusive. The MRU requires you to use the ClientBase<T> (or equivalent) proxy. This proxy wrapper wraps the channel factory, and news up the channel as needed. So, it caches the channel for this particular proxy.

 

Newing up the proxy the way you are doing it will use the MRU, but what do you gain? Both use a cached channel factory, the MRU creates a cache that is automatic and that can (in theory) be shared across any equivalent proxy request. For Windows clients you usually want to cache the actual channel, especially if it is multithreaded. Caching a single version of the channel factory is usually enough as well, unless you create many instances of the same channel across threads - but I say again - you will usuall share the proxy across those threads.

 

For server-side - MRU can be useful - say from ASP.NET to WCF services. But, then you wouldn't need this proxy wrapper anyways because it is not for that scenario. And, I would argue you can't leverage the MRU if you have to set credentials from ASP.NET to WCF.