小编典典

抽象类可以作为控制器动作的参数吗?

ajax

我在Controller内部有一个Action函数,该函数被AJAX调用。该操作采用1个参数。在客户端,我构造了一个JSON对象,该对象应序列化为该1参数。我遇到的问题是参数类被声明为抽象。因此,它不能被实例化。

当AJAX击中该动作时,我得到以下信息:

无法创建抽象类。

堆栈跟踪:

[MissingMethodException:无法创建抽象类。]

System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,布尔publicOnly,布尔noCheck,布尔&canBeCached,RuntimeMethodHandleInternal&ctor,布尔&bNeedSecurityCheck)+0
System.RuntimeType.CreateInstanceSlow(布尔publicOnly,布尔skipCheckThis,布尔)+98

System.RuntimeType.CreateInstanceDefaultCtor(布尔publicOnly,布尔skipVisibilityChecks,布尔skipCheckThis,布尔fillCache)+241
System.Activator.CreateInstance(类型,布尔非公共)+69 ............. ..

有什么方法可以在不创建其他参数对象,“取消声明”参数对象为抽象或挖掘MVC机制的情况下实现这种情况?

更新资料

我目前正在与后端开发人员一起调整对象。无论哪种方式,我认为这都是最终的解决方案。谢谢大家的答案。


阅读 233

收藏
2020-07-26

共1个答案

小编典典

更新: 示例现在使用AJAX JSON POST

如果必须使用抽象类型,则可以提供自定义模型绑定程序来创建具体实例。一个例子如下所示:

模型/模型粘合剂

public abstract class Student
{
    public abstract int Age { get; set; }
    public abstract string Name { get; set; }
}
public class GoodStudent : Student
{
    public override int Age { get; set; }
    public override string Name { get; set; }
}
public class BadStudent : Student
{
    public override int Age { get; set; }
    public override string Name { get; set; }
}
public class StudentBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var values = (ValueProviderCollection) bindingContext.ValueProvider;
        var age = (int) values.GetValue("Age").ConvertTo(typeof (int));
        var name = (string) values.GetValue("Name").ConvertTo(typeof(string));
        return age > 10 ? (Student) new GoodStudent { Age = age, Name = name } : new BadStudent { Age = age, Name = name };
    }
}

控制器动作

public ActionResult Index()
{
    return View(new GoodStudent { Age = 13, Name = "John Smith" });
}
[HttpPost]
public ActionResult Index(Student student)
{
    return View(student);
}

视图

@model AbstractTest.Models.Student

@using (Html.BeginForm())
{
    <div id="StudentEditor">
        <p>Age @Html.TextBoxFor(m => m.Age)</p>
        <p>Name @Html.TextBoxFor(m => m.Name)</p>
        <p><input type="button" value="Save" id="Save" /></p>
    </div>
}

<script type="text/javascript">
    $('document').ready(function () {
        $('input#Save').click(function () {
            $.ajax({
                url: '@Ajax.JavaScriptStringEncode(Url.Action("Index"))',
                type: 'POST',
                data: GetStudentJsonData($('div#StudentEditor')),
                contentType: 'application/json; charset=utf-8',
                success: function (data, status, jqxhr) { window.location.href = '@Url.Action("Index")'; }
            });
        });
    });

    var GetStudentJsonData = function ($container) {
             return JSON.stringify({
                 'Age': $container.find('input#Age').attr('value'),
                 'Name': $container.find('input#Name').attr('value')
             });
         };
</script>

添加到Global.asax.cs

protected void Application_Start()
{
    ...
    ModelBinders.Binders.Add(new KeyValuePair<Type, IModelBinder>(typeof(Student), new StudentBinder()));
}
2020-07-26