Il presente articolo è stato tradotto automaticamente.

Servizi RIA

Modelli aziendali con servizi WCF RIA

Michael d. Marrone

Scaricare il codice di esempio

Due annunci principali da PDC09 e Mix10 erano la disponibilità di 4 Silverlight beta e RC, rispettivamente. Nel momento in cui che leggere questo rilascio completo per il Web di Silverlight 4 sarà disponibile per il download. Con un ampio supporto di stampa, include il supporto per autorizzazioni elevate, webcam, microfoni, toast, accesso agli Appunti e altro ancora. Con il nuovo insieme di funzionalità Silverlight 4 è destinata a passare ottenere per ottenere con Adobe AIR come framework UI RTF multipiattaforma.

Sebbene tutto ciò eccitare me, si è principalmente uno sviluppatore di applicazioni aziendali e una cosa che sarebbe bello è un metodo semplice per recuperare i dati aziendali e la logica in un'applicazione Silverlight.

Un problema con applicazioni line-of-business di Silverlight è in corso la connessione ai dati. Nulla impedisce di creare il proprio servizio Windows Communication Foundation (WCF) e la connessione in Silverlight 3, ma che lascia un gruppo di transazioni per essere desiderato, soprattutto se si considera le innumerevoli modalità che è possibile connettersi ai dati da ASP.NET o applicazioni desktop. Mentre desktop e applicazioni Web possono connettersi direttamente al database tramite NHibernate, costrutti EF (Entity Framework) o ADO.NET non elaborati, applicazioni Silverlight sono separate dai dati da “ cloud. ” Viene chiamata questa separazione chasm dati.

Incrocio questo chasm potrebbe sembrare apparentemente semplice inizialmente. Ovviamente, è stato eseguito in qualche misura in numerose applicazioni Silverlight ricchi di dati esistenti. Ma quello che sembra essere un compito facile inizialmente diventa sempre più complessa problematiche più. Come è tenere traccia delle modifiche apportate in rete o incapsulare logica aziendale in entità live in entrambi i lati del firewall?  Mantenere i dettagli di trasmissione da perdite delle problematiche aziendali

Strumenti di terze parti sono emergenti per risolvere questi problemi, ma Microsoft visto inoltre necessari per fornire una soluzione, pertanto introdotto RIA WCF Services (precedentemente definito servizi RIA .NET) o per brevità, RIA servizi. (È possibile trovare un'introduzione completa ai servizi RIA in “ Building una spesa basato sui dati applicazioni con Silverlight 3 ” nella edizione di maggio 2009 di MSDN Magazine (informazioni in lingua inglese) (MSDN.Microsoft.com/magazine/dd695920). Ho stato dopo di esso poiché era innanzitutto invitato nel programma beta fornendo suggerimenti al team di sviluppo e apprendere come sfruttare il framework all'interno di applicazioni personalizzate.

Una domanda frequente nei forum RIA servizi è come servizi RIA inserisce nell'architettura di procedure ottimale. È sempre stato colpito con le funzionalità di moduli su dati di base dei servizi RIA, ma ho visto certamente l'opportunità di meglio architettura dell'applicazione in modo che i problemi di infrastruttura non ha una perdita nella logica dell'applicazione.

Introduzione a KharaPOS

Ho sviluppato un'applicazione exemplar KharaPOS, per fornire un esempio tangibile di concetti presentate in questo articolo. È un'applicazione POS (POS) implementata in 4 Silverlight utilizzando servizi RIA, Entity Framework e SQL Server 2008. L'obiettivo principale è per attivare l'applicazione possa essere contenuta nella piattaforma Windows Azure e SQL Azure, ma è presente il problema del supporto Microsoft .NET Framework 4 (o assenza) con la piattaforma Windows Azure.

Nel frattempo, KharaPOS fornisce un buon esempio di utilizzo di .NET Framework 4 per creare un'applicazione reale. Il progetto è ospitato tramite CodePlex all'indirizzo KharaPOS.codeplex.com. È possibile visitare il sito per scaricare il codice, vedere la documentazione e unire la discussione riguardante lo sviluppo dell'applicazione.

È consigliabile tenere presente che mutuate da libro, “ modelli a oggetti: Strategie, modelli e applicazioni, Second Edition ” (Prentice Hall PTR, 1996), da Peter Coad con David Nord e Mark Mayfield, per la maggior parte della progettazione e funzionalità dell'applicazione KharaPOS. Mi concentrerò su un singolo sottosistema dell'applicazione, gestione del catalogo (vedere Nella figura 1).

Figure 1 The Entity Data Model for Catalog Management
Figura 1 Entity Data Model per la gestione dei cataloghi

Modelli Enterprise

Un numero di libri eccellente discutere i modelli di progettazione per lo sviluppo di applicazioni aziendali. Un libro che viene costantemente utilizzato come riferimento è “ modelli di Enterprise Application Architecture ” (Addison-Wesley, 2003), Martin Fowler. In questo manuale e il relativo sito Web supplementare (martinfowler.com/eaaCatalog/) fornire un riepilogo eccellente di software utili modelli per lo sviluppo di applicazioni aziendali dell'organizzazione.

Alcuni dei modelli nel catalogo del Fowler gestiscono la presentazione e la modifica dei dati e l'aspetto interessante è che, occupino lo stesso spazio RIA servizi. Informazioni su questi fornirà un'immagine più chiara di come RIA Services possono essere adattate per soddisfare le esigenze del più semplice per le applicazioni aziendali più complesse. Tratterò i motivi seguenti:

  • Form e controlli
  • Transazione script
  • Modello di dominio
  • Livello di servizio dell'applicazione

Let’s presentazione rapida di tali criteri. I primi tre riguardano diversi modi di affrontare la logica che circondano i dati. Avanzamento attraverso di essi, la logica viene spostato da vengano distribuiti in tutta l'applicazione e ripetuti secondo le esigenze per corso centralizzato e concentrato.

Controlli e moduli

I moduli-e-controlli motivo (o come riferimenti, moduli su dati) posiziona tutte le regole all'interno dell'interfaccia. A prima vista, questo sembra una pessima idea. Ma per l'immissione di dati semplice e viste di dettagli master, è l'approccio più semplice e più diretto per ottenere dall'interfaccia utente al database. Supporto intrinseco per questo modello dispone di molti Framework (trascrizione on Rails scaffolding ASP.NET Dynamic Data e sono SubSonic tre primo esempi), in modo che non vi è certamente un'ora e luogo per il quale alcuni chiamare un anti-modello. Sebbene molti sviluppatori relegate l'approccio del form su dati di solo creazione di prototipi iniziali, esistono utilizza definita per tale nelle applicazioni finale.

Indipendentemente dalla tua opinione sulla relativa utilità, non esiste nessun negare la semplicità o approachability dei moduli sui dati. Non viene chiamato lo sviluppo rapido di applicazioni (RAD) perché è noioso. I servizi WCF RIA riporta RAD in Silverlight. Utilizzo di Entity Framework, RIA Services e la progettazione di Silverlight, è possibile creare un semplice editor di moduli su dati rispetto a una tabella di database in cinque passaggi:

  1. Creare una nuova applicazione aziendale di Silverlight.
  2. Aggiungere un nuovo Entity Data Model (EDM) all'applicazione Web creata (utilizzando la procedura guidata per importare il database).
  3. Aggiungere un servizio di dominio dell'applicazione Web (assicurarsi di generare innanzitutto in modo che venga rilevato correttamente l'EDM) che fa riferimento il modello di dati.
  4. Utilizzare il Pannello di origini dati per trascinare un'entità esposta da servizi RIA sulla superficie di una pagina o un controllo utente nell'applicazione Silverlight (assicurarsi di generare di nuovo inoltre possibile visualizzare il nuovo servizio di dominio).
  5. Aggiungere un pulsante e il code-behind per salvare le modifiche nel form per il database con questa semplice riga:
this.categoryDomainDataSource.SubmitChanges();

Ora è una griglia di dati semplice che può essere utilizzata per modificare direttamente le righe esistenti nella tabella. Con alcune aggiunte più, è possibile creare un modulo che consente di aggiungere nuove righe alla tabella.

Sebbene questo modello è stato dimostrato ripetutamente, che mostra il vantaggio di RAD con WCF RIA Services è rilevante anche qui perché fornisce una base per lo sviluppo con il framework. Inoltre, come indicato, questo è un valido motivo all'interno di applicazioni RIA servizi.

Raccomandazione Come con dati dinamici di ASP.NET, il modello di form su dati deve essere utilizzato per amministrazione semplice interfacce utente (ad esempio KharaPOS prodotto categoria editor), dove la logica è semplice e diretto: aggiungere, rimuovere e modificare le righe all'interno di una tabella di ricerca. Ma servizi RIA di Silverlight e scalare le applicazioni molto più complesse, come vedremo ora.

Tabella dati gateway Approccio standard e in uscita-di-la finestra Servizi RIA applicazioni che appena discusso inoltre possono essere visualizzate come un'implementazione del modello di gateway dati tabella come viene presentato in PE. 144–151 del Fowler libro. Attraverso due livelli di riferimento indiretto (mapping EF sul database seguito da mapping dominio servizio su EF), ho creato un gateway semplice per creare tabelle di base utilizzando il database, leggere, aggiornare ed eliminare operazioni (CRUD) restituzione di oggetti (DTOs) trasferimento dati fortemente tipizzati.

Tecnicamente, questo non qualifica come gateway pure tabella dati a causa dei relativi livelli di riferimento indiretto doppi. Ma se squint, molto simile lo schema di gateway tabella dati. Per essere onesti, sarebbe stato una progressione più logica per discutere il mapping tra i servizi RIA e il modello di gateway tabella dati, poiché tutti i modelli rimanenti nell'elenco sono modelli di interfaccia dati ma moduli sui dati è principalmente un modello di interfaccia utente. Tuttavia, ho ritenuto più prudente iniziare con lo scenario di base e concentrarsi sull'interfaccia utente lo spostamento indietro verso il database.

Visualizzazione modello ViewModel (MVVM) Anche se è semplice creare un modulo funzionale utilizzando moduli sui dati, è ancora presente alcuni semplice coinvolti. Nella figura 2, il codice XAML per la gestione di categoria, come illustrato.

Nella figura 2 XAML per la gestione di categoria

<Controls:TabItem Header="Categories">
  <Controls:TabItem.Resources>
    <DataSource:DomainDataSource
      x:Key="LookupSource"
      AutoLoad="True"
      LoadedData="DomainDataSourceLoaded"
      QueryName="GetCategoriesQuery"
      Width="0">
      <DataSource:DomainDataSource.DomainContext>
        <my:CatalogContext />
      </DataSource:DomainDataSource.DomainContext>
    </DataSource:DomainDataSource>
    <DataSource:DomainDataSource
      x:Name="CategoryDomainDataSource"
      AutoLoad="True"
      LoadedData="DomainDataSourceLoaded"
      QueryName="GetCategoriesQuery"
      Width="0">
      <DataSource:DomainDataSource.DomainContext>
        <my:CatalogContext />
      </DataSource:DomainDataSource.DomainContext>
      <DataSource:DomainDataSource.FilterDescriptors>
        <DataSource:FilterDescriptor 
          PropertyPath="Id" 
          Operator="IsNotEqualTo" Value="3"/>
      </DataSource:DomainDataSource.FilterDescriptors>
    </DataSource:DomainDataSource>
  </Controls:TabItem.Resources>
  <Grid>
    <DataControls:DataGrid
      AutoGenerateColumns="False" 
      ItemsSource="{Binding Path=Data,
        Source={StaticResource CategoryDomainDataSource}}" 
      x:Name="CategoryDataGrid">
      <DataControls:DataGrid.Columns>
        <DataControls:DataGridTextColumn 
          Binding="{Binding Name}" Header="Name" Width="100" />
        <DataControls:DataGridTemplateColumn 
          Header="Parent Category" Width="125">
            <DataControls:DataGridTemplateColumn.CellEditingTemplate>
              <DataTemplate>
                <ComboBox 
                  IsSynchronizedWithCurrentItem="False" 
                  ItemsSource="{Binding Source=
                    {StaticResource LookupSource}, Path=Data}"  
                  SelectedValue="{Binding ParentId}" 
                  SelectedValuePath="Id" 
                  DisplayMemberPath="Name"/>
              </DataTemplate>
            </DataControls:DataGridTemplateColumn.CellEditingTemplate>
            <DataControls:DataGridTemplateColumn.CellTemplate>
              <DataTemplate>
                <TextBlock Text="{Binding Path=Parent.Name}"/>
              </DataTemplate>
            </DataControls:DataGridTemplateColumn.CellTemplate>
          </DataControls:DataGridTemplateColumn>
          <DataControls:DataGridTextColumn
            Binding="{Binding ShortDescription}"
            Header="Short Description" Width="150" />
          <DataControls:DataGridTextColumn 
            Binding="{Binding LongDescription}" 
            Header="Long Description" Width="*" />
        </DataControls:DataGrid.Columns>
    </DataControls:DataGrid>
  </Grid>
</Controls:TabItem>

La colonna per la categoria padre nella griglia dei dati è una casella combinata che utilizza un elenco di categorie esistenti in modo che sia possibile selezionare la categoria padre dal nome invece di studiare l'ID della categoria. Sfortunatamente, Silverlight non piace quando lo stesso oggetto viene caricato due volte all'interno della struttura ad albero visuale. Di conseguenza, è stato necessario dichiarare due origini dati di dominio: uno per la griglia e uno per la casella combinata di ricerca. Inoltre, è piuttosto complicato code-behind per la gestione delle categorie (vedere Nella figura 3).

Nella figura 3 Code-behind per la gestione delle categorie

private void DomainDataSourceLoaded(object sender, LoadedDataEventArgs e)
{
  if (e.HasError)
  {
    MessageBox.Show(e.Error.ToString(), "Load Error", MessageBoxButton.OK);
    e.MarkErrorAsHandled();
  }
}

private void SaveButtonClick(object sender, RoutedEventArgs e)
{
  CategoryDomainDataSource.SubmitChanges();
}

private void CancelButtonClick(object sender, RoutedEventArgs e)
{
  CategoryDomainDataSource.Load();
}

void ReloadChanges(object sender, SubmittedChangesEventArgs e)
{
  CategoryDomainDataSource.Load();
}

Non si intende fornire un'esercitazione completa su MVVM qui, vedere l'articolo “ WPF applicazioni con il modello Visualizza ViewModel Design Pattern ” nel numero di febbraio 2009 (MSDN.Microsoft.com/magazine/dd419663) Per un treatise eccellente sull'argomento. Nella figura 4 viene illustrato un modo per sfruttare MVVM all'interno di un'applicazione RIA Services.

Nella figura 4 Categoria Gestione tramite un modello di visualizzazione

public CategoryManagementViewModel()
{
  _dataContext = new CatalogContext();
  LoadCategories();
}

private void LoadCategories()
{
  IsLoading = true;
  var loadOperation= _dataContext.Load(_dataContext.
    GetCategoriesQuery());
  loadOperation.Completed += FinishedLoading;
}

protected bool IsLoading
{
  get { return _IsLoading; }
  set
  {
    _IsLoading = value;
    NotifyPropertyChanged("IsLoading");
  }
}

private void NotifyPropertyChanged(string propertyName)
{
  if (PropertyChanged!=null)
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

void FinishedLoading(object sender, EventArgs e)
{
  IsLoading = false;
  AvailableCategories=
    new ObservableCollection<Category>(_dataContext.Categories);
}

public ObservableCollection<Category>AvailableCategories
{
  get
  {
    return _AvailableCategories;
  }
  set
  {
    _AvailableCategories = value;
    NotifyPropertyChanged("AvailableCategories");
  }
}

Come è visualizzato, il ViewModel è responsabile per l'inizializzazione del contesto di dominio e che informa dell'interfaccia utente quando si verifica un carico, con la gestione delle richieste dall'interfaccia utente per creare nuove categorie, salvare le modifiche apportate alle categorie esistenti e ricaricare i dati dal servizio di dominio. In tal modo una chiara separazione tra la UI e la logica che esso. Il motivo MVVM potrebbe sembrare che richiedono maggiore lavoro, ma la bellezza stesso rivela la prima volta che è necessario modificare la logica per il recupero di dati nell'interfaccia utente. Inoltre, spostare il processo di caricamento le categorie di ViewModel ci consente pulire la visualizzazione in modo significativo (XAML e code-behind uguali).

Raccomandazione Utilizzare MVVM per impedire la logica dell'interfaccia utente complessa ingombrare l'interfaccia utente, o peggio, da occupare il modello a oggetti business.

Transazione script

Per iniziare l'aggiunta di logica per l'applicazione, il modello di form su dati diventa eccessivamente complesso. Poiché la logica relative alle operazioni con i dati è incorporata nell'interfaccia utente (o in ViewModel,), se è già acquisita tale passaggio verranno distribuito all'interno dell'applicazione. Un altro effetto collaterale di decentralizzata logica è che gli sviluppatori potrebbero non essere a conoscenza di funzionalità specifiche già esistente nell'applicazione, può provocare la duplicazione. In questo modo viene creato incubi quando cambia la logica, poiché deve essere aggiornato in tutte le posizioni (supponendo che tutte le posizioni implementando la logica avere catalogate correttamente).

Il modello di script delle transazioni (pagine. 110–115 nella Rubrica del Fowler) fornisce alcuni sicurezza. Consente di separare la logica aziendale che gestisce i dati dall'interfaccia utente.

Come definito dal Fowler, lo script di transazione “ Organizza logica aziendale tramite le procedure in cui ogni routine gestisce una singola richiesta dalla presentazione. ” Gli script di transazione sono molto più di semplici operazioni CRUD. Infatti, essi si trovano davanti al gateway di dati di tabella per gestire le operazioni CRUD. Uno script di transazione separato adottate per i casi, potrebbe gestire ogni recupero e l'invio al database. Tuttavia, la logica di persone, è possibile sapere che è presente una risorsa per tutti gli elementi e un'ora.

Uno script delle transazioni risulta utile quando l'applicazione dispone di un'interazione tra due entità, ad esempio quando si crea un'associazione tra due istanze di classi di entità diverse delle coordinate. Ad esempio, nel sistema di gestione del catalogo, è possibile indicare che un prodotto è disponibile per una business unit all'ordine per il proprio inventario mediante la creazione di una voce di catalogo. La voce identifica il prodotto, la business unit, un prodotto SKU e il tempo durante il quale è possibile ordinare entrambi internamente ed esternamente. Per semplificare la creazione di voci di catalogo, ho creato un metodo del servizio di dominio (vedere il seguente frammento di codice) che fornisce uno script di transazione per la modifica di disponibilità del prodotto di un'unità aziendale senza interfaccia utente di dover modificare direttamente le voci del catalogo.

Le voci del catalogo, infatti, anche non sono esposti tramite il servizio di dominio, come illustrato di seguito:

public void CatalogProductForBusinessUnit(Product product, int businessUnitId)
{
  var entry = ObjectContext.CreateObject<CatalogEntry>();
  entry.BusinessUnitId = businessUnitId;
  entry.ProductId = product.Id;
  entry.DateAdded = DateTime.Now;
  ObjectContext.CatalogEntries.AddObject(entry);
  ObjectContext.SaveChanges();
}

Invece di essere esposta come funzione il contesto di dominio del client, RIA Services genera una funzione sull'entità in questione (in questo caso Product) che, se chiamato, una notifica di modifica viene inserito l'oggetto che sul lato server ottiene interpretata come una chiamata al metodo del servizio di dominio.

Si consiglia di Fowler due approcci per implementare lo script di transazione:

  1. Con i comandi che consentono di incapsulano le operazioni e possono essere passati intorno
  2. Con un'unica classe che contiene un insieme di script di transazione

Qui impiegato il secondo approccio, ma non c'è nulla impedisce l'utilizzo dei comandi. Il vantaggio di non esporre la voce di catalogo per il livello UI è che lo script di transazione diventa l'unico mezzo di creazione delle voci del catalogo. Se si utilizza il modello di comando, per convenzione viene applicata la regola. Se uno sviluppatore si dimentica che un comando esistente, si verrà finisce posteriore destro in cui è stata avviata con la frammentazione logica e la duplicazione.

Un altro vantaggio di inserire lo script delle transazioni del servizio di dominio è che la logica viene eseguita sul lato server (come indicato in precedenza). Se si dispone di algoritmi proprietari o si desidera essere certi che l'utente non ha modificato i dati da utenti malintenzionati, inserendo lo script di transazione nel servizio di dominio è il modo di procedere.

Raccomandazione Utilizzare lo script di transazione quando la logica aziendale diventa troppo complessa per i moduli sui dati, si desidera eseguire la logica per un'operazione sul lato server o entrambi.

Logica di Business Logic e interfaccia utente Si crea più riferimenti alla logica dell'interfaccia utente e la logica aziendale e anche se la differenza può sembrare meno evidenti in primo luogo, è importante. Logica di interfaccia utente è una logica che si occupano della presentazione, ovvero le informazioni che verranno visualizzate sullo schermo e la modalità (ad esempio, gli elementi utilizzati per popolare una casella combinata). Logica business, invece, è ciò che controlla l'applicazione di se stesso (ad esempio, lo sconto applicato a un acquisto in linea). Entrambi sono importanti aspetti di un'applicazione e un altro modello multiple quando è consentiti combinare, consultare l'articolo “ grande sfera di fango, ” da Brian Foote e Joseph Yoder (laputan.org/MUD).

Il passaggio di più entità per il servizio di dominio Per impostazione predefinita, è possibile passare solo una entità a un metodo di servizio del dominio personalizzato. Ad esempio, il metodo

public void CatalogProductForBusinessUnit(Product product, int businessUnitId)

non funziona se si tenta di utilizzare questa firma invece di un valore integer:

public void CatalogProductForBusinessUnit(Product product, BusinessUnit bu)

RIA Services non genera un proxy client per questa funzione perché … Beh, queste sono le regole. È possibile avere solo un'entità in un metodo di servizio personalizzato. Ciò non dovrebbe costituire un problema nella maggior parte dei casi, perché se si dispone di un'entità, rendere le chiavi e possibile recuperarlo nel back-end nuovamente.

Let’s sufficiente pronunciare, per ragioni di dimostrazione, che è un'operazione costosa per recuperare un'entità (ad esempio è su altro lato di un servizio Web). È possibile indicare al servizio di dominio che si desidera tenere una copia di una determinata entità, come illustrato di seguito:

public void StoreBusinessUnit(BusinessUnit bu)
{
  HttpContext.Current.Session[bu.GetType().FullName+bu.Id] = bu;
}

public void CatalogProductForBusinessUnit(Product product, int businessUnitId)
{
  var currentBu = (BusinessUnit)HttpContext.Current.
    Session[typeof(BusinessUnit).FullName + businessUnitId];
  // Use the retrieved BusinessUnit Here.
}

Poiché il servizio di dominio è in esecuzione in ASP.NET, ha accesso completo per la sessione ASP.NET e la cache, nel caso in cui si desidera rimuovere automaticamente l'oggetto dalla memoria dopo un determinato periodo di tempo. Sto effettivamente utilizzando questa tecnica su un progetto in cui è necessario recuperare i dati del cliente relazione management (CRM) da più servizi Web remoti e presentare all'utente in un'interfaccia utente unificata. Viene utilizzato un metodo esplicito perché alcuni dati vale la pena la memorizzazione nella cache e alcuni non sono.

Modello di dominio

A volte diventa talmente complesso che anche gli script di transazione non è possibile gestire correttamente tale logica aziendale. Spesso, questo visualizzato come logica complessa diramazione all'interno di uno script di transazione o di più script transazione conto delle sfumature nella logica. Un altro segno che un'applicazione ha outgrown l'utilità di script delle transazioni è la necessità di aggiornamenti frequenti all'indirizzo modificando rapidamente i requisiti aziendali.

Se è stato notato uno di questi sintomi, è necessario prendere in considerazione un modello di dominio completo (pagine. 116–124 nella Rubrica Fowler). I modelli descritti finora hanno in comune una cosa: Le entità sono leggermente più DTOs, ovvero non contengono alcuna logica (considerato da alcuni sia un anti-modello indicato come modello di domini Anemic). Uno dei principali vantaggi dello sviluppo orientato ad oggetti è la possibilità di incapsulare la logica associata e dati. Un modello di dominio completo in grado di sfruttare tale vantaggio inserendo la logica nuovamente all'interno dell'entità a cui esso appartiene.

I dettagli della progettazione di un modello di dominio non rientrano nell'ambito di questo articolo. Vedere il manuale “ struttura basato su dominio: Affrontare le complessità nel cuore del software ” (Addison-Wesley, 2004), Eric Evans o il libro Coad menzionato in precedenza in modelli di oggetti per la copertura ottima su questo argomento. È possibile, tuttavia, di fornire uno scenario che consente di illustrare come un modello di dominio può gestire alcuni questo stress.

Alcuni clienti KharaPOS da esaminare storico vendite di determinate righe decidere, in base al mercato dal mercato, se le righe verranno ridotte, expanded (rendere più prodotti da esso disponibile), Taglia tutto o di rimanere flat per una determinato stagione.

I dati di vendita è già installato un altro nel sottosistema di KharaPOS e tutti gli altri elementi che è necessario qui si trova nel sistema di catalogo. Appena verrà portare una visualizzazione in sola lettura delle vendite di prodotti nel nostro modello di data entità come illustrato in Nella figura 5.

Figure 5 Entity Data Model Updated with Sales Data
Nella figura 5 Entity Data Model aggiornato con dati sulle vendite

A questo punto è necessario eseguire è aggiungere la logica di selezione di prodotti per il modello di dominio. Poiché sto selezionando i prodotti per un mercato, verrà inserire la logica della classe BusinessUnit (utilizzare una classe parziale con un'estensione shared.cs o shared.vb per informare RIA servizi che si desidera che questa funzione shuttled al client). Nella Figura 6 viene illustrato il codice.

Nella figura 6 Logica di dominio per la selezione di prodotti per la Business Unit

public partial class BusinessUnit
{
  public void SelectSeasonalProductsForBusinessUnit(
    DateTime seasonStart, DateTime seasonEnd)
  {
    // Get the total sales for the season
    var totalSales = (from sale in Sales
                     where sale.DateOfSale > seasonStart
                     && sale.DateOfSale < seasonEnd
                     select sale.LineItems.Sum(line => line.Cost)).
                     Sum(total=>total);
    // Get the manufacturers for the business unit
    var manufacturers =
      Catalogs.Select(c =>c.Product.ManuFacturer).
        Distinct(new Equality<ManuFacturer>(i => i.Id));
    // Group the sales by manufacturer
    var salesByManufacturer = 
      (from sale in Sales
      where sale.DateOfSale > seasonStart
      && sale.DateOfSale < seasonEnd
      from lineitem in sale.LineItems
      join manufacturer in manufacturers on
      lineitem.Product.ManufacturerId equals manuFacturer.Id
      select new
      {
        Manfacturer = manuFacturer,
          Amount = lineitem.Cost
      }).GroupBy(i => i.Manfacturer);
    foreach (var group in salesByManufacturer)
    {
      var manufacturer = group.Key;
      var pct = group.Sum(t => t.Amount)/totalSales;
      SelectCatalogItemsBasedOnPercentage(manufacturer, pct);
    }
  }

  private void SelectCatalogItemsBasedOnPercentage(
    ManuFacturer manufacturer, decimal pct)
  {
     // Rest of logic here.
  }
}

L'esecuzione di una selezione automatica per i prodotti da eseguire su una stagione è semplice come chiamando la funzione di nuova in seguito che da una chiamata a SubmitChanges la funzione DomainContext e BusinessUnit.In futuro, se viene trovato un bug nella logica o la logica deve essere aggiornata, è possibile sapere esattamente dove cercare.Non solo è possibile centralizzare la logica, inoltre apportate al modello a oggetti più esplicite dello scopo.In p.Alboni 246 del suo libro “ Domain-Driven struttura ”, spiega perché si tratta di una cosa positiva:

Se uno sviluppatore deve prendere in considerazione l'implementazione di un componente per utilizzarlo, il valore di incapsulamento viene perso.Se un utente diverso da quello originale sviluppatore deve dedurre lo scopo di un oggetto o di operazione basata sulla relativa implementazione, tale nuovo sviluppatore può dedurre uno scopo che soddisfa l'operazione o la classe solo da possibilità.Se non era l'intento, il codice potrebbe funzionare per il momento ma la base della progettazione concettuale verrà siano danneggiata e utilizzerà due sviluppatori a cross-purposes.

Per paraphrase esplicitamente la funzione di denominazione per il suo scopo e incapsulare la logica (con alcuni commenti per cancellare ciò che accade), apportate facile per ragazzo successivo (anche se ragazzo successivo mi è cinque mesi da adesso) per determinare cosa accadendo prima anche andare all'implementazione.Inserire questa logica con i dati a cui sono associati naturalmente è in grado di sfruttare la natura esplicita di linguaggi di programmazione orientati ad oggetti.

Raccomandazione Utilizzare un modello di dominio quando la logica è complesso e gnarly e potrebbe richiedere diverse entità alla volta.Incorporare la logica con l'oggetto a cui ha la maggior parte delle affinità e fornire un nome significativo, intenzionale per l'operazione.

Differenza tra il modello di domini e script di transazioni in servizi RIA Si sarà notato che per lo script di transazione e il modello di dominio è stata effettuata la chiamata direttamente sull'entità.Si noti, sebbene la logica di due schemi si trova in due posizioni distinte.In caso di script di transazione, chiamare la funzione sull'entità appena serve per indicare al contesto di dominio/servizio che è necessario chiamare la funzione corrispondente sul servizio di dominio viene chiamato il successiva modifiche in fase di invio.In caso di un modello di dominio, viene eseguita la logica viene chiamato lato client e quindi eseguito il commit quando inviare le modifiche.

Il repository e oggetti di query Dominio servizio naturalmente implementa lo schema di repository (vedere Fowler p.322).In WCF RIA servizi Code Gallery (code.msdn.Microsoft.com/RiaServices), il team RIA Services fornisce un ottimo esempio di creazione di un'implementazione esplicita del motivo tramite il DomainContext.Questo consente un aumento testabilità dell'applicazione senza la necessità di effettivamente raggiunto il livello di servizio e il database.Inoltre, nel mio blog (azurecoding.NET/blogs/brownie) È possibile fornire un'implementazione del modello di query oggetto (Fowler, p.316) tramite l'archivio, quale Rinvia sul lato server, l'esecuzione della query fino a quando l'enumerazione effettiva.

Livello servizio delle applicazioni

Domanda rapido: Che cosa è necessario fare quando si desidera utilizzare un modello di dominio completo, ma non si desidera esporre la logica per il livello UI?È in cui il servizio di livello motivo (Fowler, p.133) è disponibile in pratica.Una volta ottenuto il modello di dominio, questo modello è semplice da implementare la logica di dominio di shared.cs lo spostamento in una classe parziale separato e inserendo una funzione del servizio di dominio che richiama la funzione sull'entità.

Il livello di applicazione servizio agisce come un aspetto semplificato rispetto al modello di dominio, esponendo le operazioni ma non i relativi dettagli.Un altro vantaggio è che sarà in grado di sfruttare le dipendenze interne senza che i client di livello di servizio per consegnarli anche gli oggetti dominio.In alcuni casi (vedere l'esempio di selezione di prodotti stagionale illustrato in Nella figura 6), il servizio di dominio effettua una chiamata semplice nel dominio.A volte può orchestrare alcune entità, ma prestare attenzione, ovvero lo eccessiva orchestrazione trasforma nuovamente in uno script delle transazioni e i vantaggi di incapsulare la logica all'interno del dominio sono persi.

Raccomandazione Utilizzare il livello di servizio dell'applicazione per fornire un aspetto semplice tramite il modello di dominio e rimuovere il requisito che è necessario richiedere le dipendenze che delle entità potrebbero richiedere al livello dell'interfaccia utente.

Credito aggiuntiva: Il contesto delimitato

Nei forum RIA partecipanti spesso chiedono “ How suddividere mio database di grandi dimensioni in tutti i servizi di dominio in modo che sia più gestibile? ” È una domanda di follow-up, “ How sono è possibile gestire le entità che devono esistere in più servizi di dominio? ” Inizialmente ho pensato non devono essere presenti la necessità di eseguire queste operazioni, il servizio del dominio deve fungere da un livello di servizio sul modello di dominio e un servizio unico dominio dovrà essere utilizzati come una facciata attraverso l'intero dominio.

Durante la mia ricerca per questo articolo, tuttavia, ho trovato il criterio di contesto delimitata (Garghentini, p.336), che si desidera leggere sulla prima ma non erano memorizzate quando risposto originariamente a queste domande.La premessa di base del motivo è che in qualsiasi progetto di grandi dimensioni non vi saranno più sottodomini in riproduzione.Si consideri ad esempio KharaPOS, in cui si dispone di un dominio per i cataloghi e uno separato per le vendite.

Il contesto delimitato consente di tali domini per coesistere senza problemi anche se vi sono elementi condivisi tra di essi (ad esempio vendita, Business Unit, prodotto e LineItem, che sono in vendita e i domini catalogo).Vengono applicate regole diverse per le entità in base a quale dominio interagisce con essi (LineItem e vendita sono di sola lettura nel dominio di catalogo).Una regola finale è che le operazioni non intersecano mai su contesti.Si tratta rende vita utile, poiché Silverlight non supporta le transazioni su più servizi di dominio.

Raccomandazione Utilizzare contesti delimitati per suddividere un sistema di grandi dimensioni in sottosistemi logici.

Pit di successo

In questo articolo, abbiamo visto come RIA servizi supportano i modelli enterprise principali con il minimo sforzo.Raramente sono Framework così accessibile durante il corso inoltre sufficientemente flessibile da supportare tutti i dati dalle applicazioni di immissione dei dati di foglio di calcolo più semplice per le applicazioni aziendali più complesse senza richiedere risorse principali per effettuare la transizione.Si tratta di Brad Abrams “ pit di successo ” menzionato nel suo blog di registrazione, lo stesso nome (blogs.msdn.com/brada/Archive/2003/10/02/50420.aspx).

Mike Brown è il presidente e cofondatore di KharaSoft Inc.(kharasoft.com), una società di tecnologia specializzato in corsi di formazione, lo sviluppo di software personalizzati e software come servizio.È un specialista in tecnologia svolta con più di 14 anni di esperienza nel settore, destinatario MVP Award back-to-back, cofondatore del gruppo utenti Indy Alt.NET (indyalt.NET) e die-hard ventilatore Bears!

Grazie all'esperto tecnica seguente per la revisione di questo articolo:  Brad Abrams