Sto cercando di estendere WCF in modo che possa avere un servizio web RESTful, nel quale, per ogni operazione, eseguo una verifica dell'intestazione dell'autorizzazione HTTP, il cui valore utilizzo per chiamare un metodo Login().Quando e dove impostare un IOperationInvoker personalizzato?
Dopo il login è fatto, desidero richiamare il metodo corrispondente dell'operazione controllare se un'eccezione di protezione viene lanciata, nel qual caso vi risponderò con un costume "Accesso negato" messaggio" utilizzando il codice di stato HTTP appropriata.
Con questo in mente, ho pensato che l'attuazione di un IEndpointBehavior che applica un implementaion di IOperationInvoker per ogni operazione (impostando la proprietà DispatchOperation.Invoker) sarebbe una buona idea.
ho deciso di implementare un IOperationInvoker con il design Decorator La mia implementazione necessiterebbe di un altro IOperationInvoker nel suo costruttore a cui le chiamate di metodo sarebbero delegate .
Questo è il mio 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;
}
}
}
ho deciso di implementare un IEndpointBehavior estendendo il comportamento che già serviva (WebHttpBehavior) in questo modo io uso un solo beavior. Ecco il codice che ho scritto:
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.");
}
}
Ora qui è il problema:
- Solo il costruttore viene richiamato nel IOperationInvoker, nessuno degli altri metodi sono.
- Il decoratore IOperationInvoker (quello che è passato nel costruttore del decoratore) è null.
Sto indovinando che forse qualche altro codice da qualche altro comportamento sta creando un'altra IOperationInvoker nel OperationDispatcher.Invoker impostazione in seguito. Quindi, scavalcando il mio. Questo spiegherebbe chiaramente la mia situazione.
Cosa sta succedendo e cosa dovrei fare?
Il mio servizio è auto-ospitato.
Nel caso in cui sia necessario vederlo, ecco la configurazione che ho nel file app.config in 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>
Ho letto fino a qui e sono profondamente grato a voi. Grazie davvero!
Questo la soluzione ha funzionato con me +1 –