Warm tip: This article is reproduced from stackoverflow.com, please click
asp.net-mvc c# javascript post razor

Submit values from razor view to a controller action which accept values by HTTP Post method

发布于 2020-04-13 09:20:32

I have a view in one of my controller which have list of items. When user clicks each item, browser must navigate to page which brings details about this item.

Controller for Details accepts values through post method and have complex input object as its input.

Here is sample method for to navigate to details page using GET method to send values:

function openDetailsPage(commodityID, commodityName) {

     dateFrom = convertNumbers2English('@(((FilterViewModel)ViewBag.ViewModel).dateValue_1)');
    dateTo = convertNumbers2English('@(((FilterViewModel)ViewBag.ViewModel).dateValue_2)');

    dateFrom = changeDateSeparator(dateFrom);
    dateTo = changeDateSeparator(dateTo);

    if (dateTo == null || dateTo == undefined)
        dateTo = "0";

    if (dateFrom == null || dateFrom == undefined)
        dateFrom = "0";
    @{
        string reportTypes = "0";
        if (((FilterViewModel)ViewBag.ViewModel).purchaseReportTypes != null)
        {
            reportTypes = String.Join(",", ((FilterViewModel)ViewBag.ViewModel).purchaseReportTypes);
        }
    }
    alert('@reportTypes');
    var url = '@Url.Action("ReportDetailed","BuyReport",new {
        commodityType =(((FilterViewModel)ViewBag.ViewModel).commodityType),
        commodityName="dummyCommodityName",
        department=((FilterViewModel)ViewBag.ViewModel).department,
        repository=((FilterViewModel)ViewBag.ViewModel).repository,
        commodity ="dummyCommodityID",
        purchaseReportTypes=reportTypes,
        dateValue_1="dummyDate1",
        dateValue_2="dummyDate2"
    })';
    alert(url);

    @*var url = '@Url.Action("ReportDetailed","BuyReport",
    new RouteValueDictionary
    {
        {"commodityType",((FilterViewModel)ViewBag.ViewModel).commodityType},
        {"commodityName","dummyCommodityName" },
        {"department",((FilterViewModel)ViewBag.ViewModel).department },
        {"repository",((FilterViewModel)ViewBag.ViewModel).repository },
        {"commodity","dummyCommodityID"},
        {"purchaseReportTypes",((FilterViewModel)ViewBag.ViewModel).purchaseReportTypes },
        {"dateValue_1",((FilterViewModel)ViewBag.ViewModel).dateValue_1 },
        { "dateValue_2",((FilterViewModel)ViewBag.ViewModel).dateValue_2 }

    })';*@
    url = url.replace("dummyCommodityID", commodityID);
    url = url.replace("dummyCommodityName", commodityName);
    url = url.replace("dummyDate1", dateFrom);
    url = url.replace("dummyDate2", dateTo);
    alert(url);
    openLink(url);
}

I have some difficulties with this type of routing for values:

  1. Input object is complex so route would be so complex. E.g. /BuyReport/ReportDetailed?commodityType=0&commodityName=dummyCommodityName&department=1&repository=2&commodity=dummyCommodityID&dateValue_1=dummyDate1&dateValue_2=dummyDate2 or /BuyReport/ReportDetailed/0/itemName/1/2/1/123/
  2. Any special characters in get parameters such as / will break routing
  3. I cannot pass stuff like arrays so I should convert them before sending

So I'm looking for a method to send parameters using 'Post' method like what form submit button does with below constraints:

  1. I have no forms in my view
  2. I want to post values to controller and page must navigate to details view
    1. Each item in first page, have different row and different ID so I think creating a form for each row is not reasonable.

I want to know are there any ways to implement Post parameters according to my requirements? I would not care if it would be a mixture of C#, JS and jQuery.

More Details:

Here is a sample row in my list page which calls openDetailsPage js function:

<a onclick="openDetailsPage(@item.CommodityId,'@Html.DisplayFor(modelItem => item.CommodityName)')">
    <div class="ios-content-box px-4 py-1 mb-3 ios-hover-box">
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 f-w-600 color-orange text-right">@Html.DisplayFor(modelItem => item.CommodityName)</div>
            <div class="col-6 text-left"> <i class="fas fa-chevron-left  fa-fw  color-orange "></i></div>
        </div>
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 text-gray-600 text-right">type</div>
            <div class="col-6 text-gray-600 text-left">@Html.DisplayFor(modelItem => item.TypesName)</div>
        </div>
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 text-gray-600 text-right">Code</div>
            <div class="col-6 text-gray-600 text-left">@Html.DisplayFor(modelItem => item.CommodityCode)</div>
        </div>
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 text-gray-600 text-right">Barcode</div>
            <div class="col-6 text-gray-600 text-left">@Html.DisplayFor(modelItem => item.CommodityBarcode)</div>
        </div>
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 text-gray-600 text-right">Unit Price</div>
            <div class="col-6 text-gray-600 text-left">@Html.DisplayFor(modelItem => item.UnitPrice)</div>
        </div>
        <div class="row font-12 my-2 ios-divider-line">
            <div class="col-6 text-gray-600 text-right">Total Price</div>
            <div class="col-6 text-gray-600 text-left">@Html.DisplayFor(modelItem => item.SumPrice)</div>
        </div>
    </div>
</a>

Currently my controller is as below:

[Route("BuyReport/ReportDetailed/{commodityType}/{commodityName}/{department}/{repository}/{commodity}/{purchaseReportTypes}/{dateValue_1}/{dateValue_2}")]

public async Task<ActionResult> ReportDetailed(
    string commodityType, 
    string commodityName,
    string department,
    string repository,
    string commodity,
    string purchaseReportTypes,
    string dateValue_1,
    string dateValue_2
    )
{


}

But I want to change it to something like this:

[HttpPost]
public async Task<ActionResult> ReportDetailed(DetailedViewModel detailedviewmodel){

    string commodity = detailedviewmodel.commodity;
    string commoditytype = detailedviewmodel.commoditytype;
    string department = detailedviewmodel.department;
    string purchasereporttypes = detailedviewmodel.purchasereporttypes;
    string repository = detailedviewmodel.repository;
    string startdate = detailedviewmodel.datevalue_1;
    string enddate = detailedviewmodel.datevalue_2;
    string commdoityname = detailedviewmodel.commodityname;

}

Where DetailedViewModel is defined as below:

public class DetailedViewModel
{
    public string commodityType { get; set; }
    public string commodityName { get; set; }
    public string department { get; set; }
    public string repository { get; set; }
    public string commodity { get; set; }
    public string[] purchaseReportTypes { get; set; }

    public string dateValue_1 { get; set; }//start date
    public string dateValue_2 { get; set; }//end date

}
Questioner
VSB
Viewed
77
Amirhossein Mehrvarzi 2020-02-08 04:49

This is not the right way to meet your purpose. Your code looks vulnerable for exploiters too. Don't use solutions which break the normal web application behavior.

Instead, send the parameters to the corresponding controller method and then make an internal redirection with model passing (controller side). If your data is stored in database just send CommodityId and find details in controller side instead of sending entire details as form (HTTPPOST). In this way, you have a well designed project without unwanted crashes which come from breaking the behaviors and your code looks simple and clear as you want.