2011-05-02 98 views
15

我有一个控制器,它被称为使用AJAX的内部的动作的功能。该操作采用1个参数。在客户端,我构建了一个JSON对象,它应该序列化成1个参数。我碰到的问题是参数类被声明为抽象。因此,它不能被实例化。当AJAX命中该行动,我得到以下内容:抽象类可以是控制器操作中的参数吗?

无法创建抽象类。

堆栈跟踪:

[MissingMethodException:无法创建 一个抽象类]
System.RuntimeTypeHandle.CreateInstance(RuntimeType 类型,布尔publicOnly,布尔 NOCHECK,布尔& canBeCached, RuntimeMethodHandleInternal &构造函数, 布尔型& bNeedSecurityCheck)+0
System.RuntimeType.CreateInstanceSlow(布尔型 publicOnly,Boolean skipCheckThis, 布尔fillCache)98
System.RuntimeType.CreateInstanceDefaultCtor(布尔 publicOnly,布尔 skipVisibilityChecks,布尔 skipCheckThis,布尔fillCache)241 System.Activator.CreateInstance(类型 类型,布尔非公开)69 .. .............

是否有任何方法可以在不创建不同的参数对象的情况下拉开这样的场景,“取消声明”参数对象为抽象,或挖掘到MVC的机制?谢谢。

更新:我目前正在与后端开发人员合作,以调整自己的对象。无论哪种方式,我认为这将是最终的解决方案。谢谢大家的答案。

+4

我觉得参数必须是一个具体的type.No抽象类型或接口类型是允许的。 – 2011-05-02 19:04:24

回答

22

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

如果你必须使用一个抽象类,你可以提供一个custom model binder创建的具体实例。一个例子如下所示:

型号/模型绑定

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())); 
} 
+3

这真是太好了,帮了我一个紧张的约束。 – John 2012-05-01 19:00:40

+0

感谢您在Application_Start()中建议ModelBinders.Binders.Add。 – Dilip0165 2015-05-29 08:39:38

-2

都能跟得上 - 它是没有意义有尝试反序列化JSON到一个抽象类的一个对象。你不能让它成为一个合适的班级吗?

+0

这些对象来自应用中的另一层,它们几乎都给了我。我对他们没有任何权力。所以,我想我只是让自己的对象,然后用我自己的数据填充抽象的对象:( – Dimskiy 2011-05-02 19:08:04

+1

@Dimskiy - 你总是可以从抽象对象继承你的类。 – 2011-05-02 19:11:56

4

您必须创建一个子类的抽象类,并传递代替。抽象类从根本上不允许自己实例化。不过,如果你有一个像C#方法:

protected void Foo(MyAbstractClass param1) 

...那么你仍然可以通过富从MyAbstractClass派生的类的实例。所以你可以创建一个具体的子类MyChildClass : MyAbstractClass并传递给你的方法,它应该仍然有效。你不会有改变Foo方法,但是你需要一些访问C#代码,以便您可以创建MyChildClass

如果你使用泛型的工作 - 例如,如果你的方法签名是:

protected void Foo(IEnumerable<MyAbstractClass> param1) 

...那么它变得更加复杂,你会想看看covariance and contravariance在C#泛型。

+0

正确的是我在想什么,所以我写了一个或多或少的重复答案,但+1 :) – 2011-05-02 19:17:39

+0

我实际上有一个List ,是的,我可以访问C#,但只能在我的MVC项目中使用。我无法触摸商业/ DAL图层。 – Dimskiy 2011-05-02 19:31:47

+0

@Dimskiy - 在这种情况下,您仍然可以传入填充了'ThatDerivedClass'对象的'List '。如果方法允许协变,你可能*能够传递一个'List ',但我不确定。如果您可以编写一个C#包装器来捕获JSON数据并在将其发送到您的业务/ DAL层之前重新打包它,那将会很好。 – 2011-05-02 19:50:58

4

框架无法知道你想要的具体实施办法,既不它会采取这样的决定的责任。所以,你这里有两种可能性:

  1. 用一个具体类型为动作参数
  2. 写上基于一些请求参数会返回一个特定背景的抽象类的自定义模型粘合剂。
0

如果你有机会到控制器您可以加入其他类继承抽象类没有specifing任何成员,并使用该序列化反序列化,然后将其基地返回到其他层?

我知道这不是好的做法,但有些黑客,但我不知道抽象类是否可以以某种方式序列化。

相关问题