简体   繁体   中英

C# MVC Post Model and additional data to controller from js

I am working with a custom workflow solution that I am creating. I would like to create a postback that has the model, and two integer values that represent the action and step that I have completed. I don't want to add them to the model because they are only used in this one place. The signature for this postback would be something like this.

[HttpPost]
public void ProcessWorkflowAction(EditScreenModelValidation model, int stepActionId, int stepNumber)
{
    //Some work on model and actions
}

I would really like to do this through JS because that is currently how I am getting StepActionId and StepId. Is there a way to package up the model to send through JS?

 var modelObj = CreateModelData();
 var postObj = JSON.stringify(modelObj);
 $.ajax({
        type: "POST",
        traditional: true,
        dataType: "json",
        url: "url",
        data: { model: modelObj, stepActionId: stepId, stepNumber: 3 }
        cache: false,
        complete: function (data) {
        }});

CreateModelData = function () {
    var modelObj = {};
    var modelArray = $('#frm').serializeArray()
    $.each(modelArray, function (index, value) {
        assign(modelObj, value.name, value.value);
    })

    return modelObj;
};

function assign(obj, prop, value) {
    if (prop != undefined) {
        if (typeof prop === "string")
            prop = prop.split(".");

        if (prop.length > 1) {
            var e = prop.shift();
            assign(obj[e] =
                     Object.prototype.toString.call(obj[e]) === "[object Object]"
                     ? obj[e]
                     : {},
                   prop,
                   value);
        } else
            obj[prop[0]] = value;
    }
}

The model comes back as null in the controller. I have also tried the following code with the same result.

$.ajax({
        type: "POST",
        traditional: true,
        dataType: "json",
        url: "url",
        data: { model: $('#frm').serializeArray(), stepActionId: stepId, stepNumber: 3 }
        cache: false,
        complete: function (data) {
        }});

You need to build up the object, assign the properties (make sure it matches any model validation and the field names are the same as your model) and use JSON.stringify to make the conversion:

 var modelObj = {};
 modelObj.prop1 = $('#txtField1').val();
 modelObj.prop2 = $('#txtField2').val();
 // etc... make sure the properties of this model match EditScreenModelValidation

 var postObj = JSON.stringify(modelObj); // convert object to json

 $.ajax({
    type: "POST",
    traditional: true,
    dataType: "json",
    url: "/Workflow/Home/ProcessWorkflowAction",
    data: { model: postObj, stepActionId: stepId, stepNumber: 3 }
    cache: false,
    complete: function (data) {
        if (data.responseText.length > 0) {
            var values = $.parseJSON(data.responseText)
            $('#ActionErrors').html(values.message)
        }
        else {
            location.reload();
        }
    }});

It's possible and pretty easy to do. MVC is nice about packaging up what you send it.

So if your model looks like:

public class TestModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}

And your post method looks like:

[HttpPost]
public void TestMethod(TestModel model, int num1, int num2)
{
    // Stuff
}

Your javascript POST would look like:

function doPost(){
    $.post("/Home/TestMethod",
    {
        model: {
            Name: "Joe",
            Age: 29
        },
        num1 : 5,
        num2 : 10
     },
     function (data, status) {
         //Handle status if you decide to return something
     });
}

Hope that helps!

The fastest and easiest way to get all the fields in the Model is to serialize the Form which is bound with Model.

Update

The problem that you were receiving null in properties is because serializeArray() create key value format json. you just need to get re-build the json from key value to Property value that can be mapped to the model.

var modelObj = $('#formId').serializeArray()
                           .reduce(function (a, x) { a[x.name] = x.value; return a; }, {});

A little tweak in you ajax call instead of datatype use contentType . This is another reason you were getting null in controller's model object parameter.

         $.ajax({
            type: "post",
            url: "/Account/RegisterSome",
            data: { model: modelobj, id: 3 },
            contentType: 'application/json',
            cache: false,
            complete: function (data) {
            }
        });

So here is how I got it to work. The CreateModelData uses the (frm).serializeArray() method, but I found that if the item was disabled or not on the page, then it didn't create that property.

    var modelObj = CreateModelData();

    var postObj = JSON.stringify(modelObj);

    $.ajax({
        type: "POST",
        traditional: true,
        dataType: "json",
        url: "url",
        data: { modelString: postObj, stepActionId: stepId, stepNumber: 3 },
        cache: false,
        complete: function (data) {
        }});
});

CreateModelData = function () {
    var modelObj = {};
    var modelArray = $('#frm').serializeArray();
    $.each(modelArray, function (index, value) {
        assign(modelObj, value.name, value.value);
    })

    return modelObj;
};

function assign(obj, prop, value) {
    if (prop != undefined) {
        if (typeof prop === "string")
            prop = prop.split(".");

        if (prop.length > 1) {
            var e = prop.shift();
            assign(obj[e] =
                     Object.prototype.toString.call(obj[e]) === "[object Object]"
                     ? obj[e]
                     : {},
                   prop,
                   value);
        } else
            obj[prop[0]] = value;
    }
}

On the controller side, I changed the signature to be all string values like so.

[HttpPost]
public void ProcessWorkflow(string modelString, int stepActionId, int stepNumber)
{
}

To make the modelString value the actual model object, I did this.

using (Stream s = GenerateStreamFromString(json))
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(modelObj));
    return (modelObj)serializer.ReadObject(s);
}

In the end, this worked for me. All the fields were there and I got no errors. When i tried to have the first variable in the controller method to be the model object, it always came back as null for me no matter what I did.

I resolved the issue by removing the JSON.stringify() and just posting my javascript object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM