I have this weird issue. I just switched from develoment pc (win7 to win10) and when I run my website now (in debug) the parameters being posted by an ajax call are not being mapped to the parameters on the controller action. On my old development pc it is being mapped, but on my new one it just won't do it.
this is my ajax call:
var obj = { companies: activeCompanyFilters, vesselTypes: activeVesselTypeFilters, vessels: activeVesselFilters, mapFilterType: getMapFilterType(), flushSession: flushSession };
var json = JSON.stringify(obj);
$.ajax({
type: "POST",
url: $("#filter-section").attr("data-source-link"),
data: json,
contentType: "application/json; charset=utf-8",
success: retrieveSuccess
}).done(() => {
layerChanged();
if (indicator) {
indicator.close();
}
});
this is the content being sent (captured with fiddler):
{"companies":[],"vesselTypes":[],"vessels":[2317],"mapFilterType":1,"flushSession":false}
and this is my controller:
[AjaxOnly]
public JsonResult FilterMarkers(long[] companies, long[] vesselTypes, long[] vessels, int? mapFilterType, bool? flushSession)
{
if (flushSession.HasValue && flushSession.Value)
Session["HomeSession"] = null;
MapFilterType filterType = HomeControllerHelper.CastToMapFilterTypeOrDefault(mapFilterType, GetSidUser());
var session = HomeControllerHelper.GetCurrentSession(Session, filterType);
var filtered = MapFilter.FilterData(session.VesselDetails, companies, vesselTypes, vessels).ToList();
return new JsonResult()
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
VesselDetails = filtered
}
};
}
I don't know what I'm missing. And I know it works because it works on my old pc. Is there a setting in IIS I'm missing?
I found the problem. Via visual studio you can create a virtual directory if you're using a local iis. i configured it like 'localhost/test'.
Things in the website are configured to Test.
so it was just a casing problem. Just strange only mapping failed but everything else worked
Related
My model is held in a JavaScript object on the client side, where the user can edit its properties via the UI controls. I want to offer the user an option to download a JSON file representing the model they're editing. I'm using MVC core with .net 6.
What I've tried
Action method (using Newtonsoft.Json to serialize the model to JSON):
public IActionResult Download([FromForm]SomeModel someModel)
{
var json = JsonConvert.SerializeObject(someModel);
var characters = json.ToCharArray();
var bytes = new byte[characters.Length];
for (var i = 0; i < characters.Length; i++)
{
bytes[i] = (byte)characters[i];
}
var stream = new MemoryStream();
stream.Write(bytes);
stream.Position = 0;
return this.File(stream, "APPLICATION/octet-stream", "someFile.json");
}
Code in the view to call this method:
<button class="btn btn-primary" onclick="download()">Download</button>
And the event handler for this button (using jQuery's ajax magic):
function download() {
$.ajax({
url: 'https://hostname/ControllerName/Download',
method: 'POST',
data: { someModel: someModel },
success: function (data) {
console.log('downloading', data);
},
});
}
What happened
The browser console shows that my model has been posted to the server, serialized to JSON and the JSON has been returned to the browser. However no file is downloaded.
Something else I tried
I also tried a link like this to call the action method:
#Html.ActionLink("Download", "Download", "ControllerName")
What happened
This time a file was downloaded, however, because ActionLink can only make GET requests, which have no request body, the user's model isn't passed to the server and instead the file which is downloaded represents a default instance of SomeModel.
The ask
So I know I can post my model to the server, serialize it to JSON and return that JSON to the client, and I know I can get the browser to download a JSON-serialized version of a model, but how can I do both in the same request?
Edit: What I've done with the answer
I've accepted Xinran Shen's answer, because it works as-is, but because I believe that just copying code from Stack Overflow without understanding what it does or why isn't good practice, I did a bit of digging and my version of the saveData function now looks like this:
function saveData(data, fileName) {
// Convert the data to a JSON string and store it in a blob, a file-like
// object which can be downloaded without it existing on the server.
// See https://developer.mozilla.org/en-US/docs/Web/API/Blob
var json = JSON.stringify(data);
var blob = new Blob([json], { type: "octet/stream" });
// Create a URL from which the blob can be downloaded - see
// https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
var url = window.URL.createObjectURL(blob);
// Add a hidden hyperlink to the page, which will download the file when clicked
var a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = fileName;
document.body.appendChild(a);
// Trigger the click event on the hyperlink to download the file
a.click();
// Release the blob's URL.
// Browsers do this when the page is unloaded, but it's good practice to
// do so as soon as it's no longer needed.
window.URL.revokeObjectURL(url);
// Remove the hidden hyperlink from the page
a.remove();
}
Hope someone finds this useful
First, Your code is right, You can try to access this method without ajax, You will find it can download file successfully,But You can't use ajax to achieve this, because JavaScript cannot interact with disk, you need to use Blob to save the file. change your javascript like this:
function download() {
$.ajax({
url: 'https://hostname/ControllerName/Download',
method: 'Post',
data: { someModel: someModel },,
success: function (data) {
fileName = "my-download.json";
saveData(data,fileName)
},
});
}
var saveData = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, fileName) {
var json = JSON.stringify(data),
blob = new Blob([json], {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
};
}());
I think you may need FileStreamResult, also you need to set the MIME type to text file or json file.
// instead of this
return this.File(stream, "APPLICATION/octet-stream", "someFile.json");
// try this
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))
{
FileDownloadName = "someFile.txt"
};
// or
return new FileStreamResult(stream, new MediaTypeHeaderValue("application/json"))
{
FileDownloadName = "someFile.json"
};
Reference: https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/
I am using an Ajax post method to pass a JSON string to a server-side MVC action. The IActionResult method parses the JSON string into an array which is uploaded into SQL Server via Microsoft.Data.SqlClient methods. The IActionResult returns an Ok() result to the caller upon completion.
The anomaly I have observed is that the database upload (server-side) only completes if I pause/interrupt the browser by placing an alert just after the Ajax method (client-side). My code is as follows:
Client-side:
function ExportJSON() {
var myJson = "some JSON stuff goes here";
$.ajax({
type: "POST",
url: "/Dailies/UploadJson/",
dataType: 'json',
data: { jsonString: myJson },
success: function (data) {
console.log(data);
}
});
alert("Your data has been saved.");
}
Server-side action:
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> UploadJson(string jsonString)
{
if (jsonString != null) {
var myJArray = JsonConvert.DeserializeObject<JArray>(jsonString);
TimePunches[] timePunches = myJArray.ToObject<TimePunches[]>();
try
{
string constr = _configuration.GetConnectionString("MYSQLSERVER");
using (SqlConnection sqlConnection = new SqlConnection(constr)) {
await sqlConnection.OpenAsync();
foreach (TimePunches timePunch in timePunches) {
string query = "INSERT INTO TimePunches([Projectid], [CrewLeaderId]) ";
query += "VALUES(#Projectid, #CrewLeaderId) ";
using (SqlCommand cmd = new SqlCommand(query)) {
cmd.Connection = sqlConnection;
cmd.Parameters.AddWithValue("#Projectid", timePunch.Projectid);
cmd.Parameters.AddWithValue("#CrewLeaderId", timePunch.CrewLeaderId);
await cmd.ExecuteNonQueryAsync();
}
}
sqlConnection.Close();
}
}
catch (Exception ex) {
TempData["msg"] = ex.Message;
}
}
return Ok();
}
To reiterate, the server-side action uploads data to the database (as expected) so long as the alert is present in the client-side ExportJSON() method. Conversely, removing the alert causes the database upload to fail.
Any assistance would be greatly appreciated.
I found an answer to this issue. The following link provides an excellent article explaining the nuances of asynchronous JavaScript calls and, in particular, how to manage synchronization issues when using Ajax: https://stackify.com/return-ajax-response-asynchronous-javascript-call/
In my particular case the solution was as simple as adding an async: false qualifier to my Ajax "post" method.
I am using .net Web Api to get data for my data grid. The call is made via ajax call like this
$.ajax({
type: 'GET',
dataType: 'json',
contentType: "application/json; charset=utf-8",
url: ReportURL, // "api/AppData/InvoiceReport/10"
success: function (mydata) {
console.log(mydata);
createReportGrid(myData); // this function creates a KENDO grid
},
error: function (error) {
alert(error);
}
});
The Web API method Looks like this
[HttpGet]
public HttpResponseMessage InvoiceReport(int Id)
{
// some llogic of data retrieving
// objReportDataList is of Type List<vmReport>
// thisstructure contains a DataTable, and 2 more list type
return Request.CreateResponse(HttpStatusCode.OK, objReportDataList);
}
These calls work perfectly for Rows Count approx 100K rows
Web Api serializes perfectly. But when the Row Count exceeds 200K i get 500 internal server error
The stack traces tells "System-OutOfMemoryException-occured-in-mscorlib-dll"
NOTE - I cant use server pagination to get little data only. This Million rows data is working on a ASP.NET Webforms application. We have migrated to MVC pattern and used WebApi for fetching Data but this error is occuring.
PS - I have tried many many solutions, but helpless
Please Guide me to Get this error removed and my reports get going
you should stream the response. then you can return millions of rows which are sent in chunks.
[HttpGet]
public HttpResponseMessage PushStreamContent()
{
var response = Request.CreateResponse();
response.Content =
new PushStreamContent((stream, content, context) =>
{
foreach (var staffMember in _staffMembers)
{
var serializer = new JsonSerializer();
using (var writer = new StreamWriter(stream))
{
serializer.Serialize(writer, staffMember);
stream.Flush();
}
}
});
return response;
}
more info here:
http://dblv.github.io/2014/07/02/streaming-web-api/
you can add below in web.config file
<configuration>
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="50000000"/>
</webServices>
</scripting>
</system.web.extensions>
</configuration>
before starting let me say that I am new to dojo and this is my first project in dojo:
when I am trying to send json data from rest client (some chrome ext) it working for me,I mean to say that my spring mvc part is working, but when i am trying to send the same json from dojo code I am getting http 400 exception
my dojo code:
postCreate : function() {
this.inherited(arguments);
var form = dom.byId("contactSubmit");
on(form, "click", function(evt) {
var box0 = registry.byId("inputEmail");
var box1 = registry.byId("inputName");
var box3 = registry.byId("message");
alert("values are: " + box0.get("value"));
jsonData = {"email":"some#gmail.com","inputName":"some name","message":"some msg"};
request.post("/pool/conta", {
data: jsonData,
handleAs: "json",
headers: {
"Content-Type": "application/json;charset=utf-8",
"Accept": "application/json"
}
}).then(function(text){
alert("values are send"+text);
});
});
}
the jason data that I am sending from rest client is which is working:
{"email":"some#gmail.com","inputName":"some name","message":"some msg"}
my spring mvc method is below:
#RequestMapping(value="/conta", method = RequestMethod.POST)
public #ResponseBody Contact getShopInJSON(#RequestBody Contact contact2) {
Contact contact = new Contact();
contact.setEmail("pro#gmail.com");
contact.setInputName("pro");
contact.setMessage("msg");
System.out.println("***********************"+contact2.getEmail());
return contact;
}
pool is name of application
The json data as passed in post request requires string to be crypted with "\" so that the javascript can handle the double codes as is within string(double quoted string).
Thus, the line
jsonData = {"email":"some#gmail.com","inputName":"some name","message":"some msg"};
would work if written as below
jsonData = " {\"email\":\"some#gmail.com\",\"inputName\":\"some name\",\"message\":\"some msg\"} " ;
Its working now, I have used toJson from dojo/_base/json" utility before passing it to request.post
I can't seem to get a JSON response from an Ajax post within a Dot Net Nuke site. It returns HTML as a response instead.
I was able to get this to work in a normal test site just fine and am wondering if anybody may know what I need to do.
Below is the code I'm testing with for now:
JavaScript:
$("#ClearTaxFormButton").click(function (e) {
e.preventDefault();
var testValue = 7;
$.ajax({
type: "GET",
url: "localhost/mywebsite/tabid/100/Default.aspx/SumbitByAjaxTest",
data: '{ "taxRate":' + testValue + '}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
// Replace the div's content with the page method's return.
//$("#Result").text(msg.d);
alert(msg.d);
}
});
});
C# Function:
//just using ths for testing
[WebMethod]
public static string SumbitByAjaxTest(string taxRate)
{
return taxRate;
}
Like I said, this exact code (aside from a different URL) works fine in a normal .NET site but when I move it over to the Dot Net Nuke site, it returns HTML.
Any ideas??
DNN's service layer allows you to follow a Webapi like approach, I think you'll find that easier for controlling the data to/from.
Here's an example of a controller for an open source articles module
https://dnnsimplearticle.codeplex.com/SourceControl/latest#cs/services/DnnSimpleArticleController.cs
Something like
public HttpResponseMessage GetAllArticles(int portalId, bool sortAsc)
{
try
{
//todo: get the latest X articles?
var articles = ArticleController.GetAllArticles(portalId, sortAsc);
//because of the circular reference when cerealizing the taxonomy within content items we have to build out our article view models manually.
var cleanArticles = new List<ArticleViewModel>();
foreach (Article a in articles)
{
var newArt = new ArticleViewModel
{
ArticleId = a.ArticleId,
Body = WebUtility.HtmlDecode(a.Body),
CreatedByUser = a.CreatedByUser,
CreatedByUserId = a.CreatedByUserId,
CreatedOnDate = a.CreatedOnDate,
Description = WebUtility.HtmlDecode(a.Description),
LastModifiedByUser = a.LastUpdatedByUser,
LastModifiedByUserId = a.LastModifiedByUserId,
LastModifiedOnDate = a.LastModifiedOnDate,
ModuleId = a.ModuleId,
Title = a.Title,
url = DotNetNuke.Common.Globals.NavigateURL(a.TabID, "", "&aid=" + a.ArticleId)
};
cleanArticles.Add(newArt);
}
var articleViewModels = new ArticleViewModels
{
Articles = cleanArticles
};
return Request.CreateResponse(HttpStatusCode.OK, articles);
}
catch (Exception exc)
{
DnnLog.Error(exc); //todo: obsolete
return Request.CreateResponse(HttpStatusCode.BadRequest, "error in request"); //todo: probably should localize that?
}
}