I have a MVC C# Controller that returns a FileResult
[HttpPost]
public FileResult FinaliseQuote(string quote)
{
var finalisedQuote = JsonConvert.DeserializeObject<FinalisedQuote>(System.Uri.UnescapeDataString(quote));
return File(finalisedQuote.ConvertToPdf(), "application/pdf");
}
Now I want to be able to download the result (I don't want it to open up in the browser)
I am calling the controller via $.ajax method in JavaScript
var postData = { quote: finalisedQuote };
var url = "/NewQuote/FinaliseQuote";
$.ajax({
type: "POST",
url: url,
data: postData,
success: function (data) {
//how do I handle data to force download
},
fail: function (msg) {
alert(msg)
},
datatype: "json"
});
How do I handle the data to force it to download?
You won't be able to use JavaScript to save the file to disk as this is blocked for security reasons.
An alternative would be to save the file in the FinaliseQuote action method (and return just an id for the file), then create another action method that responds to a GET request and returns the file. In your success function you then set window.location.href to point to your new action method (you'll need to pass an id for the file). Also make sure you set the MIME type to application/octet-stream and that should force the browser to download the file.
Controller:
[HttpPost]
public JsonResult FinaliseQuote(string quote)
{
var finalisedQuote = JsonConvert.DeserializeObject<FinalisedQuote>(System.Uri.UnescapeDataString(quote));
// save the file and return an id...
}
public FileResult DownloadFile(int id)
{
var fs = System.IO.File.OpenRead(Server.MapPath(string.Format("~/Content/file{0}.pdf", id)));
// this is needed for IE to save the file instead of opening it
HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=\"filename\"");
return File(fs, "application/octet-stream");
}
JS:
success: function (data) {
window.location.href = "/NewQuote/DownloadFile?id=" + data;
},
Related
Whilst debugging, using Unit Tests, the function returns the expected data, however when the same function is called from JavaScript, the function is hit but then doesn't return any data.
This function that I'm calling that's in the dll is hanging, but only when it is called by a function that has been called by a JS request, why would this be?
EDIT:
As in comments, my best guess is that it is something to do with a thread being in use, but I don't know, as the function itself is working, just not when called from a C# function called by AJAX.
AJAX call :
function getOnHoldTickets() {
$.ajax({
type: "GET",
url: "/cloud/getTicketCount/",
dataType: "json",
success: function (data) {
onHoldHandler(data);
},
failure: function () {
alert("getOnHoldTickets failled");
}
});
}
Controller :
// api gets hit from the JS call
[Route("cloud/getTicketCount")]
public List<UberTicket> getTicketCount()
{
var tickets = Dashboard.getTODTickets("On Hold");
return tickets;
}
[TestMethod] // calls the same method as JS
public void supportTicketTesting()
{
var openTickets = Dashboard.getTODTickets("On Hold");
var check = openTickets != null;
}
// method calling the dll
public static List<UberTicket> getTODTickets(string type)
{
var tickets = UberAPI.getTODTickets(type);
return tickets;
}
DLL Method:
// the method within the dll that's hanging when called by a function invoked by JS
public static async Task<RootObjectClass<T>> genericGet<T>(string function, string parameters)
{
try
{
// create credentials to pass to httpClient
var httpClientCredentials = new HttpClientHandler()
{
Credentials = new NetworkCredential(uberAPIUser, uberAPIPass)
};
using (var client = new HttpClient(httpClientCredentials))
{
// unsure if the headers are being passed in correctly - getting good response though
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded");
var response = await client.GetAsync(ubersmithURL + function + parameters);
var result = await response.Content.ReadAsStringAsync();
// remove nulls from json
result = Regex.Replace(result, ":null,", ":\"\",");
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var success = JsonConvert.DeserializeObject<RootObjectClass<T>>(result);
return success;
}
}
catch(Exception ex)
{
// log error
}
return new RootObjectClass<T>();
}
While this might not be addressing the issue fully, you should not be returning C# Data types as JavaScript won't be able to parse them and will result in an error similar to this in the worst case
System.Collections.Generic.List`1[...]
Like I said in my comment, you should return a JsonResult from your controller to retrieve the data in JS.
[Route("cloud/getTicketCount")]
public JsonResult getTicketCount()
{
var tickets = Dashboard.getTODTickets("On Hold");
return Json(tickets ,JsonRequestBehavior.AllowGet);
}
Understanding JsonRequestBehavior.AllowGet
and your Ajax call
$.ajax({
type: "GET",
url: "/cloud/getTicketCount/",
dataType: "json"
})
.done(function(data){
console.log(data);
})
.fail(function(xhr){
console.log(xhr.responseText);
});
Edit:
I believe this is a deadlock issue you have. Perfect answer elaborating the issue is here.
Yes, there are a whole bunch of posts with similar questions. I've tried to follow the answers in them, but my ajax call still isn't reaching the controller method.
controller (SalesController.cs):
[HttpGet]
public JsonResult fillVarietiesSelect(int species_id)
{
String[] alist = {"a","b","c"};
return Json(alist, JsonRequestBehavior.AllowGet);
}
javascript:
$('#species-select').on('change', function () {
var species_id = $('#species-select').val();
console.log("species id selected " + species_id);
alert("species id selected " + species_id);
$('#variety-select').empty();
$.ajax({
type: 'GET',
url: '#Url.Action("fillVarietiesSelect", "Sales")',
data: {species_id : species_id},
success: function (result) {
alert(result);
}
});
});
The on change event is firing, and the alert pops up with the correct data. I have a breakpoint set at the controller method, but execution doesn't seem to get there.
try doing exactly like following
Controller:
[HttpGet]
public ActionResult receive2(string p)
{
ViewBag.name = p;
List<string> lst = new List<string>() { p };
return Json(lst,JsonRequestBehavior.AllowGet);
}
Client side
$.ajax({
type: "GET",
url: "Main/receive2", // the method we are calling
contentType: "application/json; charset=utf-8",
data: { "p": $("#txtname").val() },
dataType:"json",
success: function (result) {
alert("yes");
alert('Yay! It worked!tim' + result);
window.location = "http://google.com";
// Or if you are returning something
},
error: function (result) {
alert('Oh no aa :(' + result[0]);
}
});
I have checked it's working
I had the same issue, changing the parameter from int to string resolved the problem.
On the server side I had,
public string RemoveByDocumentID(int DocumentID)
changing that to
public string RemoveByDocumentID(string DocumentID)
resolved the issue.
On the same context, I have another method in the same name (overloaded method). Which was also contributing to the issue, so I made the method name unique.
Your 404 error is telling you that #Url.Action is not being parsed by the view engine. The # is Razor syntax, so for this to work you need to be using a .cshtml extension for C# views or .vbhtml for VB views and be using MVC 3 or above.
I want to send data though Ajax to a C# file, but when I check the received data, It gives me null. Is there someting wrong with my code?
Javascript file
$(".save").click(function () {
var ss = "Helloo!";
$.ajax({
type: "POST",
url: "/Notes/save.cshtml",
global: true,
data: {fofo: ss},
processData: false,
contentType: false,
cache: false,
success: function(data){
console.log(data);
},
error: function (req, status, error) {
alert("There was a problem with the server. Try refreshing the page.");
return false;
}
});
});
C# File which receives the data (save.cshtml)
#{
var s = Request.Form["fofo"];
var result = "";
var userData = s;
var dataFile = Server.MapPath("~/Notes/lolo.txt");
File.WriteAllText(#dataFile, s);
result = "Information saved.";
}
#if(result != ""){
<p>Result: #result, #s</p>
}
You are not sending a response back to your AJAX function. Not only that what you're doing isn't standard MVC. You should be hitting a Controller which saves the data in the file at the server side and then send the result back using a JsonResult.
For example:
public JsonResult SaveNotes()
{
// Code to save file here
// Return the response
return Json({NotesSaved = true});
}
Then in your JavaScript AJAX success object you will then have the NotesSaved object set to true.
Note: You should also change your URL parameter in the AJAX command to something like:
url: '#Url.Action("SaveNotes")'
I am building an ASP.NET MVC application It currently has a button that once clicked does an Ajax call to the controller as so:
function getData() {
$.ajax({
url: "/Home/GetData/",
type: "POST",
contentType: 'application/json',
success: function (data){
//need to do stuff here
}
});
}
The controller then initializes a class, converts it to XML and then converts that to the following dictionary (There is a reason for this):
public ActionResult GetData()
{
List<People> peeps = GetPeeps();
string xml = ToXml(peeps);
Dictionary<string,List<string>> stuff = ToDictionary(xml);
return Json(stuff);
}
I would like to be able to 'Do stuff' with this data client side with javascript.
The APIs I have to work with Server side return XML data.
The APIs I have to work with Client side require string arrays. (Hence the conversions)
Is there a way to use the dictionary i've defined above client side? Could someone perhaps expand from this (if possible) to add to the ajax call a small method that prints the contents of the dictionary to a message box? just to give me a starting point from how to use the dictionary in javascript.
Thanks in advance
You can try in the ajax call as follow:
function getData() {
$.ajax({
url: "/Home/GetData/",
type: "POST",
contentType: 'application/json',
success: function (data){
console.log(data.key1); // value for key1
//or to list all values
for(var key in data){
console.log(data[key]);
}
}
});
}
Controller (for explanation purposes):
public ActionResult GetData()
{
//List<People> peeps = GetPeeps();
//string xml = ToXml(peeps);
//Dictionary<string,List<string>> stuff = ToDictionary(xml);
Dictionary<string,List<string>> stuff = new Dictionary<string, List<string>>
{
{"key1", new List<string> {"a", "b", "c"}},
{"key2", new List<string> {"d", "e", "f"}},
};
return Json(stuff);
}
I hope this is clear enough. Let me know how you go :)
Inside my MVC view I have javascript that is executed by a button click. I'm trying to set a string to a random set of characters which I can get to work fine but when I try and set that string to 'randomchars' string inside the javascript I get a NullReferenceException when I try and run the view.
Below is the code snippet, the CreateRString is where the model parameter (RString) is set to the random string.
<script type="text/javascript">
function showAndroidToast(toast) {
var url = '#Url.Action("CreateRString", "Functions")';
$.ajax({ url: url, success: function (response) { window.location.href = response.Url; }, type: 'POST', dataType: 'json' });
var randomchars = '#(Model.RString)';
}
</script>
Is the syntax correct? I'm not too sure why it's getting the NULL.
The javascript is executed after the page been delivered to the client (i.e. web browser). Your razor code here is executed on the server before the page is sent to the client. Therefore, the ajax method will execute after you try to access Model.RString
To fix this you can either call CreateRString on the server, or you can set randomchars by using the response in the success callback.
To explain option 2 a bit further. You could do something like this:
//Action Method that returns data which includes your random chars
public JsonResult CreateRString()
{
var myRandomChars = "ABCDEF";
return new JsonResult() { Data = new { RandomChars = myRandomChars } };
}
//The ajax request will receive json created in the CreateRString method which
//contains the RandomChars
$.ajax({ url: url, success: function (response) {
var randomchars = response.Data.RandomChars;
window.location.href = response.Url;
}, type: 'POST', dataType: 'json' });
More specifically, the razor calls #Url.Action("CreateRString", "Functions") and #(Model.RString) execute first on the server.
Then showAndroidToast executes in the client's browser when you call it.