Browser prompting download of JSON response, ASP.NET MVC2 - c#

I've encountered this problem all of a sudden doing a simple ajax submit of a form. The JSON comes back formatted correctly but the browser prompts to download it. Fiddler shows the content-type as correct:
application/json; charset: utf-8
Here's my javascript:
$("#submitbutton").click(function(e) {
$.post('FormTest', function(o) {
FormCallback(o);
});
});
Here is the server side:
public JsonResult FormTest(string test) {
return Json("This worked!");
}
Again, I get back an object from the server fine, but it either prompts me to download (Firefox) or simply shows the object in a new tab in the browser (Chrome).
I found one other question like this but the author didn't explain what was wrong. This is crazy! Any ideas?
Edit: The correct code is below, beside the e.preventDefault, I also needed to tell it which form data to use:
$("#submit-button").click(function(e) {
$.post('address', $("#form").serialize(), function(o) {
FormCallback(o);
});
e.preventDefault();
});

You want to cancel the default action, I expect:
$("#submitbutton").click(function(e) {
$.post('FormTest', function(o) {
FormCallback(o);
});
return false; // <<=====
});
You can also try:
e.preventDefault();
if that doesn't work by itself

In addition to #Marc's answer I would like to add that:
return Json("This worked!");
in fact doesn't work as it doesn't return a valid JSON object. It simply returns "This worked!" to the client. You need to construct the object:
return Json(new { Message = "This worked!" });

MVC 2 returns JSON mimetype by default. If you want to receive JSON data in plain HTML you should pass your JSON data as following:
return Json(model, "text/html", JsonRequestBehavior.AllowGet);
Another point, you can mark your Action with [ChildActionOnly] and call your action in your view this way
var json = <%= Html.Action("YourActionMethod", "YourControllerName") %>

Related

Parse JSON from C# to AngularJS

I have an array of file names:
[HttpPost]
public JsonResult GetJSONFilesList()
{
string[] filesArray = Directory.GetFiles("/UploadedFiles/");
for (int i = 0; i < filesArray.Length; i++)
{
filesArray[i] = Path.GetFileName(filesArray[i]);
}
return Json(filesArray);
}
I need this in AngularJS as a list of objects so I can ng-repeat it out and apply filters. I'm unable to figure out how to get the JSON from the MVC controller to AngularJS.
I've tried the following to make it visible to the view for angular to grab, but I don't know how to make the ng-init see the function to return the list. It erros on "SerializeObject(GetJSONFilesList())" saying it doesn't exist in current context.
<div ng-controller="MyController" data-ng-init="init(#Newtonsoft.Json.JsonConvert.SerializeObject(GetJSONFilesList()),
#Newtonsoft.Json.JsonConvert.SerializeObject(Model.Done))" ng-cloak>
</div>
EDIT:
I've tried using http.get.
Test one:
alert('page load');
$scope.hello = 'hello';
$http.get('http://rest-service.guides.spring.io/greeting').
then(function (response) {
$scope.greeting = response.data;
alert($scope.greeting);
});
alert($scope.hello);
The alert in the http.get never fires, the other alerts do however.
Test two:
$http({
url: '/Home/testHello',
method: 'GET'
}).success(function (data, status, headers, config) {
$scope.hello = data;
alert('hi');
});
[HttpPost]
public string testHello()
{
return "hello world";
}
This causes the angular to break and nothing in the .js works.
Test three
alert('page load');
$scope.hello = 'hello';
$scope.GetJSONFilesList = function () {
$http.get('/Home/testHello')
.success(function (result) {
$scope.availableFiles = result;
alert('success');
})
.error(function (data) {
console.log(data);
alert('error');
});
alert('hi');
};
alert($scope.hello);
[HttpPost]
public string testHello()
{
return "hello world";
}
Alerts nothing from within it, other alerts work.
Fixed:
After some googling, I've found that using .success and .error are deprecated and that .then should be used. So by using .then this resulted in the C# being hit via debug.
Then after using console.log on the returned value found that to have anything be returned I needed to return the value from C# using "return Json(myValue, JsonRequestBehavior.AllowGet); "
And by viewing the object in the console in Chrome by using console.log, I could see my values were in the data part of the returned object.
It was stored in data as an array (as I was passing an array).
I could then get the data out of there by assigning the returned value.data to a scope and could call that in the view {{result[1]}} etc.
return Json(filesArray, JsonRequestBehavior.AllowGet);
$scope.fileList;
$http.get("/Home/GetFileList").then(function (result) {
console.log(result)
$scope.fileList = result.data;
})
Imagine that you divide your front end in three layers (MVC or MVVM) whatever you want.
When you need info from server, the best practice is to separate the logic that makes the request and the logic that manipulates the data.
More info about how to make the request you can find it reading about REST APIS in Consuming a RESTful Web Service with AngularJS.
Normally one of the layers requires the use of services and you can have your controllers and your services (the place where you get the raw data from the server and you make the request. For that you need to use the $http service from angularjs.
$http: The $http service is a core AngularJS service that facilitates communication with the remote HTTP servers via the browser's XMLHttpRequest object or via JSONP.
So basically it shows you how to make get, post and put requests. One example from the documentation is :
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Pay attention to the url because there is the place where you let your request knwow which method is going to be hit on the server to take the action. If your request is succesful, then you can use the parameter called response. From there, you can do whatever you want. If you decide to make that request part from your controller, you can assign it directly to a variable on your scope. Pay attention if you need to serialize the data. Something like
$scope.myResponseName = response.name ;
The first documentation link from above shows this example which does exactly what I tell you.
angular.module('demo', [])
.controller('Hello', function($scope, $http) {
$http.get('http://rest-service.guides.spring.io/greeting').
then(function(response) {
$scope.greeting = response.data;
});
});
After all the mentioned above, pay attention to what you want to display. Are you going to display the elements of an object array? The use on your HTML the ng-repeat directive. Are you going to display just a variable (No array nor object) then you use need to use an angular expression {{ }}
In summary:
By making an HTTP request, hit the correct method on server.
Make sure you are sending the JSON correctly and that the data is correct.
Retrieve the data on your response.
Assign the data to a variable on your scope and serialize the data if needed.
Display the data correctly depending if it is within an array, if it´s an object or if its just a variable.
I hope the explanation makes sense and check the documentation if you need more info.
You can build your viewmodel so that it contains the data you'd like to serialize and then pass it to angularJS in your view as follows:
<div ng-controller="MyController" data-ng-init="init(#JsonConvert.SerializeObject(myArrayData),
#Newtonsoft.Json.JsonConvert.SerializeObject(Model.Done))" ng-cloak>
and then in your angular controller have a function to receive the data as follows:
$scope.init = function (myArrayData) {
//do something with data
};
The above assumes you're trying to pass data from mvc to angularjs on page load. If you're trying to hit a controller and get data back to angularjs upon some event such as a button click, then you can write an angularjs function similar to the following (this will be an asynchronous request):
app.controller('MyController', function ($scope, $http, $window) {
$scope.ButtonClick = function () {
var post = $http({
method: "POST",
url: "/SomeController/SomeAjaxMethod",
dataType: 'json',
data: { path: $scope.Path},
headers: { "Content-Type": "application/json" }
});
post.success(function (data, status) {
//do something with your data
});
post.error(function (data, status) {
$window.alert(data.Message);
});
}
}
and your controller action would look something like:
[HttpPost]
public JsonResult SomeAjaxMethod(string path)
{
string[] filesArray = Directory.GetFiles(path);
for (int i = 0; i < filesArray.Length; i++)
{
filesArray[i] = Path.GetFileName(filesArray[i]);
}
return Json(filesArray);
}
other answers say to use .success in the angular function, .success and .error are deprecated, instead .then should be used.
Working result:
MVC:
public JsonResult GetFileList()
{
//form array here
return Json(myArray, JsonRequestBehavior.AllowGet);
}
The function needs to be of type JsonResult, and the returned value of Json using JsonRequestBehavior.AllowGet.
AngularJS:
$scope.fileList;
$http.get("/Home/GetFileList").then(function (result) {
console.log(result)
$scope.fileList = result.data;
})
This is in my AJS controller, using .then instead of .success. If you use console.log the result returned from the mvc controller and view it in the browser inspect you'll see the object with lots of other info and the values you want are in the .data section of the object.
So to access the values you need to do result.data. In my case this gives me and array. I assign this to a scope. Then in my view I can access the values by doing {{fileList[1]}} etc. This can also be used in ng-repeat e.g:
<div ng-repeat="file in fileList">
{{fileList[$index]}}
</div>
Each value in the array in the repeat can be accessed using $index which is the number of the repeat starting at 0.

C# Click HTML Button from Webclient

I'm working on a Windows Forms Application. I want the webclient to post the values from the NameValueCollection and then hit the submit button. But now it only adds the values to the html but never submits them. How can I simulate this buttonclick?
private void button2_Click(object sender, EventArgs e)
{
var requestData = new NameValueCollection
{
{"prodids", "somevalue" },
{"customerid", "somevalue" },
{"submit_button", "submit" }
};
byte[] request = client.UploadValues("myurl", "POST", requestData);
string result = Encoding.UTF8.GetString(request);
You need to get the <form> element that contains you button, and then get its action attribute. That's the URL that your client should make a request to. You might need to get also the action attribute to find out whether to make GET or POST request.
The thing is, the button itself is not important: in the web browser, if it has action "submit" it just triggers the containing form to serialize contents and send them to the action url using `method.
When you use a client to interact with a webpage, you cannot be thinking of it like of a web browser, more like downloading a page and opening it with a text editor. Nothing's clickable, there's no JS, there's nothing even rendered - it's just the raw content sent from the server.
EDIT:
So, this is done purely with JavaScript, which is all kinds of wrong. Anyhow, your method is POST and your action is /View/DashboardProxy.php?location=Dashboard/RequestServlet&postdata=1, so your call will be:
byte[] request = client.UploadValues("/View/DashboardProxy.php?location=Dashboard/RequestServlet&postdata=1", "POST", requestData);
Note, that the response will not be a full page, but possibly nothing or some text to put in post_result_textarea.
Oh, and also note that there are more than 3 values passed in that POST request - values from: server_id, prodids, shopid, customerid and specialbids. Possibly the server requires all of those fields to be filled.
You could use AJAX with WebMethod. (this example uses jQuery for the ajax requests but you could aswell do this with plan vanilla javascript)
$.post({
type: "POST",
url: /Default.aspx/methodX,
data: data,
dataType: dataType
}).done(function(data){
if (data === true) {
console.log('everything worked out fine.')
}
});
and edit your .cs file with the following.
[WebMethod]
public bool methodX(string data) {
var requestData = new NameValueCollection
{
{"prodids", "somevalue" },
{"customerid", "somevalue" },
{"submit_button", "submit" }
};
byte[] request = client.UploadValues("myurl", "POST", data);
string result = Encoding.UTF8.GetString(request);
return true;
}
or similar.. hope you get an idea from this.
Read more
http://api.jquery.com/jquery.post
https://msdn.microsoft.com/en-us/library/4ef803zd(v=vs.90).aspx

Downloading File With Web API using Jquery Post

I have a web Api function that returns a file stream
[HttpPost]
public HttpResponseMessage DownloadDocument([FromBody] parameters)
{
try
{
var stream = FileHelper.GetFilesStream(fileUrl);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(stream) };
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition.FileName = fileName;
return result;
}
catch (Exception)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "File Not Found");
}
}
How can I call this method in Jquery Ajax to download the file so the save file dialog pops up. I am working with knockout.js, in click event handler of a button, I call this WebAPI method and I get the stream, but I don't know how to save it to the file.
You cannot download a file from an ajax call. You will need to use a get request to download a file.
What you could do is use your ajax post as above but save the file in a db and then return json with the id of the document or a url to download the document. You can then add a hidden iframe which will download the document.
Have a look at this answer which shows how to do it: https://stackoverflow.com/a/16086443/2326610
AFAIK you cannot directly download files via JQuery. One way around this is to declare a hidden iframe in html:
<iframe id='hiddenIframe' src="" style="display:none; visibility:hidden;" ></iframe>
When you click the Download button/link, then in jQuery, you can simply set the iframe source by doing:
$('#downloadButton').click(function(){
$('#hiddenIframe').attr('src', 'api/DownloadDocument');
})
You can get around this by modifying how you are sending data to your webapi.
In your Javascript you can create a hidden form and append the data that you need to that, and then submit it.
Sample code presented in coffeescript, but should be easily read/converted:
downloadDocument: (fileUri, otherProp, successCallback) =>
if $('#hidden-form').length > 0
$('#hidden-form').remove()
$('<form>').attr(
method: 'POST',
id: 'hidden-form',
action: '/your/url/to/method'
).appendTo('body');
$('<input>').attr({
type: 'hidden',
id: 'fileUri',
name: 'fileUri',
value: fileUri
}).appendTo('#hidden-form')
$('<input>').attr({
type: 'hidden',
id: 'otherProp',
name: 'otherProp',
value: otherProp
}).appendTo('#hidden-form')
$('#hidden-form').bind("submit", successCallback)
$('#hidden-form').submit()
I would then also create a DTO object which is taken in as a parameter in your webAPI controller, rather than reading from the request body:
public DownloadDocumentDTO
{
public string fileUri {get;set;}
public object otherProp {get;set;}
}
[HttpPost]
public HttpResponseMessage DownloadDocument(DownloadDocumentDTO _dto)
{
....
}
The code in your controller method should be alright.
It should be noted that if you are trying to pass up more complex data (don't know if you do since its not mentioned), then you will need to add more input to the hidden form, it won't work for passing object up.

Trying to return json and populate selectlist

Im trying to return a Json result from my controller and populate a selectlist using jQuery.
But the code dont even hit the Json method in my controller.
My selectlist
<select id="MyList"></select>
My javascript
<script type="text/javascript">
$(document).ready(function () {
$.getJSON("#Url.Action("GetProductJson", "Product")", null, function (data) {
$("#MyList").addItems(data);
});
});
$.fn.addItems = function (data) {
return this.each(function () {
var list = this;
$.each(data, function (index, itemData) {
var option = new Option(itemData.Text, itemData.Value);
list.add(option);
});
});
};
</script>
My Json method in ProductController
[HttpGet]
public JsonResult GetProductJson()
{
var list = new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Aron" },
new SelectListItem { Value = "2", Text = "Bob" },
new SelectListItem { Value = "3", Text = "Charlie" },
new SelectListItem { Value = "4", Text = "David" }
};
return Json(list);
}
You should enable JSON for GET requests which is disabled by default. This happens by passing a second argument to the Json method:
return Json(list, JsonRequestBehavior.AllowGet);
Now go ahead and install FireBug. If you had done that prior to posting this question on StackOverflow you could have inspected the AJAX request in your browser and could have seen that the server returns 500 status code and when you inspected the response you would have seen the exact error message and not only that - you would also have seen a suggestion on how to fix it. The suggestion is basically what I posted here in my answer. Thus you wouldn't even had the need to post your question as you would be able to solve it by yourself. I cannot possibly imagine people doing web development without a tool such as FireBug or Chrome Developer Tools. It's like trying to build a house with your own bare hands and without any tools.
you need to add JsonRequestBehavior.AllowGet in your json method
from Phil haack post JsonHijacking
By default, the ASP.NET MVC framework does not allow you to respond to
an HTTP GET request with a JSON payload. If you need to send JSON in
response to a GET, you'll need to explicitly allow the behavior by
using JsonRequestBehavior.AllowGet as the second parameter to the Json
method. However, there is a chance a malicious user can gain access to
the JSON payload through a process known as JSON Hijacking. You do not
want to return sensitive information using JSON in a GET request.

How to check in for a value in DB through jquery

How can i check in for a value in DB on blur event through jQuery.
I want to display a message if value exist in Data base.
I am using Asp.Net with csharp.
you can call C# function from your jQuery function like --
var isExist = <%=GetValueFromDB()%>;
GetValueFromDB in the codebehind should return a string result and you can check it in your jQuery. I hope this helps.
public string GetValueFromDB()
{
if(value is there)
return "your result";
return "emptystring";
}
Jquery runs on client, so you need to go to the server.
Ajax that calls a WebMethod might work for you
Do a webmethod and then do something along
$('#myInput').onblur(function()
{
$.get('myurl.aspx', {method : 'checkValue', mvalue : $(this).val()},function(data)
{
//handle your response
});
});

Categories