What is the best workaround for the WCF client `using` block issue?

前端 未结 26 1743
余生分开走
余生分开走 2020-11-22 00:03

I like instantiating my WCF service clients within a using block as it\'s pretty much the standard way to use resources that implement IDisposable:

26条回答
  •  梦毁少年i
    2020-11-22 00:19

    Our system architecture often uses the Unity IoC framework to create instances of ClientBase so there's no sure way to enforce that the other developers even use using{} blocks. In order to make it as fool-proof as possible, I made this custom class that extends ClientBase, and handles closing down the channel on dispose, or on finalize in case someone doesn't explicitly dispose of the Unity created instance.

    There is also stuff that needed to be done in the constructor to set up the channel for custom credentials and stuff, so that's in here too...

    public abstract class PFServer2ServerClientBase : ClientBase, IDisposable where TChannel : class
    {
        private bool disposed = false;
    
        public PFServer2ServerClientBase()
        {
            // Copy information from custom identity into credentials, and other channel setup...
        }
    
        ~PFServer2ServerClientBase()
        {
            this.Dispose(false);
        }
    
        void IDisposable.Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        public void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                try
                {
                        if (this.State == CommunicationState.Opened)
                            this.Close();
                }
                finally
                {
                    if (this.State == CommunicationState.Faulted)
                        this.Abort();
                }
                this.disposed = true;
            }
        }
    }
    

    Then a client can simply:

    internal class TestClient : PFServer2ServerClientBase, ITest
    {
        public string TestMethod(int value)
        {
            return base.Channel.TestMethod(value);
        }
    }
    

    And the caller can do any of these:

    public SomeClass
    {
        [Dependency]
        public ITest test { get; set; }
    
        // Not the best, but should still work due to finalizer.
        public string Method1(int value)
        {
            return this.test.TestMethod(value);
        }
    
        // The good way to do it
        public string Method2(int value)
        {
            using(ITest t = unityContainer.Resolve())
            {
                return t.TestMethod(value);
            }
        }
    }
    

提交回复
热议问题