This is my code:
#using (Html.BeginForm("UploadImages", "Administration", new { _id = Model.Album.AlbumID, enctype = "multipart/form-data" }, FormMethod.Post))
{
<input type="file" name="fileUpload" id="file1" /><br />
<input type="file" name="fileUpload" id="file2" /><br />
<input type="file" name="fileUpload" id="file3" /><br />
<input name="addPhoto" type="submit" value="Добавить фото" />
}
[Authorize]
[HttpPost]
public ActionResult UploadImages(int _id, IEnumerable<HttpPostedFileBase> fileUpload)
{
gb_albumdbEntities1 entityes = new gb_albumdbEntities1();
foreach (var file in fileUpload)
{
if (file == null) continue; // **<---fileUpload items is always null!**
string path = AppDomain.CurrentDomain.BaseDirectory + "Photos/";
if (Path.GetFileName(file.FileName) != null)
{
string filename = file.GetHashCode().ToString();
string fullpath = Path.Combine(path, filename);
file.SaveAs(fullpath);
entityes.Photos.AddObject(new Photo() { AlbumID = _id, PhotoUrl = #"http://site.ru/Photos/" + filename });
}
}
entityes.SaveChanges();
return RedirectToAction("AlbumEdit", new { id = _id });
}
fileUpload items is always null. Where is the problem?Oo
UPD: calculated result post url:
http://localhost:56193/Administration/UploadImages?_id=4&enctype=multipart%2Fform-data
your list if file inputs need to be numbered for model binding to work. In the simplest form your view should look something like this:
<html>
<head>
<title>Index</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Upload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
for (int i = 0; i < 3; i++)
{
#Html.TextBox(string.Format("fileUpload[{0}]", i), null, new { type="file" })<br />
}
<input name="submit" type="submit" value="Go" />
}
</div>
</body>
</html>
and your controller:
public class UploadController : Controller
{
//
// GET: /Upload/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload)
{
return View();
}
}
Try the following post which I've used myself before. Worked for me.
http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx
Related
I have a form that is just a checkbox and hidden inputs (to send data back to the controller) as follows:
#model List<UserRoleViewModel>
#{
var roleId = ViewBag.roleId;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>AddOrRemoveUsers</title>
</head>
<body>
<form method="post">
<div class="card">
<div class="card-header">
<h2> Add or remove users from this role</h2>
</div>
<div class="card-body">
#for (int i = 0; i < Model.Count; i++)
{
<div class="form-check m-1">
<input type="hidden" asp-for="#Model[i].UserName" />
<input type="hidden" asp-for="#Model[i].UserId" />
<input asp-for="#Model[i].IsSelected" class="form-check-input" />
<label class="form-check-label" asp-for="#Model[i].IsSelected">
#Model[i].UserName
</label>
</div>
}
</div>
<div class="card-footer">
<input type="submit" class="btn btn-primary" value="Update" />
<a asp-action="ListRoles" class="btn btn-primary"> Cancel</a>
</div>
</div>
</form>
</body>
</html>
I expect to get the data in this controller:
public class AdminController : Controller
{
private readonly RoleManager<IdentityRole> _roleManager;
private readonly UserManager<Microsoft.AspNetCore.Identity.IdentityUser> _userManager;
public AdminController(RoleManager<IdentityRole> roleManager, UserManager<Microsoft.AspNetCore.Identity.IdentityUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
[HttpGet]
public async Task<IActionResult> AddOrRemoveUsers(string roleId)
{
ViewBag.roleId = roleId;
var role = _roleManager.FindByIdAsync(roleId);
if (role == null)
{
ViewBag.ErrorMessage = $"The Role with roleId = {roleId} cannot be found";
return View("Not found");
}
var model = new List<UserRoleViewModel>();
var AllUser = _userManager.Users;
var UserInThisRole = await _userManager.GetUsersInRoleAsync(role.Result.Name);
foreach (var user in AllUser)
{
var userRoleViewModel = new UserRoleViewModel
{
UserId = user.Id,
UserName = user.UserName,
IsSelected = false
};
if (UserInThisRole.Any(p=>p.Id == userRoleViewModel.UserId))
{
userRoleViewModel.IsSelected = true;
}
model.Add(userRoleViewModel);
}
return View(model);
}
[HttpPost]
public async Task<IActionResult> AddOrRemoveUsers([FromForm]List<UserRoleViewModel> model, string roleId)
{
var role = _roleManager.FindByIdAsync(roleId);
if (role == null)
{
ViewBag.ErrorMessage = $"The Role with roleId = {roleId} cannot be found";
return View("Not found");
}
for (int i = 0; i < model.Count; i++)
{
var user = await _userManager.FindByIdAsync(model[i].UserId);
IdentityResult result = null;
if (model[i].IsSelected && !(await _userManager.IsInRoleAsync(user, role.Result.Name)))
{
result = await _userManager.AddToRoleAsync(user, role.Result.Name);
}
else if (!model[i].IsSelected && await _userManager.IsInRoleAsync(user, role.Result.Name))
{
result = await _userManager.RemoveFromRoleAsync(user, role.Result.Name);
}
else
{
continue;
}
if (result.Succeeded)
{
if (i < (model.Count - 1))
{
continue;
}
else
{
return RedirectToAction("ListRoles");
}
}
}
return RedirectToAction("ListRoles");
}
}
}
But when I add a breakpoint on the controller, I can only see the roleId the model has count=0, even though there are values being sent to the back end if you check the request data.
The userRoleViewModel
namespace BataCMS.ViewModels
{
public class UserRoleViewModel
{
public string UserId;
public string UserName;
public bool IsSelected;
}
}
Any insights on what might be causing this?
According to your view codes, I found you don't add the tag helper. Without tag helper, the aspnet core will not renter the asp-for attribute in the input tag. This is the reason why you don't receive the model in the action method.
To solve this issue, I suggest you could try to add below codes in the view and then it will work well.
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Details, you could refer to below view codes:
#model List<CoreNormalIssue.Controllers.UserRoleViewModel>
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>AddOrRemoveUsers</title>
</head>
<body>
<form method="post">
<div class="card">
<div class="card-header">
<h2> Add or remove users from this role</h2>
</div>
<div class="card-body">
#for (int i = 0; i < Model.Count; i++)
{
<div class="form-check m-1">
<input type="hidden" asp-for="#Model[i].UserName" />
<input type="hidden" asp-for="#Model[i].UserId" />
<input asp-for="#Model[i].IsSelected" class="form-check-input" />
<label class="form-check-label" asp-for="#Model[i].IsSelected">
#Model[i].UserName
</label>
</div>
}
</div>
<div class="card-footer">
<input type="submit" class="btn btn-primary" value="Update" />
<a asp-action="ListRoles" class="btn btn-primary"> Cancel</a>
</div>
</div>
</form>
</body>
</html>
Result:
UserViewModel:
public class UserRoleViewModel
{
public string UserName { get; set; }
public string UserId { get; set; }
public bool IsSelected { get; set; }
}
Mytest Action:
[HttpGet]
public async Task<IActionResult> AddOrRemoveUsers(string roleId)
{
ViewBag.roleId = roleId;
List<UserRoleViewModel> model = new List<UserRoleViewModel>() {
new UserRoleViewModel(){ UserId="test1", UserName="testname1", IsSelected=true },
new UserRoleViewModel(){ UserId="test2", UserName="testname2" , IsSelected=false },
new UserRoleViewModel(){ UserId="test3", UserName="testname3", IsSelected=true }
};
return View(model);
}
Update:
I found your userviewmodel used field not the properties. Asp.net core model binding doesn't support field.
You should use below viewmodel and then it will work well.
public class UserRoleViewModel
{
public string UserId { get; set; }
public string UserName { get; set; }
public bool IsSelected { get; set; }
}
Result:
Im trying to pass the filepath into my ProfileViewModel but it seems to stay Null even thought the other values are filled.
I have tried debugging it but cant seem to find where its going wrong.
My view
#using (Html.BeginForm("EditProfile", "Profile", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.LabelFor(model => model.Photo, htmlAttributes: new { #class = "control-label col-md-2" })
<input asp-for="Photo" type="file"/><br />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
my controller
public IActionResult profile()
{
return View();
}
private readonly IHostingEnvironment he;
public ProfileController(IHostingEnvironment e)
{
he = e;
}
[HttpPost]
public ActionResult EditProfile(ProfileViewModel profile)
{
string ID = Request.Cookies["UserID"];
if (ModelState.IsValid)
{
var Photo = profile.Photo;
var FileName = Path.Combine(he.WebRootPath, Path.GetFileName(Photo.FileName));
if (logicprofile.logicEditProfile(profile.BIO, profile.Sex, profile.Preffered, FileName, Convert.ToInt32(ID)) == true)
{
profile.Photo.CopyTo(new FileStream(FileName, FileMode.Create));
ViewBag.Message = "Profile Updated";
return View("profile", profile);
}
else
{
ViewBag.Message = "Something went wrong";
return View("profile", profile);
}
}
else
{
return View("profile", profile);
}
}
ViewModel
[DisplayName("A picture of you!")]
public IFormFile Photo { get; set; }
I expect my pictures to be saved in a folder and the path to a database so I can use them as profile pictures.
You should use enctype in form for passing file type data.
#using (Html.BeginForm("EditProfile", "Profile", FormMethod.Post, new { enctype = "multipart/form-data" }))
Help HttpPostedFileBase returns NULL, I have already tried several things and I have searched in several forums but it works.
This is my code
#using (Html.BeginForm("NuevoProveedor", "Account", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<center>
<form method="post" enctype="multipart/form-data">
<input type="file" id="btnFile" name="file" />
<input type="submit" value="Save" id="btnSave" />
</form>
</center>
}
Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult NuevoProveedor(HttpPostedFileBase file, SubirArchivoModelo model)
{
SubirArchivoModelo modelo = new SubirArchivoModelo();
if (file != null)
{
string Ruta = file.FileName;
return View();
}
else
{
ViewBag.error = "No se pudo generar la carpeta, comunicate con Soporte Tecnico";
return View("UsuarioNuevo");
}
}
you can upload file and save its url in the database table like this:
View:
#using(Html.BeginForm("NuevoProveedor", "Account",FormMethod.Post,new {enctype="multipart/form-data"}))
{
...
<div class="editor-field">
<input type="file" id="btnFile" name="file" />
<input type="submit" value="Save" id="btnSave" />
</div>
...
}
Action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult NuevoProveedor(SubirArchivoModelo model)
{
if (ModelState.IsValid)
{
if(Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
model.FileLocation = Path.Combine(
Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(model.FileLocation);
}
//db.TableEntity.Add(model);
//db.SaveChanges();
//return RedirectToAction("Index");
}
}
return View("UsuarioNuevo");
}
I have tried my best however HttpPostedFileBase filee is always null
Controller Action
public ActionResult UploadFile(HttpPostedFileBase filee)
{
try
{
if (filee.ContentLength > 0)
{
string _FileName = Path.GetFileName(filee.FileName);
string _path = Path.Combine(Server.MapPath("~/UploadedFiles"), _FileName);
filee.SaveAs(_path);
}
ViewBag.Message = "File Uploaded Successfully!!";
return View();
}
catch
{
ViewBag.Message = "File upload failed!!";
return View();
}
}
Razor View
#{
ViewBag.Title = "UploadFile";
}
<h2>UploadFile</h2>
#using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
#Html.TextBox("file", "", new { type = "file" }) <br />
<input type="submit" value="Upload" />
#ViewBag.Message
</div>
}
Either change the name of parameter in public ActionResult UploadFile(HttpPostedFileBase filee) to public ActionResult UploadFile(HttpPostedFileBase file) or change the input name #Html.TextBox("file", "", new { type = "file" }) to #Html.TextBox("filee", "", new { type = "file" }).
You have to use same name of yor input field as your HttpPostedFileBase object name while you are working on loosly type view !
Example :
#{
ViewBag.Title = "UploadFile";
}
<h2>UploadFile</h2>
#using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
#Html.TextBox("filee", "", new { type = "file" }) <br />
<input type="submit" value="Upload" />
#ViewBag.Message
</div>
}
Or If you don't want to use same names ?
you just have to use a tightly coupled view type view
Tightly
Example:
#model PROJECTNAME.Models.MODELNAME
#{
ViewBag.Title = "UploadFile";
}
<h2>UploadFile</h2>
#using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
#Html.TextBox(model => model.YOURCOLUMNNAME , "", new { type = "file" }) <br />
<input type="submit" value="Upload" />
#ViewBag.Message
</div>
}
I am having some difficulties in validation of form.
Since I want to populate combobox from database (another table, I'm using viewbags to do this), is there a way to use ComboBoxFor in this case so I could use System.ComponentModel.DataAnnotations and jquery.validate.js?
View:
#model MyProject.OpenAccess.Document
#using (Html.BeginForm("CreateDocument", "Create", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<label>Select file:</label><br />
<input type="file" name="file" /><br />
<label>Filetype</label><br />
#Html.DropDownList("fileType", (IEnumerable<SelectListItem>)ViewBag.ListFiletypes, "-Filetypes", new { #class = "filetype-cb" }) <br />
<input type="submit" value="Add"/>
}
Controller:
public ActionResult CreateDocument(HttpPostedFileBase file, string fileType)
{
if (file != null && file.ContentLength > 0)
{
Document doc = new Document()
{
Filetype = fileType
}
if (this.TryValidateModel(doc))
{
this.dbContext.Add(doc);
this.dbContext.SaveChanges();
id = doc.ID;
//save document using document ID
}
}
}
EDIT:
Here is my current implementation of this:
Layout.cshtml
Remember to add:
<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>
View
#model MyProject.OpenAccess.Document
#using (Html.BeginForm("CreateDocument", "Create", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<label>Select file:</label><br />
<input type="file" data-val="true" data-val-required="Please select a file!" name="file" /><br />
<label>Filetype</label><br />
#Html.DropDownListFor(m => m.FileType, (IEnumerable<SelectListItem>)ViewBag.ListFiletypes, "", new { #class = "filetype-cb" })
<input type="submit" value="Add"/>
}
Controller
[HttpGet]
public ActionResult CreateDocument()
{
ViewBag.ListFiletypes = new SelectList(this.dbContext.ListFiletypes.ToList(), "FileType", "FileType");
//Populate dropdownlist from database
}
[HttpPost]
public ActionResult CreateDocument(HttpPostedFileBase file, Document doc)
{
if (file != null && file.ContentLength > 0)
{
if (this.TryValidateModel(doc))
{
this.dbContext.Add(doc);
this.dbContext.SaveChanges();
id = doc.ID;
//save document using document ID
}
}
}
Model
public partial class Document
{
private int _iD;
public virtual int ID
{
get
{
return this._iD;
}
set
{
this._iD = value;
}
}
private string _fileType;
[Required(ErrorMessage = "Required!")]
public virtual string FileType
{
get
{
return this._fileType;
}
set
{
this._fileType = value;
}
}
}
Is there good reasons to use Viewmodel over Viewbag to populate DropDownListFors (found this from http://www.codeproject.com/Articles/687061/Multiple-Models-in-a-View-in-ASP-NET-MVC-MVC)?
Only problem with this implementation is that I can't validate file on client-side (so user couldn't post empty file).
EDIT: Got this working by just adding:
<input type="file" data-val="true" data-val-required="Please select a file!" name="file" />
Normally you have 3 different parts, which build a proper implementation of your scenario.
The ViewModel:
In a proper implementation, you got for every view its own Viewmodel. In your case that would be something like this:
public class CreateDocumentViewModel
{
[Required]
public IEnumerable<SelectListItem> filetypes { get; set; }
// Maybe some more attributes you need in the view?
}
Note: here you can use the DataAnnotations you want.
The View:
The view contains the actual data in the dropdown.
#model CreateDocumentViewModel
#using (Html.BeginForm("CreateDocument", "Create", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<label>Select file:</label><br />
<input type="file" name="file" /><br />
<label>Filetype</label><br />
#Html.DropDownListFor(model => model.filetypes, model.filetypes, "-Filetypes", new { #class = "filetype-cb" })
<br />
<input type="submit" value="Add"/>
}
The controller:
The controller you need, has 2 actions. A GET- and a POST-action.
[HttpGet]
public ActionResult CreateDocument()
{
CreateDocumentViewModel model = new CreateDocumentViewModel();
model.filetypes = FillFileTypesFromDB; // Here you fill the data for the dropdown!
return View(model);
}
Finally you need the POST-action which saves back to your db.
[HttpPost]
public ActionResult CreateDocument(HttpPostedFileBase file, string fileType)
{
if (file != null && file.ContentLength > 0)
{
Document doc = new Document()
{
Filetype = fileType
}
if (this.TryValidateModel(doc))
{
this.dbContext.Add(doc);
this.dbContext.SaveChanges();
id = doc.ID;
//save document using document ID
}
}
}
I hope I fully understood your problem and it helps solving it.