关于asp.net mvc:需要帮助理解这段代码

Need Help understanding this code

我正在努力学习单元测试。我正在尝试对我在ASP.NET MVC 1.0中制作的一些membership进行单元测试。我在看一本关于MVC的书,我对一些希望有人能帮我解决的事情感到困惑。

我正在使用nunit和moq作为框架。

问题1:

1
2
3
4
5
  public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
        {
            FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
            Provider = provider ?? Membership.Provider;
        }

我有点困惑什么?"我以前真的没见过吗?好像我都不知道这里到底发生了什么。就像他们通过接口然后??"Mark发生并生成一个新的窗体。是否制作身份验证包装纸?

问题2。

1
2
3
 public AuthenticationController(): this(null, null)
        {
        }

我知道这是默认的构造函数,但我不知道为什么:这个(空,空)正在这样做。

比如它是在实现什么?这也是什么意思。最重要的是,为什么不能把它忽略掉呢?只需按原样粘贴默认的构造函数。

问题3。

在这本书中(ASP.NET MVC 1.0很快),它讨论了实现membership提供程序需要多少工作。所以他们使用moq模型框架来简化生活。

现在我的问题是,他们没有在"形式认证"上使用MOQ。相反,它们形成了一个接口

1
2
3
4
5
6
7
   public interface IFormsAuthentication
        {
            void SetAuthCookie(string userName, bool createPersistentCookie);
            void SignOut();


        }

然后做个包装纸

公共类FormsAuthenticationWrapper:IFormsAuthentication{public void setauthcookie(字符串用户名,bool createpsistentcookie){formsAuthentication.setAuthcookie(用户名,createPersistentcookie);}公共注销()){formsAuthentication.signout();}

1
}

最后一个属性

1
2
3
4
5
   public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

他们只拥有会员资格

公共静态成员身份提供程序{得到;私人集合;}

我也不知道该怎么改变这些东西。我也要换这条线吗?

formsauth=formsauth??新的FormsAuthenticationWrapper();

我还尝试将另一个方法添加到FormsAuthentication接口和包装器中。

public void redirectFromLoginPage(字符串用户名,bool createpsistentcookie){FormsAuthentication.RedirectFromLoginPage(用户名,CreatePersistentCookie);}

然而,我不确定发生了什么,但是我的单元测试总是失败,不管我试图做什么来修复它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
     public ActionResult Login(string returnUrl, FormCollection form, bool rememberMe)
            {
                LoginValidation loginValidation = new LoginValidation();
                try
                {
                    UpdateModel(loginValidation, form.ToValueProvider());

                }
                catch
                {

                    return View("Login");
                }

                if (ModelState.IsValid == true)
                {

                    bool valid = authenticate.VerifyUser(loginValidation.UserName, loginValidation.Password);

                    if (valid == false)
                    {
                        ModelState.AddModelError("frm_Login","Either the Password or UserName is invalid");

                    }
                    else if (string.IsNullOrEmpty(returnUrl) == false)
                    {
                        /* if the user has been sent away from a page that requires them to login and they do
                         * login then redirect them back to this area*/
                        return Redirect(returnUrl);
                    }
                    else
                    {

                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);
                    }

                }


                return View("Login");


Here is my test

[试验]公共无效测试如果用户被重定向回页面,他们会在登录后从页面返回{system.diagnostics.debugger.break();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
       var formsAuthenticationMock =  new Mock<AuthenticationController.IFormsAuthentication>();

       var membershipMock = new Mock<MembershipProvider>();

       membershipMock.Setup(m => m.ValidateUser("chobo2","1234567")).Returns(true);


       // Setup controller
       AuthenticationController target = new AuthenticationController(formsAuthenticationMock.Object, membershipMock.Object);


       // Execute
       FormCollection form = new FormCollection();
       form.Add("Username","chobo2");
       form.Add("password","1234567");

       ViewResult actual = target.Login(null, form, false) as ViewResult;

       Assert.That(actual.View, Is.EqualTo("home"));
       formsAuthenticationMock.Verify();

   }

实际值总是返回到空值。我尝试了viewresult、redirectresult和redirectoroutereult,但每个人都返回空值。所以我不知道为什么会发生这样的事,因为我首先觉得很奇怪

1
                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);

不会停止视图并开始重定向。我起初认为,一旦它到达这一行,它就像一个返回语句,因此不会执行其他代码,但HTIS似乎不是这样,所以我不确定这是否是问题所在。

谢谢


问题1

??被称为空合并运算符,是C 2.0以后非常有用的特性。

在你的情况下,

1
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

简单的意思是"将formsAuth分配给formsAuth,除非它为空,在这种情况下,将new FormsAuthenticationWrapper()分配给formsAuth"。这基本上是一种防止代码中出现空引用的方法。您也可以将其视为以下条件表达式的快捷方式:

1
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

问题2

使用this(null, null)被称为构造函数链接。这意味着,在执行构造函数主体之前,应该调用同一类(因此,this而不是父类的base中采用两个参数的构造函数。

重载构造函数是一种常见的实践,它使开发人员在只想使用默认属性/设置时更容易创建新对象。

问题3

正如其他人提到的,这确实是一个单独的问题。与前两个不同,它更具体地针对上下文/您的代码,而不是C的语言特性。

更新

好的,我现在所做的实际上是重写这里的两个构造函数,因为我认为将它们放在另一个(实际上等价的)形式中可能会更清楚一些,而且可能也是更好的设计实践。这里不需要空合并运算符。

1
2
3
4
5
6
7
8
9
10
11
public AuthenticationController()
    : this(new FormsAuthenticationWrapper(), Membership.Provider)
{
}

public AuthenticationController(IFormsAuthentication formsAuth,
    MembershipProvider provider)
{
    this.FormsAuth = formsAuth;
    this.Provider = provider;
}

在这种形式中,显然采用两个参数的构造函数只是将类变量分配给参数的值。无参数构造器(通常称为默认构造器)只使用默认的formsAuthProvider对象创建一个新对象,这些对象是通过构造器链接指定的。


这个??操作员说"使用这个,除非它是空的,在这种情况下使用另一个东西"。

所以,这一行代码:

1
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

相同:

1
2
if ( formsAuth != null ) FormsAuth = formsAuth
else FormsAuth = new FormsAuthenticationWrapper();


问题1:??是空合并运算符。这个??运算符检查表达式左侧提供的值是否为空,如果为空,则返回表达式右侧指示的备用值。

在您的情况下,它检查formsAuth是否为空,如果为空则返回新的formsAuthenticationWrapper()。


问题2

1
2
3
public AuthenticationController(): this(null, null)
{
}

authenticationController的无参数构造函数将调用采用iformsAuthentication和membershipProvider的构造函数,并传递两个空值(这是在执行无参数构造函数代码块中的任何代码之前完成的)。因为两个参数的构造函数使用了空合并(??)用于分配变量的运算符,传递的参数为空,新的MembershipProvider与Membership.Provider对象一起使用。

如果没有显式定义此构造函数,则不会使用默认的无参数构造函数。如果创建了新的authenticationController(不向构造函数传递任何参数),这可能会导致意外的行为,因为成员变量不会被初始化。


问题1:??操作符简单地说:"取我左边的东西,如果不是空的,就取它;如果是,就取我右边的。"所以你的代码:

1
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

等于

1
2
3
4
5
if (formsAuth != null) {
    FormsAuth = formsAuth;
} else {
    FormsAuth 0 new FormsAuthenticationWrapper();
}

问题2::this(null, null)语法是"构造函数继承"(我的命名…)的缩写。你的代码

1
2
3
4
5
6
7
8
public AuthenticationController(): this(null, null)
    {
    }
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider  provider)
    {
        FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
        Provider = provider ?? Membership.Provider;
    }

等于

1
2
3
4
5
6
7
8
9
10
public AuthenticationController()
    {
        FormsAuth = new FormsAuthenticationWrapper();
        Provider = Membership.Provider;
    }
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
    {
        FormsAuth = formsAuth;
        Provider = provider;
    }


问题1:

1
2
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Provider = provider ?? Membership.Provider;

等于:

1
2
FormsAuth = (formsAuth == null ? new FormsAuthenticationWrapper() : formsAuth);
Provider = (provider == null ? Membership.Provider : provider);

问题2:

它只是将空值传递给formsauth和provider构造函数参数。这不是很好的练习。另一个没有参数的构造函数会更适合。

编辑:这没有意义。抱歉,我当时很着急,没有真正意识到它是一个调用另一个构造函数的构造函数。

我现在没有时间回答第三个问题,稍后再谈……


回答Q2

它正在重载构造函数。

如果意味着打电话

1
Foo()

和打电话一样吗

1
Foo(null, null)