2010-06-15 92 views
7

这是我进入stackoverflow世界的第一步,所以如果我把任何东西搞砸了,我都很抱歉。使用IOperationBehavior提供一个WCF参数

我想创建一个WCF操作,它有一个参数不会暴露给外部世界,但会自动传入函数。

因此,世界看到了这一点:int Add(int a, int b)

但它是这样实现的:int Add(object context, int a, int b)

之后,上下文得到由系统在运行时提供。我正在使用的示例完全是人为的,但它模仿了我在现实世界中正在研究的内容。

我能够接近,但不是那么完整。

首先,我创建了一个简单的方法并编写了一个应用程序来确认它的工作原理。它的确如此。它返回一个+ b并将上下文作为字符串写入我的调试。好极了。

[OperationContract] 
    int Add(object context, int a, int b); 

然后我写了下面的代码:

public class SupplyContextAttribute : Attribute, IOperationBehavior 
{ 
    public void Validate(OperationDescription operationDescription) 
    { 
     if (!operationDescription.Messages.Any(m => m.Body.Parts.First().Name == "context")) 
      throw new FaultException("Parameter 'context' is missing."); 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
     dispatchOperation.Invoker = new SupplyContextInvoker(dispatchOperation.Invoker); 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
    } 

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
     // Remove the 'context' parameter from the inbound message 
     operationDescription.Messages[0].Body.Parts.RemoveAt(0); 
    } 
} 

public class SupplyContextInvoker : IOperationInvoker 
{ 
    readonly IOperationInvoker _invoker; 

    public SupplyContextInvoker(IOperationInvoker invoker) 
    { 
     _invoker = invoker; 
    } 

    public object[] AllocateInputs() 
    { 
     return _invoker.AllocateInputs().Skip(1).ToArray(); 
    } 

    private object[] IntroduceContext(object[] inputs) 
    { 
     return new[] { "MyContext" }.Concat(inputs).ToArray(); 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     return _invoker.Invoke(instance, IntroduceContext(inputs), out outputs); 
    } 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     return _invoker.InvokeBegin(instance, IntroduceContext(inputs), callback, state); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     return _invoker.InvokeEnd(instance, out outputs, result); 
    } 

    public bool IsSynchronous 
    { 
     get { return _invoker.IsSynchronous; } 
    } 
} 

我的WCF操作现在看起来是这样的:

[OperationContract, SupplyContext] 
    int Amend(object context, int a, int b); 

我更新引用不再显示 '语境' 参数,该参数正是我想要的。

问题是,当我运行代码时,它会通过AllocateInputs,然后在WCF内容的某个地方抛出一个Index was outside the bounds of the Array.错误。

我试过其他的东西,我发现我可以成功地改变参数的类型并重命名它并让我的代码工作。但是当我删除参数时,它就会崩溃。

任何人都可以给我一些想法如何让这个工作(或者如果它可以完成)。

回答

5

嗯,我想到了我自己。 MessagePartDescription具有一个Index属性。我只需要重新调整这些值。

public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
     var parts = operationDescription.Messages[0].Body.Parts; 
     parts.RemoveAt(0); 
     for (int i = 0; i < parts.Count; i++) 
      parts[i].Index = i; 
    }