2011-09-07 81 views
0

當我看到INotifyDataErrorInfo將用於異步驗證時,我正要實施IDataErrorInfo。當進一步挖掘時,我注意到使用這些接口的例子都在ViewModel上。我需要對模型進行驗證,並且需要與模型一起存儲的錯誤進行持久化。我有很多實體的大圖。此圖需要傳回服務器以進行復雜的驗證。我不知道我現在應該採用什麼方法。Silverlight應用程序的服務器端驗證

我是否簡單地將我的inteface實現移至模型?

我看到的另一個例子有一個單獨的驗證服務。就我而言,我的驗證規則很複雜,我正在考慮使用Windows Workflow及其規則引擎來提高驗證規則的可維護性。

我需要單獨的驗證服務嗎?

驗證完成後,圖形必須傳回客戶端。那麼需要顯示任何錯誤/警告。

我應該在模型中實現INotifyDataErrors,並在驗證返回給客戶端以將錯誤發佈到View(通過ViewModel)時引發事件?

事實證明,我在引用包含類庫中的INotifyDataErrors的程序集時遇到了問題。它會在共享這些類的程序集中創建衝突。

+0

Silverlight的重點在於提供一個豐富的客戶端。這通常意味着客戶端的第一級驗證(除了服務器上的任何驗證外)。 RIA服務允許共享自定義驗證器(在客戶端和服務器上運行),但是您的數據模型可能太複雜而無法使用RIA。 –

+0

@HiTech Magic,RIA絕對不在。我已經有一個類庫和一個Silverlight類庫共享課程。我使用啓用Silverlight的WCF服務將數據從服務器發送到客戶端。我確實有一些客戶端驗證,但這還不夠。該圖必須返回到服務器進行完整驗證。 –

+0

如果您的驗證代碼可以用於客戶端和服務器,那麼您可以使用RIA服務項目的* .shared.cs *功能來保存跨項目的文件鏈接。沒有太多的幫助,但比添加鏈接更整潔。 –

回答

0

當你有大項目RIA可能不是一個好主意,例如具有不同層次(服務,應用程序,域,基礎結構)的應用程序。

前段時間我不得不在Silverlight應用程序中使用複雜的規則實現驗證。我使用的是使用實體框架生成的自我跟蹤實體。我的一個需要是重新調整所有的驗證代碼。

首先,我嘗試使用EntLib驗證塊並在客戶端和服務器上使用相同的代碼。這種方法不起作用,因爲SL和.NET4.0使用不同版本的DataAnnotations程序集時會遇到一些問題。

最後我最終在服務器上寫了一些驗證服務,返回實體的錯誤(如果有的話)。事情是這樣的:

interface IValidate 
{ 
    IEnumerable<string> Validate(Entity entity); 
} 

,然後在客戶端做的ViewModels實施INotifyDataErrorInfo(此接口支持異步驗證),這樣你就可以驗證與服務的實體,並保存在視圖模型的誤差。

class SomeViewModel : INotifyDataErrorInfo 
{ 
    public Entity Entity { get; set; } 

    public void Validate() 
    { 
     this.ClearErrors(); 
     // this method make the service calls 
     var service = -- service instance --; 
     var errors = -- get errors from service --; 
     foreach (string error in errors) 
      this.AddTopLevelError(error); 
    } 

    {...} 
} 

這樣,所有的驗證邏輯位於服務器上,它可以隨時被添加到一個數據庫之前更改而不影響客戶端,因爲所有的實體througth該服務通過(如果你使用一)。

該服務還可以返回與錯誤相關的錯誤和屬性,這樣您可以與Silverlight進行更豐富的交互。因此,該服務可以是:

interface IValidate 
{ 
    IEnumerable<PropertyError> Validate(Entity entity); 
} 

class PropertyError 
{ 
    public string PropertyName { get; } 
    public IEnumerable<string> Errors { get; } 
} 

在這裏,你可以看到,驗證規則可以在服務器上的改變,也無所謂這個邏輯是如何實現的。所有這些工作正常並滿足您的請求,問題是Silverlight要求被驗證的對象包含所有帶有錯誤的屬性。

使用數據庫時,這是不是一個常見的情況,因爲你可以有例如(這是一個簡單的模型)

simple model

這種模式進行使用實體框架4.1

因爲如果你有一個用戶實例並且想要訪問Email屬性,你必須輸入:user_instance.Person.Email。因此,Email屬性不在用戶類型中,並且這裏是此解決方案的問題,因爲您可能也想驗證EMails。

這是不是這樣,當你有一個實體(像上面)的ViewModel(實現INotifyDataErrorInfo),並希望實體(在這種情況下,用戶)進行驗證,你只需要添加一個錯誤物業Entity.Person.Email

但世界是不完美的,所以我找到了解決辦法是複製的屬性中的每一個對視圖模型進行驗證,這樣的事:

class SomeViewModel : INotifyDataErrorInfo 
{ 
    public User Entity { get; set; } 

    public string Name { get { return Entity.UserName; } set {...} }   
    public string Email { get { return Entity.Person.Email; } set {...} } 

    {...} 
} 

這樣你就可以綁定控件到ViewModels屬性而不是實體屬性,但它有點難以處理更改通知。

您可能還想檢查:this工具包。它解決了爲您的實體定義wapper的這個問題,並且使用DynamicObject模擬了一個包含所有包裝屬性的對象。當處理大量數據時,這有點慢,但是很大程度上簡化了工作。

希望這會有所幫助。

+0

您的視圖模型是通過服務器上的服務暴露的嗎?你沒有遇到實現INotifyDataErrorInfo服務器端的問題嗎?我做到了。 –

+0

不,INotifyDataErrorInfo僅在客戶端上實現。該服務只驗證實體並返回錯誤。 – Ariel

+0

那麼這是什麼意思:「然後在服務器上,我使視圖模型實現INotifyDataErrorInfo」 –