WCF 扩展之我见: OperationSelector


Use the OperationSelector property to decide which operation receives a given message. The default operation selector returns the value of the action header for the message, which is used as the key to locate the correct DispatchOperation. If no matching operation is found, the invocation is dispatched to the return value from the UnhandledDispatchOperation property.

-- 摘自 《MSDN


作 用

MSDN 的解释已经比较明确了,OperationSelector 的目的就是用于决定到底由哪个 operation 来对消息进行处理。如果没有一个 operation 是符合条件的,则会被 UnhandledDispatchOperation 来处理。


根据《消息处理流程》一文, 当通过 InstanceContextProvider 获取了 InstanceContext 之后,便会去调用 GetOperation 来得到选择目标 DispatchOperation。不过一般情况下,WCF 运行时并没有一个预置的 OperationSelector 来进行选择,而是直接通过消息头的 Action 来找到匹配的 operation,如下:

public DispatchOperationRuntime GetOperation(ref Message request)
{
    string action = request.Headers.Action;
    if (action == null)
    {
        action = MessageHeaders.WildcardAction;
    }
    DispatchOperationRuntime operation = (DispatchOperationRuntime)this.map[action];
    if (operation != null)
    {
        return operation;
    }
 
    return this.unhandled;
}


当默认的这种方式无法满足我们的需求的时候,比如实际调用的 operation 并非与 header 中 action 所对应,而是包含在 message 的 body 中;又比如 REST 服务,同样的 URL (http://blog.chenxu.me/post/ID) ,会因为 Http verb 的不同而执行不同的请求,(e.g. Http verb 是 Get,上述的请求会返回 post ID 与 URL 的 ID 相同的文章; Http verb 是 put,上述的请求则是用于编辑文章)。


如何扩展 OperationSelector

为了满足这些特殊情况,我们可以通过自定义一个 OperationSelector 来实现。


首先,实现接口 I[Dispatch/Client]OperationSelector 

public interface IDispatchOperationSelector
{
    string SelectOperation(ref Message message);
}
 
public interface IClientOperationSelector
{
    bool AreParametersRequiredForSelection { get; }
    string SelectOperation(MethodBase method, object[] parameters);
}


这里只介绍 IDispatchOperationSelector。从上述接口定义中可以发现它的原理很简单,就是根据传入的 Message 来找到对应的 Operation 的名字。

public class MyOperationSelector : IDispatchOperationSelector
{
    public string SelectOperation(ref Message message)
    {
        if (message.Properties.ContainsKey("Test"))
        {
            return "Op";
        }
        else        {
            return message.Headers.Action.Substring(message.Headers.Action.LastIndexOf('/') + 1);
        }
    }
}

然后,只要把自定义的 OperationSelector 通过 Behavior 应用到 DispatchRuntime 就可以了,详细步骤请参考 《WCF 扩展之我见: Behaviors


文章索引

[隐 藏]

本站采用知识共享署名 3.0 中国大陆许可协议进行许可。 ©2014 Charley Box | About Site | 浙ICP备13014059号