Il presente articolo è stato tradotto automaticamente.

Servizi RIA .NET

Creazione di spese basate sui dati applicazioni con Silverlight 3

Jonathan Carter

Download codice disponibile dalla Raccolta di codice di MSDN
Selezionare il codice in linea

In questo articolo si basa su una versione preliminare di .NET RIA servizi. Tutte le informazioni sono soggette a modifiche.

Nell'articolo viene descritto:

  • Guida introduttiva a .NET RIA Services
  • Operazioni di dominio e i servizi di dati
  • Proiezione di codice
  • Controlli dati flessibile
In questo articolo vengono utilizzate le seguenti tecnologie:
Silverlight 3, .NET RIA Services, WPF

Contenuto

Guida introduttiva
Raccolta di servizi dei dati
Operazioni del dominio
Previsioni di codice
Controlli dati
ObjectDataSource
DataPager
DataForm
I metadati
Convalida
Codice condiviso
Eseguire il wrapping dei

all'interno di sviluppo di software è sono numerosi stili diversi di applicazioni, ciascuno dei quali dotato di un proprio scopo requisiti, punti di forza e punti deboli. Quando si sceglie una piattaforma di sviluppo o di un framework, il processo decisionale di verranno probabilmente si basano su se il framework possibile attivare facilmente il tipo di applicazione desiderato per la creazione. Non per gli sviluppatori dedicare ore idraulici o codice di infrastruttura la scrittura, e nessun cliente desidera retribuzione per quel tipo di lavoro da eseguire. La possibilità per principalmente concentrarsi sulle esigenze dell'azienda è importante, con una piattaforma di sviluppo che meglio consente che lo stato attivo e aumenta la produttività è che necessario un assoluto.

Silverlight è una tecnologia grande per la creazione di applicazioni Web complete e interessanti. Mentre Silverlight 2.0 include un sottoinsieme di Windows Presentation Foundation (WPF), non è stata ereditata una notevole quantità della funzionalità di WPF apportate creare applicazioni basate sui dati. Ciò ha causato molti sviluppatori infine passare i su utilizzando Silverlight perché richiederebbe lavoro eccessiva per implementare l'infrastruttura basati sui dati di soluzioni Web più sofisticate. Come parte della versione 3 di Silverlight, nuovi controlli e funzionalità vengono da introdotti che specificamente facilitano applicazioni guidate dai dati lo sviluppo. Questo include nuovi controlli dati, spostamento, convalida e incorporate finestre di dialogo.

Mentre questi miglioramenti lato client forniscono una quantità considerevole di valore sul proprio, Silverlight è un ambiente multitiered e pertanto richiede la conoscenza di affrontare comunicazione client / server. Per risolvere questo problema, .NET RIA servizi (nome in codice " Alexandria") fornisce un insieme di componenti server ed estensioni ASP.NET che facilitano il processo di sviluppo di livello n, semplificando le applicazioni quasi come sviluppare come se sono stati eseguito su un singolo livello. Inoltre, sono disponibili servizi quali l'autenticazione, ruoli e profilo gestione. La combinazione di miglioramenti client e server correlati alla 3 Silverlight e ASP.NET, insieme con l'aggiunta di .NET RIA servizi, semplificare l'esperienza end-to-end di sviluppo di applicazioni Web basate sui dati, detta anche applicazioni Internet RTF o applicazioni RIA.

fig01.gif

Figura 1 progetto Services .NET RIA predefinito

In questo articolo mostra come i miglioramenti apportati a Silverlight 3, in interagisce con la funzionalità introdotte da .NET RIA servizi, fornire un ambiente completo per applicazioni Web di sviluppo basati sui dati. Per meglio illustrare le funzionalità Silverlight 3 e .NET RIA servizi, mi intendo creazione di una nota spese applicazione sfrutterà nuovo set di funzionalità di. L'applicazione verrà consentire a dipendenti di accedere e gestire e creare le spese personali. Al termine di una nota spese, può quindi essere inviato, in attesa di approvazione di un gestore.

Guida introduttiva

Una volta è stato installato Servizi RIA .NET e 3 di Silverlight, Visual Studio include un nuovo modello di progetto denominato Silverlight Data Application consente di ottenere i e in esecuzione rapidamente. Quando viene creata la soluzione, è visualizzata due progetti: un progetto di Silverlight e un ASP.NET progetto (vedere la Figura 1 ). Il progetto di Silverlight rappresenta l'applicazione client e il progetto ASP.NET conterrà la logica di server back-end.

Che cos'è il vantaggio di questa struttura di progetto predefinita? Portata come Silverlight fornito progetto va, è identico a ciò che otterrebbe se è stato creato un normale progetto Silverlight. Si dispone di un file App.xaml standard e di una pagina predefinita. Esistono, tuttavia, sottili differenze al progetto Silverlight che verrà agevolare gli obiettivi di sviluppo.

Anche il progetto ASP.NET è semplice, ma se si osserva all'interno della pagina default.aspx, si noterà che rende Utilizzo di un nuovo controllo server chiamato SilverlightApplication.

<ria:SilverlightApplication 
  ID="Xaml1" runat="server" 
  Source="~/ClientBin/ExpenseReports.xap" 
  MinimumVersion="1.0" 
  Width="100%" Height="100%" />

Questo controllo è destinato a rendere l'operazione di ospitare un'applicazione Silverlight all'interno di un'applicazione Web Form ASP.NET più semplice. Il controllo SilverlightApplication è già configurato di destinazione XAP che verrà creato dal progetto di Silverlight.

A questo punto, è disponibile un'applicazione di Silverlight funzionale e contenuta. A questo punto è sufficiente iniziare ad aggiungere regole business personalizzate e dell'interfaccia utente.

Si supponga che è stato già ottenuto un database posto per questa applicazione, la prossima cosa da fare è aggiungere un ADO.NET Entity Data Model al progetto server. Entity Framework verranno utilizzati come il mapping di relazionali a oggetti (o/gestore delle risorse) in questo articolo, ma è anche possibile utilizzare LINQ a SQL, NHibernate, ADO.NET tradizionali o qualsiasi altro metodo di accesso ai dati.

Il modello di dati è molto semplice, che contiene solo tre entità: ExpenseReport, ExpenseReportDetail ed Employee (vedere la Figura 2 ). Per ulteriori informazioni sulADO.NET Entity Frameworksu MSDN.

fig02.gif

Nella figura 2 modalità immissione dati

Con il modello dei dati e la selezione o gestore delle risorse O eseguita, è ora possibile iniziare implementa la logica di server back-end. Poiché questo progetto utilizza Silverlight come il client e ASP.NET come l'host, è necessario stabilire un approccio per la comunicazione tra i due livelli. È possibile utilizzare uno qualsiasi delle infrastrutture di comunicazione attualmente disponibili, ad esempio Windows Communication Foundation (WCF) o servizi dati ADO.NET, in base alle esigenze.

Raccolta di servizi dei dati

Services RIA di .NET introduce una raccolta di componenti server di generazione basato su dati RIA più semplici. La raccolta non è basata su qualsiasi framework dell'interfaccia utente specifico, e durante questo articolo viene approfondito il consumo da Silverlight, che è solo una delle opzioni possibili client. Nelle future versioni .NET RIA servizi funzionerà anche con servizi di dati ADO.NET.

Servizi RIA .NET principalmente ruota intorno a una nuova classe denominata DomainService che funge da un endpoint server per l'interazione modello logica e i dati business. Creazione di uno è semplice come sfruttare i modelli di classe di logica di business installati da servizi di RIA .NET in Visual Studio.

Un DomainService può esistere in due forme: dati model–specific o generico. L'implementazione di model–specific dei dati include in modo efficiente un modello di dati, consentendo la possibilità di scrivere una combinazione di codice accesso logica e i dati business. Ciò rende più semplice per ottenere i e in esecuzione rapidamente in scenari in cui si dispone già un modello dati che si desidera lavorare.

Vi sono due dati model–specific DomainService implementazioni fornite con .NET RIA servizi: ADO.NET Entity Framework e LINQ a SQL. Se l'applicazione utilizza uno di quelli, selezionare l'opzione appropriata nella procedura guidata quando si crea un DomainService. Se si sta utilizzando un altro tipo di modello di dati o/gestore delle risorse, è possibile creare propria implementazione specifica della nonché un DomainService.

Per questo articolo, poiché già un Entity Data Model posto, verrà procedere e creare un DomainService Framework–specific entità. VIENE visualizzato una nuova classe che eredita da LinqToEntitiesDomainService <t>:

[EnableClientAccess]
public class ExpenseService : 
  LinqToEntitiesDomainService<ObjectContext> {

  //public IEnumerable<Employee> GetEmployees()
  //{
  //    return this.Context.Employee;
  //}
}

In questo caso, il parametro generico rappresenta il tipo dell'istanza di ObjectContext che rappresenta la connessione a Entity Data Model. Il primo passaggio consiste nel heed l'avviso del commento TODO e sostituire il segnaposto di parametro di tipo con ObjectContext effettivo, in questo caso ExpenseReportContext.

Oltre a ereditare da DomainService (o una derivata), un dominio servizio possibile dispone un EnableClientAccessAttribute collegato. Questo attributo è ciò che effettivamente indica la classe come un servizio di dominio e consente di specificare se è necessario publically esporre. Da publically esposto, intendo accessibile l'applicazione client. Questo consente di scegliere per determinare se alcuni logica è richiesto esclusivamente nel server di o se deve inoltre essere disponibile sul client.

Operazioni del dominio

Un servizio di dominio non è molto utile autonomamente solo aggiungendo alcune funzionalità in forma di operazioni di dominio. Un'operazione del dominio rappresenta un endpoint del servizio del dominio e può eseguire creare, leggere, aggiornare ed eliminare le operazioni (CRUD) per il modello di dati, le regole di business arbitrario o entrambi. Ogni operazione di dominio deve mappare a un tipo di operazione specifica, tra cui query, inserimento, aggiornamento, eliminazione, operazione del servizio e personalizzato. Il mapping del tipo di operazione può essere eseguita dalla convenzione o dalla configurazione.

A seconda che tipo di operazione l'operazione di dominio a verranno assegnati, deve seguire una firma specifica. Inoltre, alcune operazioni necessario seguire una convenzione di denominazione specifica o avere un attributo che determina il tipo di operazione è. Ad esempio, se è un'operazione di query, quindi il tipo restituito deve essere o IEnumerable <T> <T> IQueryable dove T è un tipo di entità funziona con. Può accettare qualsiasi numero di parametri, che può essere utilizzato come filtri, ma non sono obbligatorie.

Creazione di un'operazione di dominio per il recupero di tutte le note spese potrebbe simile al seguente:

public IEnumerable<ExpenseReport> 
  GetExpenseReports() {

  return Context.ExpenseReports;
}

ExpenseReport è un'entità nel modello dei dati sottostante ed è, di conseguenza, un tipo restituito valido. La classe DomainService contiene una proprietà denominata scelta rapida che consente di accedere a un'istanza del modello di dati (il tipo fornito come un parametro generico), consentendo in questo caso di query per un elenco di tutte le spese. Questa operazione viene mappata a un tipo per convenzione.

Creazione di un metodo di dati per il recupero di un report a specific expense potrebbe simile al seguente:

[Query(IsComposable = false)]
public IEnumerable<ExpenseReport> 
  GetExpenseReport(int id) {

  var expenseReport = 
    from rep in Context.ExpenseReports
    where rep.Id == id
    select rep;

  return expenseReport;
}

Si noti che questo metodo dei dati accetta un parametro per il recupero delle spese specifico dall'ID. Poiché si dispone dell'accesso a ObjectContext sottostante, è inoltre possibile scrivere query mediante LINQ. Questo metodo è associato a configurazione, utilizzando il QueryAttribute, consente inoltre di specificare proprietà aggiuntive che non può essere raggiunta conventionally. È possibile Accennare alle che la proprietà IsComposable di QueryAttribute la cosa più avanti in questo articolo.

Un DomainService può contenere come molte query metodi base alle esigenze. Oltre al recupero dei dati, è possibile creare operazioni per i dati persistenti al modello dati. Implementazione di operazioni di base persistenza (inserimento/aggiornamento/eliminazione) per le note spese potrebbe simile al seguente:

public void InsertExpenseReport(
  ExpenseReport expenseReport) {
  Context.AddToExpenseReports(expenseReport);
}

public void UpdateExpenseReport(
  ExpenseReport current, ExpenseReport original) {
  Context.AttachAsModified(current, original);
}

public void DeleteExpenseReport(
  ExpenseReport expenseReport) {
  Context.DeleteObject(expenseReport);
}

È possibile definire le operazioni di persistenza per i dettagli di report di spesa molto analoga a. È possibile impostare un solo inserire, aggiornare ed eliminare metodo al tipo di entità (ExpenseReport in questo scenario) perché, quando una richiesta in DomainService salvare le modifiche il modello di dati, il DomainService deve sapere quale metodo da chiamare.

Una cosa da notare su queste operazioni è le relative firme. Quando si crea un'operazione di inserimento o del metodo delete, deve accettare un singolo parametro conforme al tipo di entità, che il metodo è responsabile dell'inserimento o l'eliminazione. Quando si crea un metodo di aggiornamento, deve accettare due parametri: l'istanza di entità modificato o corrente e l'istanza entità originale. La firma di metodo in combinazione con il nome del metodo è ciò che indica a DomainService quale metodo responsabile per l'operazione per il tipo di entità.

Convenzione di denominazione che può essere utilizzata quando definisce le operazioni di persistenza è prefisso i nomi di metodo con il tipo di operazione. Ad esempio, poiché il metodo viene chiamato DeleteExpenseReport, il prefisso di eliminazione indica che è un'operazione di eliminazione per convenzione. La firma quindi definisce il tipo di entità è associato (ExpenseReport). Come prevedibile, il prefisso del nome di metodo convenzionale per operazioni di aggiornamento è di aggiornamento e inserire le operazioni è Inserisci. Questo è il motivo per cui non È necessario eseguire qualsiasi configurazione aggiuntive per queste operazioni per l'utilizzo.

Se un'operazione non seguono la convenzione di denominazione prevista oppure è necessario specificare ulteriori metadati per l'operazione (ad esempio ha con il metodo GetExpenseReport), quindi è possibile applicare attributi di configurazione quali QueryAttribute, InsertAttribute, DeleteAttribute e UpdateAttribute come con il metodo GetExpenseReport.

Se è necessario definire le regole business che non sono necessariamente correlata a un'operazione CRUD ma sono associato a un tipo di entità, è possibile creare un'operazione del servizio. In questo caso, desidera che le operazioni per l'approvazione e rifiuto di spese. Questo significa semplicemente Modifica valore dello stato del report di spesa (vedere la Figura 3 ). La firma di un'operazione del servizio deve accettare un'istanza del tipo di entità è associato e si deve restituire void. Si noti che non è convenzione per definire operazioni del servizio, pertanto è necessario applicare ServiceOperationAttribute per configurare qualsiasi operazione di dominio appropriato.

Nella figura 3 operazioni di servizio

[ServiceOperation]
public void ApproveExpenseReport(
  ExpenseReport expenseReport) {

  if (expenseReport.Status == 1) {
    if (expenseReport.EntityState == 
      System.Data.EntityState.Detached) {
      Context.Attach(expenseReport);
    }
    expenseReport.Status = 2;
  }
}

[ServiceOperation]
public void RejectExpenseReport(ExpenseReport er) {
  if (er.Status == 1) {
    if (er.EntityState == 
      System.Data.EntityState.Detached) {
       Context.Attach(er);
    }
    er.Status = 0;
  }
}

Ora che è stato ottenuto il servizio di dominio e operazioni create, come si è passare sull'interazione con il servizio dall'host del server ASP.NET all'applicazione client di Silverlight? Se si utilizza servizi di dati ADO.NET o WCF, è necessario creare un riferimento nel progetto di Silverlight che puntava al servizio, che genera un proxy. .NET RIA Services offre una gamma leggermente più avanzata.

Previsioni di codice

Quando si crea la soluzione .NET RIA servizi, il file di progetto di Silverlight era alcuni particolari attività MSBuild aggiunto che gestiscono inserimento componenti server specifico per il client. Quando si crea un servizio di dominio nel progetto ASP.NET contenente un EnableClientAccessAttribute applicata, l'attività di MSBuild sarà progetto tale servizio di dominio per l'applicazione Silverlight. (Se si non crea la soluzione utilizzando il nuovo modello di progetto Silverlight Data Application, è possibile collegare manualmente un progetto di Silverlight e un progetto ASP.NET all'interno di Visual Studio per ottenere lo stesso effetto.)

Se cercherà in code-behind del file Main.xaml nel progetto di Silverlight, potrà risultare ExpenseContext e ExpenseReport tipi. Quando è previsto un provider di dati a un'applicazione client di Silverlight, è non è più un DomainService (o sottotipo), ma piuttosto un DomainContext. Infatti, se il servizio di dominio è suffisso con la parola servizio, verrà sostituita con scelta rapida al momento di proiezione (ossia perché la classe ExpenseService viene riflessa come scelta rapida di spese nel progetto di Silverlight). La classe di DomainContext funge da proxy sul lato client, per un DomainService e contiene la logica necessaria per comunicare le richieste tra i due livelli. Rappresenta un'unità di lavoro e può generare una serie di insiemi di modifiche apportate a qualsiasi istanza di entità che tiene traccia attualmente.

Inoltre, alcuni metodi (metodi pubblici che sono considerati operazioni del dominio mediante convenzione o configurazione) verranno da previsto assieme i Servizi di dominio padre. Dei sei tipi di dati metodo, è previsto solo tre: servizio personalizzato e query. Se il nome di un metodo di query è preceduto da Get, al momento di proiezione Get verranno sostituite con carico. Ad esempio perché È definito un metodo di query con il nome GetExpenseReports, verrà superficie sul client come LoadExpenseReports. Le operazioni di due servizi sono stati previsto anche e verranno visualizzate come metodi di istanza su DomainContext.

Infine, inoltre viene previsto qualsiasi tipo di entità restituito da un'operazione di dominio. <expensereport>In questo esempio, perché tipo restituito del metodo report GetExpense è IEnumerable < ExpenseReport > La classe dell'entità ExpenseReport verrà essere previsto per il client di Silverlight. Le classi di entità previsto ereditare da una classe speciale denominata entità che fornisce il comportamento di rilevamento delle modifiche, controllo di convalida ed editability WPF, SL, compatibile con. Dal punto di vista di API, la classe dell'entità sul lato client, aspetto esattamente come l'entità sul server, ma conterrà funzionalità aggiuntive necessarie per l'interazione con i controlli dati Silverlight.

Sono disponibili molte più dettagli che circonda il comportamento di proiezione di codice più sono illustrati di seguito. In questo articolo non tocco in molti scenari aggiuntivi che sono possibili, inclusa la possibilità di personalizzare la logica che determina la modalità di forma di codice di un tipo specifico prima proiettando all'applicazione client.

STO utilizzando la proiezione di codice termine perché RITENGO che descrive in modo appropriato che cosa accade. La classe ExpenseService non è semplicemente corso la copia da un progetto un'altra (si è effettivamente verificata un'eccezione a questa verrà illustrato più avanti. Si è esaminato, con data shaping e previsto nell'applicazione client come un proxy di facile utilizzo. Di conseguenza, è possibile sfruttare il tipo dal livello client come se fosse un oggetto locale.

In cui viene nascosto il servizio di dominio previsto Il progetto di Silverlight è invariato da relativo stato creato. Se si attiva l'opzione per visualizzare tutti i file per il progetto di Silverlight, si noterà che il colpevole (vedere la Figura 4 ). Generated_Code chiamato che contiene il codice che è stato previsto dal progetto server partner tutti viene creata una cartella. È attualmente solo un singolo file in cui ExpenseReportsServer.g.cs (i corrisponde g per generato), che contiene il codice per l'intero progetto ExpenseReportsServer ed home della classe ExpenseContext.

fig04.gif

Nella figura 4 il codice generato per il progetto di Silverlight

Se si crea un nuovo provider di dati o si modifica uno esistente, le modifiche verranno aggiornate automaticamente all'interno del progetto Silverlight, mantenere il client e il server costantemente sincronizzate. In scenari in cui vengono creati servizi unico scopo di supportare client un'applicazione, la necessità di aggiornare continuamente i proxy del servizio durante la fase di sviluppo può essere un problemi. Questo comportamento sottile, oltre a ripetizione del data lo shaping durante la proiezione, scopre da una funzionalità molto utile.

Controlli dati

Pertanto È stato ottenuto un database, modello di dati, servizi e proxy sul lato client posto. Ora È necessario creare dall'interfaccia utente per la visualizzazione e la modifica delle dati dei spese di report all'interno del client di Silverlight. Quando si utilizzano applicazioni basate sui dati, esistono in genere due tipi di modalità di presentazione dei dati: tabulare e in base a maschera. Quando Gestione con le applicazioni RIA basate sui dati, i dati tabulari e basata su form devono essere presentate in modo che rende l'utente esperienza altamente informativo e la produttività.

Silverlight 2 non è molto complessa il supporto per i dati in formato tabulare presentazione all'esterno della finestra. Nemmeno il controllo ListView (che fornito presentazione base griglia in WPF) è presente in Silverlight, apportate alquanto difficile creare software di business. Silverlight ha ricevuto in seguito un controllo DataGrid, in modo definito contribuito, ma molte funzionalità necessarie sono tuttora mancanti. I controlli intrinseci erano disponibili, ad esempio TextBox, ComboBox, Button, ListBox e RadioButton, apportate possibile, lo sviluppo di moduli, ma non è sicuro supporto per altri comportamenti sono necessari, ad esempio la convalida dei dati e la segnalazione degli errori.

3 Silverlight introduce un set di nuovi controlli che in particolare cui obiettivo a semplificare la creazione di applicazioni RIA basati sui dati. Tali controlli includono DataGrid, DataForm, DataPager, FieldLabel, DescriptionViewer, ErrorSummary e ChildWindow. Richiede funzionalità di DataGrid, DataForm e DataPager per consentire la presentazione dei dati negli stili sia tabulari che basata su form per mia applicazione di esempio. FieldLabel, DescriptionViewer e ErrorSummary forniscono gli interfaccia utente dinamica la convalida dei dati e necessari per lo sviluppo di immissione dei dati risponde segnalazione degli errori. Infine, ChildWindow consente di finestre di dialogo modali RTF.

Il controllo DataGrid fornito con Silverlight 3 è affidabile. Tra le altre cose, include colonne reorderable e ridimensionabile, raggruppamenti di righe, modifica inline e convalida. Consente di definire le colonne visualizzate nella griglia in due modi: generati e, in modo esplicito.

Un DataGrid AutoGenerateColumns proprietà è impostata su true verrà creato automaticamente una colonna per ogni proprietà pubblica sul tipo a cui è associato, l'eccezione che se una proprietà ha un BindableAttribute collegato che specifica non è associabile, quindi il controllo DataGrid non crea una colonna corrispondente. Questo è un esempio di come i nuovi controlli dati sfruttano i metadati di entità.

Quando si definiscono in modo esplicito le colonne in un DataGrid, si sono ambito i dati visualizzati solo le colonne da visualizzare. In questo modo controllare quali tipi di colonna da utilizzare, nonché il testo dell'intestazione e numerose altre proprietà di colonna. Un DataGrid che definisce in modo esplicito le colonne per la visualizzazione dati del rapporto delle nota spese potrebbe essere simile nella figura 5 .

Nella figura 5 DataGrid per spese

<dataGrid:DataGrid
  x:Name="ExpenseReportDataGrid"
  AutoGenerateColumns="False">
  <dataGrid:DataGrid.Columns>
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Company}" 
      Header="Company" />
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Department}" 
      Header="Department" />
    <dataGrid:DataGridTextColumn 
      Binding="{Binding Description}" 
      Header="Description" />
    <dataGrid:DataGridCheckBoxColumn 
      Binding="{Binding Status}" 
      Header="Approved" />
  </dataGrid:DataGrid.Columns>
</dataGrid:DataGrid>

Le proprietà specificate nelle associazioni di colonna fanno riferimento alle proprietà sull'entità ExpenseReport. Tenere presente che la classe è stato previsto dell'applicazione Silverlight, rendendo utilizzabili nel client. La classe DataGridTextColumn visualizzerà i dati come testo in modalità di sola lettura e come una casella di testo in modalità di modifica. Il DataGridCheckBoxColumn visualizza un campo come una casella di controllo in tutte le modalità e contenere tre stati.

Per inserire un controllo DataGrid sufficiente impostare la relativa ItemSource proprietà a qualsiasi oggetto IEnumerable. Tenere presente che quando definito lo spese-servizio e il metodo di dati GetExpenseReports, il tipo restituito è IEnumerable <expensereport>. A questo punto solo necessario scoprire come utilizzare il proxy sul lato client, per il provider di dati che è stato generato.

Quando la classe ExpenseService è stato previsto all'applicazione client, il metodo GetExpenseReports è stato previsto anche dopo che viene rinominato LoadExpenseReports). Ciò significa che sarà possibile solo creare un'istanza di ExpenseService e chiamare il metodo LoadExpenseReports. Mentre che è l'approccio corretto da intraprendere, non produrre qualsiasi risultati autonomamente. Aspetto interessante è che sufficiente, il metodo LoadExpenseReports non restituisce nulla. Come si ottengono i dati del rapporto delle spese?

Silverlight richiede eventuali chiamate di Blocca da eseguire in modo asincrono in modo che il thread dell'interfaccia utente non viene bloccata. Di conseguenza, quando .NET RIA servizi progetti per i Servizi di dominio a un client di Silverlight refactors tutte le operazioni di query in modo che non restituiscano nulla. Questo viene spiegato perché .NET RIA Services verranno rinominati i metodi di query per essere con il prefisso carico invece di lettura (richieste di recupero, ricerca, query, recuperare o selezionare), poiché riflette il comportamento in modo più appropriato.

Invece di che utilizza un metodo di callback, classi generate da .NET RIA Services utilizzano un modello di eventi per le notifiche è una volta completata una chiamata asincrona. Di conseguenza, per rispondere al caricamento di un'operazione di query, è sufficiente sottoscrivere caricamento evento il DomainContext che verrà attivata non appena viene completata qualsiasi operazione di query. Poiché il gestore eventi viene chiamato sul thread UI, è possibile eseguire qualsiasi associazione dati in essa contenute.

Durante il caricamento dei dati di spese nella figura 6

public partial class Main : Page {
  ExpenseContext _dataContext;

  public Main() {
    InitializeComponent();

    this.Loaded += Main_Loaded;

    _dataContext = new ExpenseContext();
    _dataContext.Loaded += dataContext_Loaded;
  }

  void dataContext_Loaded(object sender, LoadedDataEventArgs e) {
    ExpenseReportDataGrid.ItemsSource = e.LoadedEntities;
  }

  void Main_Loaded(object sender, RoutedEventArgs e)  {
    _dataContext.LoadExpenseReports();
  }
}

fig07.gif

Nella figura 7 spese report griglia dell'interfaccia utente

Dopo che è stato generato il gestore eventi di caricamento, non esistono due modi per recuperare i dati richiesti: tramite la proprietà LoadedDataEventArgs.LoadedEntities o tramite una delle proprietà fortemente tipizzate entità del contesto di dominio (ad esempio ExpenseContext). Accede ai dati mediante gli argomenti dell'evento rappresenta l'approccio preferito perché questo sarà garantisce che vengono trasferiti solo i dati che si desidera. Ogni volta che un'operazione di query viene chiamata, l'entità restituito istanze verranno aggiunto il contesto di dominio, pertanto ogni volta che per accedere il contenuto è recupero costituito ogni query, non solo per quella più recentemente eseguita.

Implementa la logica per il recupero di tutte le note spese e riempire il controllo DataGrid con i dati restituiti potrebbe essere simile nella figura 6 . A questo punto, nostro RIA basate sui dati è simile a figura 7 .

Oltre a essere in grado di caricare i dati, la classe DomainContext (e il sottotipo generato) contiene metodi per la gestione di rilevamento delle modifiche e persistenza dei dati. Ogni modifica apportata a un'entità che è stata recuperata (o aggiunti o eliminata) tramite un DomainContext verrà tenere traccia. Quando si desidera salvare le modifiche, è possibile chiamare semplicemente il metodo SubmitChanges:

private void SaveChangesButton_Click(
  object sender, RoutedEventArgs e) {
  if (_dataContext.HasChanges) {
    _dataContext.SubmitChanges();
  }
}

Poiché il controllo DataGrid consente in linea modifica per impostazione predefinita, è possibile modificare i record del report di spesa e fare clic sul pulsante Salva le modifiche per rendere persistenti nel server. Quando viene chiamato il metodo SubmitChanges, il DomainContext assembla una modifica impostato per tutti i relative entità revisioni e invia DomainService corrispondente. Il DomainService decomposes il set modifica quindi chiama l'operazione domini relativi per ogni entità che inserita, aggiornata o eliminata.

Quando si modifica i dati all'interno del controllo DataGrid, fornisce convalida e la segnalazione automaticamente. Se si immettono dati non validi, è possibile visivamente notificato con una spiegazione su ciò che non è corretto (vedere la Figura 8 ). Questa funzionalità risulta senza configurazione o lavoro parte dell'utente. Come si vedrà più avanti in questo articolo, è possibile definire anche le regole di convalida personalizzata sul modello di dati che verrà prelevato e garantita per il controllo DataGrid.

fig08.gif

Nella figura 8 convalida DataGrid

La visualizzazione dei rapporti delle spese è corretta ma sarebbe molto più utile visualizzare le spese raggruppate per stato. In questo modo che È possibile immediatamente scoprire che i report sono in attesa di approvazione da un manager. Fortunatamente, questo è possibile ottenere con facilità in Silverlight 3 aggiungendo questo codice la definizione di DataGrid esistente:

<dataGrid:DataGrid.GroupDescriptions>
  <dataGrid:PropertyGroupDescription  
    PropertyName="Status" />
</dataGrid:DataGrid.GroupDescriptions>

Il risultato sarà simile al Nella figura 9 .

fig09.gif

Nella Figura 9 raggruppamento DataGrid

ObjectDataSource

Mentre alcuni sviluppatori verranno comunque i dati imperativi associazione approccio utilizzato fino ad altri utenti potrebbero come la possibilità di eseguire l'associazione esclusivamente in modo dichiarativo, molto nello stesso modo in cui funzionino con ObjectDataProvider in WPF di dati. A tal fine, 3 Silverlight introduce il controllo ObjectDataSource.

ObjectDataSource è un controllo non visive che conosca l'utilizzo in particolare di tipi DomainContext. Può essere considerato come fornire tutte le funzionalità che ha l'approccio imperativa precedente ma in modo completamente dichiarativa (più più). Semplicemente indicare il tipo di DomainContext si sta lavorando e quali le operazioni di query desiderato chiamato. ObjectDataSource gestirà il resto.

È possibile rimuovere tutto il codice dalla sezione precedente e sostituirlo con un ObjectDataSource e chiamerà automaticamente il metodo di carico specificato:

<ria:ObjectDataSource
  x:Name="ExpenseReportsObjectDataSource"
  DataContextType="ExpenseReports.ExpenseContext"
  LoadMethodName="LoadExpenseReports"
  PageSize="20">
  <ria:ObjectDataSource.Filter>
    <data:FilterDescriptor Member="Department" 
      Operator="IsEqualTo" Value="IT" />
  </ria:ObjectDataSource.Filter>
  <ria:ObjectDataSource.Sort>
    <data:SortDescriptor Member="Status" 
      Direction="Descending" />
  </ria:ObjectDataSource.Sort>
</ria:ObjectDataSource>

Utilizzando il controllo ObjectDataSource non solo consentono dichiarative di associazione dati, rende query componibile. È possibile aggiungere ordinare, raggruppare e le espressioni di filtro per un ObjectDataSource, nonché per dimensioni della pagina, che verranno applicati alla chiamata a relativa operazione di query. La parte migliore è che ObjectDataSource modificherà la richiesta al servizio di dominio in modo che qualsiasi ordinamento specificato o un filtro viene applicato sul lato server, ovvero che senza dati non necessari verranno passati in rete.

Tenere presente la proprietà IsComposable del DomainOperationAttribute? Ovvero determina se un'operazione di dominio consente di parametri di query aggiuntive da passare, rendendo i dati restituiti componibile. Il metodo GetExpenseReports non sono state aggiunte qualsiasi codice di ordinamento o filtro ma causa di composability il DomainService e il fatto che l'oggetto ObjectDataSource sa come rendere composto da query, È possibile ottenere automaticamente tale funzionalità.

ObjectDataSource è effettivamente un wrapper per un'istanza DomainContext e pertanto vantaggi da stesso comportamento di rilevamento delle modifiche. Contiene gli stessi metodi Load e SubmitChanges che DataContext, consentono di controllare a livello di codice come un DomainContext.

DataPager

Poiché la quantità di dati attualmente visualizzati nella griglia è un po'difficoltoso, avrebbe probabilmente senso alla pagina per scopi di presentazione. Mentre il controllo DataGrid stesso non include lo spostamento, 3 Silverlight introduce un nuovo controllo DataPager che funziona perfettamente con altri controlli di dati per fornire facilmente funzionalità di spostamento con essi.

Il controllo DataPager presenta semplicemente l'interfaccia utente necessario per lo spostamento tramite un'origine dei dati forniti. Se si associa un DataPager alla stessa origine dei dati come un altro controllo di dati (ad esempio DataGrid), lo spostamento tra i dati utilizzando la DataPager verrà inoltre pagina i dati visualizzati in altri controlli associati. Il codice per aggiungere un DataPager all'elenco delle spese potrebbe essere simile alla seguente:

<data:DataPager
  Source="{Binding Mode=TwoWay, Source={StaticResource ExpenseReportDataSource}, Path=Data}"/>

fig10.gif

Nella figura 10 DataPager effettuate alla parte inferiore di un DataGrid

Si noti che È necessario eseguire è definire il controllo e associarlo a origine corretto e che il controllo gestirà il resto (vedere la Nella figura 10 ).

Il DataPager dispone di numerose modalità è possibile selezionare che variano come presenta pagine disponibili per l'utente. È inoltre possibile re-skin completamente DataPager per la ricerca tuttavia si desidera mantenendo comunque la funzionalità esistente.

Mentre il controllo DataGrid e DataPager forniscono un ottimo inline modifica, cosa succede se si desidera visualizzare i dati in un layout basata su form? Per creare o modificare note spese, che si desidera fornire all'utente una maschera intuitiva da utilizzare anziché fare affidamento sulla griglia. Che è possibile utilizzare il nuovo controllo DataForm.

DataForm

Il controllo DataForm consente di definire un set di campi che verrà visualizzato in un layout basata su form e può essere associato a un'istanza singola entità o un insieme. Consente di utilizzo dei dati in sola lettura, inserire e modificare le modalità, con la possibilità di personalizzare l'aspetto di ogni. È possibile visualizzare facoltativamente controlli per il passaggio tra le modalità e, quando è associato a un insieme, il DataForm inoltre possibile visualizzare un pager per lo spostamento. Come il controllo DataGrid DataForm inoltre disponibile in varie forme: generato, esplicite e il modello.

La modalità generata funziona esattamente come il controllo DataGrid. Crea una coppia di campo e l'etichetta per ogni proprietà pubblica nel tipo di che cui è associato. DataForm rispetta, nonché il BindableAttribute che consente di definire l'elenco dei campi associabili a livello di entità. Definizione di un modulo di modifica per le note spese potrebbe essere semplice come questo:

<dataControls:DataForm
  x:Name="ExpenseReportDataForm" Header="Expense Report"
  ItemsSource="{Binding Source={StaticResource ExpenseReportsObjectDataSource}, Path=Data}" />

Utilizzando la modalità generata, si sta consente DataForm affinché tutti i presupposti dell'interfaccia utente basati sui metadati dell'entità. Il modulo risultante è illustrato nella Figura 11 .

fig11.gif

Nella figura 11 modulo immissione spese derivate DataForm

Etichette per eventuali campi obbligatori (proprietà contrassegnata con l'attributo obbligatorio) appaiono in grassetto, che indica il requisito per l'utente. Inoltre, a destra dei controlli di input, l'icona informazioni fornisce una descrizione della descrizione comandi mouse dell'input previsto. Una descrizione è facoltativa e viene recuperata mediante l'esame se la proprietà del campo corrispondente è un DescriptionAttribute collegato. Questi sono due esempi più di come i nuovi controlli dei dati 3 Silverlight attivare scenari basate sui dati, aggiungendo l'interfaccia utente in risposta a metadati dei modelli di dati.

Esattamente come il controllo DataGrid il DataForm fornisce inoltre la convalida dei dati e la segnalazione degli errori. I due controlli disporre di un aspetto coerente e una funzionalità, che fornisce per un'esperienza utente globale valida indipendentemente dalla quale presentazione dei dati è necessario.

Utilizzando il modulo esplicito, è possibile dichiarare i campi che si desidera visualizzare, il tipo di campi da utilizzare e il testo dell'etichetta da visualizzare tra l'altro). Questo modulo è utile quando non si desidera lasciare la creazione dell'interfaccia utente fino ai metadati DataForm ed entità. Dichiarare in modo esplicito un DataForm potrebbe essere simile Figura 12 .

Nella figura 12 creazione esplicita di un DataForm

<dataControls:DataForm
  x:Name="ExpenseReportDataForm"
  ItemsSource="{Binding Source={StaticResource ExpenseReportsObjectDataSource}, Path=Data}"
  AutoGenerateFields="False">
  <dataControls:DataForm.Fields>
    <dataControls:DataFormTextField 
      Binding="{Binding Company}" Label="Company" />
    <dataControls:DataFormTextField 
      Binding="{Binding Department}" Label="Department" />                
    <dataControls:DataFormTextField 
      Binding="{Binding Description}" Label="Description" />
    <dataControls:DataFormCheckBoxField 
      Binding="{Binding Status}" Label="Approved" />
  </dataControls:DataForm.Fields>
</dataControls:DataForm>

Oltre ai campi per il testo e caselle di controllo, vi sono campi disponibili per data, casella combinata, modello, separatore, intestazione e gruppo di campi. Con questi è possibile definire in modo esplicito i campi desiderati per visualizzare e fornire istruzioni base il DataForm per visualizzare le. Anche con questa flessibilità, si è ancora limitato a un alto, verso il basso modulo, in cui ogni campo è un tradizionale etichetta e input controllano coppia. Mentre il DataFormTemplateField consente di definire un modello per tutte le modalità (visualizzazione e modifica), è limitato a livello di campo. Cosa succede se si desidera modello l'intero modulo?

Quando controllo completo sull'interfaccia utente è necessario (o desiderato), il DataForm consente di definire modelli di dati personalizzati per ognuno dei relative modalità (visualizzazione, inserimento e modifica). Questa possibilità, è possibile interrompere lo stile di modulo dall'alto verso il basso predefinito e creare qualsiasi aspetto significativo per la situazione.

Alcuni comportamento è globale per tutti i tre formati di DataForm, quali spostamento, convalida e la segnalazione degli errori. Quando si desidera ridefinire anche se i modelli di dati, si perde il campo automatica etichetta e la descrizione visualizzatore, che ha lavorato con metadati del modello. Quando si sviluppa un'applicazione di basata sui dati, sarebbe un shame perdere questo comportamento utile solo perché è necessario personalizzare il layout. Fortunatamente, i controlli che sono usati internamente dal dataform e che forniscono questo comportamento sono inoltre utilizzabili manualmente.

I metadati

Quando Consenti DataForm generare l'elenco dei campi per è, rende automatica consente di due controlli di fornire il comportamento di etichetta e la descrizione: FieldLabel e DescriptionViewer. Entrambi i controlli sono facili da utilizzare e possono essere utilizzati in uno scenario con associazione a dati, inclusi i modelli DataForm personalizzati.

FieldLabel risulta utile visualizzare un'etichetta per un controllo che è determinato dai metadati della proprietà associata associato. Il testo utilizzato per l'etichetta viene derivato dalla proprietà Name di DisplayAttribute collegata la proprietà che è associato. Inoltre, se la proprietà è necessaria (contrassegnato graficamente dall'con un RequiredAttribute contrassegnato come true collegato), il testo dell'etichetta campo sarà in grassetto.

Oltre a essere in grado di specificare un nome personalizzato con la DisplayAttribute, è possibile specificare una descrizione per una proprietà. Se si desidera visualizzare descrizione un campo, è possibile utilizzare il controllo DescriptionViewer, che gestisce questa per consentire automaticamente. Verrà visualizzata un'icona informazioni che fornisce una descrizione comando contenente la descrizione della proprietà che è associato.

Con i controlli FieldLabel e DescriptionViewer, è possibile sviluppare moduli dati personalizzati che sfruttano dei metadati dal modello dei dati senza dover di replicare le informazioni (ad esempio i nomi dei campi e descrizioni). Se si utilizzano questi controlli in tutta l'applicazione, qualsiasi volta che è apporta una modifica a una proprietà nome, descrizione o stato richiesto (livello di modello), l'interfaccia utente riflette automaticamente la modifica a causa della dipendenza il modello di dati. Questo è il tipo di comportamento che è prevedibile durante lo sviluppo di applicazioni basate sui dati.

Convalida

Poiché si sta concentrandosi sullo sviluppo di applicazioni basate sui dati, vorremmo mantenere la logica aziendale e convalida vicino per il modello di dati. Quando si utilizza .NET RIA servizi è possibile esprimere la logica di convalida in due modi: le annotazioni di dati e logica condivisa o personalizzata.

Un insieme di attributi denominato le annotazioni di dati sono intese per associare regole dei metadati e la convalida a un modello di data è stata introdotta nella versione SP1 di Microsoft .NET Framework 3.5. Queste annotazioni inizialmente sono state utilizzate da dati dinamici di ASP.NET e sono comprese e rispettate .NET RIA servizi e nuove 3 di Silverlight controlli dati. Con questi è possibile esprimere tali aspetti convalida esempio lunghezza della stringa, intervallo, tipo di dati e i vincoli di espressione regolare:

[Bindable(true, BindingDirection.TwoWay)]
[Display(Name = "Expense Amount", 
  Description = "The amount of the incurred expense.")]
[Range(0.0, 1000000.00)]
public object Amount;

[Bindable(true, BindingDirection.TwoWay)]
[Display(Name = "Category", 
  Description = "The category of expense, i.e., mileage.")]
[StringLength(10)]
public object Category;

Quando la proiezione .NET RIA servizi processo che viene eseguita, si otterrà un punto per scorrere le annotazioni di dati del lato server al client. Come è possibile sfruttare le annotazioni di dati generico per rappresentare le regole di convalida del modello di dati del lato server, che convalida verrà eseguire all'applicazione Silverlight ed essere completamente utilizzabili dai controlli con supporto (DataForm, DataGrid FieldLabel e così via). Questo efficace consente convalida client e server.

Utilizzando le annotazioni di dati è semplice, ma non può esprimere ogni requisito di convalida possibili. Infatti, può realmente rappresentano solo gli scenari più comuni. Per le altre situazioni sarà probabilmente necessario definire la convalida in modo imperativo. Sebbene sia semplice a scopo, il processo di proiezione di .NET RIA Services non solo flusso la logica personalizzata per il client tale processo è limitato alla creazione di classi proxy DataContext ed entità.

Mantenere la logica personalizzata sul server e verificare un servizio chiamare a esso dal client di Silverlight, ma che si termina la capacità di risposta dell'applicazione e rimuovere la possibilità per i controlli dati per determinare automaticamente la validità dei dati. È possibile copiare e incollare la logica per il client ed eseguire manualmente convalida su entrambi i livelli ma codice replica è mai una buona cosa e il problema la convalida automatica si continuano a esistere. Questo è uno scenario che disponga necessari l'utilizzo della funzionalità .NET RIA servizi codice condiviso di.

Codice condiviso

Per l'applicazione rapporto delle nota spese, È necessario verificare due regole di convalida personalizzata: qualsiasi report esportazione su 1.000 deve includere una descrizione struttura lo scopo ed è Nessuna spesa rapporti archiviazione per acquisti futuri. Nessuna di queste condizioni possono essere soddisfatti utilizzando le annotazioni di dati, ma È possibile facilmente esprimere loro in modo imperativo.

In servizi RIA .NET sono inclusi una funzionalità denominata codice condiviso che consente di definire la logica del progetto di server sarà disponibile nell'applicazione client nonché e sincronizzato. Durante il processo di proiezione del codice, qualsiasi codice contrassegnato come condiviso verrà copiato tra progetti invece di tradurre e proxy. Per sfruttare questa funzionalità, è necessario creare un nuovo file di codice nel progetto server con il suffisso di .Shared. [estensione del linguaggio] (ad esempio, ExpenseData.shared.cs). Quando viene eseguito il processo di proiezione di codice, verrà specificamente cercare file all'interno del progetto con tale suffisso e considerare codice come condiviso.

È disponibile una nuova annotazione di dati in versione 4.0 di Framework .NET denominato CustomValidationAttribute consente di associare una regola di convalida personalizzata con un modello dei dati il livello di proprietà o l'entità. Specifica le due regole di convalida personalizzata potrebbe simile al seguente:

[MetadataType(typeof(ExpenseReportDetailsMetadata))]
[CustomValidation(typeof(ExpenseReportValidation),
  "ValidateDescription")]
public partial class ExpenseReportDetails { }

public partial class ExpenseReportDetailsMetadata {
  [Bindable(true, BindingDirection.TwoWay)]
  [CustomValidation(typeof(ExpenseReportValidation), 
    "ValidateDateIncurred")]
  [Display(Name = "Date", 
    Description = "The date of when this expense was incurred.")]
  public object DateIncurred;

Il processo di proiezione .NET RIA servizi tenere in considerazione il CustomValidationAttribute e verrà instradato a del proxy client. Poiché la convalida personalizzata è contenuta all'interno di un tipo di convalida (che probabilmente si desidera definire sul server), è possibile sfruttare codice condiviso per gestire la sincronizzazione.

La firma per un metodo di convalida personalizzata, attenersi un modello specifico:

[Shared]
public static class ExpenseReportValidation {
  public static bool ValidateDateIncurred(object property, 
    ValidationContext context, out ValidationResult validationResult) {

    validationResult = null;
    bool result =       DateTime.Compare((DateTime)property, DateTime.Now) < 0;

    if (!result)
      validationResult = new ValidationResult(context.DisplayName + 
        " must be today or in the past.");
      return result;
  }
}

Si noti l'utilizzo di SharedAttribute sulla classe ExpenseReportValidation. Ciò indica al processo di proiezione che non è necessario convertire al client perché inoltre trattata da parte di codice condiviso.

Eseguire il wrapping dei

In giorni precedenti è necessario sviluppare applicazioni di report delle spese eseguendo il wrapping operazioni CRUD attorno i dati del rapporto delle spese. Il nuovo DataGrid 3 Silverlight, DataForm, DataPager e ObjectDataSource consentono creare rapidamente l'interfaccia utente senza dover a investire nello sviluppo di infrastruttura o sacrificare la funzionalità per utilizzare i controlli incorporati. Inoltre, tramite .NET RIA servizi è possibile definire regole di business sul lato server, con le regole di convalida e accesso ai dati e che essere facilmente utilizzabili grazie al processo di proiezione.

È necessario mio esempio Nota spese ancora indicarne il sezione dettagli report, nonché lo spostamento e l'autenticazione. A tale scopo, È necessario utilizzare alcuni controlli aggiuntivi introdotti in Silverlight 3, nonché un insieme di servizi di applicazione forniti da .NET RIA servizi. In un articolo futuro, illustrerò il funzionamento.

Jonathan Carter è un Technical Evangelist presso Microsoft.