2011-03-10 55 views
2

我們與同事討論了流量控制模式和通用代碼設計。需要您的意見 - 哪種編寫代碼更好/更清潔/更受歡迎?流量控制模式和最佳實踐

這是爲MVC 3,但這並不重要。
版本1:

public ActionResult Login(LoginData loginData) 
{ 
    if (!ModelState.IsValid) 
    { 
     ShowGlobalError("Invalid credentials."); 
     return View(loginData); 
    } 

    UserProfile profile = null; 
    try 
    { 
     // see if we have profile with those credentials 
     profile = this.RetrieveUserProfile(loginData.Email.Trim(), loginData.Password.Trim()); // this just goes to db and tries to get user profile. Returns null if profile isn't found 
    } 
    catch (Exception ex) 
    { 
     ShowGlobalError("DB is down"); 
     LogError(...); 
     return View(loginData); 
    } 


    if (profile == null) 
    { 
     // nope, we don't.. ask again 
     ShowGlobalError("Invalid credentials."); 
     return View(loginData); 
    } 

    // ok, we're good 
    Session["Profile"] = profile; 
    FormsAuthentication.SetAuthCookie(profile.Email, false); 
    FormsAuthentication.RedirectFromLoginPage(profile.Email, loginData.EnablePermanentCookie); 

    return View(loginData); 
} 

版本2:

public ActionResult Login(Credentials credentials){ 
    try{ 
     PersonalProfile profile = AuthenticateUser(credentials); 
     SetProfileSessionstate(profile); // this does 'Session["Profile"] = profile;' 
     SetFormsAuthenticationAndRedirect(profile); 
    } 
    catch(Exception ex){ 
      ShowGlobalError("invalid login, please try again."); 
    } 
    return View(credentials); 
} 

public void SetFormsAuthenticationAndRedirect(PersonalProfile profile){ 
    FormsAuthentication.SetAuthCookie(profile.Email, loginData.EnablePermanentCookie); 
    FormsAuthentication.RedirectFromLoginPage(profile.Email, loginData.EnablePermanentCookie); 
} 

1版充滿了return語句,第2版使用try/catch語句進行流量控制。 那麼,哪種方式更好,還是我們都做錯了,還有更好的方法可以分享?

謝謝!

+2

所以第1版應該是相當於2個版本?因爲它看起來不像他們做同樣的事情。 – Phil 2011-03-10 14:34:40

+0

是的,他們基本上是做同樣的事情 - 用戶登錄,如果個人資料已被實際檢索 – Evgeni 2011-03-10 14:39:44

回答

1

我喜歡#1比#2

二號好得多是懶惰編碼

沒有。1明確捕獲錯誤

依靠異常來捕獲#2中的邏輯錯誤或錯誤 不是一個好主意,如果配置文件爲空,則不檢查該異常並依靠拋出異常來捕獲異常很昂貴一般 和操作應僅用於不可預見的邏輯結果(例外!)靠它

+0

那麼,爲什麼不使用#2,只是添加「if(profile == null){showError(); return;}」? – Phil 2011-03-10 21:26:55

+0

作爲一個方面說明,我完全同意,趕上一般例外,而不是更具體的人是一個壞主意。但我不認爲這就是問題所在。 – Phil 2011-03-10 21:29:03

+0

我捕捉異常的原因是這個try/catch塊只包含數據庫操作。所以如果在這個時候拋出一個異常,那麼它很有可能與數據庫相關,除非我有幸得到OutOfMemoryException或類似的東西。所以是的,我對此有點懶惰,但是我沒有看到在這段代碼中具有特定捕獲的價值。當你添加if(profile == null)的時候 - 它將會變成#1 :) – Evgeni 2011-03-10 23:55:56

0

我不認爲版本2是使用try/catch進行流量控制。使用try/catch進行流量控制看起來像this

我認爲這兩種方法都是有效的,但第二種方法對我來說更容易遵循。

編輯:

異常停止執行,並通知調用方法的目的,存在「我不能執行完畢,這裏的原因。」在某種程度上,這就是流量控制。

考慮下面的代碼

try 
{ 
    foo = doSomething1(); // Could throw an Exception here 
    doSomething2(foo); 
} 
catch (Exception ex) 
{ 
    // Show error message 
} 

這可能在技術上是「流量控制」,但它是那種流量控制的,說:「嘿,這個過程不完,這裏的原因。」這正是Exceptions的用途。

考慮下面的代碼:

try 
{ 
    foo = doSomething1(); // Could throw an Exception here 
} 
catch (Exception ex) 
{ 
    // Show error message and return 
} 

if (foo != null) 
{ 
    doSomething2(foo); 
} 
else 
{ 
    // Show an error message and return 
} 

此代碼完全相同的事情前面的代碼段,但較長,具有相同的異常處理開銷,更令人費解。在這兩種情況下,除非doSomething1成功完成,否則doSomething2將不會執行。那麼爲什麼不用簡單的代碼呢?

編輯:

最起碼,你能做到這一點,它會工作的流量控制規則周圍:

public ActionResult Login(Credentials credentials) 
{ 
    try 
    { 
     innerLogin(credentials); 
    } 
    catch(Exception ex) 
    { 
     ShowGlobalError("invalid login, please try again."); 
    } 
    return View(credentials); 
} 

private void innerLogin(Credentials credentials) 
{ 
    PersonalProfile profile = AuthenticateUser(credentials); 
    SetProfileSessionstate(profile); 
    SetFormsAuthenticationAndRedirect(profile); 
} 
+0

1版正在測試,第2名試圖訪問配置文件屬性,如果配置文件不存在,就會失敗 - 那麼它進入catch語句。 – Evgeni 2011-03-10 14:54:55

+1

如果未從AuthenticateUser()收到配置文件,則會拋出異常,是否正確?你在捕獲塊中捕獲這個異常,這意味着你不需要測試它是否被實際接收。 – Phil 2011-03-10 15:15:56

+1

這將是不同的,如果的authenticateUser()沒有拋出異常,或者如果有一個名爲CanAuthenticate()方法。如果你可以使用類似CanAuthenticate(憑證)來避免異常,那就這樣做。 – Phil 2011-03-10 15:17:11

2

我說,最好的辦法在這個流量控制情景將是測試人員模式。就我個人而言,我從不使用異常來控制應用程序的流程。

if (this.CanAuthenticateUser(credentials)) 
{ 
    PersonalProfile profile = AuthenticateUser(credentials); 
    SetProfileSessionstate(profile); // this does 'Session["Profile"] = profile;' 
    SetFormsAuthenticationAndRedirect(profile); 
} 
else 
{ 
    ShowGlobalError("invalid login, please try again."); 
} 

return View(credentials); 
+1

AuthenticateUser轉到數據庫並嘗試獲取用戶配置文件。所以,你還需要一個try/catch此方法,你仍然需要或者檢查是否輪廓實際上檢索,或有一個try/catch爲SetProfileSessionstate,因爲這將訪問文件的屬性。 – Evgeni 2011-03-10 15:56:01

+0

我想你錯過了我的帖子。這裏有一點是** **方法,CanAuthenticateUser和AuthenticateUser。 CanAuthenticateUser(tester)返回一個布爾值,指示AuthenticateUser(doer)是否會成功。提供像這樣的代碼路徑總是一個好主意,可以避免拋出異常。 – MattDavey 2011-03-15 13:26:06