ActionResult将参数基类转换为派生类

时间:2013-04-17 09:05:15

标签: c# asp.net-mvc casting derived-class

我编写了一个基类和一些派生自它的类。

我想在一个ActionResult中使用这些类,但如果我试图将PSBase转换为PS1,我会收到一个System.InvalidCastException类型PSBase无法转换为PS1。

类:

public class PSBase
{
      public int stationId { get; set; }
      public string name { get; set; }
}

public class PS1 : PSBase
{
      public string reference { get; set; }
}

public class PS2 : PSBase
{
}

的ActionResult:

    [HttpPost]
    public ActionResult ProductionStep(PSBase ps)
    {
        if (ModelState.IsValid)
        {
            var product = db.Product.FirstOrDefault(.........);

            switch (ps.stationId )
            {
                case 1:
                    {
                        product.Reference = ((PS1)ps).reference;
                        db.SaveChanges();
                        break;
                    }
            }
        }
        return View();
    }

因为我不希望每个类都有自己的ActionResult(多次重复相同的代码)我想把所有这些都放到一个ActionResult中。任何想法如何实现这个?

1 个答案:

答案 0 :(得分:1)

如果没有自定义的ModelBinder,你要做的事情将永远无法工作(即便如此,我也不建议实施它将是一个巨大的混乱),对不起。

只有当您将模型从Controller传递给View时,它才会记住它最初的类型(包括继承等),因为此时您仍然在页面的服务器端,而您只是传递一个对象。

一旦您输入视图并提交表单,它就会创建一些POST请求,其中body包含基于输入名称的值列表。

在您的情况下,如果您有一个基于PS1的表单并使用所有字段作为输入,您会得到类似的结果:

POST:
stationId = some value
name = some value
reference = some value

(没有提到原始类型,控制器,方法等)

现在,MVC所做的是它检查你在方法的标题中使用了什么参数(在你的情况下是ProductionStep(PSBase ps))。

基于参数,它称为模型绑定器。默认模型绑定器的作用是它创建该类的新实例(在您的情况下为PSBase)并通过反射通过该类的所有属性并尝试从POST主体获取它们。

如果POST主体中有一些额外的值,则会忘记这些值。

除非您为此默认MVC实现编写自定义模型绑定器,否则无法帮助您。

我建议创建两个单独的方法,每个方法都接受不同的PSBase实现。

如果您想了解有关模型粘合剂的更多信息,请查看http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

编辑:

通过创建两个单独的方法,我的意思是这样的:

[HttpPost]
public ActionResult ProductionStepA(PS1 ps)
{
    if (ModelState.IsValid)
    {

    }
    return View();
}

[HttpPost]
public ActionResult ProductionStepB(PS2 ps)
{
    if (ModelState.IsValid)
    {

    }
    return View();
}

然后你必须通过不同的表单动作在视图中区分它们。