Upload multiple files in ASP.NET Core MVC - c#

I want to upload multiple files in ASP.NET Core MVC. However, it may not select all files at once. After selecting a file, it can open it again after File Dialog and load it in another file. In addition, the names of the uploaded files should be displayed on the screen. Files and entries uploaded to the form should be saved when the form is submitted.
Can anyone help with related JS and C# code?
I tried the input file, but multiple files are only uploaded once

I suggest you try jQuery FilePond.
Below is a work demo, you can refer to it.
Product:
public class Product
{
public string Name { get; set; }
public IList<IFormFile> photos { get; set; }
}
filepond2Controller:
public class filepond2Controller : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Product product, IFormFile[] photos)
{
return View();
}
}
Index view:
#model Product
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://unpkg.com/filepond/dist/filepond.min.js"></script>
<script src="https://unpkg.com/jquery-filepond/filepond.jquery.js"></script>
<link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet"/>
<script src="https://unpkg.com/filepond/dist/filepond.js"></script>
<form id="uploadform" enctype="multipart/form-data">
<input type="text" asp-for="Name" />
<input type="file" class="filepond"asp-for="photos">
<button type="submit" class="uploadbtn">Upload Document</button>
</form>
<script>
$(document).ready(function(e){
pond = FilePond.create(
document.querySelector('.filepond'), {
allowMultiple: true,
instantUpload: false,
allowProcess: false
});
$("#uploadform").submit(function (e) {
e.preventDefault();
var formdata = new FormData(this);
// append FilePond files into the form data
pondFiles = pond.getFiles();
for (var i = 0; i < pondFiles.length; i++) {
// append the blob file
formdata.append('photos', pondFiles[i].file);
}
$.ajax({
url: "/filepond2/Index",
data: formdata,
processData: false,
contentType: false,
method:"post"
});
})
});
</script>
result:

Related

How to pass a AJAX Response(true/false) from Controller using ASP .NET CORE

I want to retrieve the response from my ASP.NET Core Controller through AJAX. Here's the example of my code
public IActionResult Submit(ViewModel model) {
var isValid = true;
if (isValid) {
return Json(new {
success = true
});
}
return Json(new {
success = false
});
}
CSHTML part
<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
<input type="text" id="Name" name="Name">
<input type="text" id="Address" name="Address">
<input type="text" id="JobDescription" name="JobDescription">
</form>
$("#formSubmit").on('submit', function(e) {
var datas = {
Name: $("input[name='Name']").val(),
Address: $("input[name='Address']").val(),
JobDescription: $("input[name='JobDescription']").val()
};
var formAction = $(this).attr("action");
$.ajax({
method: "POST",
url: formAction,
data: JSON.stringify(datas),
dataType: "json",
contentType: 'application/json',
success: function(response) {
if (response.success) {
alert("Test");
return true;
} else {
alert("Invalid/Error");
e.preventDefault();
}
});
});
The problem in this code it redirect/loading to page showing the {"success":false}.
My ViewModel
public class ViewModel{
public string Name { get; set; }
public string Address { get; set; }
public string JobDescription { get; set; }
}
it seems there are a few issues present here
<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
You are specifying asp-action and asp-controller. Omit all of these properties. Start with just:
<form>...</form>
The reason being, when you set those attributes it uses the old-school form submission mechanism which redirects (one of the side affects you listed).
Also the name type seems to be a mismatch, you use ViewModel but in your example the type name is TFAViewModel
Try the following, above your controller (for each method) or above the method itself add
[Consumes("application/json")]
[Produces("application/json")]
public IActionResult Submit([FromBody]ViewModel model)
{
ModelState.IsValid; //use to inspect. You will also see any violations
....
}
In your JS code ensure to do the following (as has been commented)
e.preventDefault(); //stops redirect
Have you use [HttpPost] attribute on the Submit action? You need to set a specific url like "/Home/Submit" and have a reference to jquery.
Action:
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
public IActionResult Submit(ViewModel model)
{
var isValid = true;
if (isValid)
{
return Json(new
{
success = true
});
}
return Json(new
{
success = false
});
}
View:
<form id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
<input type="text" id="Name" name="Name">
<input type="text" id="Address" name="Address">
<input type="text" id="JobDescription" name="JobDescription">
<input type="submit" value="Create" class="btn btn-default" />
</form>
#section Scripts{
<script src="~/lib/jquery/dist/jquery.js"></script>
<script>
$("#formSubmit").on('submit', function (e) {
var datas = {
Name: $("input[name='Name']").val(),
Address: $("input[name='Address']").val(),
JobDescription: $("input[name='JobDescription']").val()
};
e.preventDefault();
//var formAction = $(this).attr("action");
$.ajax({
method: "POST",
url: "/Home/Submit",
data: JSON.stringify(datas),
dataType: "json",
contentType: 'application/json',
success: function (response) {
if (response.success) {
alert("Test");
return true;
} else {
alert("Invalid/Error");
// e.preventDefault();
}
}
});
});
</script>
}

AJAX does not get triggered, asp.net

Now it only get the AuctionId value in to the controller the other props are either null or 0...
Here is the form:
<form id="createBid">
<div id="frmBid" class="form-inline">
<input name="Bidder" asp-for="#bidModel.Bidder" value="#User.Identity.Name" type="hidden" />
<input name="AuctionId" asp-for="#bidModel.AuctionId" value="#Model.AuctionId" type="hidden" id="auctionId" />
<label asp-for="#bidModel.Amount" />
<input name="Amount" asp-for="#bidModel.Amount" />
<button type="submit" id="submitBtn" class="btn btn-primary">Lägg</button>
</div>
</form>
Here is the action in the controller:
public async Task<IActionResult> AddBid(BidModel Bid)
{
var result = await _bidBusinessInterface.CreateBidAsync(Bid, Bid.AuctionId);
if (result)
{
ViewBag.Message = "Bud lagt!";
}
else
{
ViewBag.Message = "Bud förlågt!";
}
return RedirectToAction("ViewDetails");
}
And then we have the actual AJAX call:
$('#createBid').on('submit', function (e)
{
e.preventDefault();
var $form = $(this);
$.ajax({
url: '#Url.Action("AddBid")',
type: 'POST',
dataType: 'html',
data: $form.serialize(),
success: function (html)
{
$('#frmBid').html(html);
}
});
});
I'm posting the model here aswell, if it is needed to see where it goes wrong:
public class BidModel
{
[JsonProperty("BudID")]
public string BidId { get; set; }
[JsonProperty("Summa")]
public int Amount { get; set; }
[JsonProperty("AuktionID")]
public string AuctionId { get; set; }
[JsonProperty("Budgivare")]
public string Bidder { get; set; }
}
I'm very grateful for every answer! This has been bugging me for 2 hours..
You are using your asp helpers wrong.
let's take this sample of code:
<input name="Bidder" asp-for="#bidModel.Bidder" value="#User.Identity.Name" type="hidden" />
you set the name to "Bidder" this is what the data will be bound to, when you need "Bid.Bidder" since "Bid" is the name of the object that the action receives.
Now you DO NOT need to set the name attribute since asp-for helper does it for you, it will automatically generate name, id attributes for you.
now make sure at the top of you page you have #model YourNamespace.BidModel
and reference it like so:
<input asp-for="#Model.Bidder" value="#User.Identity.Name" type="hidden" />
the attributes will be generated automatically and the model should be bound correctly.

How to pass the model items between MVC Actions

I want create a Master/Detail page that shows properties of the model as well items of properties of the same model that are collections. The page itself should only have one save button, that stores the values in a database. I also want to allow the the user to make changes to the collection properties, that are shown on the page without saving them into the database. The following code shows the setup for the picture collection, but I also want to do this for a "Child-table/grid" i.e. collection of "pocos". Is there a way to do this in MVC?
To my understanding, I would have to keep the instance of the object and pass it between the HTMLActions, as this instance holds all the changes.
Just some pointers in the right direction would be nice or, if the case, pointing out, that MVC should not be used for this...
The model:
public class MasterModel : ModelBase
{
public MasterModel()
{
}
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private ListBase<PicModel> pics;
public ListBase<PicModel> Pics
{
get { return pics; }
set { pics = value; }
}
}
Controller:
public ActionResult Edit(int id)
{
if (id <= 0 )
{
return RedirectToAction("Index");
}
m = new MasterModel (id);
return View(m);
}
[HttpPost]
public ActionResult NewPic(int id, HttpPostedFileBase uploadFile)
{
PicModel p = new PicModel();
MemoryStream ms = new MemoryStream();
uploadFile.InputStream.CopyTo(ms);
b.Picture= ms.ToArray();
m.Pics.Add(b); //Here it fails, as the MasterModel m is a different one then when the ActionResult Edit is called
}
View:
#model app1.Models.MasterModel
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/index.js")" type="text/javascript"></script>
<script>
$("#PicForm").on("submit", function (e) {
e.preventDefault();
var form = $(this);
var formData = new FormData(form.get(0));
$.ajax({
url: form.attr("action"),
method: form.attr("method"),
data: formData,
processData: false,
contentType: false
})
});
</script>
<div class="col-md-4 col-lg-4">
#using (Html.BeginForm("NewPic", "MasterModel ", FormMethod.Post, new { id = "PicForm", enctype = "multipart/form-data" }))
{
#Html.HiddenFor(model => model.Id)
<div class="container-fluid">
#foreach (app1.Models.PicModel b in Model.Pics)
{
var base64 = Convert.ToBase64String(b.Picture);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img src="#imgSrc" width="200" height="200" />
}
</div>
<div>
<input type="file" id="uploadFile" name="uploadFile" />
<input type="submit" value="uploadFile" class="submit" />
</div>
}
</div>
Update 06.01.2018:
What works in MVC5 is to use the sessionString. However, I've learned that this won't work in asp.net Core.
Set:
m = (MasterModel )System.Web.HttpContext.Current.Session["sessionString"];
Get:
System.Web.HttpContext.Current.Session["sessionString"] = m;
or, ..., that MVC should not be used for this...
Pure MVC won't cut it, and you're already on your way with the Ajax calls.
But you'll find that that gets more and more complicated.
The best route would be to study up on SPA, with for instance Angular.
What works in MVC5 is to use the Session[].
Yes, but that is server-side state manangment, problems with scale-out etc.
But usable, for ASP.NET Core you could use the MemoryCache, or step up to ReDis. You still have (can configure) a Session Id.
With a SPA you won't need the cache/session so much, just use it for optimization.
Try TempData to store your Data and access in next Request.

ASP.Net MVC + Autocomplete Search not working

I'm a beginner & I'm trying to develop a autocomplete search box with ASP.Net MVC 5. I use Northwind Database and Entity Framework 6.
Here is my index.cshtml code
#model IEnumerable<AutoComplete3.Models.Customers>
<link href="~/Content/jquery-ui.css" rel="stylesheet" />
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.js"></script>
<script type="text/javascript" src="~/Scripts/jquery-ui.js"></script>
<script type="text/javascript">
$(function () {
$("#txtSearch").autocomplete({
source: '#Url.Action("GetCustomers")'
});
});
</script>
#using (#Html.BeginForm())
{
<b>Name : </b>
#Html.TextBox("searchTerm", null, new { #id = "txtSearch" })
<input type="submit" value="Search" />
}
Here is my CustomerController class
public class CustomersController : Controller
{
northwindEntities db = new northwindEntities();
public ActionResult Index()
{
return View(db.Customers);
}
[HttpPost]
public ActionResult Index(string SearchTerm)
{
List<Customers> customers;
if (string.IsNullOrEmpty(SearchTerm))
{
customers = db.Customers.ToList();
}
else
{
customers = db.Customers.Where(c => c.CompanyName.StartsWith(SearchTerm)).ToList();
}
return View(customers);
}
public JsonResult GetCustomers(string term)
{
List<string> customers;
customers = db.Customers.Where(c => c.CompanyName.StartsWith(term)).Select(y => y.CompanyName).ToList();
return Json(customers,JsonRequestBehavior.AllowGet);
}
}
This code is working when i am searching records, by entering keyword & clicking submit button. But the GetCustomer method cannot be called by the jquery script. Inspect Elements shows following error.
Uncaught TypeError: $(...).autocomplete is not a function
The text box should be suggest Company Names to the textbox itself. How to correct this.
Thanks.
Javascript
$(document).ready(function () {
$("#txtSearch").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("GetCustomers","Home")',
type: "POST",
dataType: "json",
data: { searchTerm: request.term },
success: function (data) {
response($.map(data, function (item) {
return { label: item.CompanyName, value: item.CompanyName };
}))
}
})
},
messages: {
noResults: "", results: ""
},
});
})
View
#using (#Html.BeginForm())
{
<b>Name : </b>
#Html.TextBox("searchTerm", null, new { #id = "txtSearch" })
<input type="submit" value="Search" />
}
Controller
Please update your controller with [HttpPost]
[HttpPost]
public JsonResult GetCustomers(string searchTerm)
{
List<string> customers;
customers = db.Customers.Where(c => c.CompanyName.StartsWith(term)).Select(y => y.CompanyName).ToList();
return Json(customers,JsonRequestBehavior.AllowGet);
}

File Upload Causes Model Validation to Fail

I have an MVC3 form bound to a model with a file upload control. (Extra HTML removed for brevity):
#model Models.MessageModel
<script type="text/javascript">
var numAttachments = 0;
$(function () {
$(".add-attachment").click(function () {
$(".attachments").append("<div><input type=\"file\" name=\"attachments\" id=\"attachment" + numAttachments + "\" /></div>");
});
});
</script>
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<div class="field-label">Subject:
#Html.EditorFor(model => model.Subject)
</div>
<div class="attachments">
</div>
<div>
Add Attachment
</div>
<div class="message-text">#Html.TextAreaFor(model => model.Text, new { cols = 107, rows = 10 })</div>
<input type="submit" value="Send Message" />
</div>
}
Users can choose to add multiple attachments by clicking the "add attachment" link, attachments are not required.
My model is as follows:
public class MessageModel
{
[Required]
public string Subject { get; set; }
[Required]
public string Text { get; set; }
public IEnumerable<HttpPostedFileBase> Attachments { get; set; }
}
(NOTE: I've also tried moving the attachments out of the model, into an argument to my action method with the same results)
My Action:
[HttpPost]
public ActionResult New(MessageModel message)
{
// this check passes if no file is uploaded
// but once a file is uploaded, this evaluates to false
// even if the model is valid
if (ModelState.IsValid)
{
// do stuff
}
}
This form works fine and validation passes when no file is selected for upload. When I choose a file for upload, ModelState.IsValid becomes false. How can I cause validation to ignore uploaded files?
You need to make sure your form is using the correct "enctype".
#using (Html.BeginForm("New", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
MVC 3 file upload and model binding

Categories

Resources