我正在尝试扩展WCF,以便我可以拥有一个RESTful Web服务,其中,对于每个操作,我执行HTTP Authorization标头的验证,其值用于调用Login()方法.
登录完成后,我希望调用操作的相应方法检查是否抛出了安全异常,在这种情况下,我将使用适当的HTTP状态代码回复自定义的"访问被拒绝"消息.
考虑到这一点,我认为实现一个IEndpointBehavior,它将IOperationInvoker的实现应用于每个操作(设置DispatchOperation.Invoker属性)将是一个好主意.
我决定使用Decorator设计模式实现IOperationInvoker.我的实现需要在其构造函数中使用另一个IOperationInvoker,方法调用将被委托给它.
这是我的IOperationInvokerImplementation:
public class BookSmarTkOperationInvoker : IOperationInvoker{ private readonly IOperationInvoker invoker; public BookSmarTkOperationInvoker(IOperationInvoker decoratee) { this.invoker = decoratee; } public object[] AllocateInputs() { return this.invoker.AllocateInputs(); } public object Invoke(object instance, object[] inputs, out object[] outputs) { BeforeOperation(); // Where there's code to perform the login using WebOperationContext.Current object o = null; try { o = this.invoker.Invoke(instance, inputs, out outputs); } catch (Exception exception) { outputs = null; return AfterFailedOperation(exception); // Return a custom access denied response } return o; } public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) { throw new Exception("The operation invoker is not asynchronous."); } public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) { throw new Exception("The operation invoker is not asynchronous."); } public bool IsSynchronous { get { return false; } } }
我决定通过扩展我已经需要的行为(WebHttpBehavior)来实现IEndpointBehavior,这样我只使用一个beavior.这是我写的代码:
public class BookSmarTkEndpointBehavior : WebHttpBehavior { public override void Validate(ServiceEndpoint endpoint) { base.Validate(endpoint); } public override void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { base.AddBindingParameters(endpoint, bindingParameters); } public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { base.ApplyDispatchBehavior(endpoint, endpointDispatcher); foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations) { IOperationInvoker defaultInvoker = operation.Invoker; IOperationInvoker decoratorInvoker = new BookSmarTkOperationInvoker(defaultInvoker); operation.Invoker = decoratorInvoker; Console.Write("Before: " + ((object)defaultInvoker ?? "null")); Console.WriteLine(" After: " + operation.Invoker); } } public override void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { base.ApplyClientBehavior(endpoint, clientRuntime); throw new Exception("The BookSmarTkEndointBehavior cannot be used in client endpoints."); } }
现在问题在于:
只有在IOperationInvoker中调用构造函数,其他方法都没有.
decoratee IOperationInvoker(在装饰器的构造函数中传递的那个)为null.
我猜测,其他一些行为的其他代码可能是之后在OperationDispatcher.Invoker设置中设置另一个IOperationInvoker.因此,压倒我的.这清楚地解释了我的情况.
发生了什么,我该怎么办?
我的服务是自托管的.
如果您需要查看它,这是我在system.serviceModel下的app.config文件中的配置.
我读到这里,我非常感谢你.真的很谢谢你!
您必须创建一个IOperationBehavior实现者,而不是在ApplyDispatchBehavior()方法中设置调用者:
public class MyOperationBehavior: IOperationBehavior { public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { } public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { dispatchOperation.Invoker = new BookSmarTkOperationInvoker(dispatchOperation.Invoker); } public void Validate(OperationDescription operationDescription) { } }
然后在ApplyDispatchBehavior()中你应该设置该行为:
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { foreach (var operation in endpoint.Contract.Operations) { if (operation.Behaviors.Contains(typeof(MyOperationBehavior))) continue; operation.Behaviors.Add(new MyOperationBehavior()); } }