2013-06-04 90 views
2

在閱讀了關於Custom EFContextProvider並實現它之後,我仍然試圖找出執行服務器端驗證的最佳方法以及如何在保存之前應用業務規則...即我的問題是圍繞旋轉的2種方法,都應該被否決:服務器端驗證w/Breeze JS和自定義EFContextProvider

  • protected override bool BeforeSaveEntity(EntityInfo entityInfo) { //}
  • protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { // }

我知道文檔指定「BeforeSaveEntities方法調用「之前,將爲每個實體調用BeforeSaveEntity方法」一次。此外,我所提出的問題圍繞着對具有特定領域關係的多個實體進行驗證/應用業務規則,而不一定要驗證單個實體的屬性(爲此,我相信自定義驗證可以作爲explained here

所以我的問題是:

  1. 如何從服務器返回驗證錯誤? 一旦我應用了業務規則,並且在他們失敗的情況下如何向一個或多個實體添加驗證錯誤?
  2. 如何傳遞某種驗證上下文,以便服務器端代碼「知道」要應用哪個業務規則? 我的應用程序可以在幾個不同的地方添加新的客戶,並且基於應用程序上下文應該應用業務規則,或者應該是可選的。例如,如果存在明確的「添加新客戶」屏幕以及允許「即時」創建新客戶的「打印檢查」屏幕(在這種情況下,必須檢查更多規則)。這可能不是期望的設計,但它是要求。有很少的地方可以創建客戶......但在服務器方面,我沒有得到這個「上下文」以決定如何應用(以及以何種順序)業務規則......此外我不能爲了使用檢查我在saveMap哪些實體的邏輯(在BeforeSaveEntities的情況下),以確定上下文,因爲這是不確定性(saveMap可能對不同的應用程序的上下文相同的實體)

由於 Z. ..

回答

1

1)通常,將「自定義」驗證錯誤從服務器返回給客戶端的最簡單方法是僅在服務器上引發錯誤。我沒有嘗試但認爲可能會發揮作用的是,如果您希望將該錯誤應用於特定實體,請創建一個包含屬性的異常,該屬性包含失敗的實體/實體的EntityKey,並引發此異常。在客戶端上,您應該能夠在承諾失敗分支中檢索到此錯誤,並將驗證錯誤自己應用於特定實體。 (順便說一下,這聽起來像是一個合理的功能要求,讓微風簡化了這個過程,請把它張貼在Breeze User Voice上,這樣我們就可以評估社區的興趣了。)

2)你有兩種方法來應用'上下文「保存。最簡單的是通過SaveOptions.tag屬性。該屬性可以在客戶端上設置,並將在服務器上反序列化,以便通過SaveOptions屬性在ContextProvider中使用。 (如下所示):

public class NorthwindContextProvider : EFContextProvider<NorthwindIBContext_EDMX_2012> { 

    protected override bool BeforeSaveEntity(EntityInfo entityInfo) { 
     if ((string)SaveOptions.Tag == "myCustomSaveSetting") { 

     } 
    } 

另一種方法是爲您的保存的每個「版本」創建一個完全獨立的端點。您可以通過SaveOptions實例的'resourceName'屬性來執行此操作。

var so = new SaveOptions({ resourceName: "MyCustomSave" }); 
return myEntityManager.saveChanges(null, so); 

將轉到'MyCustomSave'控制器方法而不是標準的「SaveChanges」方法。即

public class NorthwindIBModelController : ApiController { 

    [HttpPost] 
    public SaveResult MyCustomSave(JObject saveBundle) { 
     ContextProvider.BeforeSaveEntitiesDelegate = MyCustomBeforeSaveEntities; 
     return ContextProvider.SaveChanges(saveBundle); 
    } 

    private Dictionary<Type, List<EntityInfo>> MyCustomBeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) {  
     // your code... 
    } 
} 
+0

重新#1)拋出一個錯誤似乎相當反應,是否沒有辦法主動驗證服務器上並返回驗證錯誤?如何在模型實現上實現IValidatableObject - Breeze會「拾取」驗證嗎?重新#2)SaveOptions.Tag似乎是一個很好的方式來傳遞上下文,我會嘗試 – zam6ak

+0

我剛剛添加一個額外的方法作爲一個單獨的答案。 –

2

Breeze將在保存期間使用.NET驗證屬性執行任何已註冊的驗證。以下是在實體級別和屬性級別上應用驗證屬性的示例。這兩個驗證都將在任何Customer對象的保存期間執行,並且任何驗證錯誤將在SaveChanges的「失敗」中返回。諾言。但現在,您將需要通過檢查錯誤結果將結果錯誤附加到正確的實體/屬性。

[AttributeUsage(AttributeTargets.Class)] // NEW 
public class CustomerValidator : ValidationAttribute { 
    public override Boolean IsValid(Object value) { 
    var cust = value as Customer; 
    if (cust != null && cust.CompanyName.ToLower() == "xxx") { 
     ErrorMessage = "This customer is not valid!"; 
     return false; 
    } 
    return true; 
    } 
} 

[AttributeUsage(AttributeTargets.Property)] 
public class ContactNameValidator : ValidationAttribute { 
    public override Boolean IsValid(Object value) { 
    try { 
     var val = (string)value; 
     if (!string.IsNullOrEmpty(val) && val.StartsWith("xxx")) { 
     ErrorMessage = "{0} should not start with 'xxx'""; 
     return false; 
     } 
     return true; 
    } catch (Exception e) { 
     var x = e; 
     return false; 
    } 
    } 
} 

[MetadataType(typeof(CustomerMetaData))] 
[CustomerValidator] 
public partial class Customer { 

    [ContactNameValidator] 
    public string ContactName { 
    get; 
    set; 
    } 
} 
+0

謝謝 - 那麼'IValidatableObject'呢?我們可以有'公共類客戶:IValidatableObject' - 這是一個例子http://stackoverflow.com/a/3401178/481904 – zam6ak