Getting a downloadable file with an ajax request - c#

Edit: Not sure why this was marked as a duplicate given that the original doesn't even really have an answer other than "use this third party tool that adds extra interface stuff that you probably don't want or need". The reason I was using ajax is because I need to send an array of ids and I'm not sure how to do it other than with ajax. I figured out what I need to do, so I don't really need any more help from this post, but this definitely isn't a duplicate question, and even if it were, there isn't a real answer to the original.
I've been trying to get a link that will download a file generated by my export script. However, I can't get it to get the returned file. This is the JS function I've been using...
function sendSelected(path) {
var ids;
ids = jQuery("#grid").jqGrid('getGridParam', 'selarrrow');
if (ids.length > 0) {
alert("");
$.ajax({
url: path,
data: { ids: ids },
type: "POST",
traditional: true,
});
} else {
alert("You have not selected any rows.");
return false;
}
}
and then here's the HTML portion...
<input type="submit" name="command" value="Export" />
<script type="text/javascript">
jQuery("#export").click(function () { sendSelected("/Forms/Export"); });
</script>
This all works fine, except my exporter ends with document.Save(response, "file.pdf"); and the page isn't getting this back. If I change it to document.Save(response, #"C:\some\location\to\save\at.pdf"); the file is created there, so I know it's not a problem creating the file. Also, if I just create a standard form that points to /Forms/Export and then manually enter the ids, I can download the file fine, but that doesn't work for my implementation.

$.ajax will not work, i was attempting something similar recently but ended up with different solution. Simply have a form with hidden input and then in your sendSelected set the field and action and then submit form.
$("#hiddenField").val(data);
$("#yourForm").attr("action", path)
$("#yourForm").submit();

Related

How to handle validation error(s) Server Side when a file is uploaded

I have a form which is validated server side and if the form has invalid items, the model is returned to the View and JavaScript then highlights fields which are invalid. This is a multi-part form which contains an input type file for a file upload. I am using Visual Studio 2017, ASP.Net Core 2.1 and ASP.Net MVC design pattern.
Problem: User submits the form and has a file attached but the form is invalid due to one or many input fields. When passing the Model back to the View with validation errors, the file is no longer attached as you can't populate an input type file from the server (at least not that I know of, think this is a security feature).
Desired Behavior: The user doesn't have to re-select the file in the input for upload a second time.
Current Solution: I serialize and save the uploaded file in Session on the server and then set a property on the Model which tells the View that a file is saved in session and remove the input type file for upload, then on resubmit, if the form is valid, deserialize the file out of Session, do what I need to do with the file, and remove it from Session.
Question: Is there a better way of handling this? If so, please offer example documentation or advice.
As you guessed, for security reasons, no major browsers gives you access to the actual path to the file selected by the user. Your server code will not receive the real path, and even JavaScript is not allowed access to it. Instead, the browser generates a fake path, and the only real value in it is the file name.
For that reason, the only way to keep the file in your current design (i.e. standard form) after the form is submitted is the way you did it as you described it in your question. Obviously, this is not a good way especially if the file is too big, then each round trip to the server will take a long time.
To solve it differently, you'll need to change the design. You need to make the browser retain the real path value. The only way to do this is by not submitting the form. So you need to submit the form values without submitting the form. The only way to do this I can think of is by submitting the form using Ajax. This means that the result of the server-side validation will have to come back as an Ajax response (usually JSON, but can be serialized in other ways if you like) and then JavaScript will take that response and display the errors on the form as required. In this way, the file is still re-submitted every time to the server, but at least the server doesn't need to send it back to the client like the way described in the question. That saves half of the bandwidth, but will require more programming. It is still not recommended if the file can be big. In that case, it is probably better to let the user reselect the file again rather than having to wait a long time for the file to be uploaded again.
To add the Ajax helper to .Net Core, you can simply download the JavaScript file from the project GitHub and link to it in the header of your HTML. However, I prefer to only link to it on the pages where I need it, because most pages don't need it. What I do is, first create a partial view for it:
<environment names="Development">
<script src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.min.js"></script>
</environment>
You can use CDN if you like. I cannot find a CDN other than cdn.jsdelivr.net, and I cannot find a good fallback test so I left asp-fallback-test empty:
<environment names="Development">
<script src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdn.jsdelivr.net/npm/jquery-ajax-unobtrusive#3.2.6/dist/jquery.unobtrusive-ajax.min.js"
asp-fallback-src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.min.js"
asp-fallback-test=""
crossorigin="anonymous"
integrity="sha256-PAC000yuHt78nszJ2RO0OiDMu/uLzPLRlYTk8J3AO10="></script>
</environment>
Either way, call this file anything you like, let's say _AjaxScriptsPartial.cshtml. Now in the view where you need it, add it like this:
#section Scripts {
#{ await Html.RenderPartialAsync("_AjaxScriptsPartial"); }
}
Here is a good explanation on how to use it: Using Unobtrusive Ajax In Razor Pages.
Alternatively, you can keep your current design, but instead of serializing the file and send it back to the browser, save it on the server and send the URL to the browser. Now, in the JavaScript, replace the file input field with a simple message like "File uploaded successfully" or any other way to indicate to the user that the file doesn't need to be re-selected. When the form is re-submitted and all server validation succeed, get the physical file on the server. Your code will have to know whether to upload the file or get it from the server (by checking if the file input field has a file). It also needs to know where to get it on the server. This way will work fine for all file sizes, because the files is only uploaded once, but it requires some work.
I'm not sure of the validation you are doing, but can it be moved to the front-end? Typically validation in the front-end is more for user experience. (Eg. Incorrect Formats, fields left blank, incorrect data type in field). If that's the case I'd move it to the front-end, if not you can leave it in the back-end.
You could validate the fields in the form using AJAX when they leave focus. This can guarantee that when they submit the form, the fields in the form will always be correct. I find a healthy mix of front-end and server side validation works best and not have everything in the back-end.
The crude example below sends off an ajax request to the controller to validate the input field when the onblur method fires. It will set the border to either green or red if it passed validation and display a message if there is one to display. Just make sure your model matches up with what you would be sending in your request:
JS:
<script>
function validate() {
var input = { input: $('#one').val() };
$.ajax({
url: 'ValidateTextBox/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(input),
success: function (data) {
if (JSON.parse(data.Result)) {
$('#one').css('border', '5px solid green');
} else {
$('#one').css('border', '5px solid red');
}
$('#result').text(data.Message);
}
})
}
</script>
<input id="one" type="text" onblur="validate()"/>
<label id="result"></label>
Controller.cs
[HttpPost]
public ActionResult ValidateTextBox(Dummy data)
{
int result = 0;
if (!int.TryParse(data.input, out result)) {
return Json(new { Result = false, Message = "Please enter in numbers" });
}
return Json(new { Result = true, Message = "Success" });
}
Model.cs
public class Dummy
{
public string input { get; set; }
}

How to return two pdf files in one action result?

I need to return two PDF files on postback in MVC, but the action result is returning only one file. Is there any other way is there to return more than one file in an action result?
return File(stream, "application/pdf", Summary.pdf);
Like this I need to return more than one file.
An ActionResult returned from an action in a controller always represents one thing, and since there is no concept of multi-file references in HTML, you have to make two separate steps, or merge the existing action in one step.
So you have three options:
Create two hyperlinks, with two separate actions to call. Generate a report in either of them. Return a FileResult like you do now.
Put your files in a zip file, and send that one over. The nice thing is that you only need one action. The bad thing is that users have to unzip the file before they can view the report. To make this work, you first have to generate both documents, use a library to zip the files, and then return that using a FileResult or a stream.
Merge the two reports into one. If this is feasible depends if the documents are that related they can be considered one. You can use a library to merge them together and send back the merged report.
My bet would be on option 1 unless you have very good reasons not to do so.
if you use ajax , you can create file links and send back link with json and then open links in javascripts.
server side:
...
retrun Json(new {.link1 = "stackoverflow.com" ,
.link2 = "stackexchange.com"})
and client side :
$.ajax({
url: "#Url.Action("ActionName" , "ControllerName")",
type: "post",
datatype: "json",
data: data,
success: function(sucess) {
if(success.link1 != undefined)
{
var win = window.open(d.link1 , '_blank');
var win1 = window.open(d.link2 , '_blank');
if (win==undefined) {
//Broswer has blocked it
alert(' Activate your browser popup');
}
}
},
error: function () { console.log("error"); }
});

How the form data is converted to a model in C# .Net MVC3 , entity framework?

I have a code like below
View:
$("form").live('submit', function () {
var formData = $(this).toObject();
$.ajax({
url: "../Home/Index",
type: "POST",
dataType: "json",
data: formData,
success: function (data) {<<Some handling>>
}
Controller:
public JsonResult Index(Task task)
{
//operations on the task object like getting data from task and setting to it.
}
Task is a model here.
Here when the form is submitted, the form object is directly sent to the controller and the controller is receiving it as a model.
How this conversion takes place? I have added a file component to the form now
<input type="file" name = "file" id="file"/>
and added the file attribute to model Task.
public HttpPostedFileBase file{ get; set; }
But I am getting null for the file in the controller. But all other values are coming well.
Please help me out. Please let me know if you need any additional info to understand my question correctly.
Normally it's the model binder that is responsible for converting the request values into a model.
But in your case you seem to be attempting to send a file using AJAX. This is not supported. The reason for that is because jQuery's ajax method doesn't support that. You could use HTML5 File API if the client browser supports it because the XHR2 object allows you to asynchronously upload files to the server. Here's an example:
$(document).on('submit', 'form', function () {
var xhr = new XMLHttpRequest();
xhr.open(this.method, this.action);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText); // handle response.
}
};
xhr.send(new FormData(this));
return false;
}
Also notice that I have used the .on() method to subscribe to the submit event instead of .live() which is obsolete and has been removed in jQuery 1.9.
If on the other hand you need to support legacy browsers you could use a plugin such as Fine Uploader or jQuery form to achieve this task. What those plugins do is detect the capabilities of your browser and if it supports XHR2 it will use it, and if it doesn't it will use a different technique (such as hidden iframes, flash, ...).
You can not file upload using jquery ajax post directly. You should you some plug-in for this.
May be you can use this plug-in
This question will show you a start point for using this plug in.
Also, I learned it from #DarinDimitov suggestions, too :)

What is the correct way of posting a form with jquery ajax and MVC3?

I've seen a couple of methods on how to do this. My own method that I like, except from one part, is the following:
Hijack submit-event of form
Collect the data and build a json object
var objToSend = { Property : $('#propertyField').val(), Property2 : ... };
This is the part I don't like since it's tedious to collect 25 values like this
Call $.ajax({}) and specify the url to point to an [HttpPost] enabled action somewhere
in the success: part of the ajax-query, collect the returned data (which I return as a string) and write it out where appropriate. I handle errors here as well, checking to see if the first word is "Error:" and then taking appropriate action.
I like this method apart from the collection stage. I am sure there is a better way of doing this but I'v thrown myself headlong into jquery coming from an ASP.NET WebForms-background so the whole "embrace the web" part is totally foreign to me.
You could use the serialize() method to avoid passing all the fields one by one. It will send the entire form data to the server using application/x-www-form-urlencoded content type as if it was a standard form submission:
$('#myform').submit(function() {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
// TODO: handle the success case
}
});
return false;
});
Another possibility is the jQuery form plugin:
$('#myform').ajaxForm(function(result) {
// TODO: handle the success case
});
Some people find it also useful to use the Ajax.BeginForm helpers to render the form:
#using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "success" }))
{
... some input fields
}
In ASP.NET MVC 3 you need to include the jquery.unobtrusive-ajax.js script which unobtrusively AJAXifies the HTML 5 data-* attributes emitted by the Ajax helper.
Allow jQuery to build your json for you. You can serialize a form which will create a data set for you to submit.
$.post("myUrl",
$("form").serialize(),
function(callback) { ... }
);
That's how I'd do it!
You also have the option of using the MVC helpers to create the post code handling code for you if you're dealing with a form e.g.
<% using (html.BeginForm()) {%>
// html for the form
<input type='submit' value='post' />
<% } %>
The transition from WebForms to MVC can be a tricky one for people has you really are dealing with the raw aspects of web programming i.e. http, html and javascript... BTW I believe this to be a good thing as I'm not a fan of the pseudo single process event model of WebForms.
Long live MVC! :)
I tend to use the "jQuery form plugin". It allows you to cleanly abstract a standard form into an AJAX form with very little effort:
http://jquery.malsup.com/form/
It also allows you to easily trap various events, failure conditions, validations etc and can convert your form to a JSON request or XML if you desire. Handles file uploads too.

How access Jquery TreeView on the server?

How do I access Jquery Treeview inside the .aspx file upon form submit?
also, Can I add nodes to Jquery Treeview on the fly? (on the client side)
I am using asp.net web forms, c#
EDITED:
someone mentioned the following in one of the questions:
"on form submit, someone is going to have to write code on the client to collect that data and send it via Ajax to a server method"
how is this done?????
Well, I think I've found what you want. Take a look here.
In brief, you must define a WebMethod on your server side, and then you can easily access it using jQuery. An exellent working example is under the link above, and here I'll modify it to show how you can pass arguments. So...
In your page code-behind *.cs:
// We'll use this class to communicate
public class Dog
{
public string Name { get; set; }
public string Color { get; set; }
}
// This is your page, in my case Default.aspx
public partial class _Default : System.Web.UI.Page
{
[WebMethod]
public static string ProcessData(Dog myDog)
{
return "Your " + myDog.Color + " dog's name is " + myDog.Name + "!";
}
}
Then on your *.aspx:
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="json2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#btnProcess").click(function() {
// This is what we want to send to the server
var dogItem =
{
Color: $("#txtColor").val(),
Name: $("#txtName").val()
};
// And this is how it should be sent - in serialized way
var dogItemSerialized = JSON.stringify(dogItem);
$.ajax({
type: "POST",
url: "Default.aspx/ProcessData",
data: "{'myDog':" + dogItemSerialized + "}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$("#result").text(msg.d);
}
});
});
});
</script>
Color: <input id="txtColor" type="text" /><br />
Name: <input id="txtName" type="text" /><br />
<input id="btnProcess" type="button" value="Click Me" />
<div id="result"></div>
So here you fill textboxes and then your data is sent to the server which understands it as a Dog object. Pay attention to arguments passing, because this is the most confusing part. You should pass them in JSON format, which is a little bit "too-much-stringy". So I use here json2.js script which helps to convert usual javascript object into JSON-serialized string (JSON.stringify() method). It is available here. But it is still rather ugly =) It is important that I pass argument called "myDog" which value is the serialized dogItem. Because this is exactly what the server expects to get (so, for example, I can't change the argument name, this won't work:
data: "{'someAnotherArgumentName':" + dogItemSerialized + "}"
And the last thing. Pay attention to the following line:
success: function(msg) {
$("#result").text(msg.d);
}
If you are working with ASP.NET prior to 3.5 (for example, ASP.NET 2.0), then you'll need to write just $("#result").text(msg) instead of msg.d. Only ASP.NET 3.5 encapsulates all the data under "d" member for some reason...
Anyway, in the above article you can find useful links (both inside the article and in comments), so you can read more about arguments, "msg.d" and so on.
I hope this helps!
Since jQuery Treeview is a client-side component, you can't access it from the server-side. So in order to pass any data from your tree to the server, you have to write client-side javascript code (actually jQuery code). The same thing regarding adding nodes to the treeview on the fly: only using client-side jQuery code. Remember that your C# on the server-side has no idea about your TreeView.
The integration between jQuery and ASP.NET WebForms is rather problematic and "not so natural", because ASP.NET is built on different concept... So if you are working with ASP.NET WebForms, I would suggest you to use server-side components instead (it can be Microsoft's own ASP:TreeView or other 3rd-party WebForms-aimed components). Alternatively, you can try the new ASP.NET MVC Framework - it is built on more common (for other web-development platforms) concept, and the integration between it and jQuery is straightforward (actually jQuery is even shipped with it).
Don't get me wrong... I am not saying that the integration between jQuery and ASP.NET WebForms is totally impossible. It is possible. But you'll need to do "not-so-beautiful" things and work hard for every simple operation. If you still want to use jQuery, then use it only for the client-side animations...
UPDATE: As for this quote - "on form submit, someone is going to have to write code on the client to collect that data and send it via Ajax to a server method" - well, this is exactly what I am talking about. On the client-side you call javascript method when submitting the form (for example, by setting onclick='mymethod();' on your "Submit" button). This code does what it needs to do and then... it is supposed to perform AJAX call using jQuery nice syntax. But this won't work with ASP.NET WebForms, as I've explained before. Well, you can read about Microsoft AJAX Client-side library (here: http://msdn.microsoft.com/en-us/magazine/cc163300.aspx), perhaps this will help. But I still think that this integration won't be easy and straightforward. Use jQuery for the animation and ASP.NET server-side components for all other things!

Categories

Resources