Introduzione agli ADO.NET Data Services con Visual Basic 2008 - Seconda parte: il client WPF
a cura di Alessandro Del Sole (requisiti: conoscenze di base su LINQ, WPF e WCF)Introduzione
Nella prima parte di questa mini serie di articoli introduttivi agli ADO.NET Data Services in Visual Basic 2008, abbiamo visto come creare con Visual Studio un servizio basato su WCF per esporre in rete dei dati attraverso un approccio REST (REpresentational State Transfer) sfruttando il modello a oggetti offerto da ADO.NET Entity Framework.In questa seconda parte completeremo l'introduzione all'argomento passando alla creazione di un'applicazione client basata su Windows Presentation Foundation e faremo utilizzo di LINQ to Data Services per interrogare i dati.
Vedremo aspetti decisamente interessanti della creazione di applicazioni data-centric con WPF, ma il codice da scrivere stavolta non sarà poco e richiederà una certa dimestichezza con WPF e LINQ, poiché, essendo di media complessità, non potremo soffermarci a spiegare ogni aspetto delle menzionate tecnologie. Ci soffermeremo in particolare su tutto ciò che riguarda gli ADO.NET Data Services, limitandoci ad accenni su tutto il resto.
Anche in questo caso potete utilizzare le edizioni Express di Microsoft Visual Studio 2008.
Con riferimento a quanto visto la volta precedente, è possibile utilizzare Visual Web Developer Express per creare il servizio, mentre, con riferimento al presente articolo, è possibile utilizzare Visual Basic 2008 Express che permette di creare le applicazioni client alle quali è possibile aggiungere riferimenti ai servizi WCF.Tipologie valide di client
Lavorando con gli ADO.NET Data Services è possibile utilizzare la maggior parte delle applicazioni client realizzabili con Visual Studio 2008, quindi Windows (Windows Forms, Windows Presentation Foundation, Console) e Web (Silverlight, Web applications). In giro per il Web troverete la maggior parte dei tutorial con client Silverlight e C# come linguaggio. Noi invece, ci occuperemo di vedere in azione la potenza di Windows Presentation Foundation col nostro amato Visual Basic. Iniziamo subito con la pratica, mettendo mano al codice.Cosa realizzeremo
Ritengo opportuno darvi un'immagine di quello che sarà il risultato finale del nostro lavoro, di modo che possiate avere un'idea ben precisa di come lavorerà la nostra applicazione client. Una volta completata e in esecuzione, essa si presenterà come in figura:![]()
Probabilmente da un'applicazione WPF vi sareste aspettati un'estetica ben diversa, tuttavia non è questo lo scopo principale da perseguire, in questo contesto. A noi interessa, infatti, osservare come sia semplice creare applicazioni per l'accesso ai dati con WPF e come queste non abbiano alcunché da invidiare alle 'vecchie' Windows Forms, soprattutto a livello di potenza. Avremo quindi un rapporto master-detail, ottenuto attraverso la selezione di categorie di prodotti da una ComboBox, e la conseguente visualizzazione in una ListView dei prodotti appartenenti alla categoria specificata, con la possibilità di eseguire operazioni di creazione, modifica ed eliminazione dei dati.
Creazione del progetto
Se utilizzate Visual Studio 2008 Standard o superiore, riaprite la soluzione NorthwindDataServices iniziata la volta scorsa. Nel caso in cui, invece, utilizziate Visual Basic 2008 Express questo non serve. Nel primo caso, aggiungete alla soluzione un nuovo progetto Visual Basic per WPF; nel secondo, create un nuovo progetto WPF. In entrambi i casi, il progetto si chiamerà NorthwindClient, come mostrato in figura:![]()
Dopo alcuni secondi la creazione del nuovo progetto viene completata. Ora è necessario aggiungere un riferimento al servizio creato in precedenza. Questo avviene selezionando il comando Project/Add service reference, comando specifico per l'aggiunta di riferimenti a servizi WCF e non ai Web service classici. Quando compare la finestra Add Service Reference, fate clic sul pulsante Discover in modo che Visual Studio vada a cercare i servizi WCF presenti nella soluzione. Dopo alcuni secondi Visual Studio mostra nella finestra il servizio NorthwindService; dobbiamo fare clic su di esso al fine di attivare l'hosting nel server ASP.NET utilizzato da Visual Studio in fase di debug e affinché il servizio stesso sia utilizzabile. Da ultimo, nella casella Namespace specificate l'identificatore NorthwindServiceReference. Alla fine di queste operazioni, la finestra si presenta in questo modo:
![]()
Fate attenzione alla casella chiamata Address. In questa casella deve essere digitato l'URL del servizio. Nel nostro caso il servizio è disponibile nella soluzione, ma in scenari reali è solitamente ospitato su un server Web. In questo caso è sufficiente sostituire l'URL locale con quello effettivo, per esempio http://www.visual-basic.it/Northwind.svc se il servizio è esposto da un sito Internet. Questo per dire che non c'è alcuna differenza tra una demo in locale e un'applicazione reale, basta specificare l'URL esatto (e, ovviamente, accertarsi che la pubblicazione del servizio sull'host sia avvenuta correttamente). In altre parole, provate a pensare che il servizio sia ospitato su un server posto in tutt'altra località diversa da quella del vostro ufficio o di casa vostra, staccandovi dal concetto di demo in locale: il funzionamento è esattamente identico.
Fate clic su OK. In questa fase, Visual Studio 2008 richiama, dietro le scene, un tool a riga di comando chiamato DataSvcUtil.exe che genera una classe proxy, necessaria in tutti i client che referenziano un servizio WCF, ma in questo caso specifica per i Data Services. Se in Solution Explorer attivate la visualizzazione di tutti i file, noterete come venga creata una cartella chiamata Service References all'interno della cui struttura esiste un file chiamato Reference.vb che costituisce la classe proxy citata e che contiene tutto il codice lato client per l'accesso alle entità.
Scriveremo ora il codice per l'esecuzione delle operazioni CRUD (Create, Read, Update, Delete).
Una classe per le operazioni sui dati
Per praticità aggiungeremo al progetto una classe che esporrà alcuni metodi per ottenere i dati ed elaborarli con operazioni di Insert/Update/Delete: aggiungete al progetto un nuovo file di codice chiamato Helper.vb. Innanzitutto importiamo i namespace System.Data.Services.Client (che ci permette di usare LINQ) e NorthwindClient.NorthwindServiceReference (per abbreviare i richiami agli oggetti da questo esposti), quindi dichiariamo un campo che identifichi il contesto per lavorare con le entità di ADO.NET Entity Framework:Imports NorthwindClient.NorthwindServiceReference Imports System.Data.Services.Client Public Class Helper Public NorthwindContext As NORTHWNDEntitiesL'istanza del contesto viene definita nel costruttore della classe, in questo modo:
Public Sub New() NorthwindContext = New NORTHWNDEntities(New Uri("http://localhost:6265/Northwind.svc")) End SubIl costruttore della classse NORTHWNDEntities riceve, quale argomento, un oggetto di tipo Uri con l'indirizzo del servizio, che è uguale a quello digitato nella finestra Add Service Reference. Per una dimostrazione come questa, l'aggiunta dell'URI direttamente da codice Visual Basic può andar bene, ma in uno scenario reale è opportuno memorizzare l'URL del servizio in un file di configurazione e ricavare l'informazione da codice. Infatti potremmo avere la necessità di spostare il servizio a un altro indirizzo e, in questo modo, ci basta modificare il contenuto del file di configurazione senza dover ricompilare il progetto.
Definiamo ora due metodi, uno per recuperare l'elenco delle categorie dall'entità Categories e uno per ottenere l'elenco dei prodotti dall'entità Products:
Public Function GetCategories() As IQueryable(Of Categories) 'LINQ to DataServices in action: Dim categorie = From cat In NorthwindContext.Categories _ Order By cat.CategoryName _ Select cat Return categorie End Function Public Function GetProducts(ByVal Category As Categories) As IQueryable(Of Products) 'Eager loading con Expand Dim prodotti = From prod In NorthwindContext.Products.Expand("Categories") _ Where prod.Categories.CategoryName = Category.CategoryName _ Order By prod.ProductName _ Select prod Return prodotti End FunctionIn entrambi i metodi facciamo uso di semplici query LINQ (LINQ to Data Services), eseguendo l'ordinamento dei dati in base ai nomi di categorie e prodotti. Nel secondo metodo facciamo uso di una tecnica chiamata Eager Loading (letteralmente: caricamento assiduo; a senso: caricamento precoce), molto importante nell'Entity Framework poiché ci consente di ottenere anche i dati relazionati a quelli su cui stiamo lavorando. Nel caso specifico, il metodo GetProducts riceve un argomento di tipo Categories, ossia una categoria di prodotti. Per ottenere i prodotti appartenenti alla categoria ricevuta dal metodo, si utilizza il metodo Expand dell'entità Products e poi si fa il confronto in base al nome della categoria. Entrambi i metodi restituiscono IQueryable(Of T), il tipo di dato restituito da LINQ in ADO.NET Entity Framework.
Ci occorrono poi tre nuovi metodi, rispettivamente per la rimozione, l'aggiunta e la modifica di un prodotto. Iniziamo col meotodo per rimuovere i dati:
Public Sub DeleteProduct(ByVal Product As Products) Try NorthwindContext.AttachTo("Products", Product) NorthwindContext.DeleteObject(Product) NorthwindContext.SaveChanges() Catch ex As DataServiceRequestException MessageBox.Show(ex.InnerException.Message) Catch ex As ArgumentNullException MessageBox.Show("No row was selected.") End Try End SubL'argomento del metodo è l'istanza del prodotto che si vorrà rimuovere dall'entità e verrà successivamente specificato dall'utente attraverso l'interfaccia grafica. Il metodo AttachTo indica ad ADO.NET Entity Framework di avviare il tracking sull'entità specificata (ossia di dire al contesto di seguire cosa succede alle entità), quindi Products. Questo metodo è necessario, poiché negli ADO.NET Data Services le entità assumono per default lo stato di detached, al contrario di quanto può avvenire in applicazioni sempre basate su Entity Framework, ma non in ambito WCF. Troverete sempre questa situazione nei servizi WCF che sfruttano Entity Framework o LINQ-to-SQL, dovrete pertanto sempre tenere a mente che lo stato delle entità è detached per default e quindi va fatto l'attachment manualmente. Non a caso, abbiamo creato una classe che espone metodi di istanza e non condivisi, proprio perché ad ogni operazione CRUD dobbiamo rieseguire l'attachment delle entità al contesto. I rimanenti metodi, DeleteObject e SaveChanges, si spiegano da soli e sono i soliti metodi utilizzati in Entity Framework. Due eccezioni sono state intercettate: la DataServiceRequestException si verifica se ci sono errori in fase di esecuzione dell'operazione da parte del servizio, la seconda (ArgumentNullException) è stata prevista per comunicare all'utente che nessun prodotto è stato ricevuto dal metodo come argomento (lo capiremo meglio nell'implementare l'interfaccia).
Il metodo per la modifica dei dati ha funzionamento analogo, ma chiama il metodo UpdateObject del contesto:
Public Sub UpdateProduct(ByVal Product As Products) Try NorthwindContext.AttachTo("Products", Product) NorthwindContext.UpdateObject(Product) NorthwindContext.SaveChanges() Catch ex As DataServiceRequestException MessageBox.Show(ex.InnerException.Message) Catch ex As ArgumentNullException MessageBox.Show("No row was selected.") End Try End SubDa ultimo, è necessario esporre un metodo per l'aggiunta di un nuovo prodotto e che commenteremo di seguito:
Public Sub AddNewProduct(ByVal Product As Products) NorthwindContext.AddToProducts(Product) NorthwindContext.AttachTo("Categories", Product.Categories) NorthwindContext.SetLink(Product, "Categories", Product.Categories) NorthwindContext.SaveChanges() End SubNel generare l'Entity Data Model, Visual Studio ha altresì generato tanti metodi AddTo quante sono le entità confluite nell'EDM stesso, quindi anche un metodo AddToProducts che viene richiamato per aggiungere all'entità Products il prodotto specificato. Qui la situazione è un po' più complessa, poiché bisogna definire la relazione tra il prodotto e la relativa categoria di appartenenza. Pertanto l'attachment viene fatto, stavolta, sull'entità Categories specificando l'omonima proprietà dell'entità Product ricevuta come argomento dal metodo. La relazione va stabilita esplicitamente tramite il metodo SetLink che riceve tre argomenti: l'istanza della nuova entità (in questo caso un nuovo prodotto), l'EntitySet che assume la posizione Master nella relazione master-details (in questo caso Categories), e la proprietà che rappresenta l'oggetto di tipo Master al quale appartiene l'entità ricevuta come argomento dal metodo (in questo caso, Product.Categories).
Mi rendo conto che questo insieme di concetti possa non essere di immediata comprensione, per questo motivo è bene avere un po' di dimestichezza con LINQ e ADO.NET Entity Framework. Allora riposiamoci un po' e facciamo qualcosa di più piacevole (ma altrettanto importante) come la definizione dell'interfaccia grafica.
Definizione dell'interfaccia
In Solution Explorer, fate doppio clic sul file Window1.xaml per attivare il designer WPF di Visual Studio 2008. L'interfaccia sarà costituita da una griglia (Grid) di partenza, suddivisa in quattro righe (RowDefinition). Nella prima riga sarà specificato un testo (TextBlock) di benvenuto, nella seconda una ComboBox per la selezione della categoria dei prodotti da visualizzare, nella terza una ListView che mostrerà i prodotti appartenenti alla categoria desiderata e nella quarta ci saranno alcuni pulsanti per eseguire le operazioni di inserimento, modifica ed eliminazione dei dati.Nel corso dei prossimi passaggi faremo uso dei DataTemplate per la ListView, di cui abbiamo parlato in un precedente articolo, WPF: Trattare i dati con LINQ-to-Entities, al quale vi rimando per gli approfondimenti su questi concetti.
Passando all'editor di codice XAML, in primo luogo suddividiamo la griglia in quattro righe:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="40"/> <RowDefinition Height="35"/> <RowDefinition/> <RowDefinition Height="50"/> </Grid.RowDefinitions>Quindi presentiamo un messaggio di intestazione:
<TextBlock Grid.Row="0" Text="Northwind Traders products" FontSize="24" FontWeight="Bold" Margin="5" />Poi definiamo la ComboBox per la selezione delle categorie:
<ComboBox Margin="5" ItemsSource="{Binding}" DisplayMemberPath="CategoryName" Grid.Row="1" Name="CategoriesCombo"/>Qui dobbiamo fare attenzione a due proprietà: la ItemsSource indica che la sorgente dati è in binding, quindi il codice dice al motore di WPF di tenere in sospeso il popolamento della Combobox, poiché verrà fatto via codice attraverso la tecnica del data-binding. La proprietà DisplayMemberPath, invece, indica quale proprietà della sorgente dati collegata al controllo deve essere visualizzata. Nel nostro caso alla Combobox verrà collegato l'insieme delle entità Categories, pertanto per ciascuna categoria dovrà essere visualizzato il testo riferibile alla proprietà CategoryName.
Successivamente definiamo la ListView che, come detto, fa utilizzo dei DataTemplate e che mostrerà solo alcune delle proprietà delle entità:
<ListView ItemsSource="{Binding}" Grid.Row="2" Name="ProductsListView" Margin="5" > <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> <EventSetter Event="GotFocus" Handler="Item_GotFocus"/> </Style> </ListView.ItemContainerStyle> <ListView.View> <GridView> <GridViewColumn Header="Product Name"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=ProductName}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Product ID"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=ProductID}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Discontinued"> <GridViewColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding Path=Discontinued}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Unit Price"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=UnitPrice}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Units in stock"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=UnitsInStock}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="Units on Order"> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Path=UnitsOnOrder}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView>Anche il popolamento di questo controllo è lasciato in sospeso (ItemsSource in binding) e verrà finalizzato da codice. E' interessante notare come, per la proprietà Discontinued, venga utilizzata una CheckBox nel Data Template, in grado di autodeterminare il proprio stato di checked o unchecked a seconda del valore booleano ricevuto. L'utilizzo delle TextBox nei Data Template, inoltre, ci consentirà la modifica dei dati. Questo è possibile perché gli oggetti esposti dall'Entity Framework implementano l'interfaccia INotifyPropertyChanged e questo ci dà la possibilità di porre in essere il data-binding di tipo two-way (bidirezionale).
Da ultimo, un contenitore al cui interno insistono alcuni pulsanti:
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="5"> <Button Content="New Product" Height="30" Margin="5" Name="NewProductButton" /> <Button Content="Update Product" Height="30" Margin="5" Name="UpdateProductButton" /> <Button Content="Delete Product" Height="30" Margin="5" Name="DeleteProductButton" /> </StackPanel> </Grid>Il designer di Visual Studio si presenta ora come in figura:
![]()
Non ci resta ora che completare il lavoro rendendo operativa l'interfaccia.
Rendiamo operativa l'applicazione
Passate ora al file di code behind, Window1.xaml.vb. Innanzitutto importiamo il namespace NorthwindClient.NorthwindServiceReference:Imports NorthwindClient.NorthwindServiceReferenceQuindi predisponiamo un metodo che si occupi di caricare l'elenco delle categorie di prodotti quando l'applicazione viene eseguita:
Private Sub LoadCategories() Dim helperClass As New Helper CategoriesCombo.ItemsSource = helperClass.GetCategories CategoriesCombo.SelectedIndex = 0 End SubNel metodo LoadCategories viene istanziata la classe Helper e, tramite il metodo di istanza GetCategories scritto in precedenza, l'elenco delle categorie di prodotti viene ottenuto e assegnato alla proprietà ItemsSource della Combobox, la cui proprietà SelectedIndex impostata a zero ci consente di rendere visibile il valore del suo primo elemento. Possiamo richiamare il metodo al caricamento della finestra:
Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) _ Handles Me.Loaded LoadCategories() End SubCi vuole, ora, un altro metodo che si occupi di caricare i prodotti appartenenti a ciascuna categoria, nel momento in cui l'utente seleziona la categoria desiderata dalla Combobox. Il metodo, che chiameremo LoadProducts, è il seguente:
Private Sub LoadProducts() Dim SelectedCategory As Categories = DirectCast(CategoriesCombo.SelectedItem, Categories) Dim helperClass As New Helper ProductsListView.ItemsSource = HelperClass.GetProducts(SelectedCategory) End SubSe vi ricordate, il metodo GetProducts della classe Helper riceve come argomento un'entità di tipo Categories. In realtà, tutti gli elementi della Combobox sono oggetti Categories (noi visualizziamo nell'elenco solo il valore della proprietà CategoryName). Ciò posto, viene eseguita la conversione dell'oggetto selezionato nella Combobox nel tipo Categories e passato al metodo GetProducts. L'elenco dei prodotti ottenuto per la categoria specificata viene poi assegnato alla proprietà ItemsSource della ListView che viene popolata in data-binding. Questo metodo viene richiamato alla selezione della categoria nella Combobox, quindi al verificarsi dell'evento SelectionChanged:
Private Sub CategoriesCombo_SelectionChanged(ByVal sender As Object, _ ByVal e As System.Windows.Controls.SelectionChangedEventArgs) _ Handles CategoriesCombo.SelectionChanged LoadProducts() End SubPredisponiamo, prima di altre cose, un gestore di evento GotFocus per gli elementi della ListView in modo da sincronizzare il passaggio del mouse con gli elementi della ListView stessa:
Private Sub Item_GotFocus(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) Dim item = CType(sender, ListViewItem) Me.ProductsListView.SelectedItem = item.DataContext End SubDobbiamo ora definire il comportamento in seguito al clic sul pulsante Add new product. Chiaramente, sarebbe opportuno prevedere un'apposita finestra per l'inserimento dei dati da parte dell'utente. Nella nostra piccola dimostrazione, però, può essere sufficiente istanziare un nuovo oggetto Products da codice per verificare che il tutto funzioni. Lo facciamo tramite il seguente gestore di evento:
Private Sub NewProductButton_Click(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) _ Handles NewProductButton.Click Dim ProgProduct As New Products With ProgProduct .Discontinued = False .ProductName = "Test Product" .UnitsInStock = 2 .UnitPrice = 2.5D .Categories = DirectCast(CategoriesCombo.SelectedItem, Categories) .UnitsOnOrder = 2 .QuantityPerUnit = "5" .ReorderLevel = 2 End With Dim helperClass As New Helper helperClass.AddNewProduct(ProgProduct) LoadProducts() End SubIn modo più astratto, invece, gestiamo l'aggiornamento degli elementi della ListView corrispondenti ai vari prodotti (vedi commenti nel codice):
Private Sub UpdateProductButton_Click(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) _ Handles UpdateProductButton.Click 'ottengo l'elemento selezionato nella ListView e lo converto nel Products corrispondente Dim prod As Products = DirectCast(ProductsListView.SelectedItem, Products) Dim helperClass As New Helper 'Aggiorno il prodotto helperClass.UpdateProduct(prod) 'e rieseguo il data-binding LoadProducts() End SubIn maniera analoga si comporta la gestione dell'eliminazione del prodotto selezionato:
Private Sub DeleteProductButton_Click(ByVal sender As System.Object, _ ByVal e As System.Windows.RoutedEventArgs) _ Handles DeleteProductButton.Click Dim prod As Products = DirectCast(ProductsListView.SelectedItem, Products) Dim helperClass As New Helper helperClass.DeleteProduct(prod) LoadProducts() End SubBene! Dopo tanta fatica il nostro lavoro è completato. L'ultima operazione è impostare il progetto WPF come progetto di avvio, facendo clic destro sul suo nome in Solution Explorer -> Set as startup project.
Test dell'applicazione
Premete F5 per avviare l'applicazione. Se tutto è andato a buon fine, dopo alcuni secondi necessari al caricamento dei dati otterrete un risultato simile a quello mostrato nella prima figura dell'articolo. Provate a utilizzare i pulsanti; per esempio, la seguente figura mostra il risultato dell'aggiunta di un nuovo prodotto a una categoria:![]()
Per rimuovere o modificare il prodotto desiderato è sufficiente utilizzare uno dei pulsanti preposti, l'importante è ricordare di fare clic sulla riga corrispondente al prodotto per selezionarla, pena un messaggio di errore.
Spero di avervi dato un ulteriore esempio di come Windows Presentation Foundation sia una tecnologia matura e completa anche sul fronte dell'accesso ai dati, con un motore di data-binding molto più potente e flessibile di quello utilizzato in Windows Forms.
Un'avvertenza personale
Ho avuto la possibilità di provare l'hosting di un ADO.NET Data Service su un server 'vero', quindi scenario reale e accesso ai dati tramite Internet, e mi sono scontrato con alcuni piccoli problemi di configurazione.
Innanzitutto, se decidete di utilizzare Microsoft Internet Information Services come host per il vostro servizio WCF, ricordatevi di abilitare i verbi GET, POST, PUT e DELETE sull'estensione .svc e ricordate, soprattutto, di configurare SQL Server in modo che abbiate i permessi necessari per accedere al database, onde evitare spiacevoli errori Http 500.
Infine, se avete problemi con il codice sorgente a corredo dell'articolo, provate a configurare SQL Server affinché il database sia accessibile dall'utente che ha eseguito l'accesso al sistema.Conclusioni
Gli ADO.NET Data Services sono un'importantissima frontiera nello sviluppo orientato alla gestione dei dati in rete. Grazie a .NET Framework 3.5 Service Pack 1, esporre i dati in rete e fruirne da applicazioni client non è mai stato così semplice e le varie tecnologie come WCF, LINQ e ADO.NET Entity Framework lavorano in una meravigliosa simbiosi limitando in maniera molto forte il ricorso a tecnologie esterne. Ovviamente, molto altro ci sarebbe da dire sui Data Services, ma ci riserviamo di farlo in futuro.Potete scaricare il codice sorgente a corredo dell'articolo dall'area Download di Visual Basic Tips & Tricks.
Per commenti e quant'altro di vostro interesse, potete contattarmi al mio indirizzo visitare il mio blog, per approfondimenti.