<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>WCF</title>
        <link>http://blogs.ugidotnet.org/dsantarelli/category/WCF.aspx</link>
        <description>WCF</description>
        <language>it-IT</language>
        <copyright>Dario Santarelli</copyright>
        <generator>Subtext Version 2.6.0.0</generator>
        <item>
            <title>[WCF 4.0] Default Endpoints</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2011/02/19/wcf-4.0-default-endpoints.aspx</link>
            <description>Un’ approccio introdotto in WCF 4.0 è la “Convention Over Configuration”. Sostanzialmente essa permette di assegnare una configurazione predefinita ad un endpoint in assenza di una configurazione esplicita (cosa impossibile in WCF 3.x). Ciò avviene tramite la definizione di un mapping tra lo schema/protocollo (es. http, tcp etc.) e le varie tipologie di binding (es. BasicHttpBinding, NetTcpBinding etc.) all’interno del file:     
%WINDIR%\Microsoft.NET\Framework\v4.0.30319\Config\machine.config.comments 

     &amp;lt;protocolMapping&amp;gt;                    
         &amp;lt;clear /&amp;gt;                    
         &amp;lt;add scheme="http" binding="basicHttpBinding" bindingConfiguration="" /&amp;gt;                        
         &amp;lt;add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration="" /&amp;gt;                        
         &amp;lt;add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration="" /&amp;gt;                        
         &amp;lt;add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration="" /&amp;gt;                        
&amp;lt;/protocolMapping&amp;gt;

Volendo verificare la cosa, creiamo un’ interfaccia di prova
[ServiceContract]       
public interface IDummyService       
{       
   [OperationContract(IsOneWay=true)]       
   void DoNothing();          
}

Puntualizziamo il fatto che la scelta di impostare l’operation contract come “OneWay” deriva dal fatto che un contratto esposto da un endpoint che utilizza NetMsmqBinding può supportare solo operazioni one-way. Implementiamo quindi l’interfaccia IDummyService...
public class MyDummyService : IDummyService         
{         
   public void DoNothing() { }        
}
     
Costruiamo un test per verificare quanto asserito, ponendo attenzione a non specificare alcuna configurazione per gli endpoint:
ServiceHost host = new ServiceHost(typeof(MyDummyService),       
                                   new Uri("http://localhost:8080/MyDummyService"),       
                                   new Uri("net.tcp://localhost:8081/MyDummyService"),       
                                   new Uri("net.pipe://localhost/MyDummyService"),       
                                   new Uri("net.msmq://localhost/private/MyDummyService"));                        
host.Open();             
        
Assert.AreEqual(4, host.Description.Endpoints.Count);             
Assert.IsTrue(host.Description.Endpoints[0].Binding is BasicHttpBinding);       
Assert.IsTrue(host.Description.Endpoints[1].Binding is NetTcpBinding);       
Assert.IsTrue(host.Description.Endpoints[2].Binding is NetNamedPipeBinding);    
Assert.IsTrue(host.Description.Endpoints[3].Binding is NetMsmqBinding);

Verde!    
Ovviamente, se ne abbiamo la necessità, possiamo effettuare l’override di questi mappings sia a livello di machine che a livello di application. Ad esempio, se specificassimo la seguente configurazione nell’app.config…
&amp;lt;configuration&amp;gt;    
  &amp;lt;system.serviceModel&amp;gt;         
    &amp;lt;protocolMapping&amp;gt;         
      &amp;lt;add scheme="http" binding="webHttpBinding"/&amp;gt;         
    &amp;lt;/protocolMapping&amp;gt;         
  &amp;lt;/system.serviceModel&amp;gt;         
&amp;lt;/configuration&amp;gt;

…il test precedente fallirebbe poiché lo schema http è stato assegnato al WebHttpBinding e non più al BasicHttpBinding. Invece, il seguente test avrebbe successo
ServiceHost host = new ServiceHost(typeof(MyDummyService),new Uri("http://localhost:8080/MyDummyService"));       
host.Open();       
Assert.IsTrue(host.Description.Endpoints[0].Binding is WebHttpBinding);

Per avere più informazioni riguardo al funzionamento di questa feature e delle altre novità di WCF 4.0 rimando a questo link MSDN:    
http://msdn.microsoft.com/en-us/library/ee354381.aspx (A Developer's Introduction to Windows Communication Foundation 4)
Tag di Technorati: WCF&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/99741.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2011/02/19/wcf-4.0-default-endpoints.aspx</guid>
            <pubDate>Sat, 19 Feb 2011 17:34:24 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2011/02/19/wcf-4.0-default-endpoints.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/99741.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/99741.aspx</trackback:ping>
        </item>
        <item>
            <title>[WCF] IOperationBehavior e IParameterInspector</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/24/wcf-ioperationbehavior-e-iparameterinspector.aspx</link>
            <description>Dal punto di vista della flessibilità, ritengo che WCF sia una delle tecnologie più potenti attualmente disponibili per lo sviluppo di applicazioni orientate ai servizi. In particolare, una delle caratteristiche che apprezzo maggiormente è la facilità di personalizzazione del comportamento runtime degli OperationContract sia client-side che service-side ( pratica per altro molto usata nel WCF REST Starter Kit :D ). 
In questo post volevo soffermarmi proprio su questo aspetto, mostrando un semplice esempio di implementazione dell’interfaccia IOperationBehavior, che per l'appunto definisce quattro metodi finalizzati all'estensione del runtime behavior di un'operation: 

    AddBindingParameters : serve per aggiungere nuovi elementi di binding utilizzabili dall'operation in fase di esecuzione.  
    ApplyClientBehavior : viene chiamato client-side 
    
        prima che il contenuto della richiesta sia serializzato e inviato al service 
        dopo che la risposta è stata deserializzata ma prima che i valori restituiti vengano forniti al metodo proxy 
    
    
    ApplyDispatchBehavior : viene chiamato service-side dopo la deserializzazione dei parametri, ma prima che essi siano forniti all'operation del service. 
    Validate : permette di verificare che l'operation soddisfi dei criteri custom ( es. autorizzazioni ). 

Vediamo ora una semplice implementazione che mette in evidenza come sia veramente semplice agganciare un OperationBehavior ad un OperationContract  tramite un attributo. Gli ambiti di applicazione sono veramente tanti: ad esempio potremmo usare questa tecnica service-side per eseguire della logica custom prima e dopo l’invocazione di un’operation da parte di un client. Nello specifico, supponiamo di voler scrivere in un file di log sul server sia i parametri di input passati all'operation che il risultato dell'invocazione. Per ottenere questo scenario necessitiamo anzitutto della definizione di un oggetto che sia in grado di ispezionare i parametri dell'operation sia prima che dopo la chiamata: in altre parole abbiamo bisogno di un IParameterInspector. Questa interfaccia definisce due metodi, BeforeCall(…) e AfterCall(…), che ci permettono di inserire della logica custom ( sempre sia client-side che service-side ) per accedere alle informazioni inerenti una operation ed i relativi parametri di input/output nelle fasi immediatamente precedenti e successive all’invocazione. 
Partiamo dunque dal nostro IParameterInspector: 
public class ParameterLogInspector : IParameterInspector 
{ 
   private FileInfo _logFileInfo; 

   public ParameterLogInspector(string fileName) 
   { 
     _logFileInfo = new FileInfo(fileName); 
     if (!_logFileInfo.Exists) _logFileInfo.Create();       
   } 

   #region IParameterInspector Members 
   
   public object BeforeCall(string operationName, object[] inputs) 
   { 
     StringBuilder sb = new StringBuilder(); 
     foreach (object input in inputs) sb.AppendFormat("{0};", input.ToString()); 
     this.Log(string.Format("Operation \"{0}\" is calling... inputs: {1}", operationName, sb.ToString())); 
     return null; 
   }        


   public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) 
   { 
     this.Log(string.Format("Operation \"{0}\" called. returnValue: {1}",operationName,returnValue.ToString()));             
   } 
   
   #endregion 

   private void Log(string message) 
   { 
     using (StreamWriter sw = _logFileInfo.AppendText()) 
     { 
       sw.WriteLine(string.Format("{0}&amp;gt; {1}", DateTime.Now.ToString(), message)); 
     } 
   } 
}

Quindi, ci posizioniamo all'interno del metodo ApplyDispatchBehavior(...) semplicemente per aggiungere il nostro IParameterInspector alla collection ParameterInspectors dell'oggetto DispatchOperation (che rappresenta l'operation service-side) : 

public class ParametersLog : Attribute, IOperationBehavior 
{ 
  public string FileName { get; set; } 

  #region IOperationBehavior Members 

  ... 

  public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
  { 
   dispatchOperation.ParameterInspectors.Add(new ParameterLogInspector(this.FileName)); 
  } 

  ... 
  
  #endregion 
} 

Il gioco è fatto: non rimane che decorare l'OperationContract di interesse con il nostro attributo ParametersLog per ottenere l' estensione del runtime che ad ogni chiamata scriverà in un file di log i valori dei parametri di input/output .

[ServiceContract] 
public interface IAuthentication 
{ 
  [OperationContract] 
  [ParametersLog(FileName="C:/log.txt")] 
  UserInfo Login(string userName, string password); 

  [OperationContract] 
  void Logout(string userName); 
} 


Technorati Tag: WCF &lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/95538.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/24/wcf-ioperationbehavior-e-iparameterinspector.aspx</guid>
            <pubDate>Tue, 24 Feb 2009 16:02:08 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/24/wcf-ioperationbehavior-e-iparameterinspector.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/95538.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/95538.aspx</trackback:ping>
        </item>
        <item>
            <title>[WCF] Operazioni asincrone client-side</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/10/wcf-operazioni-asincrone-client-side.aspx</link>
            <description>WCF è un framework concepito per sviluppare scenari di comunicazione completamente disaccoppiati sotto ogni punto di vista. In particolare, per quanto riguarda la sincronizzazione dei messaggi, è prevista internamente una rigida implementazione di pattern asincroni per ottenere chiamate non bloccanti tra i vari livelli strutturali. Esternamente, invece, WCF espone possibilità di programmazione asincrona sia client-side che server-side. L'aspetto interessante da approfondire in merito è come il programming model asincrono client-side non abbia nulla a che vedere con quello server-side: ovvero, un client può sostanzialmente invocare in modo asincrono un servizio indipendentemente dal fatto che esso sia implementato con un pattern sincrono piuttosto che asincrono.    Il disaccoppiamento avviene infatti a livello di trasporto quando i dati vengono serializzati/deserializzati.     Per capire l’importanza di tale feature pensiamo semplicemente ad un’ architettura N-tier che poggia su WCF: potremmo avere diverse “operation” che a loro volta utilizzano proxy client verso altre operation WCF, rendendo vitale l’utilizzo di pattern di comunicazione asincroni.  Vediamo un semplice esempio. Supponiamo di avere il seguente ServiceContract:         [ServiceContract]      public interface IAuthentication       {       [OperationContract]        UserInfo Login(string username, string password);                  [OperationContract]        void Logout(string username);      }           Se lato client utilizzassimo Svcutil ( con gli opportuni parametri ) o il solito “Add Service Reference” di VisualStudio, otterremmo la generazione automatica del seguente object model:              Come si può osservare abbiamo una versione asincrona client-side del ServiceContract (IAuthentication), un' interfaccia &amp;lt;ServiceContract&amp;gt;Channel (IAuthenticationChannel) ed una classe Client (AuthenticationClient) che espone metodi di invocazione sia asincroni che sincroni. Nello specifico, si prospettano due possibili modalità di invocazione asincrona client-side di un’ operation:   1. Invocazione asincrona “event-based” (o “event-driven”)  E' la modalità più semplice e raccomandata poiché richede solamente l’aggiunta di un EventHandler per ricevere una notifica all’occorrenza di una risposta. Questa modalità ( disponibile solo nel framework 3.5 e comunque solo per questo tipo di invocazione ) permette di sfruttare l’approccio asincrono event-based tramite un metodo nella forma &amp;lt;operationName&amp;gt;Async e l’intercettazione di un evento &amp;lt;operationName&amp;gt;Completed al cui interno si ha accesso al risultato dell’invocazione &amp;lt;operationName&amp;gt;CompletedEventArgs.        ...           ServiceReference.AuthenticationClient client = new ServiceReference.AuthenticationClient();      client.LoginCompleted += new EventHandler&amp;lt;ServiceReference.LoginCompletedEventArgs&amp;gt;(client_LoginCompleted);      client.LoginAsync("dario.santarelli", "password");            Console.ReadLine();            client.Close();           ...  protected void client_LoginCompleted(object sender, ServiceReference.LoginCompletedEventArgs e)      {       UserInfo info = e.Result as UserInfo;        Console.WriteLine(string.Format("UserName: {0} - Password: {1}",info.UserName,info.Email));      }               2. Invocazione asincrona via ChannelFactory    Il pattern asincrono previsto in questa modalità è quello classico previsto a partire dal framework 1.1: tramite lo split di un operation in due metodi ( Begin&amp;lt;operationName&amp;gt; e End&amp;lt;operationName&amp;gt; ), si sfruttano oggetti che implementano l’interfaccia System.IAsyncResult per rappresentare lo stato di una operazione asincrona.  ...     EndpointAddress endpointAddress = new EndpointAddress("http://.../AuthenticationService.svc");      ServiceReference.IAuthenticationChannel channelClient = ChannelFactory&amp;lt;ServiceReference.IAuthenticationChannel&amp;gt;.CreateChannel(new BasicHttpBinding(), endpointAddress);      IAsyncResult result = channelClient.BeginLogin("dario.santarelli", "password", LoginCallBack, channelClient);            Console.ReadLine();            channelClient.Close();     channelClient.Dispose();            ...           protected void LoginCallBack(IAsyncResult ar)      {       UserInfo result = ((ServiceReference.IAuthenticationChannel)ar.AsyncState).EndLogin(ar);        Console.WriteLine("Result: {0}", result.UserName);      }             Conclusioni    In entrambe le soluzioni presentate, una nostra application può invocare un’operazione in maniera asincrona anche se il servizio è implementato in maniera sincrona, allo stesso modo con cui una applicazione può usare lo stesso pattern per invocare in maniera asincrona un metodo sincrono locale. “Come” è poi implementato l’ OperationContract è assolutamente insignificante per il client.     Risorse MSDN:     Synchronous and Asynchronous Operations    How to: Call WCF Service Operations Asynchronously    How to: Call Operations Asynchronously Using a Channel Factory      Technorati Tag: WCF,Async&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/95433.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/10/wcf-operazioni-asincrone-client-side.aspx</guid>
            <pubDate>Tue, 10 Feb 2009 00:24:15 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2009/02/10/wcf-operazioni-asincrone-client-side.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/95433.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/95433.aspx</trackback:ping>
        </item>
        <item>
            <title>[WCF] Esempio di Integration Test</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/31/wcf-esempio-di-integration-test.aspx</link>
            <description>Esistono molti strumenti e tecniche per effettuare un integration test di servizi WCF. Un modo che ho trovato molto semplice ed utile si ottiene sruttando il framework di unit testing di Visual Studio: infatti, utilizzando due metodi decorati rispettivamente con ClassInitialize e ClassCleanup possiamo gestire il ciclo di vita di un ServiceHost, evitando così il deploy preventivo (es. Cassini, IIS etc.) del servizio.     Nel seguente esempio viene mostrata questa tecnica supponendo di voler testare un servizio di autenticazione AuthenticationService che implementa un service contract IAuthentication, il quale definisce due metodi: Login(…) e Logout().                [TestClass]       public class AuthenticationUnitTest        {        private static ServiceHost _serviceHost;         private static string _address = "AuthenticationService";         private static string _baseAddress = "http://127.0.0.1:5656/";              [ClassInitialize]         public static void ServiceHostInitialize(TestContext testContext)         {          _serviceHost = new ServiceHost(typeof(AuthenticationService), new[] { new Uri(_baseAddress) });           _serviceHost.AddServiceEndpoint(typeof(IAuthentication), new WSHttpBinding(), _address);           _serviceHost.Open();        }              [ClassCleanup]         public static void ServiceHostCleanup() { _serviceHost.Close(); }               [TestMethod]         public void AuthenticateUser()         {          string userName = "dario.santarelli";           string password = "password";                 EndpointAddress endpointAddress = new EndpointAddress(string.Format("{0}{1}", _baseAddress,_address));           IAuthentication proxy = ChannelFactory&amp;lt;IAuthentication&amp;gt;.CreateChannel(new WSHttpBinding(), endpointAddress);                 UserInfo userInfo = proxy.Login(userName, password);                 Assert.IsNotNull(userInfo);           Assert.AreEqual(userInfo.Username, userName);                 proxy.Logout(userName);               }      }     Update: con questa tecnica non si intende sostituire il test in ambiente di produzione, bensì fornire un modo “base” per verificare il funzionamento di una WCF Service Library. Infatti, come si può notare, in questo caso sia lo UnitTest che il ServiceHost girano nello stesso AppDomain, il che NON garantisce by design il corretto comportamento del test come se fosse in produzione. Per avere test maggiormente efficaci, si consiglia l’utilizzo di soluzioni più “evolute” come WcfSvcHost o, meglio, direttamente un ambiente di test dedicato su IIS :D.         Technorati Tag: WCF,Testing&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/95355.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/31/wcf-esempio-di-integration-test.aspx</guid>
            <pubDate>Sat, 31 Jan 2009 17:22:29 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/31/wcf-esempio-di-integration-test.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/95355.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/95355.aspx</trackback:ping>
        </item>
        <item>
            <title>[WCF] Web Caching con WCF REST Starter Kit</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/10/wcf-web-caching-con-wcf-rest-starter-kit.aspx</link>
            <description>Il WCF REST Starter Kit rende disponibile tra le varie utility anche una semplice soluzione per abilitare il web caching per WCF sfruttando l'interazione con la proprietà HttpResponse.Cache di ASP.NET. La soluzione si basa sull'utilizzo di un attributo WebCache con cui decorare i nostri OperationContract che sono suscettibili a meccanismi di caching secondo una specifica profilatura. L'attributo è definito all'interno della library Microsoft.ServiceModel.Web.dll fornita con il Kit. Vediamo nel dettaglio i vari aspetti di utilizzo aiutandoci con un semplice esempio: la pubblicazione di un feed RSS 2.0 che gestisca un meccanismo di caching web in base al numero di item richiesti (es. 10, 20 etc.. ).    Supponiamo di avere un ServiceContract come il seguente:          [ServiceContract(SessionMode=SessionMode.NotAllowed, ProtectionLevel=ProtectionLevel.None)]      public interface IServiceRSS       {       [WebCache(CacheProfileName = "RssCacheDefault")]          [WebGet(UriTemplate = "?numItems={num}")]        [OperationContract]        Rss20FeedFormatter GetRss20(int num);                }              Notiamo subito la presenza dell'attributo WebCache la cui proprietà CacheProfileName serve per specificare il nome della nostra profilatura di caching (es. "RssCacheDefault"). Il comportamento di caching è configurabile sia valorizzando da codice le proprietà dell'attributo WebCache (vedi figura sotto) che dichiarativamente nella sezione outputCacheProfiles di ASP.NET.  Qua sotto viene riportato un esempio di configurazione per il nostro l'esempio.         &amp;lt;system.web&amp;gt;       &amp;lt;caching&amp;gt;         &amp;lt;outputCacheSettings&amp;gt;           &amp;lt;outputCacheProfiles&amp;gt;             &amp;lt;clear/&amp;gt;             &amp;lt;add name="RssCacheDefault" duration="60" enabled="true" location="ServerAndClient" varyByParam="numItems"/&amp;gt;             &amp;lt;/outputCacheProfiles&amp;gt;         &amp;lt;/outputCacheSettings&amp;gt;     &amp;lt;/caching&amp;gt;     ...     &amp;lt;/system.web&amp;gt;        ...      &amp;lt;system.serviceModel&amp;gt;        &amp;lt;serviceHostingEnvironment aspNetCompatibilityEnabled="true"/&amp;gt;           &amp;lt;services&amp;gt;          &amp;lt;service name="TestCachingApp.SampleServiceRSS" behaviorConfiguration="SampleServiceRSSBehavior" &amp;gt;               &amp;lt;endpoint address="" binding="webHttpBinding" contract="TestCachingApp.IServiceRSS"&amp;gt;&amp;lt;/endpoint&amp;gt;                ...               &amp;lt;/service&amp;gt;        &amp;lt;/services&amp;gt;       ...  &amp;lt;/system.serviceModel&amp;gt;        E' importante notare come occorra abilitare la compatibilità dell'ambiente di hosting del servizio WCF con ASP.NET, impostando a "true" l'attributo aspNetCompatibilityEnabled del tag serviceHostingEnvironment.        A questo punto il gioco è fatto!  Nell'implementazione del nostro servizio dobbiamo porre attenzione ad impostare la compatibilità con ASP.NET mediante l'attributo AspNetCompatibilityRequirements :       [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]      [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single,                       ConcurrencyMode = ConcurrencyMode.Single)]      public class SampleServiceRSS : IServiceRSS       {          public Rss20FeedFormatter GetRss20(int num)        {         SyndicationFeed feed = new SyndicationFeed("Title: ...", "Description: ...", new Uri("http://tempuri.org"));          ...         // Initialize the feed with 'num' items          ...          return new Rss20FeedFormatter(feed);               }        }      Poiché l'uso di un meccanismo di caching costituisce una prassi ormai ordinaria nei vari paradigmi di programmazione Web, questo tipo di soluzione che integra la Web Cache di ASP.NET all'interno di WCF costituisce sicuramente un vantaggio significativo soprattutto per motivi pratici. Sebbene esistano scenari che richiedono soluzioni di natura diversa (es. Enterprise Library Caching Block :D ), questo approccio può risolvere elegantemente i casi più comuni.  Behind the Scenes  Per chi fosse interessato ad approfondire l'argomento riporto alcune note secondo me interessanti.   L'attributo WebCache è implementato come un operation behavior di WCF ed implementa l'interfaccia IOperationBehavior. Il trucco si trova nell'implementazione del metodo ApplyDispatchBehavior di tale interfaccia: ogni volta che a run-time viene invocato un metodo decorato con l'attibuto WebCache, il nostro eventuale profilo di caching (ovvero un oggetto di tipo Systen.Web.Configuration.OutputCacheProfile) viene passato ad un' istanza di una classe utility del kit: CachingParameterInspector (che implementa IParameterInspector). Questa classe in pratica non fa altro che provvedere alla configurazione della proprietà HttpContext.Current.Response.Cache.     L'aspetto interessante si trova proprio a questo punto: la classe CachingParameterInspector creata viene aggiunta alla collection di ParameterIspector dell' oggetto DispatchOperation passato in input come argomento del metodo. In questo modo il runtime scatenerà l'esecuzione degli algoritmi di caching all'interno dell'infrastruttura di ASP.NET secondo la nostra eventuale profilatura.           Technorati Tag: WCF,ASP.NET,RSS,Caching&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/95153.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/10/wcf-web-caching-con-wcf-rest-starter-kit.aspx</guid>
            <pubDate>Sat, 10 Jan 2009 17:16:28 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2009/01/10/wcf-web-caching-con-wcf-rest-starter-kit.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/95153.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/95153.aspx</trackback:ping>
        </item>
        <item>
            <title>WCF REST Starter Kit</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2008/11/05/wcf-rest-starter-kit.aspx</link>
            <description>Da pochi giorni ho iniziato a studiare il WCF REST Starter Kit, un insieme veramente completo di di feature, template Visual Studio ed esempi pratici per realizzare servizi WCF in stile REST . 
Niente di nuovo per chi sguazza già da (molto) tempo nel mondo REST... tuttavia devo dire che è stata apportata una graditissima semplificazione dell'utilizzo delle potenzialità di WCF su HTTP (es. caching, conditional PUT...) nonché una maggiore produttività relativamente a servizi sempre più comuni come Atom feed/Publishing Protocol.
Per chi fosse interessato all'argomento, consiglio la lettura di questo bellissimo articolo: A Guide to Designing and Building RESTful Web Services with WCF 3.5.

Buona lettura :)





Technorati Tag: WCF,REST

&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/94528.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2008/11/05/wcf-rest-starter-kit.aspx</guid>
            <pubDate>Wed, 05 Nov 2008 19:25:24 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2008/11/05/wcf-rest-starter-kit.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/94528.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/94528.aspx</trackback:ping>
        </item>
        <item>
            <title>[WCF] Inviare e ricevere messaggi POX</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2008/07/20/wcf-inviare-e-ricevere-messaggi-pox.aspx</link>
            <description>Nel framework 3.5 abbiamo il supporto diretto all'implementazione di servizi POX all'interno di WCF. In questo post intendo dunque mostrare come generare e trasmettere messaggi "plain old XML" (ovvero costituiti esclusivamente da un payload XML) utilizzando il programming model messo a disposizione da WCF.    Domanda: quando si ha bisogno di inviare/ricevere messaggi POX?     Risposta: quando i client non supportano nativamente protocolli basati su SOAP oppure quando è richiesto un "leggero" scambio di dati via HTTP senza alcun requisito relativo a standard come WS-* (es. invio di un semplice feed RSS). In aggiunta, un'infrastruttura POX/HTTP costituisce la base naturale per l'implementazione di applicazioni Web REST-ful (es. il client invia una richiesta HTTP del tipo "GET http://.../customers/39" e il service risponde con un semplice documento POX contenente le informazioni di un customer).    Vediamo dunque come realizzare un semplice scenario client-server WCF per lo scambio di messaggi POX su HTTP:  Service  Partiamo da un contratto ICustomerService di esempio, che prevede un solo metodo ProcessMessage:   [ServiceContract]       public interface ICustomerService        {        [OperationContract(Action = "*", ReplyAction = "*", IsOneWay=false, ProtectionLevel=System.Net.Security.ProtectionLevel.None)]          Message ProcessMessage(Message request);       }     Consideriamo immediatamente due aspetti:     Nel contesto di default di WCF, gli attributi Action e ReplyAction servono per impostare rispettivamente l'azione WS-Addressing del messaggio di richiesta e l'azione SOAP relativa al messaggio di risposta. Infatti, per default WCF utilizza le azioni specificate nell'header SOAP per elaborare correttamente i messaggi scambiati tra client e service. Nel nostro caso, la "wildcard action" (*) bypassa questo comportamento e permette quindi il dispatch di un qualunque messaggio ricevuto dell'endpoint del servizio verso il nostro metodo ProcessMessage.     Sia l'argomento che il valore restituito dal metodo ProcessMessage sono degli oggetti di tipo System.ServiceModel.Channels.Message, una nuova astrazione che ci permette di creare e manipolare messaggi "raw", nonostante essa rappresenti nativamente una busta SOAP a tutti gli effetti.    Tutto diventa più chiaro se osserviamo l'implementazione del servizio: la classe CustomerService elabora una richiesta POX in ingresso e restituisce un Message contenente dati XML relativi ad un Customer.  public class CustomerService : ICustomerService       {        public Message ProcessMessage(Message request)         {                XmlDictionaryReader reader = request.GetReaderAtBodyContents();           string customerID = reader.ReadElementContentAsString();                                       Customer customer = GetCustomerById(customerID);           Message response = Message.CreateMessage(MessageVersion.None, "*", new CustomerInfoBodyWriter(true, customer));           return response;         }        }          Per creare un messaggio POX specifico per le nostre esigenze utilizzando la classe Message, abbiamo semplicemente bisogno di invocarne il metodo statico CreateMessage, il quale possiede diversi overload a supporto del trasferimento in modalità sia push che pull. In questo caso è stato usato l'overload "push-mode" che si avvale di un BodyWriter custom ottenuto ereditando la classe base astratta, in modo da avere il pieno controllo sulla creazione del messaggio POX da inviare al client tramite l'override del metodo OnWriteBodyContents.          public class CustomerInfoBodyWriter : BodyWriter        {        private Customer _customer;           public CustomerInfoBodyWriter(bool isBuffered, Customer customer) : base(isBuffered)         {            _customer = customer;         }               protected override void OnWriteBodyContents(XmlDictionaryWriter writer)         {          writer.WriteStartElement("CustomerInfo");           writer.WriteAttributeString("id", _customer.ID);           writer.WriteAttributeString("name", _customer.Name);           writer.WriteAttributeString("email", _customer.Email);           writer.WriteEndElement();          writer.Flush();        }     }      Vediamo infine la configurazione dell'endpoint, che si interfaccia con la rete tramite un customBinding che prevede la generazione di stream su HTTP facendo uso di un encoder che permette la ricezione e l'invio di messaggi POX privi di un qualunque incapsulamento SOAP (&amp;lt;textMessageEncoding messageVersion="None" /&amp;gt;).         &amp;lt;configuration&amp;gt;        &amp;lt;system.serviceModel&amp;gt;          &amp;lt;bindings&amp;gt;            &amp;lt;customBinding&amp;gt;               &amp;lt;binding name="poxBinding"&amp;gt;                    &amp;lt;textMessageEncoding messageVersion="None" /&amp;gt;              &amp;lt;httpTransport transferMode="StreamedResponse" maxBufferSize="1024" /&amp;gt;                  &amp;lt;/binding&amp;gt;            &amp;lt;/customBinding&amp;gt;           &amp;lt;/bindings&amp;gt;           &amp;lt;services&amp;gt;               &amp;lt;service name="SamplePOXService.CustomerService"&amp;gt;                    &amp;lt;host&amp;gt;                   &amp;lt;baseAddresses&amp;gt;                       &amp;lt;add baseAddress="http://localhost:4971/" /&amp;gt;                     &amp;lt;/baseAddresses&amp;gt;                  &amp;lt;/host&amp;gt;                  &amp;lt;endpoint address="customers" binding="customBinding"  bindingConfiguration="poxBinding"                                     contract="ServiceClassLibrary.ICustomerService" /&amp;gt;                  &amp;lt;/service&amp;gt;            &amp;lt;/services&amp;gt;          &amp;lt;/system.serviceModel&amp;gt;      &amp;lt;/configuration&amp;gt;     Client     Il client POX condivide ovviamente la stessa configurazione del servizio, in maniera tale che la richiesta generata sia anch'essa POX su HTTP. Ecco quindi un semplice esempio di client WCF che genera un Message POX di richiesta contenente un ID di un Customer e stampa quindi a video l'XML risultante dall'invocazione del servizio.         ChannelFactory&amp;lt;ICustomerService&amp;gt; channelFactory = new ChannelFactory&amp;lt;ICustomerService&amp;gt;("CustomerService_ClientEndPoint");       ICustomerService customer_service = channelFactory.CreateChannel();       string customerID = "1";       Message request = Message.CreateMessage(MessageVersion.None, "*", customerID);       Message response = customer_service.ProcessMessage(request);       XmlDictionaryReader reader = response.GetReaderAtBodyContents();            Console.WriteLine("{0}", reader.ReadOuterXml());            Console.ReadLine();  Analizzando il traffico generato per l'esempio proposto, si rileva che i messaggi scambiati sono effettivamente di dimensioni minime. Degna di nota è inoltre l'introduzione dell' xmlns nella generazione di default di un Message POX ottenuto tramite l'overload di CreateMessage che prevede il BodyWriter di default:        Request: &amp;lt;string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"&amp;gt;1&amp;lt;/string&amp;gt;     Response: &amp;lt;CustomerInfo id="1" name="Dario Santarelli" email="dario.santarelli@xxx.yy" /&amp;gt;  Come già anticipato all'inizio di questo post, l'utilizzo di un' infrastruttura POX/HTTP è consigliabile per:      soluzioni in cui i client non possiedono nativamente il supporto allo standard SOAP o comunque a protocolli non-HTTP     scenari in cui lo scambio dati deve essere il più leggero possibile ed in cui occorre aumentare sensibilmente le prestazioni del ciclo "request-response" (vedi AJAX).     implementazioni REST-ful    Chiaramente un esempio come quello mostrato non contempla affatto l'aspetto "security": HTTPS a parte, se si intende utilizzare POX/HTTP senza alcun meccanismo di autenticazione ed encryption dei dati, è comunque obbligatorio NON trasmettere messaggi contenenti dati sensibili.  Per maggiori informazioni, consiglio la lettura di questo articolo MSDN: REST and POX     Technorati tags: POX, REST, WCF&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/93466.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2008/07/20/wcf-inviare-e-ricevere-messaggi-pox.aspx</guid>
            <pubDate>Sun, 20 Jul 2008 15:25:24 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2008/07/20/wcf-inviare-e-ricevere-messaggi-pox.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/93466.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/93466.aspx</trackback:ping>
        </item>
        <item>
            <title>Cardspace e WCF: autenticazione claim-based</title>
            <link>http://blogs.ugidotnet.org/dsantarelli/archive/2008/03/17/cardspace-e-wcf-autenticazione-claim-based.aspx</link>
            <description>Partiamo da un concetto preliminare: WCF permette ad una applicazione sia client che server di richedere credenziali sia a livello di trasporto che di messaggio. In particolare, ecco le opzioni disponibili:

    Transport-Level: None, Basic, Digest, NTLM,  Windows, Certificate. 
    Message-Level: None, Username, Windows, IssuedToken, Certificate.

E' inutile precisare che il protocollo utilizzato per fornire credenziali deve essere poi abbinato opportunamente al tipo di binding previsto per lo scambio dei messaggi. Una volta stabilito il protocollo di autenticazione, bisogna stabilire il meccanismo di scambio di credenziali, che può avvenire sia programmaticamente (tramite la classe ClientCredentials del namespace System.ServiceModel.Description, esposta sia dal proxy del servizio che dal channel factory) che dichiarativamente da configurazione (sezione &amp;lt;serviceCredentials&amp;gt; ad esempio per specificare un certificato locale).
Passiamo ora a Windows Cardspace, un 'identity selector' introdotto a partire dal framework 3.0 per gestire più identità digitali per ciascun utente secondo uno schema claim-based. Come molti sapranno una 'Carspace information card' può essere personal o managed e definisce un insieme di claims rappresentati di default da token SAML 1.1. 
WCF integra CardSpace tramite WSFederationHttpBinding, un binding che permette di esporre servizi via HTTP facendo affidamento su token forniti da un identity provider. Le credenziali sono di tipo IssuedToken a livello di messaggio ed i parametri richiesti dal binding sono pressoché simili a quelli che si utilizzano all'interno dell' embedding nelle pagine web adibito all' attivazione del CardSpace identity selector.
Ecco un esempio di configurazione di un servizio WCF che richiede token SAML che includono obbligatoriamente i claim PPID (Private Personal Identifier) e email. Osserviamo inoltre come il servizio debba obbligatoriamente fornire un certificato per abilitare lo scambio sicuro di dati sensibili.
&amp;lt;system.serviceModel&amp;gt;  
 ...
 &amp;lt;bindings&amp;gt;
   &amp;lt;wsFederationHttpBinding&amp;gt;
     &amp;lt;binding name="ws_FederationHttpBinding"&amp;gt;
       &amp;lt;security mode="Message"&amp;gt;
         &amp;lt;message issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" 
                  negotiateServiceCredential="false" &amp;gt;
           &amp;lt;claimTypeRequirements&amp;gt;
             &amp;lt;add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" isOptional="false"/&amp;gt;
             &amp;lt;add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="false"/&amp;gt;
           &amp;lt;/claimTypeRequirements&amp;gt;
           &amp;lt;issuer address="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" /&amp;gt;
         &amp;lt;/message&amp;gt;
        &amp;lt;/security&amp;gt;
      &amp;lt;/binding&amp;gt;
    &amp;lt;/wsFederationHttpBinding&amp;gt;
   &amp;lt;/bindings&amp;gt;
   &amp;lt;behaviors&amp;gt;
     &amp;lt;serviceBehaviors&amp;gt;
       &amp;lt;behavior name="SecureServiceBehavior"&amp;gt;
         &amp;lt;serviceCredentials&amp;gt;
           &amp;lt;issuedTokenAuthentication allowUntrustedRsaIssuers="true" /&amp;gt;
           &amp;lt;serviceCertificate findValue="RPKey" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /&amp;gt;
         &amp;lt;/serviceCredentials&amp;gt;
        &amp;lt;/behavior&amp;gt;
      &amp;lt;/serviceBehaviors&amp;gt;
 &amp;lt;/behaviors&amp;gt;
&amp;lt;/system.serviceModel&amp;gt;

La proprietà allowUntrustedRsaIssuers impostata a "true" nella sezione &amp;lt;issuedTokenAuthentication&amp;gt; serve ad ammettere anche card di tipo personal, che generano token non-trusted, al contrario delle card managed. Lato client, la configurazione da utilizzare è pressoché identica, con la differenza che il client accede alla chiave pubblica utilizzata dal servizio per cifrare i messaggi. In questo aspetto, SvcUtil può velocizzare il nostro lavoro generando una vesione base-64 della chiave pubblica che possiamo quindi inserire nel file di configurazione evitando l'istallazione del certificato sullo store.
&amp;lt;system.serviceModel&amp;gt;
  &amp;lt;bindings&amp;gt;
    &amp;lt;wsFederationHttpBinding&amp;gt;...&amp;lt;/wsFederationHttpBinding&amp;gt;
  &amp;lt;/bindings&amp;gt;
  &amp;lt;client&amp;gt;
    ...    
    &amp;lt;identity&amp;gt;
      &amp;lt;certificate encodedValue="chiave pubblica codificata base64" /&amp;gt;
    &amp;lt;/identity&amp;gt;
   &amp;lt;/endpoint&amp;gt;
  &amp;lt;/client&amp;gt;
&amp;lt;/system.serviceModel&amp;gt;

Lato client, Windows CardSpace è 'triggerato' da WCF nel momento in cui l'issuer nella configurazione del servizio attiva la selezione di una card personal che soddisfi i claims specificati nel binding. Le card managed (rilasciate da un identity provider esterno) sono obbligatorie invece quando il tipo di token o i claim richiesti non possono essere soddisfatti dalle card personali. 
A livello di messaggio, il token rilasciato da CardSpace verrà incapsulato nell'header del messaggio SOAP, il quale verrà decifrato e validato dal server prima di passare all'estrazione ed all'elaborazione dei claim. Nel caso di card di tipo personal (dove i claim sono auto-forniti dall'utente), è importante basare l'identificazione univoca dell'account tramite il claim PPID. 
Il codice seguente mostra proprio come accedere ai claim di una personal card partendo dalla classe AuthorizationContext:

using System.ServiceModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Claims;
...
AuthorizationContext authorization_Context = ServiceSecurityContext.Current.AuthorizationContext;           
foreach (ClaimSet claim_set in authorization_Context.ClaimSets)
{ 
   IEnumerable&amp;lt;Claim&amp;gt; claims = claim_set.FindClaims(ClaimTypes.PPID, Rights.PossessProperty);                
   //Controllo sui claim forniti... 
}

per quanto concerne invece l'utilizzo di card managed, abbiamo una possibiltà in più dal momento che i claim hanno un proprietario identificabile da un identity provider affidabile, a cui corrisponde un ClaimSet che spesso include un claim identificativo con la chiave pubblica dell'identity provider (ClaimTypes.Rsa):

using System.ServiceModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Claims;
using System.Security.Cryptography;
...

ClaimSet csIssuer = cs.Issuer;
IEnumerable&amp;lt;Claim&amp;gt; issuerClaims = csIssuer.FindClaims(ClaimTypes.Rsa, Rights.Identity);
foreach (Claim c in issuerClaims)
{
  RSACryptoServiceProvider rsa = c.Resource as RSACryptoServiceProvider;
  if (rsa != null) 
  {                    
    // claim exists; check the public key to identify the IP
  }
}

Evidentemente l'utilizzo di card managed è maggiormente consigliata dal momento che rende più semplice la selezione di una identity da parte di un utente nonché la generazione di un insieme di claim associati ai diritti dell'utente verso il sistema partendo da token trusted rilasciati da identity provider affidabili. 

Technorati tags: WCF, Cardspace&lt;img src="http://blogs.ugidotnet.org/dsantarelli/aggbug/91745.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Dario Santarelli</dc:creator>
            <guid>http://blogs.ugidotnet.org/dsantarelli/archive/2008/03/17/cardspace-e-wcf-autenticazione-claim-based.aspx</guid>
            <pubDate>Mon, 17 Mar 2008 17:25:11 GMT</pubDate>
            <comments>http://blogs.ugidotnet.org/dsantarelli/archive/2008/03/17/cardspace-e-wcf-autenticazione-claim-based.aspx#feedback</comments>
            <wfw:commentRss>http://blogs.ugidotnet.org/dsantarelli/comments/commentRss/91745.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ugidotnet.org/dsantarelli/services/trackbacks/91745.aspx</trackback:ping>
        </item>
    </channel>
</rss>