I'm trying to upload image via AJAX in ASP.NET Webform. It's going good, accept that when I pass the form data, I can't seem to get access to my session values.
This is what I tried.
ASPX (snippet)
<asp:FileUpload runat="server" ID="profileImageFU" CssClass="profile-image-fu"/>
<input type="button" id="profileImageSaveBtn" class="profile-image-save-btn" />
<progress></progress>
JS
$(document).ready(function () {
var file, name, size, type;
$('.profile-image-fu').change(function () {
file = this.files[0];
name = file.name;
size = file.size;
type = file.type;
});
$('.profile-image-save-btn').click(function (e) {
e.preventDefault();
var fileInput = $('.profile-image-fu')[0];
var fileData = $(fileInput).prop("files")[0]; // Getting the properties of file from file field
var formData = new window.FormData(); // Creating object of FormData class
formData.append("file", fileData); // Appending parameter named file with properties of file_field to form_data
$.ajax({
url: 'ImageUploaderHandler.ashx',
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
alert('success!');
},
error: function (errorData) {
alert('error!');
}
});
});
});
ImageUploaderHandler.ashx (snippet)
public void ProcessRequest (HttpContext context) {
string result = (new UserWS()).setProfileImage(context);
}
UserWS (snippet)
[WebMethod(EnableSession = true)]
public string setProfileImage(object context)
{
....
// Get the uploaded image from the Files collection (WORKS GREAT, I put a break point here and I see postedFile contains all the details I need)
HttpPostedFile postedFile = HttpContext.Current.Request.Files[0];
if (HttpContext.Current.Session["User"] != null) {
// PROBLEM: I need to do my code here, but my Session["User"] is null, even though it's not.
// EDIT: My HttpContext.Current.Session = null
}
}
I have used [WebMethod(EnableSession = true)] in other web services and it works fine. I guess the error is caused because I am passing form data from AJAX here.
this might be a backward approach but maybe cookies are required in the service? just a thought from this article (near the end).
Related
I'm a little lost on what should I do. I'm trying to upload a file along with its form data in one click, but I can't get the file. I tried to check the file in client and it's okay, but when receiving the file in the Controller, it's empty.
Problem
How do I upload the file along its formData using jQuery?
View
Assuming the other fields
<form id="_RegisterProduct" enctype="multipart/form-data">
<div>
<label>Product Description</label>
<textarea id="product_description" name="_product_description"></textarea>
<input type="file"
id="product_file"
name="product_file"
class="dropify" />
</div>
<button type="submit" id="snippet_new_save">Register Product</button>
</form>
<script>
$(function() {
rules: {
text: { required: true, minlength: 5 },
number: { required: true, minlength: 1 }
},
submitHandler: function (form) {
var fileUpload = $("#product_file").val();
var formData = $("#_RegisterForm").serialize();
var url = "#Url.Action("RegisterProduct", "Product")";
$.get(url, { fileUpload: fileUpload, formData }, function (e) {
if (e >= 1) {
console.log("success");
} else {
console.log("error");
}
});
}
})
</script>
Controller
public string RegisterProduct(HttpPostedFileBase fileUpload, AB_ProductModel formData)
{
var data = "";
using (var con = new SqlConnection(Conn.MyConn()))
{
var path = Server.MapPath("~/Content/uploads/products");
var Extension = "";
var fileName = "";
try
{
if(fileUpload.ContentLength > 0)
{
Extension = Path.GetExtension(fileUpload.FileName);
fileName = Path.GetFileName(fileUpload.FileName);
var com = new SqlCommand("dbo.sp_some_stored_procedure_for_saving_data",
con);
con.Open
data = Convert.ToString(com.ExecuteScalar());
var file_path = Path.Combine(path, data + Extension);
fileUpload.SaveAs(file_path);
}
}
catch (Exception ex)
{
data = ex.Message;
}
// data returns id if success or error message
}
return data;
}
Why serialize the form? This method creates a string that can be sent over to the server, but that is not what you want to do... In case of a file upload; see .serialize() function description here.
FormData type automatically manages the enctype for your forms (see here on MDN), so you can omit that—although you should consider using it, because it helps other members on the team understand the intent. If you want to use plain jQuery, you can simply attach the formData variable to the data field of the $.ajax call. See like here,
/*
* i know id-based selection should only have 1 element,
* otherwise HTML is invalid for containing multiple elements
* with the same id, but this is the exact code i used back then, so using it again.
**/
var formData = new FormData($('#form')[0]);
$.ajax({
type: 'POST',
processData: false,
contentType: false,
data: formData,
success: function (data) {
// The file was uploaded successfully...
$('.result').text('File was uploaded.');
},
error: function (data) {
// there was an error.
$('.result').text('Whoops! There was an error in the request.');
}
});
This of course requires that your HTML DOM contains these elements—I used the code I wrote for my article quite a few years back. Secondly, for my other part of the feature, I used Request.Files to capture the files that might have been uploaded with the request.
files = Request.Files.Count;
if(files > 0) {
// Files are sent!
for (int i = 0; i < files; i++) {
var file = Request.Files[i];
// Got the image...
string fileName = Path.GetFileName(file.FileName);
// Save the file...
file.SaveAs(Server.MapPath("~/" + fileName));
}
}
This way, I uploaded the files using jQuery and FormData.
You can check out the complete article I posted here, Uploading the files — HTML5 and jQuery Way!
Oh, and do not forget the suggestion made in the comment,
using (var com = new SqlCommand("dbo.sp_some_stored_procedure_for_saving_data", con))
{
con.Open(); // missed call?
data = Convert.ToString(com.ExecuteScalar());
// although, using should close here!
var file_path = Path.Combine(path, data + Extension);
fileUpload.SaveAs(file_path);
}
So, this was pretty much how you can do this.
Trying to find a resource that could point me in the right direction for downloading a file with this particular stack. It's more challenging than it seems, especially since I'm unable to use Razor in accordance with house rules.
The code execution can get from the markup, to the knockout, and then the C#, but it doesn't start a download like I would expect in ordinary webforms non-MVC ASP.NET.
mark up:
<div class="row">
<div class="col-2"><img data-bind="attr: {src: image}, click: $root.downloadFile/></div>
the knockout/javascript call:
self.downloadFile = function(e){
if(e) {
attachmentId = e.id;
helpers.ajax.getJson(root, "/Files/DownloadFile/", {fileId: attachmentId }, function(x){
attachmentId=0;
getFiles();
});
}
...
related javascript functions called here:
helpers.ajax.getJson = function(path, url, data, onSuccess, onError){
helpers.ajax.async('GET', path, url, {
data: data,
cache: false,
async: true,
error: onError,
success: onSuccess
});
};
function getFiles(){
self.files([]);
helpers.ajax.getJson(root, "/Files/GetFiles",
{ profileId: self.ProfileId() },
function (files) {
if(files) {
$.each(files, function (i, v) {
self.files().push(new file(v.AttachmentId, v.FileTypeDescr, v.FileExtension, v.FileName, v.UploadedBy, v.UploadDate, v.CompletionDate));
self.files.valuehasMutated();
});
}
});
}
C#
public FileResult DownloadFile(int fileId)
{
ODSAPI.AttachmentFile file = FileFunctions.GetById(fileId);
if(file != null)
{
return File(file.FileData, file.ContentType);
}
return null;
}
this returns the correct file information and the bits from the database when I step through the code and view the file variable.
you could use http://danml.com/download.html to download file from javascript AJAX return
for exmaple
download(data, 'Export.csv', 'application/csv');
where data will be return from your ajax request and file name and file type.
The JSON call in the Javascript was incorrect as it called for a JSON object. Rather, it should have been:
window.open(root + "/Files/DownloadFile?fileId=" + attId, '_blank');
instead of helpers.ajax.getJson()
I have a file that I'm submitting using ajax, but in the server I'm not receiving anything.
let file = document.getElementById('file').files[0];
I don't do a ajax call.
axios.post('http://localhost:5000/File/Create', file)
In my .Net Core I'm expecting this.
[HttpPost]
public IActionResult Create([FromBody] IFormFile file)
{
return Ok();
}
This is not working. I'm wordering in my data type is wrong.
Unfortunately, your problem is described briefly but assuming everything else has been configured properly on your client and service,
I believe your main problem here is that your sent data missing key: 'file' which results in file being received as null. So, this must work:
axios.post
(
'http://localhost:5000/File/Create',
{
file: file
}
)
Hope this helps.
I am not sure how axios handle the upload. But generally you need to send the FormData which has the file. When using jQuery ajax to send this form data, you need to make sure that you set the processData and contentType flags to false
Something like this would work
$("#saveBtn").click(function(e) {
e.preventDefault();
var fdata = new FormData();
var fileInput = $('#logo')[0];
var file = fileInput.files[0];
fdata.append("logo", file);
$.ajax({
type: 'post',
url: "#Url.Action("Create", "File")",
data: fdata,
processData: false,
contentType: false
}).done(function(result) {
// do something with the result now
console.log(result);
});
});
Assuming you have a Create action method in FileController which takes the file and save it to your some directory in your app root.
public class FileController : Controller
{
private readonly IHostingEnvironment hostingEnvironment;
public FileController(IHostingEnvironment environment)
{
hostingEnvironment = environment;
}
[HttpPost]
public IActionResult SaveFile(IFormFile logo)
{
if (logo != null)
{
//simply saving to "uploads" directory
var uploads = Path.Combine(hostingEnvironment.WebRootPath, "uploads");
var filePath = Path.Combine(uploads, logo.FileName);
logo.CopyTo(new FileStream(filePath, FileMode.Create));
return Json(new { status = "success" });
}
return Json(new { status = "error" });
}
}
Here's my ajax call:
$(function () {
$("#chkFilter").on("click", "input", function (e)
{
var filterCheckboxes = new Array();
$("#chkFilter").find("input:checked").each(function () {
//console.log($(this).val()); //works fine
filterCheckboxes.push($(this).prop("name") + "=" + $(this).val());
console.log($(this).prop("name") + "=" + $(this).val());
//var filterCheckboxes = new Array();
//for (var i = 0; i < e.length; i++) {
// if (e[i].checked)
// filterCheckboxes.push(e[i].value);
//}
});
console.log("calling ajax");
$.ajax({
url: "/tools/oppy/Default",
type: "POST",
dataType: "json",
data: { filterValues: filterCheckboxes }, // using the parameter name
success: function (result) {
if (result.success) {
}
else {
}
}
});
});
});
And my server side code:
public partial class tools_oppy_Default : System.Web.UI.Page
{
...
protected void Page_Load(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
string checkedBoxes = Request["filterValues"];
testLabel.Text = checkedBoxes;
}
I'm just trying to obtain the post URL with the appropriate checked values so I can parse it on the server. However, I'm having trouble obtaining the URL. The string checkedBoxes is supposed to hold a query string like name=value&name=value&name.... but when I test it, the testLabel doesn't show anything. I'm using web forms app, not MVC. Also, I'm new to ajax and their behavior. Thanks.
First, I assume that the url in you JQuery call is valid as there is not aspx extension their.
Second, It looks like what you need to do is create a web method and call it from JQuery for example the following is a web method that accept string
[WebMethod]
public static string GetData(String input)
{
return DateTime.Now.ToString();
}
and you can call it using the same way with your current code just update the url parameter to include the method name
url: "PageName.aspx/MethodName",
for more details about web methods and their union with JQuery please check this article
Edited The following is complete sample
The web method should look like the following one
[WebMethod]
public static string GetData(string filterValues)
{
return filterValues; //This should be updated to return whatever value you need
}
The client side part of calling the web method should look like the following
$.ajax({
url: "/Default/GetData",
type: "POST",
contentType: "application/json; charset=utf-8", //I have added this as "contentType" parameter represents the type of data inside the request meanwhile the "data" parameter describes the data inside the response
data: "{ filterValues:\"" + filterCheckboxes + "\"}", //Note that I have updated the string here also set the name of the parameter similar to the input of the webmethod
dataType: "json",
success: function (result) {
alert(result.d);//You should access the data using the ".d"
}
});
One last thing, If you are using asp.net permanent routing the above code will not work and you should disable it by updating the file "App_Code/RouteConfig.cs" From
settings.AutoRedirectMode = RedirectMode.Permanent;
To
settings.AutoRedirectMode = RedirectMode.Off;
And remember to clear browser cache after the above update
Using the helpful information I found here:
How can I upload files asynchronously?
I was able to get form data to the server-side with the following jQuery (very slightly modified from the link above):
$('#addFileInput').change(function () {
var file = this.files[0];
name = file.name;
size = file.size;
type = file.type;
//Your validation
});
$('.submitFile').click(function () {
var formData = new FormData($("#fileUploadForm"));
$.ajax({
url: '/AJAX Pages/Compute_File_Upload.cshtml', //Server script to process data
type: 'POST',
xhr: function () { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { // Check if upload property exists
myXhr.upload.addEventListener('progress', progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
//Ajax events
beforeSend: function () {
$("#progressBar").css("visibility", "visible");
},
success: function (response) {
$(".editLabelTitle").text(response);
},
//error: errorHandler,
// Form data
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false
});
});
function progressHandlingFunction(e) {
if (e.lengthComputable) {
$('progress').attr({ value: e.loaded, max: e.total });
}
}
Here's the HTML that is involved:
<div class=\"addFileBox\">
<div class=\"editPageSubTitle dragHandle\">
Add File
<button id=\"closeAddFileBox\">X</button>
</div>
<div class=\"innerAddFileDiv\">
<form id=\"fileUploadForm\" enctype=\"multipart/form-data\">
<input id=\"addFileInput\" name=\"addFileInput\" type=\"file\" />
</form>
<br/>
<progress id=\"progressBar\"></progress>
<br/>
<button class=\"submitFile\">Submit File</button>
</div>
</div>
The Ajax request in and of itself works fine. The problem comes when I don't know how to get the file on the server-side code (normally I would just find the input with the Request.Files["someFileId"]) but as all formData is sent, this isn't working the way I am familiar with.
C# CODEBEHIND
#{
Layout = "";
if(IsAjax)
{
var file = Request.Files["addFileInput"];
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/CMS Files/UtilityBilling"), fileName);
file.SaveAs(path);
}
}
What is the proper way to access the given file, considering my scenario and environment?
Try this from codebehind:
HttpFileCollection filesCollection = HttpContext.Current.Request.Files;
var fileName = filesCollection[0];
string filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/SaveDir"), fileName.FileName);
fileName.SaveAs(filePath);