WCF服务编程读书笔记(5):操作

Example 5-1. Defining and configuring a callback contract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    public interface ISomeCallbackContract
    {
        [OperationContract]
        void OnCallback();
    }

    [ServiceContract(CallbackContract = typeof(ISomeCallbackContract))]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }
}
View Code

Example 5-2. The DuplexClientBase<T> class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace WCFServiceProgramming
{
    public interface IDuplexContextChannel : IContextChannel
    {
        InstanceContext CallbackInstance
        {
            get;
            set;
        }

        //...
    }

    public abstract class DuplexClientBase<T> : ClientBase<T> where T : class
    {
        protected DuplexClientBase(InstanceContext callbackContext);
        protected DuplexClientBase(InstanceContext callbackContext, string endpointName);
        protected DuplexClientBase(InstanceContext callbackContext, 
            Binding binding, 
            EndpointAddress remoteAddress);

        protected DuplexClientBase(object callbackInstance);
        protected DuplexClientBase(object callbackInstance, string endpointConfiguratinName);
        protected DuplexClientBase(object callbackInstance, 
            Binding binding, 
            EndpointAddress remoteAddress);

        public IDuplexContextChannel InnerDuplexChannel
        {
            get;
        }

        //...
    }
}
View Code

Example 5-3. Tool-generated duplex proxy

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCFServiceProgramming.Library;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace WCFServiceProgramming
{
    class MyContractClient : DuplexClientBase<IMyContract>, IMyContract
    {
        public MyContractClient(InstanceContext callbackContext) : base(callbackContext) { }
        public MyContractClient(InstanceContext callbackContext, string endpointName) :
            base(callbackContext, endpointName) { }
        public MyContractClient(InstanceContext callbackContext, Binding binding,
            EndpointAddress remoteAddress) :
            base(callbackContext, binding, remoteAddress) { }

        public void DoSomething()
        {
            Channel.DoSomething();
        }
    }
}
View Code

Example 5-4. Client implementing the callback contract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCFServiceProgramming.Library;
using System.ServiceModel;

namespace WCFServiceProgramming
{
    class MyClient : IMyContractCallback, IDisposable
    {
        MyContractClient m_Proxy;

        public void CallService()
        {
            InstanceContext context = new InstanceContext(this);

            m_Proxy = new MyContractClient(context);
            m_Proxy.DoSomething();
        }

        public void OnCallback()
        { 
            //...
        }

        public void Dispose()
        {
            m_Proxy.Close();
        }
    }
}
View Code

Example 5-5. Using a reworked object-based proxy

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCFServiceProgramming.Library;
using System.ServiceModel;

namespace WCFServiceProgramming
{
    class MyContractClient : DuplexClientBase<IMyContract>, IMyContract
    {
        public MyContractClient(object callbackInstance)
            : base(callbackInstance)
        { }

        public void DoSomething()
        {
            Channel.DoSomething();
        }
    }

    class MyClient : IMyContractCallback, IDisposable
    {
        MyContractClient m_Proxy;

        public void CallService()
        {
            m_Proxy = new MyContractClient(this);
            m_Proxy.DoSomething();
        }

        public void OnCallback()
        { 
            //...
        }

        public void Dispose()
        {
            m_Proxy.Close();
        }
    }
}
View Code

Example 5-6. Storing the callback references for later use

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    public interface ISomeCallbackContract
    {
        [OperationContract]
        void OnCallback();
    }

    [ServiceContract]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    class MyService : IMyContract
    {
        static List<ISomeCallbackContract> m_Callbacks = new List<ISomeCallbackContract>();

        public void DoSomething()
        {
            ISomeCallbackContract callback = 
                OperationContext.Current.GetCallbackChannel<ISomeCallbackContract>();

            if (m_Callbacks.Contains(callback) == false)
            {
                m_Callbacks.Add(callback);
            }
        }

        public static void CallClients()
        {
            Action<ISomeCallbackContract> invoke = delegate(ISomeCallbackContract callback)
            {
                callback.OnCallback();
            };

            m_Callbacks.ForEach(invoke);
        }
    }

}
View Code

Example 5-7. Configure for reentrancy to allow callbacks

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    public interface IMyContractCallback
    {
        [OperationContract]
        void OnCallback();
    }

    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
    class MyService : IMyContract
    {
        public void DoSomething()
        {
            IMyContractCallback callback = 
                OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
            callback.OnCallback();
        }
    }
}
View Code

Example 5-8. One-way callbacks are allowed by default

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    public interface IMyContractCallback
    {
        [OperationContract(IsOneWay = true)]
        void OnCallback();
    }

    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
    class MyService : IMyContract
    {
        public void DoSomething()
        {
            IMyContractCallback callback = 
                OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
            callback.OnCallback();
        }
    }
}
View Code

Example 5-9. Explicit callback connection management 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Transactions;
using System.Diagnostics;

namespace WCFServiceProgramming.Library
{
    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
    interface IMyContract
    {
        [OperationContract]
        void MyMethod();

        [OperationContract]
        void Connect();

        [OperationContract]
        void Disconnect();
    }

    interface IMyContractCallback
    {
        [OperationContract]
        void OnCallback();
    }

    class MyService : IMyContract
    {
        static List<IMyContractCallback> _callbacks = new List<IMyContractCallback>();

        public void Connect()
        {
            IMyContractCallback callback = 
                OperationContext.Current.GetCallbackChannel<IMyContractCallback>();

            if (_callbacks.Contains(callback) == false)
            {
                _callbacks.Add(callback);
            }
        }

        public void Disconnect()
        {
            IMyContractCallback callback =
                OperationContext.Current.GetCallbackChannel<IMyContractCallback>();

            if (_callbacks.Contains(callback) == true)
            {
                _callbacks.Remove(callback);
            }
            else
            {
                throw new InvalidOperationException("Cannot find callback");
            }
        }

        public static void CallClients()
        {
            Action<IMyContractCallback> invoke = delegate(IMyContractCallback callback)
            {
                callback.OnCallback();
            };

            _callbacks.ForEach(invoke);
        }

        public void MyMethod()
        {
        }
    }
}
View Code

Example 5-10. The InstanceContext<T> class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WCFServiceProgramming.Library
{
    public class InstanceContext<T>
    {
        InstanceContext _instanceContext;

        public InstanceContext(T implementation)
        {
            _instanceContext = new InstanceContext(implementation);
        }

        public InstanceContext Context
        {
            get
            {
                return _instanceContext;
            }
        }

        public T ServiceInstance
        {
            get
            {
                return (T)_instanceContext.GetServiceInstance();
            }
        }
    }
}
View Code

Example 5-11. TheDuplexClientBase<T,C>class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WCFServiceProgramming.Library;

namespace WCFServiceProgramming
{
    public abstract class DuplexClientBase<T, C> : DuplexClientBase<T> where T : class
    {
        protected DuplexClientBase(InstanceContext<C> context) : base(context.Context)
        {}

        protected DuplexClientBase(InstanceContext<C> context,
            string endpointName) : base(context.Context, endpointName)
        {}

        protected DuplexClientBase(InstanceContext<C> context,
            Binding binding, EndpointAddress remoteAddress) : 
            base(context.Context, binding, remoteAddress)
        {}

        protected DuplexClientBase(C callback) : base(callback)
        {}

        protected DuplexClientBase(C callback, string endpointName) :
            base(callback,endpointName)
        {}

        protected DuplexClientBase(C callback, Binding binding,
            EndpointAddress remoteAddress) :
            base(callback,binding, remoteAddress)
        { }

        static DuplexClientBase()
        {
            VerifyCallback();
        }

        internal static void VerifyCallback()
        {
            Type contractType = typeof(T);
            Type callbackType = typeof(C);
            object[] attributes = contractType.GetCustomAttributes(
            typeof(ServiceContractAttribute), false);

            if (attributes.Length != 1)
            {
                throw new InvalidOperationException("Type of " + contractType +
                " is not a service contract");
            }

            ServiceContractAttribute serviceContractAttribute;
            serviceContractAttribute = attributes[0] as ServiceContractAttribute;

            if (callbackType != serviceContractAttribute.CallbackContract)
            {
                throw new InvalidOperationException("Type of " + callbackType +
                " is not configured as callback contract for " + contractType);
            }
        }
    }

    public abstract class DuplexClientBase<T> : ClientBase<T> where T : class
    {
        protected DuplexClientBase(InstanceContext callbackContext);
        protected DuplexClientBase(InstanceContext callbackContext, string endpointName);
        protected DuplexClientBase(InstanceContext callbackContext, 
            Binding binding, 
            EndpointAddress remoteAddress);

        protected DuplexClientBase(object callbackInstance);
        protected DuplexClientBase(object callbackInstance, string endpointConfiguratinName);
        protected DuplexClientBase(object callbackInstance, 
            Binding binding, 
            EndpointAddress remoteAddress);

        public IDuplexContextChannel InnerDuplexChannel
        {
            get;
        }
    }

    public interface IDuplexContextChannel : IContextChannel
    {
        InstanceContext CallbackInstance
        {
            get;
            set;
        }
    }
}
View Code

Example 5-12. The DuplexChannelFactory<T,C> class

Example 5-13. Adding duplex support to InProcFactory

Example 5-14. The WsDualProxyHelper class

Example 5-15. The CallbackBaseAddressBehaviorAttribute

Example 5-16. Events management using delegates

Example 5-17. Streaming operations

原文地址:https://www.cnblogs.com/thlzhf/p/2783002.html