How to upload files in asp.net 3.1 MVC with AJAX - ajax

I'm new to asp.netcore 3.1, and now I'm learning how to upload file using AJAX in MVC, so I have tried the code that I got and here the code
in view cs.html `Upload one or more files using this form:
</p>
<input type="file" name="files" multiple />
</div></div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Upload" />
</div></div>
</form>`
In my controller:
[HttpPost("FileUpload")]
public async Task<IActionResult> Index(List<IFormFile> files) {
long size = files.Sum(f => f.Length);
var basePath = Path.Combine(Directory.GetCurrentDirectory() + "\\Files\\");
var filePaths = new List<string>();
foreach (var formFile in files) {
if (formFile.Length > 0) {
// full path to file in temp location
var filePath = Path.Combine(basePath, formFile.FileName);
filePaths.Add(filePath);
using (var stream = new FileStream(filePath, FileMode.Create)) {
await formFile.CopyToAsync(stream);
}
}
}
// process uploaded files
// Don't rely on or trust the FileName property without validation.
return Ok(new { count = files.Count, size, filePaths });
}
I tried to change this:
asp-controller="FileUpload" asp-action="Index">
The code above was made so that the action directly goes to the directed controller, but I want to change so it would pass the file to AJAX first.

Related

How to create subfolder based on user name in .NET Core on image upload?

I am trying to create a sub folder inside an already created folder every time an user registers so that every video/image a user whats to upload to go in the folder of that specific user.My problem is that i can't get it to work for some reason.I have an auto generated controller that adds the user and a method that uploads an image to the server.
[HttpPost]
public async Task<ActionResult<User>> PostUser(User user)
{
_context.User.Add(user);
if (string.IsNullOrWhiteSpace(_env.WebRootPath))
{
_env.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
if(user!=null)
{
var users = Path.Combine(_env.WebRootPath,"uploads",user.Name);
Directory.CreateDirectory(users);
}
await _context.SaveChangesAsync();
return CreatedAtAction("GetUser", new { id = user.IdUser }, user);
}
Here i try to create a sub folder inside "uploads" folder as the other is already created when the user uploads an image for the first time.The problem is that no matter what I do,it doesn't get created.On top of that I would like to save the image directly to the user folder.For now i can save it only in "uploads" folder.This is my method for the image upload:
[HttpPost]
public async Task PostImage(IFormFile file)
{
if (string.IsNullOrWhiteSpace(_env.WebRootPath))
{
_env.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
var uploads = Path.Combine(_env.WebRootPath, "uploads");
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
I have also tried to declare a User property inside the PostImage() method but the user is null in the moment I post the image as the registration is made at the same time with the image upload so automatically it will not work.I also tried to play around with the client side and check if the user has been saved and then to proceed with uploading the file,but without any luck.Can someone please point me into the right direction?
Obviously, when PostImage stores images, your path only reaches uploads folder, not subfolders, so the images will only be stored under the uploads folder.
If you want to store the images in the corresponding uploads/username folder, you also need to obtain the user information corresponding to the current uploaded image.
As you said, this is a registration page, so the user's information and images can be passed to the action at the same time. You don't need to use the two post methods, just merge them.
View:
#model User
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<form method="post" asp-action="PostUserAndImage" enctype="multipart/form-data">
<input id="Text1" type="text" asp-for="IdUser" />
<input id="Text1" type="text" asp-for="Name" />
<input id="File1" type="file" name="file" />
<input id="Submit1" type="submit" value="submit" />
</form>
Action:
[HttpPost]
public async Task<ActionResult<User>> PostUserAndImage(User user, IFormFile file)
{
if (string.IsNullOrWhiteSpace(_env.WebRootPath))
{
_env.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
if (user != null)
{
_context.User.Add(user);
var users = Path.Combine(_env.WebRootPath, "uploads", user.Name);
if (!Directory.Exists(users)) Directory.CreateDirectory(users);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(users, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
await _context.SaveChangesAsync();
}
return CreatedAtAction("GetUser", new { id = user.IdUser }, user);
}
Here is the test result:

MVC 4 Razor using Ajax forms to update a foreach loop

Where to start...I can find similar things on the Internet as to how, but they never seem to work with my specific way of wanting to do something. I have tried with and without partial views with very little success.
Quick rundown: I have a strongly-typed View with an Ajax form. underneath the form, I have a foreach loop that repeats a code block. I need to be able to update the code block from the forms choices (filters).
Here's my View, 'FindATeacher.cshtml', as it currently stands (after trying many different ideas):
#model Teachers.Models.OmniModel
#{
ViewBag.Title = "FindATeacher";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Find a Teacher</h2>
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions { HttpMethod = "Post", OnSuccess = "onSuccess" }))
{
<div id="ContentFilter">
<div class="filterLabels">
<p>Search by Name</p>
<p>Filter By Instrument</p>
<p>Filter By City</p>
</div>
<div class="filterObjects">
<p>
<input type="text" id="nameTXT" />
<button type="submit" id="findButton">find</button>
</p>
<p>#Html.DropDownList("InstrumentID", (SelectList)Model.Instruments, "-- Select an Instrument --", new { id = "instrumentDD" })</p>
<p>#Html.DropDownList("CityID", (SelectList)Model.Cities, "-- Select a City --", new { id = "cityDD" })</p>
</div>
</div>
}
<hr />
#foreach (var r in Model.Teachers)
{
<div id="ContentResults">
<div id="avatar">
<img src="i" />
</div>
<div id="demographics">
<h6>#r.Teacher</h6>
<strong>#r.StudioName</strong>
<p>#r.URL</p>
<p>#r.StreetAddress</p>
<p>#r.City, #r.AddressStateID #r.Zip</p>
<p>#r.Phone</p>
<p>#r.EmailAddress</p>
</div>
<div id="studioDetails">
<p><strong>Instrument(s) Taught</strong></p>
<p>
#{
var instrumentString = r.Instruments.Aggregate("", (a, b) => a + b.Instrument + ", ");
if (instrumentString.Length != 0)
{
instrumentString = instrumentString.Remove(instrumentString.LastIndexOf(","));
}
}
#instrumentString
</p>
<br />
#if (r.Information != "" && r.Information != null)
{
<p><strong>Information</strong></p>
<p>#r.Information</p>
}
</div>
</div>
}
Now here's my Controller. I get the results back correctly in the Controller, just not updating the code block:
public ActionResult FindATeacher()
{
Model.Instruments = new SelectList(TeacherService.GetInstrumentList(0),"InstrumentID","Instrument");
Model.Cities = new SelectList(TeacherService.GetCityList(),"CityID","City");
Model.Teachers = TeacherService.GetTeacherList("", 0);
return View(Model);
}
[HttpPost]
public JsonResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList("John", 0, 0);
return Json(Model.Teachers);
}
Thanks.
#VishalVaishya presents the right idea, but there's a simpler way, which doesn't involve custom javascript code: AjaxOptions has an UpdateTargetId property that the AJAX toolkit will interpret to mean you want the given target to be updated with the results sent back from the controller.
FindATeacher.cshtml:
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions {
HttpMethod = "Post", UpdateTargetId = "TeacherList" }))
{
...
}
<hr />
<div id="TeacherList">
#Partial("TeacherList", Model.Teachers)
</div>
TeacherList.cshtml
#model IEnumerable<Teacher>
#foreach(var teacher in Model)
{
...
}
Controller action:
[HttpPost]
public ActionResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList(teacherName, instrumentID, cityID);
return PartialView("TeacherList", Model.Teachers);
}
You can try following method:
Separate your foreach loop into another partial view.
And load your partial view on filter / click event and pass filtered parameters to your controller-action.
JS change event code will be something like this:
var teacherName = ''; //get your selected teachername
var instrumentID = ''; //get your selected instrumentid
var cityID = ''; //get your selected city id
var url = '#Url.Action("FilterTeachers", "ControllerName", new { teacherName = "teacher-Name", instrumentID="instrument-ID", cityID="city-ID" })';
url = url.replace("teacher-Name", teacherName).replace("instrument-ID", instrumentID).replace("city-ID", cityID);
$('#result').load(url);

JQuery Load using MVC3 #Url.Action does not pass parameters properly

I noticed that doing #Url.Action("myAction", new { param1 = 123, param2 = 456}) provides me with an invalid URL Home/myAction?param1=123&param2=456.
I am attempting to do
$("#myAjaxDiv").load(url);
But only param1 is getting populated in the action method.
When I remove the & and make it just & then it works, but doing a string replace is super hacky.
url = url.replace("&", "&");
Am I missing something here?
EDIT: Per request I'm including some of my sample app. (you can create a new MVC app and just add these quickly and see for yourself)
Controller:
public ActionResult AjaxTest(int? year, int? month)
{
ViewBag.Message = string.Format("Year: {0}, Month: {1}", year.HasValue ? year.ToString() : "no year", month.HasValue ? month.ToString() : "no month");
return PartialView("AjaxTest");
}
AjaxTest View:
#ViewBag.Message
Index View:
<script>
$(function () {
var url="";
$("#noParams").click(function () {
url = "Home/AjaxTest";
$("#ajaxy").load(url)
$("#url").text(url);
});
$("#yearParam").click(function () {
url = "Home/AjaxTest?year=2012";
$("#ajaxy").load(url)
$("#url").text(url);
});
$("#yearAndMonthParam").click(function () {
url = "Home/AjaxTest?year=2012&month=10";
$("#ajaxy").load(url)
$("#url").text(url);
});
$("#generated").click(function () {
url = "#(Url.Action("AjaxTest", new { year=2012, month=10}))";
$("#ajaxy").load(url);
$("#url").text(url);
});
});
</script>
<a id="noParams" href="#">No Params</a> <br />
<a id="yearParam" href="#">Year Param</a> <br />
<a id="yearAndMonthParam" href="#">Year and Month Param</a> <br />
<a id="generated" href="#">Generated</a> <br />
<div id="ajaxy">
</div>
<div>
URL: <span id="url"></span>
</div>
By default every content (which is not IHtmlString) emitted using a # block is automatically HTML encoded by Razor (see this Razor intro article Html Encoding section)
The Url.Action returns just a plain string so thats why the & gets encoded.
Use the Html.Raw if you don't want the encodeing:
url = "#(Html.Raw(Url.Action("AjaxTest", new { year=2012, month=10})))";
You can build the url in this way also.
var url = "#Url.Action("AjaxTest","YourControllerName")?year=2012&month=10";
$("#ajaxy").load(url);

Ajax form submission with Valums plugins in asp.net mvc 3

I have used Valums uploader plugins for file uploads in asp.net mvc 3. Following is the views which have form fields and ajax query upload button inside form. I am not sure that I am doing it right or not. What I have to change on view so that When I Choose the file to upload the form field's value is also send.
Views:
<link href="#Url.Content("~/Content/css/fileuploader.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Content/js/fileuploader.js")" type="text/javascript"></script>
#using (Html.BeginForm("Upload","AjaxUpload")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Upload Image File</legend>
<div class="editor-label">
#Html.Label("Select Language")
</div>
<div>
#Html.DropDownList("Language1", (SelectList) ViewBag.lang)
</div>
<div class="editor-label">
#Html.Label("Select Category")
</div>
<div>
#Html.DropDownList("ParentCategoryID", ViewBag.ParentCategoryID as SelectList)
</div>
<div id="file-uploader">
<noscript>
<p>
Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
</fieldset>
}
**<script type="text/javascript">
var uploader = new qq.FileUploader
({
element: document.getElementById('file-uploader'),
action: '#Url.Action("upload")', // put here a path to your page to handle uploading
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // user this if you want to upload only pictures
sizeLimit: 4000000, // max size, about 4MB
minSizeLimit: 0 // min size
});
</script>**
How Can I passed the value of form to controller of HTTPOST Action So that I can save data to the database. Here, I have Upload action which save the data in database but I don't know to retrieve to those value send by form post.
HttpPost Action
[HttpPost]
public ActionResult Upload(HttpPostedFileBase qqfile)
{
var wav = new PlayWav
{
Name = ***filename***,
CategoryID = ***value from category dropdown select list***,
UserID = repository.GetUserID(HttpContext.User.Identity.Name),
LanguageID = int.Parse(***value from language dropdown select list***),
UploadDateTime = DateTime.Now,
ActiveDateTime = DateTime.Now,
FilePath = "n/a"
};
if (qqfile != null)
{
// this works for IE
var filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(qqfile.FileName));
qqfile.SaveAs(filename);
return Json(new { success = true }, "text/html");
}
else
{
// this works for Firefox, Chrome
var filename = Request["qqfile"];
if (!string.IsNullOrEmpty(filename))
{
filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(filename));
using (var output = System.IO.File.Create(filename))
{
Request.InputStream.CopyTo(output);
}
**db.PlayWavs.Attach(wav);
db.SaveChanges();**
return Json(new { success = true });
}
}
return Json(new { success = false });
}
Didn't you read the documentation? There's a whole section entitled Sending additional params. Even an example is given:
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/server-side.upload',
// additional data to send, name-value pairs
params: {
param1: 'value1',
param2: 'value2'
}
});

Trouble uploading file ASP.NET MVC3. XML file to Model

I'm attempting to upload an xml file to my site. However, regardless of which file I attempt to upload, the HttpPostedFileBase element in my code is null. I don't understand why this is. I've followed all the examples I can find on uploading files and it doesn't seem to make any sense. This is the controller method
[HttpPost]
public ActionResult UploadFile(HttpPostedFileBase xmlFile)
{
if (xmlFile != null && xmlFile.ContentLength > 0)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFile.InputStream);
// other logic later
return RedirectToAction("Index");
}
return RedirectToAction("UploadFailed");
}
and the cshtml:
#{
ViewBag.Title = "Upload";
}
#using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" value="OK" />
}
It has a wrong name. The action argument is called xmlFile whereas your file input is called file. You need to be consistent in your naming conventions:
<input type="file" name="xmlFile" />
I also invite you to checkout Phil Haack's blog post on this subject.

Resources