模型绑定:安全转换返回null

时间:2018-02-20 07:48:20

标签: c# types casting

我有以下代码段。

public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (!ModelState.IsValid) return View(model as LocalRegisterViewModel);
        var user = new User
    {
        UserId = model.Username,
        Password = null,
        Email = model.Email,
        AccType = model.AccountType
    };

    var modelAsLocalRegisterViewModel = model as LocalRegisterViewModel;
    if (modelAsLocalRegisterViewModel != null)
        user.Password = modelAsLocalRegisterViewModel.Password;
    //...
}

这些课程如下所示。

public class RegisterViewModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public int AccountType { get; set; }
}

public interface IInternalPassword
{
    string Password { get; set; }
    string ConfirmPassword { get; set; }
}

public class LocalRegisterViewModel : RegisterViewModel, IInternalPassword
{
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
}

LocalRegisterViewModelcshtml页面传递给控制器​​,如下所示。

@model  LocalRegisterViewModel

@{
    ViewBag.Title = "Register";
    Layout = "~/Views/Shared/_LayoutAnonymous.cshtml";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))

我的问题是,modelAsLocalRegisterViewModel在安全演员之后为空。

    var modelAsLocalRegisterViewModel = model as LocalRegisterViewModel;
    if (modelAsLocalRegisterViewModel != null)
        user.Password = modelAsLocalRegisterViewModel.Password;

有人可以调查并告诉我原因吗?

修改

似乎我的提问风格很糟糕。所以让我澄清我的确切意图。我编写的Register操作旨在为多个ViewModel提供服务,每个ViewModel都有一些额外的信息。所以我所做的就是编写一个包含公共属性的父类,并扩展它以获得添加的属性。对于一个实例,我将一个LocalRegisterViewModel的实例传递给控制器​​,以便它首先执行公共功能,如果传递的实例是LocalRegisterViewModel类型,则执行扩展的功能即可。这就是我需要检查传递的RegisteredViewModel的原因,也是LocalRegisterViewModel类型。

编辑2 这不是试图将基类实例分配给派生类引用。事实上,以下内容在C#中完全有效。

class Program
{
    static void Test(Parent p)
    {
        var c = p as Child;
        Console.WriteLine(c == null ? "Can't do it!" : "Can do it!");
        Console.WriteLine(c.GetType().ToString());
    }

    static void Main(string[] args)
    {
        var c = new Child();
        Test(c);
    }
}

public class Parent
{
}

public class Child : Parent
{
}

2 个答案:

答案 0 :(得分:2)

右;所以如果:

var modelAsLocalRegisterViewModel = model as LocalRegisterViewModel;

给出null,然后有两个选项:

  • modelnull
  • model是一种东西,但不是LocalRegisterViewModel

所以:您需要查看model并找出它是什么。我们无法告诉您:它不在显示的代码中。但是string typeName = model?.GetType()?.Name;应该告诉你哪个;它会返回nullmodel 类型的名称。

通过最近的修改,我们可以看到modelRegisterViewModel;但是:听起来它不是LocalRegisterViewModel。由于存在继承树,因此model听起来像基本类型(RegisterViewModel)或与LocalRegisterViewModel无关的不同子类型。< / p>

答案 1 :(得分:2)

我认为你的困惑来自于认为你是从cshtml页面“调用”控制器方法Register(),并在那里“传递”你的模型。这不完全正确。

当您提交表单时,它会将所有输入发送到服务器,并将其发布到指定的URL。这些输入可能包含LocalRegisterViewModel的属性,例如Password。请求正文可能如下所示:

{"email": "my@email.com", "password": "bla" }

当请求到达服务器时,ASP.NET会查找与给定URL匹配的控制器操作。它看到匹配操作为Register(),此操作接受RegisterViewModel类型的参数。现在它尝试绑定该模型(从http请求填充其属性)。它绝对不知道在传入请求中有其他值,例如Password

因此asp.net将创建RegisterViewModel的实例并填充其属性,忽略所有其余的(例如密码),因为请求本身中没有关于应该将其解析为哪种C#类型的信息。 / p>