I've the following object which I am passing into an MVC Controller:
this.JsonData = {
"__RequestVerificationToken": $('input[name=__RequestVerificationToken]').val(),
"searchMode": {
"mode": Number(mode.val()),
"pageSize": Number(pagesize.val()) || 5, "pageNumber": Number(pagenumber.val()) || 1,
"sortField": sortfield.val() || "Ref",
"sortDirection": sortdirection.val() || "desc"
},
"searchData": {
"Compare": Number(StdComparison.val()),
"SearchTextFrom": searchText.val(),
"SearchTextTo": searchTextTo.val()
}
This works ok, but I recent requirement has arisen whereby I am looking to encode this object for use with the javascript function Window.location
Suggestions I have used:
how-to-pass-complex-json-object-in-url-using-javascript
window.location + "?SearchCriteria=" + JSON.Stringify(this.JsonData);
Creates the following request:
Controller/Action?SearchCriteria={
"__RequestVerificationToken": "tokenvalue",
"searchMode": {
"mode": 2,
"pageSize": 5,
"pageNumber": 1,
"sortField": "Ref",
"sortDirection": "desc"
},
"searchData": {
"Compare": 1,
"SearchTextFrom": "From A",
"SearchTextTo": "To Z"
}
}
Whereas
window.location + "?SearchCriteria=" + this.JsonData;
Produced the following:
Controller/Action?SearchCriteria=[object%20Object]
With a page not found error on both of the above.
UPDATE:
I have moved forward in the quest for an answer.
OK as per request from helpers, I have included more source code.
I have Three Classes.
public class MainSearch
{
public MainSearch()
{
SearchData searchData = new SearchData();
SearchMode searchMode = new SearchMode();
}
public SearchData searchData { get; set; }
public SearchMode searchMode { get; set; }
public int? page { get; set; }
public object ToPagedListParameters(int pagenumber)
{
searchMode.pageNumber = pagenumber;
return page;
}
public IList<string> ValidationErrorMessages { get; set; }
}
public class SearchData
{
// Fields used for the ticket number search
public int? ticketNumberCompare { get; set; }
public string ticketSearchTextFrom { get; set; }
public string ticketSearchTextTo { get; set; }
}
public class SearchMode
{
public int? mode { get; set; }
public int? pageNumber { get; set; }
public int? pageSize { get; set; }
public string sortDirection { get; set; }
public string sortField { get; set; }
public string userURN { get; set; }
public string __RequestVerificationToken { get; set; }
}
These classes hold the criteria used for searching (SearchData has been truncated)
The following is my controller code:
[HttpGet]
public ActionResult DownloadFileCSV(MainSearch search)
{
string fileName = Server.MapPath("~/Content/Pdf/") + "somefile.pdf";
byte[] fileContents = System.IO.File.ReadAllBytes(fileName);
return File(fileContents, "application/pdf", "result.pdf");
}
And finally, the Ajax call that is made from the cshtml file.
$("#DownloadAttachmentCSV").click(function () {
$.ajax(
{
url: '@Url.Action("DownloadFileCSV", "Home")',
contentType: 'application/json; charset=utf-8',
datatype: 'json',
data: JsonData,
type: "GET",
success: function () {
window.location = '@Url.Action("DownloadFileCSV", "Home")' + '?' + JsonData;
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
});
Oddly enough, the code above does actually work and the file is downloaded, but here is the problem. The JSON data is not populating the MainSearch variable.
So far the only way I can get the JSON data to populate the c# classes is to change the method to a POST.
Must this be the case?
You cannot pass complex javascript objects to a GET method like that. A GET has not body and to bind to a model, your query string name/value pairs must match the properties of the object your binding to. For example to bind to the mode property of the SearchMode property of MainSearch, you query string would need to include
....&SearchMode.mode=2....
Change the code your using to generate the javascript object to
var data = {
'searchMode.mode': mode.val(),
'searchMode.pageSize': pagesize.val() || 5,
'searchMode.pageNumber': pagenumber.val() || 1,
'searchMode.sortField': sortfield.val() || "Ref",
'searchMode.sortDirection': sortdirection.val() || "desc",
'searchData.SearchTextFrom': StdComparison.val(),
'searchData.Compare': searchText.val(),
'searchData.SearchTextTo': searchTextTo.val(),
}
and the ajax code to
$.ajax(
{
url: '@Url.Action("DownloadFileCSV", "Home")' + '?' + $.param(data),
type: "GET",
success: function () {
Note also the following
Number(..) to convert the values to a
number - its all sent across the wire as textcontentType option is
pointlessdatatype: 'json' does not make
sense.Having said that, its unclear what your wanting to do here. The code in your MainSearch search() method never uses any values of the model. And it returns a FileResult which cannot work with an ajax call (but it can work with window.location, it which case the code in the success callback would need to be
var baseUrl = '@Url.Action("DownloadFileCSV", "Home")';
var queryString = $.param(data);
window.location = baseUrl + '?' + queryString;
but then its unclear why you making 2 calls to the method - the ajax call, followed by the redirect (the ajax call does nothing at all).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With