我们与同事讨论了流量控制和通用代码设计的模式。需要你的意见 - 这是编写代码的更好/更清洁/首选方式吗?
这适用于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充满了返回语句,版本2使用了try / catch进行流控制。 那么,这是更好的方式,还是我们都做错了,还有更好的方式可以分享?
谢谢!
答案 0 :(得分: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 :(得分:1)
我比#2更喜欢#1
no.2是延迟编码
no.1明确捕获错误
依靠异常来捕获逻辑错误或错误并不是一个好主意 在#2中,如果profile为null,则不检查它并依赖于抛出异常以捕获异常通常是昂贵的操作 并且只应该依赖于不可预知的逻辑结果(例外!)
答案 2 :(得分: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);
}