DarioSantarelli.Blog("UgiDotNet");

<sharing mode=”On” users=”*” />
posts - 110, comments - 99, trackbacks - 41

My Links

News

Dario Santarelli
Free Blogger
This is my personal blog. These postings are provided "AS IS" with no warranties, and confer no rights.



Dario Santarelli's Facebook profile
View Dario Santarelli's profile on LinkedIn

Add to Technorati Favorites


Tag Cloud

Archives

Post Categories

.NET

ASP.NET

My Blogging Friends

My English Blog

Web 2.0

domenica 30 novembre 2008

[WPF] Considerazioni su M-V-VM

In questi giorni sto studiando a fondo il pattern M-V-VM ((Data)Model-View-ViewModel), visto che quando fu introdotto per la prima volta (ormai 3 anni fa) non lo valutai affatto positivamente poiché ero convinto che avrebbe "sporcato" troppo il pattern MVC, creando confusione sia tra gli sviluppatori che tra gli architects.
Questo pattern fu coniato nel 2005 da John Gossman mentre WPF vedeva la luce (Avalon). In uno dei suoi post a riguardo, Gossman lo definì nella seguente maniera:

Model/View/ViewModel is a variation of Model/View/Controller (MVC) that is tailored for modern UI development platforms where the View is the responsibility of a designer rather than a classic developer....The Model is defined as in MVC...The View consists of the visual elements... The ViewModel can be thought of as abstraction of the view, but it also provides a specialization of the Model that the View can use for data-binding.  In this latter role the ViewModel contains data-transformers that convert Model types into View types, and it contains Commands the View can use to interact with the Model.


A seguito di un'analisi più attenta, devo dire che ho modificato la mia posizione iniziale, soprattutto considerando che in linea teorica il pattern M-V-VM può essere utilizzato congiuntamente al pattern MVC ( MVC + VM ). D'altronde, il fatto che si possieda o meno un ViewModel è ortogonale al fatto che si possieda o meno un Controller.
Il ViewModel infatti può assumere due ruoli:

  • un livello di astrazione per la View
  • una specializzazione del (Data)Model che la View utilizza per il DataBinding (tramite una trasformazione dei tipi del Model nei tipi della View) e che contiene i Commands che la View può usare per interagire con il Model

Da una parte, gli aspetti che mi piacciono di questo pattern architetturale sono quelli che lo rendono più vicino ad un "WPF-friendly wrapper" del pattern MVC:

  • supporto totale al two-way databinding offerto da WPF (dati da-verso la View)
  • maggiore semplificazione/flessibilità dello sviluppo di un' applicazione WPF di qualità (SoC) rispetto a soluzioni MVP (già affermate in particolar modo su Windows Forms e ASP.NET) o MVC (ragazzi ASP.NET MVC è perennemente in Beta :D !!!).

...Dall'altra mi ritrovo a riflettere su alcuni punti critici di tale pattern che potrebbero minacciare seriamente lo sviluppo di applicazioni enterprise:

  • In scenari complessi potrebbe essere estremamente difficile progettare un ViewModel che risponda al giusto livello di generalità (ricordiamoci che il ViewModel ingloba Proprietà, Astrazioni del DataModel (ObservableCollection), una sfilza di ICommand, Change Notification via INotifyPropertyChanged etc..)
  • Il miracoloso meccanismo dichiarativo di DataBinding non è facile da debuggare quanto il classico approccio imperativo. E' anche vero che una semplice scappatoia per difficoltà di questo tipo rimane pur sempre l'intercettazione degli eventi che ci servono sia lato View che lato ViewModel.
  • Poiché un DataBinding dietro le quinte alloca delle risorse di "book-keeping" (contabilità :D), se si implementano pesanti scenari di MultiBinding (in cui uno stesso oggetto è associato a più componenti dell'UI) si possono ottenere situazioni in cui i Binding sono addirittura più pesanti degli oggetti bindati!!! E' sicuramente difficile che si presenti un caso di questo tipo in un' applicazione reale, ciò non toglie che un occhio alle performance dovremmo sempre darglielo.

In questo post di Karl Shifflett ho trovato interessante questa immagine che evidenzia tutte le caratteristiche di un' architettura M-V-VM in un contesto LOB. I concetti ci sono praticamente tutti... ora sta a noi portarli in vita :D


Technorati Tag: ,

posted @ domenica 30 novembre 2008 16.22 | Feedback (3) | Filed Under [ WPF ]

venerdì 28 novembre 2008

Lanciare il Document Explorer

Non è una prassi molto frequente, ma se si vuole lanciare programmaticamente il Document Explorer (dexplore.exe) per visualizzare un topic piuttosto che filtrare contenuti ed indici è interessante capire anzitutto le command-line options che esso espone (bellissima è l'opzione /UseHelpSettings la cui documentazione è "Microsoft Internal Use Only." :D). Ecco ad esempio una classe utility (mooolto semplificata) per ricercare al volo un topic tramite Document Explorer:

public class DocumentExplorer
{
 
public const int V8 = 8; // VS2005
 
public const int V9 = 9; // VS2008

 
public void SearchTopic(string keywordTopic, int majorVersion)
 
{
   
Process dExploreProcess = new Process();
   
dExploreProcess.StartInfo.FileName = GetDocumentExplorerExecutable(majorVersion);

   
if (!string.IsNullOrEmpty(keywordTopic))
   
{
     
if (keywordTopic.Trim().Contains(" ")) keywordTopic = "\"" + keywordTopic + "\"";               
     
dExploreProcess.StartInfo.Arguments = "/LaunchFKeywordTopic " + keywordTopic;               
   
}

   
dExploreProcess.Start();
  
}

  
private string GetDocumentExplorerExecutable(int majorVersion)
  
{          
    
string relativePath = "Microsoft Shared\\Help " + majorVersion.ToString() + "\\dexplore.exe";
     string commonX86 = Environment.GetEnvironmentVariable("CommonProgramFiles(x86)");
    
if (!string.IsNullOrEmpty(commonX86))
    
{
      
string pathX86 = Path.Combine(commonX86, relativePath);
      
if (File.Exists(pathX86)) return pathX86;
    
}
    
string common = Environment.GetEnvironmentVariable("CommonProgramFiles");
    
return Path.Combine(common, relativePath);
  
}
}


Ovviamente esistono altri metodi molto più raffinati per interagire da codice con il Document Explorer (in base alle specifiche esigenze). Per chi volesse approfondire l'argomento segnalo immediatamente questo bell'articolo di Alessandro del Sole.
 

posted @ venerdì 28 novembre 2008 22.19 | Feedback (0) |

mercoledì 26 novembre 2008

Slides su ASP.Net 3.5 SP1 Dynamic Data

Non che io sia un fan di ASP.NET Dynamic Data, tuttavia ho trovato questa presentazione molto utile per chi vuole avvicinarsi a questa tecnologia senza inciampare :D.

Technorati Tag:

posted @ mercoledì 26 novembre 2008 16.47 | Feedback (0) | Filed Under [ ASP.NET 3.5 ]

domenica 23 novembre 2008

jQuery e ASP.NET Server Controls

jQuery è una tecnologia puramente client-side, costituita da almeno una libreria javascript "core" il cui plug-in model è basato semplicimente su altre liberie Javascript. Banale ma non scontato, parliamo di una tecnologia che non possiede alcuna dipendenza con ASP.NET. Di conseguenza, lo sviluppo di controlli ASP.NET "jQuery-enabled" può non essere così semplice da valutare, soprattutto se by-design si pone l'attenzione solo sulle funzionalità client-side che il controllo deve soddisfare. In effetti, le best-practice ci dicono che non è poi così corretto sviluppare un controllo ASP.NET per soddisfare esclusivamente degli specifici comportamenti grafici che siano semplicemente legati al miglioramento della user experience o dell' usabilità. Piuttosto, dovremmo chiederci in fase di design se l'interazione con JQuery va lasciata a discrezione di chi utilizza il controllo oppure se debba forzatamente costituire una feature built-in.
Nel primo caso lo sviluppatore decide all'interno della sua soluzione come e quando far interagire l' (X)HTML renderizzato dal controllo con le funzionalità offerte da jQuery, registrando "manualmente" libreria e relativi plug-in a livello di pagina (es. specificando una o più ScriptReference nello ScriptManager in caso di applicazioni AJAX-enabled). Nel secondo approccio, invece, sia jQuery che altri script client-side possono essere "iniettati" nella logica di rendering del controllo sfruttando la capacità di ASP.NET di gestire WebResources. Vediamo un esempio. 
Supponiamo di dover sviluppare una class library contenente un set di WebControl ASP.NET che prevede l'embedding di script client-side (jQuery). Anzitutto, specifichiamo i vari file .js come WebResource a livello di assembly.

[assembly: System.Web.UI.WebResource("MyLibrary.Web.Resources.jquery-1.2.6.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("MyLibrary.Web.Resources.jquery_color.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("MyLibrary.Web.Resources.jquery.blockUI.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("MyLibrary.Web.Resources.MyControl.js", "text/javascript")]
. . .

Facendo attenzione a configurare ciascuna WebResource come "Embedded Resource". 

   

Potremmo poi definire una classe Helper ScriptResourceHelper condivisa da tutti i nostri WebControl (che utilizza ClientScriptManager) per gestire l' injection dinamica nella pagina dei vari script client-side di cui i nostri WebControl hanno bisogno.

public class ScriptResourceHelper
{
 
public const string JQUERY_SCRIPT_RESOURCE = "MyLibrary.Web.Resources.jquery-1.2.6.js";
 
public const string JQUERY_COLOR_SCRIPT_RESOURCE = "MyLibrary.Web.Resources.jquery_color.js";
 
public const string JQUERY_BLOCKUI_SCRIPT_RESOURCE = "MyLibrary.Web.Resources.jquery.blockUI.js";
 
public const string MYWEBCONTROL_SCRIPT_RESOURCE = "MyLibrary.Web.Resources.MyWebControl.js";      

 
public static void RegisterScriptResource(Control control, string resourceName)
 
{           
   
ClientScriptManager pageClientScriptManager = control.Page.ClientScript;
   
string webResourceURL = pageClientScriptManager.GetWebResourceUrl(control.GetType(), resourceName);       
   
   
// La stessa risorsa non deve essere registrata più volte nella stessa pagina
   
if (!pageClientScriptManager.IsClientScriptIncludeRegistered(resourceName))
   
{
     
pageClientScriptManager.RegisterClientScriptInclude(resourceName, webResourceURL);               
   
}           
  
}      
}

In questo esempio specifico è stato assicurato il fatto che ciascuno script client-side venga caricato solo una volta nella pagina. Infatti, se la logica di rendering di due nostri WebControl registrasse jQuery nella pagina in maniera indipendente, jQuery verrebbe caricata due volte nella pagina (lascio immaginare con quali risultati). 
In casi di questo tipo è opportuno ad esempio utilizzare il metodo IsClientScriptIncludeRegistered che permette proprio di controllare che una determinata risorsa sia già registrata nella pagina. Mettiamo tutto insieme e vediamo un estratto della possibile implementazione di un WebControl "jQuery-enabled" che gestisce in fase di rendering l'injection di jQuery e script client-side in generale.

[ToolboxData("<{0}:MyWebControl runat=\"server\" />")]
public class MyWebControl : WebControl
{       
   . . .

  
protected override void OnPreRender(EventArgs e)
  
{
    
ScriptResourceHelper.RegisterScriptResource(this, ScriptResourceHelper.JQUERY_SCRIPT_RESOURCE);
    
ScriptResourceHelper.RegisterScriptResource(this, ScriptResourceHelper.MYWEBCONTROL_SCRIPT_RESOURCE);
    
base.OnPreRender(e);
  
}

   . . .
}

Technorati Tag: ,

posted @ domenica 23 novembre 2008 18.24 | Feedback (0) |

sabato 15 novembre 2008

[Silverlight 2] Creare un Timer

Mi è capitato di aver bisogno di un timer per gestire il FadeIn/FadeOut di una Toolbar di un VideoPlayer custom. In pratica, la Toolbar deve scomparire automaticamente con un effetto "fadeout" (storyboard) quando il mouse si trova in aree diverse dell'UI per un certo periodo di tempo. Inizialmente pensavo che si potesse implementare un workaround andando ad agire invasivamente nel behaviour della storyboard di fadeOut (come in questo esempio), poi documentandomi un po' mi sono reso conto che la soluzione più consigliabile è in generale quella di utilizzare la classe DispatcherTimer (System.Windows.Threading). 
Nel mio caso è bastato quindi implementare un Timer custom come questo (il codice è stato opportunamente semplificato :D)

using System.Windows.Threading;

public class Timer : UserControl
{
 
private DispatcherTimer _dispatcherTimer;
 
private int _elapsed;

 
public int Duration { get; set; }       
 
public int TickInterval { get; set; }

 
public event EventHandler OnStart;       
 
public event EventHandler OnEnd;

 
public Timer()
 
{                       
   
_dispatcherTimer = new DispatcherTimer();            
   
_dispatcherTimer.Tick += new EventHandler(_dispatcherTimer_Tick);           
 
}

 
private void _dispatcherTimer_Tick(object sender, EventArgs e)
 
{
   
_elapsed += this.TickInterval;
   
if (_elapsed >= this.Duration)
   
{
     
Reset();  
     
if (OnEnd != null) OnEnd(this, null);               
   
}
 
}

 
public void Start()
 
{
   
_elapsed = 0;
   
_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, this.TickInterval);
   
_dispatcherTimer.Start();                       
   
if (OnStart != null) OnStart(this, null);                       
 
}
 
 
public void Reset()
 
{
   
_elapsed = 0;
   
_dispatcherTimer.Stop();
 
}
}


A questo punto nello stage inseriamo il nostro timer:

<myns:Timer Name="timer" Duration="3500" TickInterval="100" OnStart="Timer_OnStart" OnEnd="Timer_OnEnd"></myns:Timer>

... e se dovessimo gestire due distinte storyboard di FadeIn e FadeOut, possiamo sfruttare gli eventi OnStart/OnEnd esposti dal timer per ottenere il risultato desiderato nel seguente modo:

private void Timer_OnStart(object sender, EventArgs e) { storyBoardFadeIn.Begin(); }

private
void Timer_OnEnd(object sender, EventArgs e)
{ storyBoardFadeOut.Begin(); }  


Niente di più facile :D.

Technorati Tag:

posted @ sabato 15 novembre 2008 20.06 | Feedback (0) | Filed Under [ Silverlight ]

giovedì 13 novembre 2008

[Silverlight 2] Occhio allo Slider

Stavo provando ad utilizzare il controllo Slider di Silverlight 2 in un mio progetto



quando mi accorgo dell'assenza della proprietà IsMoveToPointEnabled che invece è presente nell'alter ego in WPF. Ma nooooooo!!!!
Fortunatamente c'è già chi ha elegantemente risolto il problema.

Technorati Tag:

posted @ giovedì 13 novembre 2008 23.41 | Feedback (0) | Filed Under [ Silverlight ]

Il Poster di Silverlight 2

Bello!!! :D

Silverlight 2 Poster

posted @ giovedì 13 novembre 2008 15.43 | Feedback (2) | Filed Under [ Silverlight ]

martedì 11 novembre 2008

[Silverlight] Utilizzo del controllo GridSplitter

Segnalo questo ottimo articolo su SilverlightShow in cui si spiega in maniera puntuale l'utilizzo del controllo GridSplitter in Silverlight 2.

Technorati Tag:

posted @ martedì 11 novembre 2008 10.38 | Feedback (0) | Filed Under [ Silverlight ]

sabato 8 novembre 2008

[ASP.NET] PageAsyncTask e pagine asincrone

A partire da ASP.NET 2.0, la classe System.Web.UI.Page introduce un metodo non molto conosciuto in grado di facilitare la realizzazione di pagine asincrone: il metodo RegisterAsyncTask. Spesso mi è capitato di vedere implementare chiamate asincrone (es. invocazione di un WebService) in maniera non corretta sfruttando la logica dell' AddOnPreRenderCompleteAsync, quando in realtà molti dei problemi potevano essere gestiti facilmente tramite Task asincroni, che in ASP.NET sono rappresentati dalla classe PageAsyncTask.
Le differenze tra i due approcci non sono moltissime ma significative. Infatti, entrambi richiedono Async="true" nella direttiva @Page (o  AsyncMode = true; da codice) e dunque la predisposizione all'esecuzione asincrona della pagina su thread diversi dopo il completamento del PreRender.
Tuttavia, il metodo RegisterAsyncTask introduce i seguenti vantaggi chiave:

  • In aggiunta ai metodi Begin/End, permette di registrare un metodo per gestire il timeout di una operazione eventualmente troppo lunga. Il timeout è per-page ed è impostabile tramite l'attributo AsyncTimeout della direttiva @Page:  <%@ Page Async="true" AsyncTimeout="10" ... %> 
  • Permette di gestire più PageAsyncTask (ovvero più "async points") all'interno di un ciclo di vita di una pagina asincrona. Questi a loro volta possono essere eseguiti sia in modalità sequenziale che in modalità parallela (grazie a questo overload del contruttore di PageAsyncTask). Anche in questo caso, analogamente al pattern MetodAsync/MethodCompleted disponibile per le classi proxy dei WS (dal framework 2.0 in poi), ASP.NET "ritarda" il rendering della pagina finché tutti i task asincroni non sono stati completati.
  • Permette di passare un oggetto 'state' ai nostri metodi BeginAsync tramite la classe PageAsyncTask.
  • Permette di mantenere l'impersonation, la culture e l'oggetto HttpContext.Current nei metodi EndAsync e Timeout (cosa non prevista dal metodo EndAsync registrato con l'approccio AddOnPreRenderCompleteAsync)

Mettiamo insieme il tutto e vediamo un esempio di applicazione dei PageAsyncTask.
Vogliamo elaborare dei feed RSS tramite PageAsyncTask diversi all'interno di una nostra pagina asincrona.

public partial class SampleAsyncPage : System.Web.UI.Page
{

  protected
void Page_Load(object sender, EventArgs e)
  {
    
List<string> feeds = new List<string>();
    
feeds.Add("http://blogs.msdn.com/MainFeed.aspx?Type=AllBlogs");
     feeds.Add("http://blogs.ugidotnet.org/MainFeed.aspx");
     feeds.Add("http://channel9.msdn.com/Feeds/RSS/");       

    
foreach (string feed in feeds)
    
{
      
RegisterAsyncTask(new PageAsyncTask(new BeginEventHandler(BeginAsyncOperation), // BeginAsync
                                          
new EndEventHandler(EndAsyncOperation), // EndAsync
                                          
new EndEventHandler(TimeoutAsyncOperation), // TimeoutAsync
                                          
WebRequest.Create(feed), // State
                                          
true // I task registrati verranno eseguiti in parallelo
                                         
)
                       
);           
    
}       
  }

  IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback callback, object state)
  {
    // In rawFeed abbiamo il feed RSS...
   
WebRequest webRequest = (WebRequest)state;
   
return webRequest.BeginGetResponse(callback, state);
  }

  void EndAsyncOperation(IAsyncResult ar)
  {               
   
WebRequest webrequest = (WebRequest)ar.AsyncState;
   
string rawFeed = null;
 
   
using (WebResponse response = webrequest.EndGetResponse(ar))
   
{
     
using (StreamReader reader = new StreamReader(response.GetResponseStream())) rawFeed = reader.ReadToEnd();           
   
}        
    // In rawFeed abbiamo il feed RSS...
 
}

  void TimeoutAsyncOperation(IAsyncResult ar)
  {
   
// Gestione del Timeout per l' AsyncTask    
  }
}

Per ciascun feed di un nostro elenco registriamo a livello di pagina un PageAsyncTask che in fase di esecuzione si occuperà di reperire lo stream del feed associato (ad esempio grazie alla classe System.Net.WebRequest). Il miglioramento delle prestazioni è garantito anche dal fatto che l'esecuzione asincrona di ciascun Task verrà gestita da ASP.NET possibilmente in parallelo.

Considerazioni:

  • Se abbiamo bisogno di una pagina asincrona che gestisca un'unica chiamata asincrona, allora gli approcci AddOnPreRenderCompleteAsync e RegisterAsyncTask sono pressoché equivalenti. Ma se le chiamate asincrone sono molte, è decisamente consigliabile sfruttare le facilitazioni introdotte da RegisterAsyncTask.
  • Il timeout è per-page e non per-call. Non possiamo cioè assegnare timeout diversi a chiamate asincrone diverse!!! Al massimo possiamo eventualmente modificare a runtime la proprietà AsyncTimeout, il che ovviamente non è la stessa cosa :D
  • In combinazione con async ADO.NET (es. SqlCommand.BeginExecuteReader) ed in generale con le feature asincrone del framework .NET, le pagine ASP.NET asincrone offrono soluzioni molto convenienti per risolvere comuni problemi di I/O legati a scenari che inibiscono la scalabilità.
  • In generale non è consigliabile/sicuro gestire operazioni asincrone in ASP.NET utilizzando le API System.Threading (es. ThreadPool.QueueUserWorkItem). Il rischio infatti è quello di "rubare" thread alla normale gestione del ThreadPool di ASP.NET, ottenendo effetti che potrebbero risultare addirittura controproducenti.
Technorati Tag: ,

posted @ sabato 8 novembre 2008 14.23 | Feedback (0) | Filed Under [ ASP.NET 2.0 ASP.NET 3.5 ]

mercoledì 5 novembre 2008

WCF REST Starter Kit

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: ,

posted @ mercoledì 5 novembre 2008 18.25 | Feedback (0) | Filed Under [ WCF ]

domenica 2 novembre 2008

Windows Live Tools for Visual Studio (November 2008 CTP)

Ho installato da poco i Windows Live Tools for Microsoft Visual Studio (November 2008 CTP). Le novità introdotte da questa versione sono le seguenti:

  • All the controls are now compatible with trust policy of Windows Azure
  • New templates - Windows Live Web Application and Windows Live Web Role. Windows Live Web Role works for creating web sites web role in a Windows Azure Cloud Project.
  • SilverlightStreamingMediaPlayer Control upgraded to Silverlight 2.0 Tools.


L'installazione integra tre nuovi template di progetto per Visual Studio:

  • ASP.NET Windows Live Web Site
  • Windows Live Web Application
  • Windows Live Web Role (template for Windows Azure Cloud Projects)


Provando a creare un progetto ASP.NET Windows Live Web Site, automaticamente vengono aggiunti al progetto i riferimenti alle library

  • Microsoft.Live.ServerControls.dll (Controlli Live e Virtual Earth)
  • System.Web.Silverlight.dll (Controlli Silverlight)

Per curiosità mi sono subito messo a studiare le potenzialità dei nuovi controlli Windows Live. Ecco una loro breve presentazione:

  •  IDLoginStatus : permette di integrare il login di Windows Live nella nostra applicazione web. Per un corretto utilizzo è necessaria una procedura di registrazione (Getting Your Application ID for Web Authentication) su Azure Services Developer Portal in modo da ottenere una coppia [ApplicationID,SecretKey] da impostare nella sezione <appSettings> del web.config (di default troviamo già due apposite keys: wll_appid e wll_secret). Tali valori vanno obbligatoriamente specificati rispettivamente nelle proprietà ApplicationIDConfigKey e ApplicationSecretConfigKey del controllo. Ad esempio:
     <live:IDLoginStatus ID="IDLoginStatus1" runat="server" ApplicationIDConfigKey="wll_appid"ApplicationSecretConfigKey="wll_secret"/>
  • IDLoginView : estende le funzionalità del controllo LoginView di ASP.NET e fornisce dei template aggiuntivi per gestire sia la singola autenticazione Windows Live (LoggedInIDTemplate) che entrambe le autenticazioni Windows Live / ASP.NET (LoggedInAllTemplate). I metodi di questo controllo ci permette inoltre di associare un MembershipUser della nostra Web application ad un Windows Live ID in modo da realizzare un meccanismo vero e proprio di single sign-on. Addirittura impostando a true la proprietà AutomaticallyAssociateAuthentication è possibile effettuare tale associazione automaticamente.
  • MessengerChat : abilita l'accesso WLM in una nostra pagina web. Anche in questo caso l'aspetto interessante è la possibilità di associare una Messenger Chat ID (CID) ad un MembershipUser di ASP.NET (se autenticato). Qua sotto ho riportato un esempio a riguardo.
  • Contacts : permette l'integrazione delle funzionalità Windows Live Contacts tramite un set di API client-side / server-side. Praticamente consiste nella versione ASP.NET del corrispondente controllo Javascript http://dev.live.com/contacts.
  • SilverlightStreamingMediaPlayer: estende il controllo Silverlight Media Player permettendo la riproduzione di video anche da un account Silverlight Streaming. In fase di design si possono specificare le credenziali di accesso e scegliere i video che si vogliono visualizzare.
  • Map: versione ASP.NET del corrispondente controllo Javascript http://dev.live.com/virtualearth/sdk/.


Vediamo ora un semplice esempio di utilizzo dei controlli Contacts e MessengerChat:

Il controllo MessengerChat offre diverse possibilità di personalizzazione, soprattutto per quanto riguarda il layout. Anzitutto, tramite la proprietà View possiamo impostare 3 diverse possibilità di visualizzazione (Window (default), Icon, Button).
La proprietà PrivacyStatementURL invece va valorizzata con l'URL della pagina Web contenente l'informativa sulla privacy da visualizzare all'utente al momento dell'accesso a WLM. Questa proprietà è OBBLIGATORIA.

<live:MessengerChat ID="MessengerChat1" runat="server" PrivacyStatementURL="~/privacyPolicy.htm" Height="400px" 
Market="it-IT" SignUpLinkText="WLM SignUp!" View="Window" onmessengerchatsignup="OnMessengerChatSignUp"> <ColorTheme Name="Default"></ColorTheme> </live:MessengerChat>


Il controllo espone un evento OnMessengerChatSignup che possiamo sfruttare per l'associazione della Chat (CID) all'utente ASP.NET correntemente "loggato":

 protected void OnMessengerChatSignup(object sender, MessengerChatSignupEventArgs e)
 {
if (Page.User.Identity.IsAuthenticated) MessengerChat1.SetUserAssociation(Page.User.Identity.Name, e.CID); }


Per quanto riguarda il controllo Contacts, allo stesso modo possiamo scegliere diverse View: List, Tile, TileList(default). Per la modalità List in particolare possiamo valorizzare la proprietà DataDesired specificando una lista di informazioni separate da virgola (es. name, email, phone, firstname...) che vogliamo rendere visibili.

<live:Contacts ID="Contacts1" runat="server" DataDesired="name,email..." 
               Height="400px" View="Tile" Width="250px" Market="it-IT" Message="ciao" 
               PrivacyStatementURL="~/privacyPolicy.htm" />


Infine, l'enanchement questo controllo permette ora l'aggiunta e la rimozione di Live contacts server-side :

using Microsoft.Live.ServerControls;
List<Contact> myContacts = new List<Contact>();
Contact myContact = new Contact();
myContact.EmailPersonal = abc@xyz.com;
myContact.FirstName = "Dario";
myContact.LastName = "Santarelli"; myContacts.Add(myContact); ContactsControl.CreateContacts(myContacts); ContactsControl.CommitContacts();


N.B.: Il metodo CommitContacts() applica effettivamente ciascun cambiamento apportato, scatenando l'aggiornamento del contact store dell'utente.

 

Riferimenti utili:


Technorati Tag: ,

posted @ domenica 2 novembre 2008 10.34 | Feedback (0) |

mercoledì 29 ottobre 2008

jQuery Color Animations

Promemoria: per far funzionare correttamente le "animazioni colorate" utilizzando versioni di jQuery successive alla 1.2 tramite la function animate, ad esempio:

$('#MyBox').animate( {backgroundColor: "#c6c6c6"} , 750 );

è consigliabile utilizzare il plugin Color Animation.
Dietro le quinte il plugin effettua un override del comportamento di animazione per tutte le possibili proprietà che supportano la colorazione.
Ecco un interessante estratto del codice del plugin (in rosso le proprietà CamelCase che possiamo eventualmente utilizzare) :

(function(jQuery)
{
   // We override the animation for all of these color styles
   jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
                'borderRightColor','borderTopColor', 'color', 'outlineColor'
],
                 function(i,attr)
                 {
                    jQuery.fx.step[attr] = function(fx)
                                           {
                                             if (fx.state == 0) 
                                             {
                                               fx.start = getColor( fx.elem, attr );
                                               fx.end = getRGB( fx.end );
                                             }
                                             fx.elem.style[attr] = "rgb(" + [
Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
                                                                            ].join(",") + ")";
                                           }
                 });
...

})(jQuery);


Spero possa essere utile.

Technorati Tag:

posted @ mercoledì 29 ottobre 2008 18.36 | Feedback (0) |

lunedì 27 ottobre 2008

[ASP.NET AJAX] Modal Progress con jQuery

In questo post viene mostrato un utilizzo del jQuery BlockUI plugin per visualizzare un Modal Progress personalizzato durante il partial postback di un UpdatePanel. Il risultato che si può ottenere con questo approccio è ad esempio il seguente:



Molto interessante :)

Technorati Tag: ,

posted @ lunedì 27 ottobre 2008 12.45 | Feedback (0) | Filed Under [ ASP.NET AJAX ]

giovedì 23 ottobre 2008

[ASP.NET 3.5] AJAX History

ASP.NET 3.5 SP1 introduce un enanchement del controllo ScriptManager che permette di gestire degli stati di navigazione all'interno di una pagina AJAX-enabled accedibili mediante i pulsanti standard "Avanti/Indietro" del browser. In due parole: "Ajax History". Questa funzionalità fu inizialmente introdotta nel vecchio "ASP.NET Futures" mediante il controllo History (in passato scrissi anche un post a riguardo).
La questione è tutt'altro che banale: poiché un browser attiva i meccanismi di navigazione in base al cambio dell' URL, in caso di richieste AJAX che non redirigono verso URL diverse, il browser non aggiorna l' history cache, precludendo all'utente il corretto utilizzo dei pulsanti di navigazione per i diversi stati che desidereremmo impostare nella nostre pagine AJAX-enabled.
La gestione dell' AJAX History non è abilitata di default, tuttavia è molto semplice da implementare. L'unico problema è stabilire che tipo di implementazione ha senso in base alla user experience che si vuole ottenere ed in base al comportamento dei controlli AJAX che si trovano nella nostra pagina.
Partiamo da un classico esempio: Database Northwind, visualizzazione di Products in una GridView ed una DropDownList con AutoPostBack="True" che filtra i Products in base alla Category selezionata. Il tutto piazzato dentro un UpdatePanel.



Senza la gestione dell'history, ogni volta che selezioniamo un Item della DropDownList i dati nella GridView vengono sì aggiornati correttamente, ma se volessimo tenere traccia delle nostre selezioni come stati diversi (navigabili tramite i pulsanti standard "Avanti/Indietro" del browser) dovremmo gestire degli history point, che inoltre ci permettono di rendere eventualmente "bookmarkabili" i vari stati memorizzati, proprio come se fossero pagine diverse. Vediamo come:

1. Impostare EnableHistory="true" nello ScriptManager

<asp:ScriptManager ID="scriptManager_Main" runat="server" EnableHistory="true" 
EnableSecureHistoryState="true|false" OnNavigate="scriptManager_Main_Navigate">