Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

ADO.NET Data Services: Query Interceptors con Visual Basic 2008

Nel terzo articolo dedicato agli ADO.NET Data Services con Visual Basic 2008, pubblicato giorni fa su Visual Basic Tips & Tricks, abbiamo introdotto le service operations e abbiamo visto come il loro scopo sia quello di fornire la possibilità di implementare una business logic personalizzata, lato server.

 

Ma le service operations non sono l’unica modalità di operare lato server, poichè abbiamo a disposizione un’altra caratteristica che è quella dei Query Interceptors (la libreria MSDN italiana li definisce intercettori).

 

Come il nome lascia intendere, sono degli speciali metodi che intercettano le richieste di accesso tramite HTTP ai dati e permettono allo sviluppatore di decidere come gestire tali richieste.

 

Per esempio, pensate a un impiegato che accede all’elenco degli ordini: lo sviluppatore vuole fare in modo che ciascun impiegato sia in grado di visualizzare solo gli ordini di cui si è occupato e non anche quelli seguìti da altri impiegati. Vediamo come esemplificare questa situazione attraverso codice Visual Basic, che commenteremo di seguito:

   

    <QueryInterceptor("Orders")> Public Function OnOrdersQuery() As  _

                                 Expressions.Expression(Of Func(Of Orders, Boolean))

 

        Return Function(ord) ord.Employees.LastName = HttpContext.Current.User.Identity.Name

    End Function

 

Facciamo alcune considerazioni inerenti l’intercettore sopra esposto, che hanno anche valenza generale:

 

1.    È decorato con l’attributo QueryInterceptor, il cui argomento è l’entità della quale si vuole intercettare l’accesso da parte dei client;

2.    Ha necessariamente visibilità pubblica;

3.    Restituisce un Expression Tree che prende forma a partire da un’espressione lambda fortemente tipizzata. L’oggetto Func, come probabilmente sapete se avete letto quest’articolo del grande Antonio, genera un metodo anonimo al volo che riceve due argomenti, il primo che è l’argomento vero e proprio, il secondo che è il tipo restituito.

 

Nelle prime versioni del progetto Astoria, restituire un expression tree non era vincolante mentre con la RTM di .NET 3.5 SP 1 lo è diventato. Per capire l’utilizzo dell’espressione lambda nel corpo del metodo sopra esposto, possiamo dire che equivale a scrivere la seguente query LINQ:

 

        Dim ordini = From ord In Me.NorthwindContext.Orders _

                     Where ord.Employees.LastName = "CognomeImpiegato" _

                     Select ord

 

che chiaramente non possiamo utilizzare in questo contesto (poiché questa restituisce IQueryable(Of T), mentre a noi serve un Expression Tree) e pertanto si ricorre alla lambda.

 

Per fare un esempio migliore, anche se chiaramente puramente dimostrativo in locale, ho creato un account utente sul mio pc chiamandolo “Davolio” (certo, come la mitica Nancy!! J). Proviamo a fare una simulazione utilizzando il servizio implementato nell’ultimo articolo per fare una simulazione sfruttando il database Northwind. L’utente che esegue l’accesso al sistema si chiama quindi DOMAINNAME\Davolio (sul vostro sistema DOMAINNAME sarà un altro identificatore). Volendo quindi eseguire il confronto sul cognome dell’impiegato, dobbiamo suddividere la stringa al fine di ottenere solo il nome utente senza il domain name, che si può fare utilizzando questa riga di codice:

 

        Dim UserNameWithoutDomain As String = HttpContext.Current.User.Identity.Name.Split(CChar("\"))(1)

 

Poichè lavoriamo con un servizio che riceve richieste via HTTP, è necessario utilizzare l’oggetto HttpContext. Di conseguenza, riscriviamo il metodo OnOrdersQuery nel modo seguente:

   

    <QueryInterceptor("Orders")> Public Function OnOrdersQuery() As  _

                                 Expressions.Expression(Of Func(Of Orders, Boolean))

 

        Dim UserNameWithoutDomain As String = HttpContext.Current.User.Identity.Name.Split(CChar("\"))(1)

 

        Return Function(ord) ord.Employees.LastName = UserNameWithoutDomain

    End Function

 

E questo è ciò che avviene lato server, quindi nell’ADO.NET Data Service che abbiamo utilizzato finora. Lato client, le cose sono piuttosto semplici. Ad esempio, ipotizzando di avere un’applicazione client che abbia referenziato il servizio (vedi questo articolo per i dettagli) utilizzando il seguente codice:

 

        'L’URI del servizio ovviamente è esemplificativo

        Dim NorthwindContext As New NORTHWNDEntities(New Uri("http://localhost:6265/Northwind.svc"))

 

        'Devo eseguire l'eager loading per ottenere gli impiegati collegati

        'Si noti l’utilizzo della simbologia ?$expand= per eseguire l’eager loading in query string

        Dim result = NorthwindContext.Execute(Of Orders)(New Uri("/Orders?$expand=Employees", UriKind.Relative))

 

        Console.WriteLine("Orders")

 

        For Each order In result

            Console.WriteLine("{0}: - {1} - {2}, {3}", order.Employees.FirstName + " " + order.Employees.LastName, _

                                                       order.OrderID, order.ShipCity, order.ShipAddress)

        Next

 

Otterremo il seguente risultato:

 

 

 

Come potete osservare, vengono visualizzati i soli ordini relativi all’impiegato Davolio, ossia quello che ha interrogato gli ordini esposti dal servizio attraverso il client in esecuzione nel suo account, ma questo è avvenuto senza eseguire alcun confronto (per esempio attraverso una Where) perchè ci ha pensato l’intercettore, lato server, ad escludere tutto ciò che non è di pertinenza dell’impiegato in questione.

 

Oppure possiamo considerare il seguente code snippet, in cui lo smistamento avviene in base alla lingua. Se la richiesta avviene da un sistema con lingua italiana, l’interceptor restituisce tutti gli ordini portati avanti da impiegati italiani, altrimenti solleva un’eccezione:

 

   

   <QueryInterceptor("Orders")> Public Function OnOrdersQuery() As  _

                                 Expressions.Expression(Of Func(Of Orders, Boolean))

 

        Dim LocalCulture = WebOperationContext.Current.IncomingRequest.Headers("Accept-Language")

 

        If LocalCulture = "it-IT" Then

            Return Function(ord) ord.Employees.Country = "Italy"

        Else

            Throw New DataServiceException("You are not authorized")

        End If

 

    End Function

 

I Query Interceptors sono una funzionalità molto utile per lo sviluppatore che deve gestire l’accesso ai dati lato server e hanno tante possibilità di utilizzo. Tuttavia i Query Interceptors sono riferibili ad operazioni che i client compiono in lettura; esistono inoltre i Change Interceptors che gestiscono le richieste in scrittura e che tratteremo in un prossimo post.

 

Alessandro

Print | posted on venerdì 23 gennaio 2009 00:59 | Filed Under [ Visual Basic WCF Data Services/WCF RIA Services/OData ]

Powered by:
Powered By Subtext Powered By ASP.NET