雖然你說你不想拋出異常,但我發現拋出異常非常有效。尤其是當您有多個子系統驗證系統時,將一種類型的異常作爲門面引發將非常有效。
您可以做的是創建一個自定義異常(即名爲ValidationException
),當您的驗證應用程序塊(VAB)報告錯誤或業務規則報告錯誤時,該異常將被拋出。在表示層中,您必須捕獲此ValidationException
並以便於用戶使用的方式向最終用戶報告此確切類型的異常。
爲兩個驗證子系統使用單一的異常類型,允許您以一致的方式報告錯誤,並確保當您(或其他開發人員)忘記處理驗證錯誤時,不會忽視驗證錯誤。處理錯誤應該是非常明確的IMO。當你讓方法返回一個錯誤列表時,很容易忘記處理它們。在創建自定義異常時,很容易將屬性添加到包含驗證錯誤列表的異常類型。這樣的錯誤列表很容易從VAB中提取。我不知道您用於業務規則驗證的驗證系統是什麼,但不能很難從中提取錯誤代碼列表。
最簡單的方法在UI來處理,這是當然的使用try
- catch
:
var businessCommand = new CreateNewMerchantCommand();
businessCommand.Name = "Wikki";
// etc
try
{
businessCommand.Execute();
}
catch (ValidationException ex)
{
UIValidationHelper.ReportValidationErrors(ex.Errors);
}
有這些try
當然 - catch
陳述到處是醜陋的,但至少這段代碼很容易遵循。取決於您構建業務層的方式以及您使用的UI技術,您可以使用更漂亮的解決方案。舉例來說,你可以用實際操作中,可以如下失敗,一個動作:
var businessCommand = new CreateNewMerchantCommand();
businessCommand.Name = "Wikki";
// etc
UIValidationHelper.ExecuteOrDisplayErrors(() =>
{
businessCommand.Execute();
});
的UIValidationHelper
應該是這樣的:
public static class UIValidationHelper
{
public static void ExecuteOrDisplayErrors (Action action)
{
try
{
action();
}
catch (ValidationException ex)
{
// Show the errors in your UI technology
ShowErrorMessage(ex.Errors);
}
}
}
的另一種選擇,那我用我自己的過去,是通過事件擴展業務層。爲了這個工作,你需要一個構造,比如命令,就像我在我的例子中使用的那樣。當使用事件,該UI看起來是這樣的:
var businessCommand = new CreateNewMerchantCommand();
businessCommand.Name = "Wikki";
// etc
businessCommand.ValidationErrorOccurred +=
UIValidationHelper.DisplayValidationErrors;
businessCommand.Execute();
這個例子鉤到ValidationErrorOccurred
事件的命令實例的靜態方法。這裏的技巧是讓該命令的Execute
方法捕獲ValidationException
,並在註冊時將它們路由到ValidationErrorOccurred
。當沒有方法註冊時,這個異常應該會喚起調用堆棧,因爲未處理的驗證異常當然不會被忽視。
儘管可以直接從業務層做到這一點,但它會使您的業務層依賴於特定的驗證技術。除此之外,此方法允許客戶選擇以任何他們想要的方式處理驗證錯誤,或決定根本不處理它們(例如,當您不希望在特定用例中出現驗證錯誤時)。
使用ASP時。NET Web窗體中,UIValidationHelper
的DisplayValidationErrors
方法看起來是這樣的:
public static class UIValidationHelper
{
public static void DisplayValidationErrors(
object sender, ValidationErrorEventArgs e)
{
Page page = GetValidPageFromCurrentHttpContext();
var summary = GetValidationSummaryFromPage()
foreach (var result in e.Error.Results)
{
summary.Controls.Add(new CustomValidator
{
ErrorMessage = result.Message,
IsValid = false
});
}
}
private static Page GetValidPageFromCurrentHttpContext()
{
return (Page)HttpContext.Current.CurrentHandler;
}
private ValidationSummary GetValidationSummaryFromPage(Page page)
{
return page.Controls.OfType<ValidationSummary>().First();
}
}
這種靜態輔助方法注入了報告的錯誤消息到頁面上的ValidationSummary
控制。它期望該頁面在頁面的根級別包含一個ValidationSummary
控件。可以輕鬆創建更靈活的解決方案。
我喜歡向您展示的最後一件事是採用此解決方案時BusinessCommand
的外觀如何。基類這些命令可能是這個樣子:
public abstract class BusinessCommand
{
public event EventHandler<ValidationErrorEventArgs>
ValidationErrorOccurred;
public void Execute()
{
try
{
this.ExecuteInternal();
}
catch (ValidationException ex)
{
if (this.ValidationErrorOccurred != null)
{
var e = new ValidationErrorEventArgs(ex);
this.ValidationErrorOccurred(this, e);
}
else
{
// Not rethrowing here would be a bad thing!
throw;
}
}
}
protected abstract void ExecuteInternal();
}
的ValidationErrorEventArgs
看起來是這樣的:
public class ValidationErrorEventArgs : EventArgs
{
public ValidationErrorEventArgs(ValidationException error)
{
this.Error = error;
}
public ValidationException Error { get; private set; }
}
我希望這一切有意義,對不起,我長的答案:-)
祝你好運。
不要忘記標記你最喜歡的答案;-) – Steven 2010-11-21 16:33:02