简体   繁体   中英

My Action won't work with HTTP POST

Hi I am having issues with trying to pass data from a js file to an Action in my MVC Controller. This is my controller.

    [HttpPost]
    [CustomAuthorize(Roles.Administrator, Roles.ContextOwner, Roles.DataOwner, Roles.DataSteward)]
    public JsonResult SaveChangesOnGrid(int id, string json)
    {
        var codeViewModels = JsonConvert.DeserializeObject<CodeViewModel[]>(json);

        var error = string.Empty;
        CodeViewModel newViewModel = null;

        foreach (var viewModel in codeViewModels)
        {
            viewModel.CodeListId = id;
            if (ModelState.IsValid)
            {
                error = codeService.Validate(viewModel);

                if (string.IsNullOrEmpty(error))
                {
                    newViewModel = codeService.SaveToStage(viewModel);
                }
            }
            else
            {
                error = "Could not save";
            }
        }

        if (id > 0 && string.IsNullOrEmpty(error))
        {
            // notify
            var codeList = codeListService.GetCurrentCodeListById(id);
            notifyGroup.NotifyDataOwnerGroup(codeList);
        }

        return Json(new
        {
            error,
            newViewModel
        });
    }

When I use the HTTPPOst annotation I can no longer get to it anymore. I am trying to access the Action using a button on my view. I have tried 2 different methods and neither work.

<a id="review_btn" class="btn btn-primary" href='@Url.Action("SaveChangesOnGrid", "Code", new {id = Model.CodeListId })'>Submit for Review</a>

EDIT: The HTML out put of the button is

<div class="btn-group offset10" style="margin-top: 20px; margin-bottom: 20px">
        <a id="review_btn" class="btn btn-primary" href='/ReferenceData.Web/Code/SaveChangesOnGrid/13'>Submit for Review</a>
</div>

In my JS file I have a function that tries to pass a JSon array to my controller action EDIT Ajax updated: There is now an internal server error Http 500 when the button is pressed. When I check the network package in my developer tools it shows the HTTP packet with the JSON packet HTTP信息的屏幕截图

    function rowsToJson(obj) {
    var selRowIds = $("#CodeGrid").jqGrid('getGridParam', 'selarrrow');

    if (selRowIds.length > 0) {

        var rowData = jQuery('#CodeGrid').jqGrid('getRowData', selRowIds[0]);
        var selectedRowsData = [{ "Code": rowData.Code, "ParentCode": rowData.ParentId, "Name": rowData.Name, "Description": rowData.Description }];

        for (var i = 1; i < selRowIds.length; i++) {

            rowData = jQuery('#CodeGrid').jqGrid('getRowData', selRowIds[i]);

            selectedRowsData.push({ "CodeId": rowData.CodeId, "Code": rowData.Code, "ParentCode": rowData.ParentId, "Name": rowData.Name, "Description": rowData.Description });
        }

        $.ajax({
            url: window.g_baseUrl + 'Code/SaveChangesOnGrid',
            type: 'POST',
            data: JSON.stringify(selectedRowsData),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            async: true,
            processData: false
        });

        //$(obj).attr('href', obj.href + "?json=" + JSON.stringify(selectedRowsData));
        return true;
    }
    else {
        alert("Please select a code");
        return false;
    }
};

$(function () {
    $('#review_btn').click(function () {
        if (confirm('These Selected Changes will be submitted for approval \n\n Are you sure you wish to proceed?')) {
            return rowsToJson(this);
        } else {
            $('#CodeGrid').jqGrid('resetSelection');
            return false;
        }
    });
});

You can see from what I have commented out I have tried using AJAX and just appending the JSON as a string onto the end of the URL.

Using AJAX with the href removed from the button I get an error 500. If I leave the href in when I debug to my controller the json parameter is null.

If I append the JSON array to the end of the URL with the HTTPPost annotation the json parameter is null. When I remove the annotation the JSON is passed through, but as I step through the code an error is thrown telling me about a security issue involving JSON and Get

I would prefer to use Ajax if possible because it avoids the data being visible to the user in the URL. But I really just want to get something working.

First, forget about using GET, it looks ugly and may fail if the JSON gets too big. Take a look at how the action is set up here:

Calling WebMethod returning IList<T> from Jquery Ajax with NHibernate And MVC

and here:

http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx

Try simplifying this as per above example.

I believe JSON.Stringify is required here. Also remove, the roles annotations for now until you get your code to function.

The data you are posting does not match your action signature. You can see the exception details on the Preview or Response tab of the debug console.

Your action signature:

[HttpPost]
public JsonResult SaveChangesOnGrid(int id, string json)

Your POST is sending:

var selectedRowsData = [{ "Code": rowData.Code, "ParentCode": rowData.ParentId, "Name": rowData.Name, "Description": rowData.Description }];
selectedRowsData.push({ "CodeId": rowData.CodeId, "Code": rowData.Code, "ParentCode": rowData.ParentId, "Name": rowData.Name, "Description": rowData.Description });

$.ajax({
    ...
    data: JSON.stringify(selectedRowsData)
});

What is expected is:

var selectedRowsData = [{ "Code": "", "ParentCode": "", "Name": "", "Description": "" }];

$.ajax({
    ...
    data: JSON.stringify({ "id": "1", "json": JSON.stringify(selectedRowsData) });
});

That's probably not what you intend so...

Try this instead

Let the framework do the binding and deserialization.

var selectedRowsData = [];
for (var i = 1; i < selRowIds.length; i++) {
    rowData = jQuery('#CodeGrid').jqGrid('getRowData', selRowIds[i]);
    selectedRowsData.push({ "CodeId": rowData.CodeId, "Code": rowData.Code, "ParentCode": rowData.ParentId, "Name": rowData.Name, "Description": rowData.Description });
}

$.ajax({
    ...
    data: JSON.stringify(selectedRowsData)
});

Now create a model that mirrors your JSON object. (Your CodeViewModel ?)

public class Country
{
    public int CodeId { get; set; }
    public string Code { get; set; }
    public string ParentCode { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

Change the action signature

[HttpPost]
public JsonResult SaveChangesOnGrid(Country[] codes)

... then forget about manually deserializing the data.

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