首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何找出当前方法是否被IsOneWay标记

如何找出当前方法是否被IsOneWay标记
EN

Stack Overflow用户
提问于 2013-03-27 19:21:51
回答 2查看 585关注 0票数 2

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

我使用的是httpBinding,这个问题与服务器端有关。

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

编辑

代码语言:javascript
复制
I used the following check:
HttpContext.Current.Response.StatusCode != 
        (int)System.Net.HttpStatusCode.Accepted;

如果发生OneWay调用,状态代码将为202,但这不是一种好方法。

有什么更好的方法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-28 22:23:19

WCF解决这一问题的方法是:

  1. 创建包含所需数据的自定义上下文对象。
  2. 创建填充数据的自定义行为。
  3. 将此行为应用于您的服务

这需要插入多个WCF扩展点。一旦掌握了它的诀窍,这并不难,但是由于需要实现的所有接口(即使方法实现是空的),它需要进行大量的输入。下面是一个例子。

首先定义一个简单的服务:

代码语言:javascript
复制
[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,所以可以在不实际承载服务的情况下进行单元测试。方法创建从这个博客获取的自定义上下文。

代码语言:javascript
复制
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。

代码语言:javascript
复制
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结构所需的所有信息。不需要反思。不依赖于绑定.

代码语言:javascript
复制
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)
    {
    }
}

现在做个快速测试。

代码语言:javascript
复制
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();
    }
}

产出应是:

代码语言:javascript
复制
Default() is marked IsOneWay:False
OneWay() is marked IsOneWay:True
Press ENTER to close the host once you see 'ALL DONE'.

注意,我们的所有抽象都是维护的。服务仅依赖于行为提供的上下文对象,该行为显然被属性标记为对服务的依赖。

该示例将[OneWayContract]放在服务类上。但是您也应该能够将它应用到[ServiceContract]中。

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

代码语言:javascript
复制
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();
            }
        }
    }
}
票数 2
EN

Stack Overflow用户

发布于 2013-03-27 20:45:47

就像提姆建议的那样,使用反射。下面的片段应该适用于您

代码语言:javascript
复制
 Type serviceInterface = typeof(IService1);
 MethodInfo mi =  serviceInterface.GetMethod((System.Reflection.MethodBase.GetCurrentMethod().Name);
 Attribute attr = mi.GetCustomAttribute(typeof(OperationContractAttribute));
 Console.WriteLine(((OperationContractAttribute)attr).IsOneWay);

您也可以使用堆栈框架来获取当前的方法名,但我一直使用反射。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15667622

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档