流量控制模式和最佳实践

时间:2011-03-10 14:30:00

标签: c#

我们与同事讨论了流量控制和通用代码设计的模式。需要你的意见 - 这是编写代码的更好/更清洁/首选方式吗?

这适用于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进行流控制。 那么,这是更好的方式,还是我们都做错了,还有更好的方式可以分享?

谢谢!

3 个答案:

答案 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); 
}