應用程序體系結構爲:MVVM [Views - > ViewModels] - > Repositories - > API。跨所有視圖模型處理令牌過期事件的策略
API層可能會拋出一個TokenExpiredException
異常,我們最終想要在UI層處理(通過顯示消息框並重定向到登錄)。
今天,我們的虛擬機,象這樣的倉庫交互:
SomeCommand {
await _repo.DoSomethingAsync();
}
我的問題是找到一個很好的模式來處理從API層這一例外。我能想到的3種方法:
1)裹在BaseViewModel
方法負責捕捉和處理這個視圖模型無關異常的每個庫調用。
SomeCommand {
await base.RepoRequest(() => _repo.DoSomethingAsync());
}
其中BaseViewModel
將有:
RepoRequest(action) {
try { action() }
catch (TokenExpiredException) {
// show message box
// redirect
}
任何其他異常,例如驗證錯誤,將在VM處理。我在這裏看到的問題是,忘記使用這種模式太容易了。我可能會直接在某處調用存儲庫,並錯過處理異常。
2)每個VM捕獲該異常
SomeCommand {
try { await _repo.DoSomethingAsync(); }
catch (InvalidUsernameException) { ... }
catch (TokenExpiredException) {
// show message box
// redirect
}
不是真的不同於1),同樣的問題,需要更多的代碼重複。
3)使用事件聚合器將消息從API層發佈到BaseViewModel
。
ApiRequest {
var response = await _httpClient.ExecuteAsync<..>(...);
if (response.ErrorId == "InvalidUsername")
throw new InvalidUsernameException();
else if (response.ErrorId == "TokenExpired")
EventAggregator.Publish(new TokenExpiredException());
}
和BaseViewModel
onMessage(TokenExpiredException e) {
// show message box
// redirect
}
這具有留下的所有VM(但基)自由的佈線起來的優點。 缺點是我很猶豫要使用事件聚合器1)在所有2)API層。 我們正在使用mvvm-light,這意味着在我們更深層的圖層中僅針對Messenger
(其事件聚合器)引用這些庫。
有沒有人有關於如何幹淨地實現此功能的建議?
有趣的與溫莎方法平行。訂閱在基本VM類中偵聽消息後,構造函數應該在事件被觸發時捕獲,而不必通過過多冗餘處理來拋出應用程序。 –
@IanPatrickHughes實際上都是關於[面向方面的編程](http://en.wikipedia.org/wiki/Aspect-oriented_programming),避免改變任何代碼行,而是注入行爲,這是一種情況,其中AOP完全適合,另一種情況是爲了記錄目的,有時在wpf應用程序中,我同時執行這兩種操作,攔截記錄異常並管理某種通知返回到應用程序。另外在WCF中,真正重要的是攔截所有的異常,並且總是避免拋出一個不是FaultException的異常,因此我攔截並記錄內部異常。 –