共用方式為


本文章是由機器翻譯。

RIA Services

使用 WCF RIA Services 的企業典範

Michael D。棕色

下載程式碼範例

來自 PDC09 和 Mix10 的兩個主要宣告分別是 Silverlight 4 Beta 版和 RC 的可用性。根據您閱讀這次,完整發行到 Web 的 Silverlight 4 會可供下載。連同廣泛列印支援它包括對提高權限、 網路攝影機、 麥克風、 吐司、 剪貼簿存取和更多的支援。其新的功能設定,Silverlight 4 poised 移腳腳與 Adobe AIR 為多平台的豐富使用者介面架構。

雖然所有的不會激發我,我 ’m 主要商務應用程式開發的而且我會喜歡的一件事是簡單的方法,可以取得 [到 Silverlight 應用程式中的 [我的商務資料和邏輯。

與商務的 Silverlight 應用程式的一個考量點連接到資料。執行任何動作可防止您從建立您自己的 Windows 通訊基礎 (WCF) 服務和連接到它在 Silverlight 3,但是,其中會需要,尤其是當您考慮各種您可以從 ASP.NET 或桌面應用程式連接至資料的方式有許多。而桌面和 Web 應用程式可以直接連線到透過 NHibernate 資料庫,Entity Framework (EF) 或未經處理的 ADO.NET 建構、 Silverlight 應用程式分開我的資料由 「 雲朵 」。我會呼叫此區隔資料 chasm。

通過這個 chasm 似乎過於簡單第一次。很明顯地,它已作過一些現有的資料豐富 Silverlight 應用程式某種程度。但一開始看起來會容易的工作變成越來越複雜,如處理更多的考量。如何嗎您透過網路追蹤變更或將商務邏輯封裝在居住在防火牆的兩邊的實體嗎?  如何讓傳輸從商業考量到遺漏詳細的資料?

新興來解決這些問題的第三方廠商工具,但 Microsoft 也會看到提供一個解決方案,讓它引入 WCF RIA 服務 (原來為.NET RIA 服務),或為求 RIA 服務所需。(您找到完整的簡介 RIA 服務在 「 建置資料導向的費用與 Silverlight 3 的應用程式 」 中的 五月 2009年版本MSDN 雜誌 (msdn.microsoft.com/magazine/dd695920).我被其後因為我第一次被邀請到 Beta 版的程式提供給開發小組的建議,並學習如何運用內我自己的應用程式架構。

RIA 服務論壇中常見的問題是 RIA 服務如何符合最佳作法架構。我已永遠欣賞與基本表單移轉資料功能的 RIA 服務,但我絕對看到有機會在更架構讓架構考量 didn’t 遺漏到我的應用程式邏輯設計人員我的應用程式。

引入 KharaPOS

我開發應用 exemplar 程式,KharaPOS,提供一個有形的範例,我在本文中提出的概念。它 ’s Silverlight 4 使用 RIA 服務、 Entity Framework 和 SQL Server 2008 中實作一個銷售點 (POS) 應用程式。最終的目標是讓應用程式裝載在 Windows Azure 平台和 SQL Azure,但有 ’s Microsoft.NET Framework 4 支援 (或缺少或是其他),與 Windows Azure 平台的小問題。

在過渡 KharaPOS 提供極佳範例使用.NET Framework 4 來建立實際的應用程式。專案被裝載透過 CodePlex KharaPOS.codeplex.com.您可以瀏覽該網站下載程式碼、 檢視文件並加入周圍開發應用程式的討論區。

我應該注意我借用在通訊錄中的 「 物件模型:策略、 圖樣和 Applications 第二版 」 (Prentice 大廳 PTR,1996年),由 Peter Coad David 北部] 和 [Mark] Mayfield 大部分的設計和 KharaPOS 應用程式的功能。我專注於應用程式類別目錄管理的單一子系統 (請參閱 圖 1).


圖 1 Entity Data Model,為全文檢索目錄管理的

企業圖樣

絕佳的書本總數討論開發企業應用程式的設計模式。我不斷地使用做為參考一本書是 「 圖樣的企業應用程式架構 」 (Addison-Wesley,2003年) 由 Martin Fowler。這本書和其補充的網站 (martinfowler.com/eaaCatalog/) 提供有用的軟體模式的絕佳摘要開發企業商務應用程式。

少數 Fowler ’s 類別目錄中的模式處理簡報及操作的資料,以及有趣的是夠,它們佔據 RIA 服務為相同的空間。瞭解這些將提供的方式 RIA 服務可以是適用於符合最簡單的需求,更清楚地查看圖片最複雜的商務應用程式。我討論下列模式:

  • 表單和控制項
  • 交易指令碼
  • 網域模型
  • 應用程式服務層

let’s 採取這些模式的快速教學。前三個有關的周圍您資料的邏輯處理不同的方式。為您進行透過它們,邏輯移從散佈整個應用程式,並可視需要集中式和著重於重複。

表單和控制項

表單-和-控制項圖樣 (或透過資料如我把它,形成) 會放置所有的使用者介面內邏輯。第一眼這看起來像是個好主意。但它 ’s 簡單資料輸入和主版詳細資料檢視表,從 UI 跳至資料庫最簡單且最直接的方法。許多架構有內建支援這種模式 (注音三個事先調整範例 scaffolding ASP.NET 動態資料和 SubSonic 是開扶手),所以有 ’s 絕對時間和位置,以讓為何某些呼叫一個 anti-pattern。雖然許多開發人員 relegate 表單移轉資料方法來初始建立原型,有明確使用它的最終應用程式中。

不論其公用程式在您發表意見,有 ’s 沒有拒絕簡易性或 approachability 表單的資料。因為 ’s 冗長乏味,它不呼叫快速應用程式開發 (RAD)。WCF RIA 服務將 RAD 帶到 Silverlight。運用 Entity Framework、 RIA 服務及 「 Silverlight 設計工具 」,’s 有可能在五個步驟中建立對資料庫資料表的簡單表單移轉資料編輯器:

  1. 建立新的 Silverlight 商務應用程式。
  2. (使用 [匯入資料庫的 [精靈]) 在建立 Web 應用程式中加入新的 Entity Data Model (EDM)。
  3. (請務必先建置它,以便適當地發現 EDM) 在 Web 應用程式中加入網域服務參考的資料模型。
  4. 使用 [資料來源] 面板拖曳至 Silverlight 應用程式 (請務必再次建置以便可以看到新的網域服務) 中的網頁或使用者控制項介面上 RIA 服務所公開的實體。
  5. 新增按鈕和程式碼後置 (Code-Behind 具有這個簡單的線條資料庫在表單上儲存的變更:
this.categoryDomainDataSource.SubmitChanges();

現在您已經有可以用來直接編輯您的資料表中現有的資料列的簡單資料格中。有幾個更多新增您可以建立表單,讓您新增新資料列到資料表。

雖然這種模式已示範了重複,顯示 WCF RIA 服務的 RAD 利用它 ’s 仍然相關這裡因為它提供了比較基準與架構的開發。而且,如前所述,這會是有效模式內 RIA 服務為基礎的應用程式。

建議事項 做為與 ASP.NET 動態資料表單移轉資料模式應該用於簡單的系統管理使用者介面 (例如 KharaPOS 產品分類編輯器),簡單且直接了當邏輯的所在:新增、 移除及編輯查閱表格中的列。但 Silverlight 及 RIA 服務擴充至更複雜的應用程式正如我們現在看到。

資料表資料閘道 應用程式只是討論可也視為是資料表資料閘道模式的實作如前置處理上所呈現的 RIA 服務的標準、 逾時的方塊方式。Fowler ’s 書籍 144–151。透過兩個層級的間接取值 (EF 對應對透過 EF 後面跟著網域服務對應的資料庫)、 我建立簡單的閘道,以使用基本的資料表建立的資料庫、 讀取、 更新和刪除 (CRUD) 作業傳回強型別的資料傳輸物件 (DTOs)。

技術上,這 doesn’t 因為其雙重的層級的間接取值的限定為純粹的資料表資料閘道。但是,如果您 squint 非常類似表格資料閘道圖樣。若要老實說,它本來應該是要討論 RIA 服務與資料表資料閘道模式之間的對應,因為清單中所有剩餘的模式是資料介面模式,但透過資料表單是大多是 UI 模式更符合邏輯進展。不過,我覺得它以基本的案例開始,專注於 UI 移回向資料庫更是小心謹慎為。

模型-檢視-ViewModel (MVVM) 即使 ’s 簡單地建立功能性的表單資料透過使用表單的有 ’s 仍有些 friction 相關。圖 2,類別管理 XAML 可說明這點。

圖 2XAML 的分類中管理

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

父類別資料格中的資料行是使用現有的類別清單,因此使用者的名稱,而不是 memorizing 分類 ID 可以選取父類別的下拉式方塊。 不幸的是,Silverlight doesn’t 喜歡它相同的物件載入兩次內視覺化樹狀結構時。 因此,我必須宣告兩個網域的資料來源:第一個是用來在格線的查閱下拉式方塊。 而且,而 convoluted 管理類別的程式碼後置 (請參閱 圖 3).

圖 3程式碼後置 (Code-Behind 管理類別

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();
}

我不打算此處提供完整的教學課程 MVVM 上 — 請參閱文章 「 WPF 應用程式與 「 模型-檢視-ViewModel 設計模式 」 中二月 2009年問題 (msdn.microsoft.com/magazine/dd419663) 對於 」 主題的絕佳 treatise。 圖 4 是運用 MVVM RIA 服務應用程式內的其中一種方式。

圖 4透過檢視模型的類別目錄管理

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");
  }
}

正如您看到 [ViewModel 會負責初始化網域內容並發生負載,一起處理要求時告知 UI 從使用者介面來建立新的類別將變更儲存至現有的類別重新載入從網域服務資料。此 UI 和磁碟機,它的邏輯之間留下乾淨的分隔。MVVM 模式可能顯得為需要更多工作,但是其美麗會揭露本身,您必須變更為擷取資料到 UI 邏輯的第一次。而且,移動到 [ViewModel 載入類別的程序可讓我們清除檢視大幅 (XAML 和程式碼後置 (Code-Behind 攤)。

建議事項 使用 MVVM 可防止複雜的 UI 邏輯塞滿您的 UI — 或糟從塞滿您的商務物件模型。

交易指令碼

當您開始將邏輯加入至您的應用程式,表單移轉資料模式會變成很麻煩。因為有關可以完成與資料邏輯內嵌在使用者介面 (UI) 中 (或在 [ViewModel),如果採取的步驟會散佈跨應用程式。非集中式邏輯的另一個副作用是開發人員可能不知道特定的功能已經存在於應用程式可能會導致重複。這會建立惡夢邏輯變更時, 因為它需要更新所有的位置 (假設所有實作邏輯的位置已經被正確地分類)。

交易指令碼模式 (前置處理。110–115 Fowler ’s 活頁簿中的) 提供一些洩壓。它可讓您分離商務邏輯,可從 UI 管理資料。

所 Fowler 定義交易指令碼 「 商務邏輯依組織其中每個程序處理單一要求從簡報的程序 」。交易指令碼,會比簡單 CRUD 作業更多。在實際上它們坐資料表資料閘道,以處理 CRUD 作業的前面。帶到在極端的情況,個別交易指令碼會處理每個擷取與送出到資料庫。但我們是邏輯的人員,知道有 ’s 時間和位置,以讓所有項目。

當您的應用程式有協調如當您建立兩個不同的實體類別執行個體之間的關聯的兩個實體之間互動時,交易指令碼是很有用的。比方說目錄管理系統中我表示產品是供業務單位為其清查的順序,藉由建立一個類別目錄項目。項目識別產品]、 [業務單位]、 [產品 SKU] 和 [期間它可以排序兩者內部和外部的時間。為簡化建立類別目錄項目,我方法上建立網域服務 (請參閱下列的程式碼片段) 提供的交易指令碼的修改業務單位的產品的可用性,沒有 UI 不必直接處理類別目錄項目。

在實際上類別目錄項目 aren’t 甚至透過公開網域] 服務如下所示:

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();
}

而不是被當作函式在用戶端網域內容上公開,RIA 服務會產生函式 (在這個案例的產品) 的有問題實體上時稱為、 變更通知放物件,在伺服器端取得解譯為網域服務上方法的呼叫。

fowler 建議實作交易指令碼的兩個方法:

  1. 封裝作業,且可以傳遞周圍的命令
  2. 與持有的交易指令碼集合的單一類別

我在這裡,花了第二種方法,但有 ’s 禁止您使用命令的執行任何動作。不公開類別目錄項目,以 UI 層的好處是交易指令碼會變成的建立類別目錄項目唯一的方法。如果您使用 [命令] 模式,規則是依慣例強制執行。如果開發人員忘記命令存在,您最後您開始使用邏輯片段和重複的右後。

在網域服務放置交易指令碼的另一個優點,是邏輯 (如我在前文有提到) 執行伺服器端。如果您有專屬的演算法,或是想要被使用者 hasn’t 惡意操作您的資料,在網域服務放置交易指令碼是移的方法。

建議事項 使用交易指令碼,當資料透過商務邏輯變成太複雜的表單,您想執行邏輯的伺服器] 側邊或兩者的運算。

商務邏輯和 UI 邏輯的比較 我讓 UI 邏輯與商務邏輯的幾個參考和不過似乎細微差異剛開始,’s 重要。UI 邏輯是邏輯關心簡報的 — 顯示在螢幕上的內容,以及 (如範例為用來填入一個下拉式方塊項目)。商務邏輯另一方面,是什麼磁碟機,應用程式本身 (比方說折扣套用到線上購買)。兩者都是在應用程式的重要 Facet,另一種模式 emerges 它們允許混用時 — 查看 「 大球的泥,」 發行項,Brian Foote Joseph Yoder ( 方法laputan.org/mud).

將多個項目傳遞至網域服務 預設情況下,您可以將只有一個實體傳遞至自訂網域服務方法。比方說方法

public void CatalogProductForBusinessUnit(Product product, int businessUnitId)

將會失效如果您嘗試使用此簽章,而不是一個整數:

public void CatalogProductForBusinessUnit(Product product, BusinessUnit bu)

因為,RIA 服務不會產生這個函式的用戶端 Proxy … 嗯,以上皆是規則。 您可以在自訂服務方法中有只能有一個實體。 這 shouldn’t 會造成問題在大部分情況下,因為如果您的實體有其索引鍵,可以上擷取它後端一次。

let’s 剛剛說,這是因為的示範,它 ’s 昂貴作業来擷取的實體 (也許它 ’s 另一邊的 Web 服務)。 它 ’s 可能會告訴網域服務您想要保留一份特定實體如下所示:

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.
}

因為 ASP.NET 執行網域服務,它具有完整存取權 ASP.NET 工作階段和快取,同時也,以防您想要自動在一段時間之後的從記憶體移除物件。我實際上利用這項技巧在專案位置我必須從多個遠端 Web 服務擷取客戶關係管理 (CRM) 資料呈現給使用者在統一的 UI。我使用明確的方法,因為某些資料值得快取中,且某些 isn’t。

網域模型

有時候商務邏輯變得複雜到甚至交易指令碼正確 can’t 管理它。經常,這顯示成交易指令碼或多個交易指令碼內複雜的分支邏輯進行了邏輯中的不同。應用程式具有 outgrown 交易指令碼公用程式的另一個符號是快速變更商務需求的地址的經常更新的需求。

如果您發現這些徵狀,它 ’s 時間考慮豐富網域模型 (前置處理。116–124 Fowler 活頁簿中)。到目前為止所涵蓋的模式有共通一件事:實體會比 DTOs 多一點 — 它們包含 (這由某些被稱為 「 Anemic 網域模型的 anti-pattern 視為) 的邏輯。物件導向開發的主要優點之一是能夠封裝資料和與其相關聯的邏輯。豐富網域模型會利用該好處藉由將邏輯回放入實體所屬的位置。

設計網域模型的詳細資料已超出本文的範圍。活頁簿,請參閱 「 網域導向設計:處理軟體紅心的複雜性 」 (Addison-Wesley,2004年),依 Eric Evans 或先前所述的 Coad 書籍上有關這個主題很棒的涵蓋範圍的物件模型。我可以不過,提供有助於說明方式,可以管理這個壓力的某些網域模型的案例。

某些 KharaPOS 客戶想要查看的特定行的歷程記錄銷售及決定以市場的市場基礎,是否在線條將會減少,(使它從多個產品可用), expanded 剪下所有一起或對給定的佳節仍然平面。

我已經在其他子系統的 KharaPOS,有銷售資料,其他我需要的一切這裡位於目錄系統。我只帶到產品銷售的唯讀檢視我們 Entity Data Model 所示圖 5.


圖 5 實體資料模型以銷售資料更新

現在我只需要是將產品選項邏輯加入至網域模型。因為我選取一個市場的產品,我將邏輯放 BusinessUnit 類別 (使用部分類別 shared.cs 或 shared.vb 副檔名為通知 RIA 服務您想要此函數以傳送至用戶端)。[圖 6] 顯示該程式碼。

圖 6選取產品的業務單位的網域邏輯

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.
  }
}

執行產品來執行上一季的自動選取就為 BusinessUnit 和 DomainContext 以下的 [SubmitChanges 的呼叫函式上呼叫新的函式一樣簡單的。 在未來如果位於邏輯中的 Bug,或必須更新邏輯我知道完全要看起來的位置。 不只需要我的集中式邏輯,我也進行物件模型更表達的意圖。 上 p。 他的 「 Domain-Driven 設計 」 活頁簿 246,Evans 說明原因這是一件好事:

如果開發人員必須考慮元件的實作,才能使用它,封裝的值將會遺失。 如果原始的程式開發人員以外的人必須推斷物件或根據它的實作作業的目的,該新的開發人員可能推斷作業或類別滿足只能由機率的用途。 如果不是目的,程式碼可能在稍後的運作但概念性設計的基礎將已經損毀,並兩個開發人員將工作在 cross-purposes。

若要 paraphrase 由明確地為它的目的命名函式和封裝 (連同幾個註解,以使它清除什麼發生) 邏輯,我對它的下一份子可以輕易 (即使下一份子是我從現在的五個月) 判斷什麼發生之前我甚至移至實作。 放入這個邏輯的它自然關聯的資料會利用的物件導向語言表達的本質。

建議事項 當您的邏輯是複雜而 gnarly,而且一次可能涉及多個實體時,請使用網域模型。 聚集與它有大部分的相似性物件邏輯,並提供有意義、 刻意的名稱,用於操作。

網域模型和交易中的指令碼 RIA 服務之間差異 您可能已經注意到交易指令碼和網域模型進行呼叫已直接在實體上。 注意雖然在兩個不同的地方在於邏輯的兩種模式。 在交易] 指令碼的情況下只實體上呼叫函式做以指出網域內容/服務應該稱為 「 下一次送出變更的網域服務上呼叫對應的函式。 在網域] 模型的情況下執行邏輯呼叫用戶端] 和 [認可的時再送出變更。

儲存機制及查詢物件 網域服務自然會實作儲存機制模式 (請參閱 Fowler p。 322). 在 WCF RIA 服務程式碼圖庫 (code.msdn.microsoft.com/RiaServices),RIA 服務小組提供透過 [DomainContext 建立明確的實作模式的極佳範例。 這可讓提升可測試性,而不需要實際叫用服務層和資料庫的應用程式。 在我的部落格 ( 而且,azurecoding.net/blogs/brownie) 我提供實作的查詢物件模式 (Fowler,p。 316) 透過 「 儲存機制的延遲伺服器端執行的查詢,直到實際的列舉型別。

應用程式服務層

快速的問題:當您想要運用豐富網域模型,但 don’t 想要公開 (Expose) 其邏輯 UI 層,該怎麼做? ’s 其中應用程式服務層級化模式 (Fowler p。 133) 進來方便好用。 一旦網域模型這個模式很容易藉由將網域邏輯超出 shared.cs 移到個別的部分類別,並將函式放在實體上的函式會叫用該網域服務實作。

應用程式服務層做為簡化外貌透過公開作業,但不是它們的詳細資料您網域模型。 另一個好處是您網域的物件都能進行而不需要服務層級用戶端把它們的內部相依性。 在某些情況下 (請參閱 所示的季節性的產品選項範例圖 6),網域服務可讓您的網域上的一個簡單呼叫。 有時它可能會協調幾個實體,但要小心 — 太多協調流程變成它回交易指令碼和優點封裝在網域內邏輯會消失。

建議事項 使用應用程式服務層提供簡單的外貌透過網域模型和移除 UI 層需要採取您實體可能要花的相依性的需求。

額外信用:封閉內容

RIA 的論壇中參與者經常問,「 如何做我分割我非常大型的資料庫跨網域服務以便 ’s 更容易管理? 」待處理的問題,「 如何做我處理需要在多個網域服務中存在的實體? 」一開始我以為 shouldn’t 會有需要,以做這些事情 ; 網域服務透過網域模型應該作為服務層並單一網域服務應該做為一個外貌透過整個網域。

在本文中我研究,不過,我附跨限制內容模式 (Evans,p。 336) 我閱讀有關之前,但 hadn’t 記憶時我原先回應這些問題。 模式的基本前提是任何大型的專案上都會有多個子網域中播放。 例如要花我有為類別目錄網域和一個個別銷售的 KharaPOS。

限制的內容可讓靜靜並存,甚至還有它們 (例如銷售、 商務單位、 產品和明細項目,[銷售額] 和 [類別目錄網域中有哪些) 之間共用的項目雖然那些網域。 不同的規則會套用到與它們進行互動哪些網域為基礎的實體 (銷售和明細項目是唯讀類別目錄網域中)。 最終的規則是作業永遠不會跨透過內容。 這是讓生活方便,因為 Silverlight doesn’t 支援透過多個網域服務的交易。

建議事項 使用限制的內容將大型的系統分割成邏輯子系統。

成功的凹穴

本文章中我們過 RIA 服務如何支援主要企業模式以極少的精力。 很少是架構因此平易近人時也被 [彈性以支援從最簡單的試算表資料輸入應用程式最複雜的商務應用程式的所有項目而不需要主要努力讓轉換。 這是名稱的他的部落格張貼相同 ( 的中提到的 「 成功 Pit 」 Brad Abrams blogs.msdn.com/brada/archive/2003/10/02/50420.aspx).

Mike Brown   是總統與 KharaSoft Inc. cofounder (kharasoft.com),訓練、 自訂軟體開發及為服務的軟體中珍貴的科技公司。 他是一個完成的技術專家與超過 14 年的業界經驗、 back-to-back MVP 獎收件者、 cofounder Indy Alt.NET 使用者群組 (indyalt.net) 和 die-hard 最風扇!

多虧給來檢閱這份文件的技術專家下列:   Brad Abrams