#model Framely2011.Models.PictureUpload
#{
ViewBag.Title = "Upload";
}
<h2>Upload</h2>
#using (Html.BeginForm("Upload", "Member", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="myFile" id="myFile" />
#Html.TextBoxFor(x => x.MetaTagsObj.Meta1)<br />
#Html.TextBoxFor(x => x.MetaTagsObj.Meta2)<br />
#Html.TextBoxFor(x => x.MetaTagsObj.Meta3)<br />
<input type="submit" value="submit" />
}
This is what I have so far, here is what my model looks like:
public class PictureUpload
{
public HttpPostedFile fileName { get; set; }
public MetaTags MetaTagsObj { get; set; }
}
I am not sure how to write my controller for the picture upload or how to upload the file at the controller when I do a [HttpPost]
Here is how I have done it in the past (asp.net mvc 2)... There may very well be a much easier way to do it with .net 4 and asp.net mvc 3
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
string mimeType = Request.Files[upload].ContentType;
Stream fileStream = Request.Files[upload].InputStream;
string fileName = Path.GetFileName(Request.Files[upload].FileName);
int fileLength = Request.Files[upload].ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
//do something with the byte array (filedata)
}
HasFile() is an extension method defined like:
public static class HttpPostedFileBaseExtensions
{
public static bool HasFile(this HttpPostedFileBase file)
{
return (file != null && file.ContentLength > 0);
}
}
enter code here
You can just take your model as a parameter in the [HttpPost] action method and read the fileName property.
Related
I am creating an application where a user can post, something like a forum. I am trying to load an image and text into the database, for that, I have two tables and they are both related through an id. I figured out how to load text content, but I really don't know how to do the same with image content.
I'm using an MVC view with it respective controller to consume the API.
The model I'm using:
public class ForumThemeModel
{
public ForumThemeModel()
{
Themes = new HashSet<Theme>();
}
//forum table
[Key]
public int IdForum { get; set; }
public string PostTittle { get; set; }
//theme table
public int? Idtheme { get; set; }
public string TextContent { get; set; }
public int? IdForum { get; set; }
public IFormFile ContentFile { get; set; } //where the image will be stored
public string FileNameA { get; set; }
public string FileType { get; set; }
}
The API controller where the post creation is made:
[HttpPost]
[Consumes("multipart/form-data")]
[Route("createPost")]
public async Task<IActionResult> createPost([FromBody]ForumThemeModel model)
{
Forum forum = new Forum();
Theme theme = new Theme();
var fileName = Path.GetFileName(model.FileNameA);
var fileExt = Path.GetExtension(fileName);
var newFileName = String.Concat(Convert.ToString(Guid.NewGuid()), fileExt);
using(var target = new MemoryStream())
{
await model.ContentFile.CopyToAsync(target);
theme.ContentFile = target.ToArray();
}
forum.PostTittle = model.PostTittle;
theme.FileNameA = newFileName;
theme.FileType = fileExt;
var postTittle = new SqlParameter("#postTittle", forum.PostTittle);
var textContent = new SqlParameter("#textContent", theme.TextContent);
var content_file = new SqlParameter("#content_file", theme.ContentFile);
var file_name_a = new SqlParameter("#file_name_a", theme.FileNameA);
var FileType = new SqlParameter("#FileType", theme.FileType);
//saves everything to database
return Ok();
}
The MVC controller where the API is used:
[HttpPost]
public IActionResult createPost(ForumThemeModel model)
{
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri("https://localhost:44325/api/Users");
var userPost = hc.PostAsJsonAsync<ForumThemeModel>("Users/createPost", model);
userPost.Wait();
//do something when the resquest result is successful
}
The view of the MVC controller:
#model Huerbog.Models.Request.ForumThemeModel
#{
ViewData["Title"] = "CreatePost";
}
<hr />
<div class="row">
<div class="col-12 col-md-9">
<form enctype="multipart/form-data" asp-action="createPost">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group h4">
<label asp-for="PostTittle" class="control-label">Tittle</label>
<input asp-for="PostTittle" class="form-control" />
<span asp-validation-for="PostTittle" class="text-danger"></span>
</div>
<div class="form-group h4">
<label asp-for="Content" class="control-label">Content of the post</label>
<textarea rows="5" asp-for="Content" class="form-control"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<div class="form-group h4">
<label asp-for="ContentFile" class="control-label">Imagen:</label><br />
<input class="form-control-file" multiple asp-for="ContentFile" type="file" />
</div>
<div class="form-group h4">
<input type="submit" value="Create post" class="btn btn-primary" />
</div>
</form>
</div>
</div>
So I have read about uploading images or files and it indicates that the attribute enctype = "multipart / form-data" should be present in the view when uploading images or different types of files in a database, due to that attribute two things happen: the first is that when I leave the attribute in the view the MVC controller does not use the API controller, but the model receives the information from the file or image such as the name, the file type, etc. The second is when I remove the attribute from the view, in this case the MVC controller makes use of the API controller, but the model does not contain anything regarding the file or the image. In both cases the text content is received by the model, but it is also not saved by the database due to the lack of information regarding the image.
I'm not very sure if the enctype = "multipart / form-data" atribute is the main reason, but as I said before, the text content, before the image upload, was working well and the enctype = "multipart / form-data" was not present.
I've stuck on the img upload for a while and really I don't know how to do it, any help is appreciated.
public IFormFile ContentFile { get; set; }
Firstly, please note that PostAsJsonAsync method would serialize the model data as JSON then send in the request body, which does not make sense to serialize a FormFile, it would cause an error.
To achieve the requirement of consuming an API from MVC controller action to upload file(s) with other data, you can refer to the following example code.
[HttpPost]
public async Task<IActionResult> CreatePost(ForumThemeModel model)
{
var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(model.PostTittle), "PostTittle");
//...
//for other properties, such as FileNameA, FileType etc
//...
formContent.Add(new StreamContent(model.ContentFile.OpenReadStream()), "ContentFile", Path.GetFileName(model.ContentFile.FileName));
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri("https://localhost:44325/api/Users/");
var userPost = await hc.PostAsync("createPost", formContent);
//...
API action
public async Task<IActionResult> createPost([FromForm]ForumThemeModel model)
{
//...
I'm really a begginer at programing so ease stuff are hard for me if can anyone explain me or help me in my situation I would apreciate a lot.
On my create method I need to save a file (pdf in db).
What I have now:
Model:
public class Candidate : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public int Number { get; set; }
public string Profile { get; set; }
public Byte[] CV { get; set; }
}
Controller:
[HttpPost("UploadFiles")]
public IActionResult Post(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);
// full path to file in temp location
var filePath = Path.GetTempFileName();
foreach (var formFile in files)
{
if (formFile.Length > 0)
{
using (var stream = new MemoryStream())
{
files.CopyTo(stream);
//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, filePath });
}
In my view i'm using this to attach the file:
<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index">
<div class="form-group">
<div class="col-md-10">
<p>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>
You're not going to get a file path to work with. An uploaded file would be in the HTTP request, but you haven't set your action method up to accept that properly. You really should read some tutorials about how to upload files in ASP.NET MVC so you have the general idea, rather than asking someone on Stack Overflow to explain what you need to do.
#mason.
This is not a complete answer to your problem but it will show you how file uploading works in asp.net mvc. You will have to modify it according to your problem.
Here’s a form that will post back to the current action.
#using (Html.BeginForm("Upload", "Upload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
}
Here’s the action method that this view will post to which saves the file into a directory in the App_Data folder named “uploads”.
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file) {
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
}
return RedirectToAction("Index");
}
Visit this for complete solution
Again this answer is only to understand how we made HTTP request to upload files and how to save files.
I have created the following view, with having file upload and submit button.
#using (Html.BeginForm("FileUpload", "Home",
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input name="uploadFile" type="file" />
<input type="submit" value="Upload File" id="btnSubmit" />
}
I have also created the action method in Controller but it gives the null at the "uploadFile"
[HttpPost)]
public ActionResult FileUpload(HttpPostedFileBase uploadFile)
{
if (uploadFile.ContentLength > 0)
{
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
}
return View();
}
Can u try Name with same as uploadFile
In your Page:
#using (Html.BeginForm("FileUpload", "Home",
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input id="uploadFile" name="uploadFile" type="file" />
<input type="submit" value="Upload File" id="btnSubmit" />
}
As per #Willian Duarte comment : [HttpPost]
In your Code behind:
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase uploadFile) // OR IEnumerable<HttpPostedFileBase> uploadFile
{
//For checking purpose
HttpPostedFileBase File = Request.Files["uploadFile"];
if (File != null)
{
//If this is True, then its Working.,
}
if (uploadFile.ContentLength > 0)
{
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
}
return View();
}
See here Same question like yours.,
Code project Article about the File upload.,
Try to use (on controller):
var file = System.Web.HttpContext.Current.Request.Files[0];
create a model and bind it to your view that controller will also expect:
Controller:
//Model (for instance I've created it inside controller, you can place it in model
public class uploadFile
{
public HttpPostedFileBase file{ get; set; }
}
//Action
public ActionResult Index(uploadFile uploadFile)
{
if (uploadFile.file.ContentLength > 0)
{
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(uploadFile.file.FileName));
uploadFile.file.SaveAs(filePath);
}
return View();
}
View
#model sampleMVCApp.Controllers.HomeController.uploadFile
#using (Html.BeginForm("FileUpload", "Home",
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(m => m.file, new { type = "file"});
<input type="submit" value="Upload File" id="btnSubmit" />
}
Tested Solution!
HTH :)
Use the following in the controller:
var file = System.Web.HttpContext.Current.Request.Files[0];
Use HttpPost instead of [AcceptVerbs(HttpVerbs.Post)]
I am making a View that has a DropDown. The view is supplied with a CategoryModel that looks like this:
public class CategoryModel
{
[Required]
[Display(Name = "Categories")]
public List<Category> Categories { get; set; }
[Required]
[GreaterThan(ExceedValue = 0, ErrorMessage = "Please select a category.")]
[Display(Name = "SelectedCategoryId")]
public int SelectedCategoryId { get; set; }
}
The List of Categories is used within the view to populate the DropDown by first taking the categories and put them in a SelectList, like this:
#model RatingMVC3.Models.CategoryModel
#{
Layout = "~/Views/Shared/_MainLayout.cshtml";
ViewBag.Title = "Upload";
}
<h2>Upload</h2>
#using (Html.BeginForm("Upload", "Upload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" value="OK" />
#Html.DropDownListFor(m => m.SelectedCategoryId, new SelectList(Model.Categories, "Id", "Description"), "-- Select Category --");
#Html.ValidationMessageFor(m => m.SelectedCategoryId);
#Html.HiddenFor(m => m.Categories);
}
When this form is submitted, and the model is returned to the Controller, I can see that the model comes back into the Controller, but it contains an empty List instead of the List of Categories that was there in the View. (The SelectedCategoryId is there as expected). Here is the ActionResult method in the Controller:
[HttpPost]
[Authorize]
public ActionResult Upload(HttpPostedFileBase file, CategoryModel model)
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
var FileExtension = Path.GetExtension(file.FileName);
string Path1 = null;
string FileName = null;
do
{
var randomName = Path.GetRandomFileName();
FileName = Path.ChangeExtension(randomName, FileExtension);
Path1 = Path.Combine(Server.MapPath("~/Images"), FileName);
} while (System.IO.File.Exists(Path1));
file.SaveAs(Path1);
if (UploadService.SaveImage(FileName, System.Web.HttpContext.Current.User.Identity.Name, model.SelectedCategoryId))
{
return RedirectToAction("Uploaded", "Upload");
}
}
return RedirectToAction("Index", "Home");
}
return View(model);
}
The empty list is a problem for me, because as you can see, if the ModelState is not valid, the view will be returned with the same model again, and needs to be populated with categories.
I hope someone can answer this ;) I will gladly specify more information if needed, Thanks in advance
During a POST operation, the entire select list (drop down) is not returned to the controller/form action, only the selected value from that list. If you have to re-render the view because of bad validation, you can either a) Do an AJAX submit instead of a full POST for validation reasons or b) recreate your list and send it back with the View on Error. Option b) can be implemented as such:
[HttpPost]
[Authorize]
public ActionResult Upload(HttpPostedFileBase file, CategoryModel model)
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
var FileExtension = Path.GetExtension(file.FileName);
string Path1 = null;
string FileName = null;
do
{
var randomName = Path.GetRandomFileName();
FileName = Path.ChangeExtension(randomName, FileExtension);
Path1 = Path.Combine(Server.MapPath("~/Images"), FileName);
} while (System.IO.File.Exists(Path1));
file.SaveAs(Path1);
if (UploadService.SaveImage(FileName, System.Web.HttpContext.Current.User.Identity.Name, model.SelectedCategoryId))
{
return RedirectToAction("Uploaded", "Upload");
}
}
return RedirectToAction("Index", "Home");
}
//I don't know how you fetch this list, but just do it again before returning
//the view
model.Categories = GetMyCategories();
return View(model);
}
I guess if you wanted, you could store the list of items as a hidden input on your page, but that just looks ugly, adds to the amount of data being sent to and from the web page and gosh darn it, just sounds a heck of a lot like ViewState (shrudders).
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