如何确定当前方法是否用IsOneWay标记

时间:2013-03-27 19:21:52

标签: .net wcf isoneway oneway

有没有办法知道当前正在执行的WCF方法是否是OneWay方法?

我正在使用httpBinding,问题与服务器端有关。

我在MSDN上搜索了OperationContext的属性,但找不到它。

修改

I used the following check:
HttpContext.Current.Response.StatusCode != 
        (int)System.Net.HttpStatusCode.Accepted;

在OneWay调用的情况下,状态代码将是202,但这不是一个好方法。

有没有更好的方法?

2 个答案:

答案 0 :(得分:2)

蒂姆建议,使用反思。以下代码段应该适合您

 Type serviceInterface = typeof(IService1);
 MethodInfo mi =  serviceInterface.GetMethod((System.Reflection.MethodBase.GetCurrentMethod().Name);
 Attribute attr = mi.GetCustomAttribute(typeof(OperationContractAttribute));
 Console.WriteLine(((OperationContractAttribute)attr).IsOneWay);

您也可以使用stackframe获取当前的方法名称,但我一直使用反射。

答案 1 :(得分:2)

解决此问题的WCF方法是:

  1. 创建包含所需数据的自定义上下文对象
  2. 创建填充数据的自定义行为
  3. 将行为应用于您的服务
  4. 这需要插入多个WCF扩展点。一旦掌握了它就不难,但由于需要实现所有接口(即使方法实现为空),也需要进行大量的输入。这是一个例子。

    首先定义一个简单服务:

    [ServiceContract]
    public interface ISimple
    {
        [OperationContract(IsOneWay = true)]
        void OneWay();
    
        [OperationContract]
        void Default();
    }
    
    [OneWayContract]
    public class SimpleService : ISimple
    {
        //[OneWayOperation]     // uncomment to Add context data on the operation level instead on contract.
        public void OneWay()
        {
            Console.WriteLine("OneWay() is marked IsOneWay:" + OneWayContext.Current.IsOneWay);
        }
    
        public void Default()
        {
            Console.WriteLine("Default() is marked IsOneWay:" + OneWayContext.Current.IsOneWay);
        }
    }
    

    它使用自定义上下文对象来存储您需要的信息。在这种情况下,如果操作IsOneWay,则为bool。请注意,由于您要包装WCF InstanceContext,因此无需实际托管服务即可进行单元测试。创建从this blog获取的自定义上下文的方法:

    public class OneWayContext : IExtension<InstanceContext>
    {
        public OneWayContext()
        {
            // if not set, default to false.
            IsOneWay = false;
        }
    
        public bool IsOneWay { get; set; }
    
        public static OneWayContext Current
        {
            get
            {
                OneWayContext context = OperationContext.Current.InstanceContext.Extensions.Find<OneWayContext>();
                if (context == null)
                {
                    context = new OneWayContext();
                    OperationContext.Current.InstanceContext.Extensions.Add(context);
                }
                return context;
            }
        }
    
        public void Attach(InstanceContext owner) { }
        public void Detach(InstanceContext owner) { }
    }
    

    创建OperationInvoker以将自定义上下文添加到OperationContext。请注意,插入WCF OperationInvoker意味着将其放入调用堆栈中。所以它不处理的所有调用都需要传递给框架的“内部”OperationInvoker。

    public class OneWayBehavior : IOperationInvoker
    {
        IOperationInvoker innerOperationInvoker;
        public readonly bool isOneWay;
    
        public OneWayBehavior(IOperationInvoker innerOperationInvoker, bool isOneWay)
        {
            this.isOneWay = isOneWay;
            this.innerOperationInvoker = innerOperationInvoker;
        }
    
        public object[] AllocateInputs()
        {
            return innerOperationInvoker.AllocateInputs();
        }
    
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            // Everytime the operation is invoked, add IsOneWay information to the context.
            OneWayContext.Current.IsOneWay = this.isOneWay;
    
            return innerOperationInvoker.Invoke(instance, inputs, out outputs);
        }
    
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            return innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
        }
    
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return innerOperationInvoker.InvokeEnd(instance, out outputs, result);
        }
    
        public bool IsSynchronous
        {
            get { return innerOperationInvoker.IsSynchronous; }
        }
    }
    

    现在将新行为应用于合同。 [OneWayContract]属性应用WCF合同行为,该行为应用操作行为。您还可以在操作级别应用该行为。

    请注意,OperationDescription提供了已填充的WCF结构所需的所有信息。没有诉诸反思。不依赖于绑定。

    public class OneWayOperationAttribute : Attribute, IOperationBehavior
    {
        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }
    
        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
        }
    
        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            // grab "IsOneWay" from the operation description and pass on the behavior's constructor.
            dispatchOperation.Invoker = new OneWayBehavior(dispatchOperation.Invoker, operationDescription.IsOneWay);
        }
    
        public void Validate(OperationDescription operationDescription)
        {
        }
    }
    
    public class OneWayContractAttribute : Attribute, IContractBehavior
    {
        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }
    
        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }
    
        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            foreach (OperationDescription operation in contractDescription.Operations)
            {
                operation.OperationBehaviors.Add(new OneWayOperationAttribute());
            }
        }
    
        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }
    }
    

    现在进行快速测试。

    public static class Program
    {
        static void Main(string[] args)
        {
            ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
            simpleHost.Open();
    
            ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
            ISimple proxy = factory.CreateChannel();
    
            proxy.OneWay();
    
            proxy.Default();
    
            Console.WriteLine("Press ENTER to close the host once you see 'ALL DONE'.");
            Console.ReadLine();
    
            ((ICommunicationObject)proxy).Shutdown();
    
            simpleHost.Shutdown();
        }
    }
    

    输出应为:

    Default() is marked IsOneWay:False
    OneWay() is marked IsOneWay:True
    Press ENTER to close the host once you see 'ALL DONE'.
    

    请注意,我们所有的抽象都得到了维护。该服务仅依赖于行为提供的上下文对象,该行为明确标记为属性对服务的依赖性。

    该示例将[OneWayContract]放在服务类上。但您也应该能够将其应用于[ServiceContract]


    为了完整起见,这是整个代码示例的副本,作为一个可以粘贴和运行的控制台应用程序。

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace ConsoleWCF
    {
        [ServiceContract]
        public interface ISimple
        {
            [OperationContract(IsOneWay = true)]
            void OneWay();
    
            [OperationContract]
            void Default();
        }
    
        [OneWayContract]
        public class SimpleService : ISimple
        {
            //[OneWayOperation]     // uncomment to Add context data on the operation level instead on contract.
            public void OneWay()
            {
                Console.WriteLine("OneWay() is marked IsOneWay:" + OneWayContext.Current.IsOneWay);
            }
    
            public void Default()
            {
                Console.WriteLine("Default() is marked IsOneWay:" + OneWayContext.Current.IsOneWay);
            }
        }
    
        public class OneWayBehavior : IOperationInvoker
        {
            IOperationInvoker innerOperationInvoker;
            public readonly bool isOneWay;
    
            public OneWayBehavior(IOperationInvoker innerOperationInvoker, bool isOneWay)
            {
                this.isOneWay = isOneWay;
                this.innerOperationInvoker = innerOperationInvoker;
            }
    
            public object[] AllocateInputs()
            {
                return innerOperationInvoker.AllocateInputs();
            }
    
            public object Invoke(object instance, object[] inputs, out object[] outputs)
            {
                // Everytime the operation is invoked, add IsOneWay information to the context.
                OneWayContext.Current.IsOneWay = this.isOneWay;
    
                return innerOperationInvoker.Invoke(instance, inputs, out outputs);
            }
    
            public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
            {
                return innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
            }
    
            public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
            {
                return innerOperationInvoker.InvokeEnd(instance, out outputs, result);
            }
    
            public bool IsSynchronous
            {
                get { return innerOperationInvoker.IsSynchronous; }
            }
        }
    
        public class OneWayOperationAttribute : Attribute, IOperationBehavior
        {
            public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
            {
            }
    
            public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
            {
                // grab "IsOneWay" from the operation description and pass on the behavior's constructor.
                dispatchOperation.Invoker = new OneWayBehavior(dispatchOperation.Invoker, operationDescription.IsOneWay);
            }
    
            public void Validate(OperationDescription operationDescription)
            {
            }
        }
    
        public class OneWayContractAttribute : Attribute, IContractBehavior
        {
            public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
            }
    
            public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
            {
                foreach (OperationDescription operation in contractDescription.Operations)
                {
                    operation.OperationBehaviors.Add(new OneWayOperationAttribute());
                }
            }
    
            public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
            {
            }
        }
    
        public class OneWayContext : IExtension<InstanceContext>
        {
            public OneWayContext()
            {
                // if not set, default to false.
                IsOneWay = false;
            }
    
            public bool IsOneWay { get; set; }
    
            public static OneWayContext Current
            {
                get
                {
                    OneWayContext context = OperationContext.Current.InstanceContext.Extensions.Find<OneWayContext>();
                    if (context == null)
                    {
                        context = new OneWayContext();
                        OperationContext.Current.InstanceContext.Extensions.Add(context);
                    }
                    return context;
                }
            }
    
            public void Attach(InstanceContext owner) { }
            public void Detach(InstanceContext owner) { }
        }
    
    
    
        public static class Program
        {
            static void Main(string[] args)
            {
                ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
                simpleHost.Open();
    
                ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
                ISimple proxy = factory.CreateChannel();
    
                proxy.OneWay();
    
                proxy.Default();
    
                Console.WriteLine("Press ENTER to close the host once you see 'ALL DONE'.");
                Console.ReadLine();
    
                ((ICommunicationObject)proxy).Shutdown();
    
                simpleHost.Shutdown();
            }
        }
    
        public static class Extensions
        {
            static public void Shutdown(this ICommunicationObject obj)
            {
                try
                {
                    obj.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Shutdown exception: {0}", ex.Message);
                    obj.Abort();
                }
            }
        }
    }