如何通过在.Net MVC4中使用JSON调用将复杂视图模型传递到控制器操作中?

时间:2014-01-04 01:30:49

标签: jquery ajax json asp.net-mvc-4 polymorphism

所以我尽可能多地搜索Stack Overflow并找不到这个特定问题的答案。如果已经被问过,请道歉。

我找到了答案:

  • 如何将对象/类传递给动作
  • 如何通过查询字符串将对象传递给操作
  • 如何通过json将对象传递给动作
  • 如何将多态对象传递给某个动作并使用自定义模型绑定器处理它

假设您有以下代码,如何将上述技术合并到一个解决方案中。所以我想在控制器上执行操作(使用jquery ajax调用)和json对象,将视图模型传递给操作,并让它确定正确的多态类型(在这种情况下,通知类型) ) - 可能使用自定义模型绑定器。

注意:这是用于说明问题的示例代码。

型号:

public class Notification
{
    public int ID { get; set; }
    public string ApplicationID { get; set; }
    public string Description { get; set; }
    public System.DateTime DateStamp { get; set; }
}

public class WarningNotification : Notification
{
    public string WarningText { get; set; }
}

public class AlertNotification : Notification
{
    public string AlertText { get; set; }
    public int AlertId { get; set; }
}

查看型号:

public class SaveNotificationViewModel
{
    public Notification Notification { get; set; }
    public string Hash { get; set; }
    public List<int> Users { get; set; }
}

控制器操作:

public ActionResult Save(SaveNotificationViewModel model)
{
    //code inside method irrelevant...
}

Model Binder:

public class NoticationModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
        var type = Type.GetType((string)typeValue.ConvertTo(typeof(string)), true);

        if (!typeof(Notification).IsAssignableFrom(type))
        {
            throw new InvalidCastException("Bad type");
        }

        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
        return model;
    }
}

最初问题的来源让我误解了这个兔子洞和代码主要借鉴于: Methodology for passing a mix of: list<>, object and primitives to an ASP MVC controller action

2 个答案:

答案 0 :(得分:4)

  

所以我想在控制器上执行操作(使用jquery ajax调用)和json对象,将视图模型传递给操作,并让它确定正确的多态类型(在这种情况下,通知类型) - 可能使用自定义模型绑定器。

我建议不要使用单一动作。首先,虽然易于实现,但自定义模型绑定与采用基本类型或接口的操作相结合通常变得更难调试,更难以进行单元测试,任何查看控制器操作的人都无法弄清楚发生了什么看着行动本身。

我强烈建议您创建特定于请求的操作。

我将这些内容贬低为示例的相关代码。

public ProcessNotify(Notification model)
{
  this.SharedNotifyCode(model);

  // specific Notification only code
}

public ProcessWarningNotification(WarningNotification model)
{
  this.SharedNotifyCode(model);

  // specific WarningNotification only code
}

public ProcessAlertNotification(AlertNotification model)
{
  this.SharedNotifyCode(model);

  // specific AlertNotification only code
}

private SharedNotifyCode(Notification notification)
{
  // shared code
}

这很容易维护,调试,测试,代码本身就是自我记录。

使用javascript(jQuery)代码可以完成同样的事情:

function ProcessNotify()
{
  notify = {
    ID = 1,
    ApplicationID = 2,
    Description = "description",
    DateStamp = new Date() // something like this.. forgot JS datetimes
    };

  SendNotify(notify, "ProcessNotify");
}

function ProcessWarning()
{
  notify = {
    ID = 1,
    ApplicationID = 2,
    Description = "description",
    DateStamp = new Date(), // something like this.. forgot JS datetimes
    WarningText = "Oh noes!"
    };

  SendNotify(notify, "ProcessWarningNotification");
}

function ProcessAlert()
{
  notify = {
    ID = 1,
    ApplicationID = 2,
    Description = "description",
    DateStamp = new Date(), // something like this.. forgot JS datetimes
    AlertText = "Oh noes!",
    AlertId = 3
    };

  SendNotify(notify, "ProcessAlertNotification");
}

function SendNotify(notify, action)
{
  var jqXHR = $.ajax({
    url: '/' + Controller + '/' + action,
    data: notify,
    type: "POST",
    success: function(result)
    {
    }
    // etc
  });
}

答案 1 :(得分:0)

所以这就是我提出的......我包含了WarningNotification和AlertNotification的代码。

我忽视的关键是:

  1. 在JSON的根级别粘贴“ModelType”而不是在通知前缀下面(如“Notification.ModelType” - 这是错误的......不要这样做)。
  2. 所有字段都在根类型下(本例中为通知),因此专用类型的字段仍以“通知”为前缀。 - 请参阅“Notification.AlertId”
  3. 将所有内容组合在一起的Javascript代码:

    // this is an example warning notification
    var data =
        {
            "Notification.Id": '21',
            "Notification.ApplicationId": 'TARDIS',
            "Notification.Description": "The most important warning notification ever!",
            "Notification.WarningText": "I gave them the wrong warning. I should have told them to run, as fast as they can. Run and hide, because the monsters are coming - the human race.",
            "ModelType": 'Models.WarningNotification',
            "Hash": '27ad5218-963a-4df8-8c90-ee67c5ba9f30'
        };
    
    // this is an example alert notification
    var data =
        {
            "Notification.Id": '21',
            "Notification.ApplicationId": 'TARDIS',
            "Notification.Description": "The most important alert notification ever!",
            "Notification.AlertText": "Rose,before I go, I just want to tell you, you were fantastic. Absolutely fantastic. And you know what....so was I.",
            "Notification.AlertId": "1024",
            "ModelType": 'Models.AlertNotification',
            "Hash": '27ad5218-963a-4df8-8c90-ee67c5ba9f32'
        };
    
    $.ajax({
        type: 'POST',
        url: '/notification/save',
        dataType: 'json',
        data: data,
        success: function (result) {
            console.log('SUCCESS:');
            console.log(result);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            console.log('ERROR:');
            console.log(thrownError);
        }
    });