WCF – Interception des operations – comment rajouter du code lors de l’appel de méthode WCF – IOperationBehavior et IOperationInvoker
Lorsque l’on utilise WCF, dans certains cas, on aimerait pouvoir exécuter du code lorsque certaines méthodes sont appelées.
J’ai récemment eu ce besoin. Je travaillais sur un “Ajax-enabled WCF service” accessible depuis JavaScript. Pour différentes raisons j’utilisais l’attribut [WebGet] afin que les méthodes soient directement disponible via la méthode GET.
Malheureusement, lorsque je debuggais mon service, mes appels étaient mis en cache par le client, je devais donc vider mon cache afin de pouvoir rappeler mes méthodes. J’ai donc décidé de rajouter le code suivant au niveau de mes méthodes :
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
Mes appels n’étaient alors plus mis en cache!
Cependant je ne trouvais pas cette solution très élégante. J’ai donc cherché une solution me permettant d’intercepter tous les appels à mes méthodes.
Je me suis tourné vers la création d’un attribut implémentant IOperationBehavior. Cette interface possède 4 méthodes :
-
AddBindingParameters méthode permettant d’envoyer des données personnalisées aux bindings lors de l’exécution.
-
ApplyClientBehavior méthode permettant de modifier, examiner ou insérer des extensions lors de l'exécution de l’opération du côté du client.
==> on utilise cette méthode lorsque l’on veut faire un Behavior qui s’exécutera coté client.
-
ApplyDispatchBehavior : méthode permettant de modifier, examiner ou insérer des extensions dans l'exécution de l’opération du côté du service.
==> on utilise cette méthode lorsque l’on veut faire un Behavior qui s’exécutera coté serveur.
-
Validate pour confirmer qu'un OperationDescription remplit les conditions requises. Elle permet d'assurer qu'une opération dispose d'un certain paramètre de configuration activé, qu'elle prend en charge une fonctionnalité particulière et d'autres spécifications.
Ces méthodes seront appelées seulement lors de la création du service. Afin d’avoir la main sur l’exécution de chaque méthode/opération nous devons créer notre propre inspector. Nous allons pour cela créer une classe implémentant IParameterInspector.
Cette interface possède 2 méthodes aux noms explicites : AfterCall et BeforeCall.
Voici l’implémentation de mon OperationBehavior :
public class PouetAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(OperationDescription operationDescription,
ClientOperation clientOperation)
{ }
public void ApplyDispatchBehavior(OperationDescription operationDescription,
DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(new PouetInspector());
}
public void Validate(OperationDescription operationDescription)
{
IOperationBehavior webGetOperationBehavior = operationDescription.Behaviors
.FirstOrDefault(operationBehavior => operationBehavior is WebGetAttribute)
as WebGetAttribute;
if (webGetOperationBehavior == null)
throw new NotSupportedException("WebGetAttribute is required for PouetAttribute");
}
}
Ainsi que l’implémentation de mon ParameterInspector
public class PouetInspector : IParameterInspector
{
public void AfterCall(string operationName, object[] outputs,
object returnValue, object correlationState)
{
if (HttpContext.Current != null)
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
}
public object BeforeCall(string operationName, object[] inputs)
{
return null;
}
}
Ainsi, au niveau de mon service, il ne me reste plus qu’a décorer ma méthode de l’attribut Pouet.
[Pouet]
[WebGet]
[OperationContract]
public String Hello(String s)
{
// won't stay in client cache
return s + " - " + DateTime.Now.ToLongTimeString();
}
Nous avons vus comment se greffer à l’appel de nos operations via un ParameterInspector. Les méthodes BeforeCall et AfterCall nous renseignent également sur les paramètres envoyés à notre opération ainsi que son retour. Il n’est cependant pas possible de faire des modifications. Un inspecteur ne permet que d’analyser, regarder, ce qu’il se passe. Si l’on souhaite modifier le comportement de l’opération, il faut alors passer par un OperationInvoker.