Personalizzare le istanze di un servizio WCF

di Cristian Civera, in Windows Communication Foundation,

Windows Communication Foundation è un framework che basa il suo funzionamento principalmente in base a tre pilastri: address, binding e contract. I primi due si identificano nell'endpoint e nel mezzo trasporto (HTTP, TCP, ecc) che si intende utilizzare configurandolo da codice o tramite file .config. Il contratto invece, definito partendo dal WSDL o da codice, trova corrispondenza in un'interfaccia .NET con i metodi corrisponendi alle operazioni che si intendono esporre tramite servizio.

Quando quest'ultimo viene richiamato, il motore di WCF necessita di instanziare una classe che implementi tale interfaccia per poter invocare su di esso il metodo richiesto, passare i parametri e ricevere il valore di ritorno. Solitamente tale classe è specificata tramite il tipo indicato nel file .config o nel costruttore del ServiceHost e il motore provvede ad istanziarla secondo le indicazioni che è possibile dare con l'attributo ServiceBehavior ed in particolare con la proprietà InstanceContextMode. Il comportamento predefinito prevede comunque di istanziare ad ogni richieta tale classe, facendola morire non appena terminata l'elaborazione.

E' possibile personalizzare questo comportamento fornendo un'implementazione dell'interfaccia IInstanceProvider che prevede principalmente due metodi per restituire un'istanza o rilasciarla.

public class MyInstanceProvider : IInstanceProvider
{

  #region IInstanceProvider Members

  public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
  {
    return new MyService();
  }

  public object GetInstance(InstanceContext instanceContext)
  {
    return GetInstance(instanceContext, null);
  }

  public void ReleaseInstance(InstanceContext instanceContext, object instance)
  {
    // Rilascio l'istanza
  }

  #endregion
}

E' possibile trarre vantaggio da questa interfaccia ad esempio per sfruttare motori di IoC o AOP per restituire un'instanza in modo dinamico, risolvendola con tali motori o generando classi proxy per supportare ad esempio il logging.
Definito il provider è necessario comunque indicare dove usarlo indicando ad ogni DispatchRuntime di usarlo. Per farlo vi sono varie strade tra cui sfruttare un custom service behavior o un contract behavior. Ecco un esempio di come creare un contract behavior applicabile sul contratto.

public class MyBehaviorAttribute : Attribute, IContractBehaviorAttribute, IContractBehavior
{

  #region IContractBehaviorAttribute Members

  public Type TargetContract
  {
    get { return typeof(IMyService); }
  }

  #endregion

  #region IContractBehavior Members

  public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection parameters)
  {
    return;
  }

  public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
    return;
  }

  public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
  {
    // Imposto il mio instance provider ad ogni servizio a cui viene applicato l'attributo
    dispatch.InstanceProvider = new MyInstanceProvider();
  }

  public void Validate(ContractDescription description, ServiceEndpoint endpoint)
  {
    return;
  }

  #endregion
}

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi