Upload File in MVC gives null Exception [duplicate] - c#

I want to upload multiple files including Word Documents, Pdf and Images.
I need to use a single input for files because we don't know how many files will be uploaded.
My code is this but I have problem that I can't send files to server side.
Controller Code :
public ActionResult Create([Bind(Include = "Id,Content")] Message message, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
// Object save logic
SaveFiles(message,files);
return RedirectToAction("Index");
}
return View(message);
}
Part of view code :
<form name="registration" action="">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label for="Content" >Content:</label>
<textarea class="form-control compose_content" rows="5" id="Content" name="content"></textarea>
<div class="fileupload">
Attachment :
<input id="files" name="files" type="file" multiple />
</div>
</div>
<button type="submit" class="btn btn-default compose_btn" >Send Message</button>
</form>
I don't have problem with saving files and saving the object.
only problem :
files list is null.

I order to upload files, your form needs to include the enctype= multipart/form-data attribute.
<form name="registration" action="" enctype= "multipart/form-data">
or better
#using (Html.BeginForm(actionName, controllerName, FormMethod.Post, new { enctype= "multipart/form-data" }))
and I strongly recommend you pass a model to the view and use the strongly typed HtmlHelper methods to create your html for the properties of your model.

Related

ASP.NET Core Web Application using .NET 5.0: IFormFile always null when passing from view to controller

I am trying to allow the user to upload a pdf file. I am not getting any errors, but the IFormFile 'PostedFile' is always null in the controller.
Create View:
<div class="form-group">
<label asp-for="PostedFile" class="control-label"></label>
<div class="col-md-10">
<input type="file" asp-for="PostedFile" />
<span asp-validation-for="PostedFile" class="text-danger"></span>
</div>
Controller, Create method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Name,Phone1,Phone2,District_Division,OrgNumber,DateOfTest,DateOfExposure,NumberOfExposed,Notes,PathToFile")] Case_Log case_Log, IFormFile PostedFile)
{
string path = "Case_Log_Docs/";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
System.Diagnostics.Debug.WriteLine("Created the folder.");
}
if (PostedFile != null)
{
string fileName = Path.GetFileName(PostedFile.FileName);
System.Diagnostics.Debug.WriteLine(fileName);
PostedFile.CopyTo(new FileStream(path, FileMode.Create));
ViewBag.Message += string.Format("<b>{0}</b> uploaded.<br />", fileName);
}
else
{
System.Diagnostics.Debug.WriteLine("Posted file was null.");
}
if (ModelState.IsValid)
{
_context.Add(case_Log);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(case_Log);
}
PLEASE NOTE: I (think I) do NOT want to use List as I do NOT want the user to be able to upload more than 1 single document at a time as the documents have a corresponding database entries with a 1 to 1 relationship.
I have a few questions.
1.) What is the problem? Why is IFormFile always null?
2.) Why does it seem like people always recommend List over IFormFile?
Passing the rest of the variables to the controller works fine:
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"> </div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Phone1" class="control-label"></label>
<input asp-for="Phone1" class="form-control" />
<span asp-validation-for="Phone1" class="text-danger"></span>
</div>
But the file upload div is still inside of the form that is directed to the Create method. Is there something wrong with the view element? If so how would I change it to correct the issue?
I tried following this example and got no errors but no results either: https://www.aspsnippets.com/Articles/ASPNet-Core-IFormFile-always-returns-NULL.aspx
You need use enctype=multipart/form-data to allows entire files to be included in the data.Like following.
<form asp-action="xxx" enctype="multipart/form-data">
//...
<input type="file" name="PostedFile" />
<input type="submit" value="click"/>
</form>
Action:
[HttpPost]
public IActionResult Demo(IFormFile PostedFile)
{
//...
}
Result:

Dropzone FileUpload

Dear friends I am currently creating an admin panel for user where they can easily can publish their articles. I also want to add to my form a little fileuploader but sadly I got some problems with DROPZONEJS.JS file in POST method. The main problem is I cannot give URL to project's local file in order to download to file there where website will access those file in order to publish them with current article's id. Please let me know if there is something not understandable.
#{
ViewBag.Title = "Uppy";
}
#{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<div class="content d-flex flex-column flex-column-fluid" id="kt_content">
<!--begin::Entry-->
<div class="d-flex flex-column-fluid">
<!--begin::Container-->
<div class="container">
<!--begin::Card-->
<div class="card card-custom gutter-b">
<div class="card-header">
<div class="card-title">
<h3 class="card-label">File Upload</h3>
</div>
</div>
<!--begin::Form-->
<form>
<div class="card-body">
<div class="form-group row">
<label class="col-form-label col-lg-3 col-sm-12 text-lg-right">Multiple File Upload</label>
<div class="col-lg-4 col-md-9 col-sm-12">
<div class="dropzone dropzone-default dropzone-primary" id="kt_dropzone_2">
<div class="dropzone-msg dz-message needsclick">
<h3 class="dropzone-msg-title">Drop files here or click to upload.</h3>
<span class="dropzone-msg-desc">Upload up to 10 files</span>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-lg-3 col-sm-12 text-lg-right">File Type Validation</label>
<div class="col-lg-4 col-md-9 col-sm-12">
<div class="dropzone dropzone-default dropzone-success" id="kt_dropzone_3">
<div class="dropzone-msg dz-message needsclick">
<h3 class="dropzone-msg-title">Drop files here or click to upload.</h3>
<span class="dropzone-msg-desc">Only image, pdf and psd files are allowed for upload</span>
</div>
</div>
</div>
</div>
</div>
#using (Html.BeginForm("Uppy",
"FileUpload",
FormMethod.Post,
new { enctype = "multipart/form-data" })) //multipart/form-data gives functionlity to inputes (search at web);
{
<div class="card-footer">
<div class="row">
<div class="col-lg-3"></div>
<div class="col-lg-4">
<input type="submit" value="Submit" class="btn btn-light-primary mr-2" />
<button type="reset" class="btn btn-primary">Cancel</button>
</div>
</div>
</div>
}
</form>
<!--end::Form-->
</div>
<!--end::Card-->
<!--end::Row-->
</div>
<!--end::Container-->
</div>
<!--end::Entry-->
</div>
<!--end::Content-->
By the way my own upload code is working correctly and also sends choosen file to url location where I wrote in controller.
<label for="file">Upload File:</label>
<input type="file" name="file" id="file" class="btn-hover-bg-success" />
<br>
<br>
<input type="submit" value="Upload Image" />
<br>
<br>
#ViewBag.Message
This is my FileUploadController:
[HttpPost]
public ActionResult Uppy(HttpPostedFileBase file)
{
ADAPTIVE_TESTEntities ent = new ADAPTIVE_TESTEntities();
Adaptive.News.Models.NEWS news = new Adaptive.News.Models.NEWS();
if (file != null && file.ContentLength > 0)
try
{
var path = Path.Combine(Server.MapPath("~/Content/images"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
news.PICTUREPATH = path;
ent.NEWS.Add(news);
ent.SaveChanges();
ViewBag.Message = "File uploaded successfully";
}
catch (Exception ex)
{
ViewBag.Message = "ERROR: " + ex.Message.ToString();
}
else
{
ViewBag.Message = "You have not specified a file.";
}
return View();
}
it is not obvious to me, what and where really your problem is. What do you mean with having problem. Is your problem with Dropzone.JS or with C#? Anyway, I examined your code slightly and have some ideas what your problem could be.
FIRST OF ALL: You have 2 DIV containers, which you use as Dropzone elements assigning them the css class "dropzone". Furthermore you generate a FORM element with ASP.Net HTML-Helper.
By default you have 2 options using Dropzone.
Declarative instantiation via assigning css class "dropzone" to any HTML element.
Dropzone discovers all DOM elements with class="dropzone" automatically and instantiates them.
Programmatically instantiating: You instantiate Dropzone by passing the id of the container element and THE OPTIONS CONTAINING POST URL to the Dropzone constructor.
DECLARATIVE DROPZONE
You must pay attention to this detail: If you use FORM element as Dropzone container element, Dropzone uses "action" attribute of the FORM element as post URL. But if you use
DIV element as container, then you get most possibly a JavaScript error. Because DIV elements do usually NOT have "action" attribute. If you use DIV as Dropzone container (and in your code you use it 2 times), you will get following JavaScript error:
dropzone.js:1027 Uncaught Error: No URL provided.
at new Dropzone (dropzone.js:1027)
at dropzone.js:2907
at Function.Dropzone.discover (dropzone.js:2919)
at Dropzone._autoDiscoverFunction (dropzone.js:3491)
at HTMLDocument.init (dropzone.js:3456)
In this case you have two options solve the problem:
Use FORM element instead of DIV as Dropzone container.
Add action="/your/post/url" to your DIV element, which you use as Dropzone container.
Where I would prefer the first option. Because it is not common that DIV elements have action attribute.

How to show succes alert on file upload?

I'm currently working on a project where I upload files with the following code:
<div class="row">
<div class="col-lg-2 d-flex align-items-stretch">
#using (Html.BeginForm("ImportOther", "Mapper", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<p>
<label class="btn btn-block btn-primary">
Other JSON / XML <input type="file" name="jsonFileOther" onchange="this.form.submit()" style="display: none;">
</label>
</p>
}
</div>
</div>
How can I show a succes alert when file has been uploaded? I've used alerts in javascript so far. Hope anyone has some suggestions.
Thanks in advance!
After you have submitted your form to the Controller, based upon your upload result, you can set a message using ViewBag.
In your Controller:
if(fileUpload == true)
{
ViewBag.UploadMessage = "File Successfully Uploaded";
}
else
{
ViewBag.UploadMessage = "Could Not Upload File";
}
You can use the ViewBag like this in your View:
#if(ViewBag.UploadMessage != null)
{
<script>
$(document).ready(function(){
alert('#ViewBag.UploadMessage ');
});
</script>
}
Note: Instead of using return RedirectToAction(), use return View() to preserve your ViewBag variable.

RedirectToAction after ajax form submit in Asp.net Core

I have a view named Index and a PartialView named '_Addbook' that shown as a bootstrap modal. In the partialView insert data into database using ajax form.
Index view :
<div class="panel panel-primary">
<div class="panel-body">
<div class="btn-group">
<a class="btn btn-primary marginbutoon" id="showBookgroup" data-toggle="modal" asp-action="AddBook"
data-target="#modal-book">
<i class="glyphicon glyphicon-plus"></i>
Add Book
</a>
</div>
</div>
Partialview :
#model WebApplication1.Models.Book
<form asp-controller="Home" asp-action="AddBook" id="myform"
data-ajax="true" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#myform">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Add Book</h4>
</div>
<div class="modal-body form-horizontal">
<div class="row">
<div class="form-group">
<label asp-for="BookName" class="col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="BookName" class="form-control" />
<span asp-validation-for="BookName" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
Controller :
[HttpGet]
public IActionResult AddBook()
{
var book = new Book();
return PartialView("_AddBooks", book);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddBook(Book model)
{
if (ModelState.IsValid)
{
using (var db = _Context.GetRequiredService<ApplicationDbContext>())
{
db.bookgroups.Add(model);
db.SaveChanges();
}
return RedirectToAction("Index");
}
else
{
return PartialView("_Addbooks", model);
}
}
The data is stored correctly in the database and modal hide after submit but index view shows Mixed up.
How can i Redirect after ajax submit?
Your current form is setup to do ajax form post. So when the response is received from the server, it will replace the inner html of the form tag. So with your current code, it will basically makes a GET call to the Index action and the response of that will be loaded to the form tag.
If you want to do a redirect, but still want to have the model validation works, You may return a view result back, which has some javascript code which does the redirection.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddBook(Book model)
{
if (ModelState.IsValid)
{
//Your code to store data
return PartialView("_AddedSuccessfully");
}
return PartialView("_AddBooks", model);
}
And in the _AddedSuccessfully.cshtml partial view will have only the below content, which is the javascript for redirect to /Home/Index
<script>
window.location.href = '#Url.Action("Index","Home")';
</script>
EDIT : As per the comment
how can i make it dynamically. because i have several partial view in
my project and i want pass ControllerName and ActionName as a
parameters to _AddedSuccessfully.cshtml?
You can pass it from your view to the action method and from there to the partial view
Just add a hidden input element to the Add form, just above your submit button and use Url.Action helper method to generate the url you want to redirect to, after saving successfully.
<input type="hidden" name="redirectUrl" value="#Url.Action("Index","Home")" />
<input type="submit" class="btn btn-primary" value="Submit"/>
Now, add a new parameter to your action method with the same name as the hidden input. Pass that string value as the model of the view when you call the PartialView method for _AddedSuccessfully view.
[HttpPost]
public IActionResult AddBook(Book model,string redirectUrl)
{
if (ModelState.IsValid)
{
// to do : Save
return PartialView("_AddedSuccessfully", redirectUrl);
}
return PartialView("_AddBook", model);
}
Now you need to udpate the partial view to be strongly typed to string and use the model of the view for redirect.
#model string
<script>
window.location.href = '#Model';
</script>
You can use FormHelper to create ajax forms, ajax redirects, showing notifications and to do many things on ASP.NET Core. Also, FormHelper helps you to transform server-side validations to client-side.
It's so easy to use. You just need to add asp-formhelper="true" to your form tag.
<form asp-formhelper="true" asp-controller="Home" asp-action="Save">
// <input...
// ...
</form>
You can check it's documentation on FormHelper GitHub Page. And you can download that package from Nuget.

Having two forms in ASP.NET MVC 4 and posting one of them with ajax

I'm developing an ASP.NET MVC 4 web application. I'm a beginner in web application. My problem is with file upload and ajax. I have two forms. One of the is for getting the data from user such as name, family and so more. The other one is to upload image. I want the user be able to upload the image before submitting the registration and also see the uploaded image in an <img> tag. Here is my code:
View
#using (Html.BeginForm("Register", "Customer", FormMethod.Post))
{
<fieldset>
<div class="control-group">
<label class="control-label">Name</label>
<div class="controls">
#Html.TextBoxFor(model => model.Name)
</div>
</div>
<div class="control-group">
<label class="control-label">Family</label>
<div class="controls">
#Html.TextBoxFor(model => model.Family)
</div>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" value="Submit" class="btn btn-info"/>
</div>
</div>
</fieldset>
}
<img src="" class="img"/>
#using (Html.BeginForm("UploadImage", "Customer", FormMethod.Post, new { d="ImageUploadForm", #enctype = "multipart/form-data" }))
{
<input type="file" name="imgfile" class="imgfile"/>
<input type="submit" value="Upload" class="btnUpload btn btn-info" />
}
Action In Controller
[HttpPost]
public string UploadImage(HttpPostedFileBase imgfile)
{
string filePath = "";
if (imgfile != null && imgfile.ContentLength > 0)
{
filePath = Path.Combine(Server.MapPath("~/Customer/"), imgfile.FileName);
imgfile.SaveAs(filePath);
}
return "~/Customer/" + imgfile.FileName;
}
Javascript
$('#ImageUploadForm').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$('.img').attr('src', result);
}
})
return false;
}
});
Now the problem is that when I select a file and hit the Upload button, the UploadImage() action is called and file is uploaded, but the success event of ajax is not called and it redirects me to another page called localhost/Customer/UplaodImage it's content is just the file path that UploadImage had returned. Is it ever possible to do this? Or I cant post a form data using ajax and not redirecting to another page? Any help is appreciated.
As I know, you cannot post a file through regular AJAX. Use some helper libraries: FileUploader, etc...
UPDATE:
By Adeel at this answer:
With XHR2, File upload through AJAX is supported. E.g. through
FormData object, but unfortunately it is not supported by all/old
browsers.

Categories

Resources