My MVC3 app uploads documents from the user to our server. I am returning a JsonResult to display any errors, if any:
[HttpPost]
public JsonResult SaveDocument(DocumentModel model, HttpPostedFileBase postedFile)
{
//my wonderful code
return Json(new { success = true, message="ok" });
}
Heres how i submit the request:
var isSubmitting = false;
var addDocumentOptions = {
beforeSubmit: beforeAddDocumentSubmit, // pre-submit callback
success: afterDocumentSubmit // post-submit callback
};
$('#btnCreateDocument').click(function (e) {
e.preventDefault();
$('#divError').html('');
if (!isSubmitting) {
$('#createDocForm').submit();
}
});
This javascript function runs when the upload is complete:
function afterDocumentSubmit(responseText, statusText, xhr, $form) {
if (responseText.success) {
//no errors
} else {
$('#divError').html('Error: ' + responseText.message);
}
}
In FF, Chrome etc., my javascript code runs fine, but in IE, the browser wants to download the Json result as text. I get a download/open file dialog box that shouldnt appear. How do i make IE not download my Json result and behave like the other browsers? Thanks
I ran into a similar problem doing the same in Spring MVC on Java. The problem was that Spring was returning the content-type of the JSON result as application/json, which seems to make IE want to download it. You can try changing the content-type to text/plain; IE won't prompt you to download the file in this case. I suspect that something similar might be happening here.
You could try:
return Json(new { success = true, message = "ok" }, "text/plain");
In response to your new problem: the issue is that responseText is just a string. What you need to do is to convert it into a Javascript Object. You can do it like this:
var response = JSON.parse(responseText);
if(response.success) {
...
}
Most browsers support JSON.parse(). If you're having issues with non-compliant browsers, you can always use the JSON Javascript Library.
Wild guess: you are using the jquery.form plugin which enables you to upload files using AJAX and you haven't read the documentation which states the following:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to.
Now that you have read it you should take the respective actions if you want your code to work under IE as I have exemplified in this post.
The proper JsonResult return should look like so:
[HttpPost]
public JsonResult SaveDocument(DocumentModel model, HttpPostedFileBase postedFile)
{
...
return Json(new { success = true, message="ok" }, "application/json; charset=utf-8", JsonRequestBehavior.AllowGet);
}
Related
I am developing Asp.Net Core 3.1 API, Everything working as expected when I send a GET request from google chrome, Edge, Postman. But when I send GET request from internet explorer it starts to download a file default.json with the content as the response of GET request.
Defualt Action method:
public IEnumerable<string> Get()
{
return new string[] { "Welcome" };
}
default.json content:
[
"Welcome"
]
I search on the internet but could not find anything useful.
FVI, I have the same observation when I run the API using visual studio or the deployed API on the server using IIS.
IE Version: 11.900.18362.0
So I have to questions.
Does IE not support this, Is this default behavior of IE?
If Yes then how can it be fixed?
This is IE default behavior, and comes down to it simply doesn't know how to treat content with mime types like */json, hence suggest a download.
Assuming this is for users in general, and you simply want to display the json data in a browser, you could convert the content server side to text.
public ContentResult Get()
{
var jsondata = new string[] { "Welcome" };
return Content(JsonSerializer.Serialize(jsondata));
}
If you are going to do something with the actual json data, which one usually does when consuming an api, you will use some kind of client side script (e.g. Ajax as in below sample, or similar) to get the content, and in those cases there won't be any problem, like the one you encountered.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api/your-method', true);
xhr.onload = function (e) {
if (this.status == 200) {
var jsonstring = this.responseText;
// do something with the json string, e.g. JSON.parse(jsonstring)
}
};
xhr.send();
Here's a couple of posts that suggests to change the registry, though they won't be viable unless it is for a local computer of your own (and if it is, picking a browser that works out-of-the-box must be easier).
Display JSON in IE as HTML Without Download
How can I convince IE to simply display application/json rather than offer to download it?
Edit
As suggested in a comment, yet another option would be to change the mime type explicit:
Json response download in IE(7~10)
I'm returning some Json via a C# MVC Controller. Other browsers work fine, but Internet Explorer (IE9) tries to Save the returned Json data as a Text file. Any ideas how to keep this from happening?
//MVC Controller Code...
return Json(new { redirectToUrl = Url.Action("Create", "Album",
new { url = url, isLocalFile = isLocalFile})});
//Clientside Javascript Code
$("#uploadImageForm").ajaxForm({
beforeSubmit: function () {
},
success: function (data, textStatus, xhr) {
window.location.href = data.redirectToUrl;
},
error: function (data, textStatus, xhr) {
}
});
I've tried adding "text/plain" and "text/json" to the second argument of the return Json method, it doesn't work.
Many thanks!
Quote from the documentation of the jquery.form plugin:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to.
This means that if your form contains file input fields and you are submitting this form to a controller action that returns JSON, you must wrap this JSON in a <textarea> tags.
So your response should not look like this:
{ "redirectToUrl":"some url" }
it should look like this:
<textarea>{ "redirectToUrl":"some url" }</textarea>
In order to achieve that you could use a custom action result that will wrap the response with those tags:
public class TextareaJsonResult : JsonResult
{
public TextareaJsonResult(object data)
{
this.Data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
bool shouldWrap = !context.HttpContext.Request.IsAjaxRequest();
if (shouldWrap)
{
response.Write("<textarea>");
}
base.ExecuteResult(context);
if (shouldWrap)
{
response.ContentType = "text/html";
response.Write("</textarea>");
}
}
}
and then have your controller action return this custom result:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
// ... some processing
var redirectToUrl = Url.Action(
"Create",
"Album",
new { url = url, isLocalFile = isLocalFile }
);
return new TextareaJsonResult(new { redirectToUrl = redirectToUrl });
}
Now obviously in your AJAX success callback you also need to account for this difference by testing the typeof result and in the case of a legacy browser (such as Internet Explorer) manually parse the response. You may take a look at the source code of the page I have linked to.
But this being said, I can see that in your success callback you are redirecting to a controller action contained in the JSON response returned by the server. Here comes my question: What's the point of using AJAX in the first place if you are going to redirect? Why don't you use a standard form post to the controller action and have the controller action directly perform the redirect? AJAX should be used when you want to stay on the same page.
I agree with Jesse's comment, this is probably a duplicate of the link he provided.
As such I'll provide an alternative. I prefer to view json coming over the wire using a http proxy similar to fiddler http://www.fiddler2.com/fiddler2/ . I mention fiddler because it works with all browsers. The advantage is that you get a treeview of the parsed json. It's MUCH easier to read and find what you're looking for.
Also, I believe firebug for firefox, chrome dev tools, and ie dev tool all provide the same functionality. (I know chrome has the treeview, I think I remember firebug having it, and I would be surprised if modern IE doesn't have it considering the other 2 do.)
So I have ajax file upload partial (using Jquery Form plugin), it's working perfectly, but I don't know to update model value after file uploading
<div>
#Html.Partial("PhotoUpload", Model.Place)
</div>
Here I'm calling partial and giving to it part of a model.
#model PlaceMap.DAL.Entities.Place
#using (Html.BeginForm("PhotoUpload", "Place", FormMethod.Post, new { #id = "photoUpload", enctype = "multipart/form-data" }))
{
{
#Html.ValidationSummary(true, "Image upload was unsuccessful")
#Html.HiddenFor(m => m.Photo)
<input type="file" id="file" name="file"/>
<input type="submit" id="sbm" />
}
}
This is view code of partial, accepting model and form for uploading
var options = {
url: "/Place/PhotoUpload",
dataType: "json",
clearForm: true,
resetForm: true,
success: showResponse
};
function showResponse(responseText, statusText, xhr, $form)
{
$('#photo').append('<img src="/Images/Places/' + responseText.Photo + '" />');
}
$('#photoUpload').submit(function ()
{
$('#photoUpload').ajaxSubmit(options);
return false;
});
Javascript code for plugin
[Authorize]
[HttpPost]
public ActionResult PhotoUpload(string Photo, HttpPostedFileBase file)
{
try
{
using (var ms = new MemoryStream())
{
//some logic here
return Json(new { Photo = filename });
}
}
catch (ArgumentException)
{
}
return PartialView();
}
Controller action code. It's returning file name, it's going to js function "showResponse" and appending image to div. It's all work perfectly, but I have to write file name to #Model.Photo of this partial and I don't know how to do it. Any suggestions?
One possibility is to use text/plain from the server:
return Json(new { Photo = filename }, "text/plain");
and on the client manually parse:
function showResponse(responseText, statusText, xhr, $form) {
var data = $.parseJSON(responseText);
$('#photo').append('<img src="/Images/Places/' + data.Photo + '" />');
}
Obviously you lust remove the dataType: 'json' option for this to work.
Another possibility is to follow what's explained in the documentation and write a custom action result which will wrap your JSON response with the <textarea> tags:
Browsers that support the XMLHttpRequest Level 2 will be able to
upload files seamlessly and even get progress updates as the upload
proceeds. For older browsers, a fallback technology is used which
involves iframes since it is not possible to upload files using the
level 1 implmenentation of the XMLHttpRequest object. This is a common
fallback technique, but it has inherent limitations. The iframe
element is used as the target of the form's submit operation which
means that the server response is written to the iframe. This is fine
if the response type is HTML or XML, but doesn't work as well if the
response type is script or JSON, both of which often contain
characters that need to be repesented using entity references when
found in HTML markup.
To account for the challenges of script and JSON responses when using
the iframe mode, the Form Plugin allows these responses to be embedded
in a textarea element and it is recommended that you do so for these
response types when used in conjuction with file uploads and older
browsers. Please note, however, that if there is no file input in the
form then the request uses normal XHR to submit the form (not an
iframe). This puts the burden on your server code to know when to use
a textarea and when not to. If you like, you can use the iframe option
of the plugin to force it to always use an iframe mode and then your
server can always embed the response in a textarea. But the
recommended solution is to test for the 'X-Requested-With' request
header. If the value of that header is 'XMLHttpRequest' then you know
that the form was posted via ajax.
I will have a widget on a remote page. In the widget I want javascript or jquery to get all the article content from the webpage and send it back to my website. I only need just the article content and not all the other information on the webpage. I would like the script to send the remote webpage url, page content, title text, and h1 text. I would not like to receive any html tags. Is this possible to do?
The script I am making is like google adsense.
Also, Ill be using c# as my backend server
will something like this work?
http://blog.nparashuram.com/2009/08/screen-scraping-with-javascript-firebug.html
my suggestion, if it's not too much data would be to use a beacon.
var beac = new Image();
beac.onload = function () {
//do somethiringng on completion
}
beac.src = "youdomain/somthing.php?var=asdasd&key=someUniqueString";
This allows you to send a moderate amount of data to a server on another domain, provided you don't need anything back.
In short you can't do this, at least not in the way you were expecting. For security reasons there's a same-origin policy in place that prevents you from making requests to another domain.
Your best option is to do this on your server and make the request to it. I can't speak as to how you'd do this on the server since your question doesn't include which framework you're on, but let's say it's PHP, then you'd have that page take a URL, or something you can generate the URL from, then return a JSON object containing the properties you listed. The jQuery part would look something like this:
$("a").click(function() {
$.ajax({
url: 'myPage.php',
data: { url: $(this).attr("href") },
dataType: 'json',
success: function(data) {
//use the properties, data.url, data.content, data.title, etc...
}
});
});
Or, the short form using $.getJSON()...
$.getJSON('myPage.php', { url: $(this).attr("href") }, function(data) {
//use the properties, data.url, data.content, data.title, etc...
});
All the above not withstanding, you're better off sending the URL to your server and doing this completely server-side, it'll be less work. If you're aiming to view the client's page as they would see it...well this is exactly what the same-origin policy is in place to prevent, e.g. what if instead of an article it was their online banking? You can see why this is prohibited :)
Basically I have this
In my Asp.net controller
public ActionResult RenderMyView()
{
data = // some data to used in rendering my partial view
return PartialView("PartialView", data);
//edit
I also return a json result if an error occurs. Say if I get an SQLException I will return a json result back and not render any partialview.
}
My ParitalView renders a table and the "data" is basically columns from the database. So it takes the information in the data my generates a table with that many rows.
This is in my java script file and is activated when a drop down list item is changed.
$.getJSON('RenderMyView', { 'field': field}, function(response)
{
$('#id').after('<div>' + response + '</div>');
});
So what this does is calls RenderMyView what renders a partialView and adds the response code to my page.
So this is my thinking. It goes to my controller and renders and returns that PartialView. Once it gets rendered it is just html. So it is sending back html and then I add that html code into a div.
This works as I expect on Firefox but no other browser works. I tired Opera, Google chrome, IE 8, Safari none of them work.
I have no clue why since I don't have my trusty firebug.
I tired to use IE 8 firebug clone but for some reason it does not go into this part
$('#id').after('<div>' + response + '</div>');
I put break points on every line but after it goes to the server its like thats the end of the debugging it never goes back to the debugger and no errors are occurring on the server side since I am walking through it with the VS2008 debugger and nothing crashes.
Edit
It seems to not go into the response part at all. Like I put an alert box there and it never gets triggered.
Is your partial view returning an JSON result? If not, your call is probably not working because the other browsers are expecting a JSON result and receiving Html/text result.
If your partial view is returning Html then you need to use an jQuery Ajax call using.
$.ajax()
or, if you are then going to dump the result in a div, I like to use
$("#Id").load("/RenderMyView/");
which runs an Ajax call and dumps it into the selected element
EDIT
In your controller you should catch the error and return a content result which contains the error message.
public ActionResult RenderMyView()
{
try
{
data = // some data to used in rendering my partial view
return PartialView("PartialView", data);
}
catch(Exception e)
{
//catches any errors returns it back as plain text
//log the error that was thrown
return Content("Error: " + e.Message);
}
}
The Content just returns plain text from the controller. You will then need to check for this result in your JavaScript.
$.ajax({
url: 'RenderMyView',
data: {field:'field'},
dataType: 'html/text',
success: function(response) {
if (response.indexOf("Error:") == 1) {
//handle error
}
else {
$('#id').after('<div>' + response + '</div>');
}
}
});
I favour the call;
$.post("/Home/jQueryGetCalendarItems", { month: this.id }, function(retHTML) {
which works in FF and IE no probs. In the code above I'm returniong a PartialView and then replacing the contents of a div like you are.
EDIT
The other thing to look out for is the use of #. Your control name may be different than you expect. Do a [View/Source] to confirm control Id's etc. I prefer the use of '.ClassName' myself.
Shouldn't you be using $.ajax() rather than $.getJSON() if you're wanting to receive HTML? Does doing this make any difference?
$.ajax({
url: 'RenderMyView',
data: {field:'field'},
dataType: 'html',
success: function(response, textStatus) {
$('#id').after('<div>' + response + '</div>');
}
});