Estoy tratando de extender WCF para que pueda tener un servicio web RESTful, en el cual, para cada operación, realizo una verificación del encabezado de Autorización HTTP, cuyo valor utilizo para llamar a un método de Login().¿Cuándo y dónde establecer un IOperationInvoker personalizado?
Después de finalizar el inicio de sesión, deseo invocar el método correspondiente para verificar si se lanza una excepción de seguridad, en cuyo caso responderé con un mensaje personalizado de "acceso denegado" utilizando el código de estado HTTP apropiado.
con esto en mente, pensé que la implementación de un IEndpointBehavior que aplica una implementaion de IOperationInvoker a cada operación (estableciendo la propiedad DispatchOperation.Invoker) sería una buena idea.
decidí poner en práctica un IOperationInvoker usando el diseño del decorador Mi implementación necesitaría otro IOperationInvoker en su constructor al que se delegarían las invocaciones de métodos .
Esta es mi 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;
}
}
}
decidí poner en práctica un IEndpointBehavior extendiendo el comportamiento que ya necesitaba (WebHttpBehavior) de esta manera Yo sólo uso uno beavior. Aquí está el código que escribí:
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.");
}
}
Ahora aquí está el problema:
- Sólo el constructor se invoca en el IOperationInvoker, ninguno de los otros métodos son.
- El IOperationInvoker decorado (el que se pasa en el constructor del decorador) es nulo.
supongo que tal vez algún otro código de algún otro comportamiento está poniendo otra IOperationInvoker en el OperationDispatcher.Invoker poniendo a continuación. Por lo tanto, anulando el mío. Esto explicaría claramente mi situación.
¿Qué está pasando y qué debo hacer?
Mi servicio es de alojamiento.
En caso de que necesite verlo, aquí está la configuración que tengo en el archivo app.config en system.serviceModel.
<services>
<service name="BookSmarTk.Web.Service.BookSmarTkService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/service"/>
</baseAddresses>
</host>
<endpoint
address=""
behaviorConfiguration="BookSmaTkEndpointBehavior"
binding="webHttpBinding"
bindingConfiguration="BookSmarTkBinding"
contract="BookSmarTk.Web.Service.BookSmarTkService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name ="BookSmartkServiceBehavior">
<serviceDebug httpHelpPageEnabled="true" httpHelpPageUrl="/help.htm" includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="BookSmaTkEndpointBehavior">
<!--<webHttp/>-->
<bookSmarTkEndpointBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="BookSmarTkBinding">
</binding>
</webHttpBinding>
</bindings>
<extensions>
<behaviorExtensions>
<add name="bookSmarTkEndpointBehavior" type="BookSmarTk.Web.Service.BookSmarTkEndpointBehaviorElement, BookSmarTk.Web.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
Léelo hasta aquí Estoy profundamente agradecido con usted. ¡De verdad gracias!
Este solución trabajó conmigo +1 –