2011-05-02 85 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任何成員,並使用該序列化反序列化,然後將其基地返回到其他層?

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

相關問題