file upload does not work in IE 8, IE 9 - asp.net-mvc-3

i have the following code to upload a file, which runs without error in mozilla firefox and google chrome but gives error in IE 8. Please provide solution. This is my view-
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<div class="input_panelleft">
<div class="input_panellabel">
#Html.LabelFor(model => model.DrawingName)
</div>
<div class="input_panelinput">
#Html.EditorFor(model => model.DrawingName)
</div>
<div class="input_panellabel">
Upload Drawing
</div>
<div class="input_panelinput">
<input type="file" name='file' id='file' />
</div>
<div class="center">
<input type="submit" value="Upload" />
</div>
</div>
</fieldset>
}
and following code in controller-
[HttpPost]
public ActionResult Create(DrawingDocumentsModel model, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (file != null)
{
var documentNameParts = file.FileName.Split('.');
var documentExtension = documentNameParts.Last();
var documentNameOnly = String.Join(".", documentNameParts.Take(documentNameParts.Length - 1));
var filename = documentNameOnly + "." + documentExtension;
if (_drawingDocumentService.IsDrawingNameAvailable(filename))
{
var path = Server.MapPath("~/Uploads/");
var Filepath = Path.Combine(path, filename);
file.SaveAs(Filepath);
var drawingDocuments = new DrawingDocuments();
drawingDocuments.ProjectId = 1;
drawingDocuments.ProjectName = "Drawing Tag";
drawingDocuments.FileName = filename;
drawingDocuments.UploadedDate = System.DateTime.Now;
drawingDocuments.UploadedBy = _workContext.CurrentUserId;
if (model.DrawingName == "" || model.DrawingName == null)
{
ModelState.AddModelError("CustomError", "Please Enter Drawing Name");
}
else
{
drawingDocuments.DrawingName = model.DrawingName;
drawingDocuments.Path = ("/Uploads/" + filename);
_drawingDocumentService.InsertDrawingDocument(drawingDocuments);
return RedirectToAction("DrawingDocuments");
}
}
else
{
ModelState.AddModelError("CustomError", "Drawing With Same File Name Already Available");
}
}
else
{
ModelState.AddModelError("CustomError", "Please Select Drawing");
}
}
return View(model);
}

Related

Bind multiple Dropdowns and retrieve user selction at postback

I'm working on an MVC Core form where a requester has to define some approvers for his application. When preparing the model for the Get request, I first get the roles for the approvers. Currently, there are always four roles returned:
Category Head
Governance Head
Concessions VP
Commercial EVP
And here is the HttpGet:
[HttpGet]
public async Task<IActionResult> Create()
{
// omitted for brevity...
// Get the SystemRole models (4 models will be returned)
model.ApprovingRoles = (await serviceLookup.GetAllRolesAsync(ct)).ToList();
}
The SystemRoleModel is simply:
public class SystemRoleModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
The view is composed of EditorTemplate as follows:
Create.cshtml -> LetterEditor.cshtml -> LetterAttachmentEditor.cshtml
Create.cshtml:
#model LetterModel
#{
ViewData["Title"] = "Create RL";
}
#Html.EditorFor(m => m, "LetterEditor", new { ShowApprovers = "1", ShowAttachments = "1", ShowButtons = "1" } )
LetterEditor.cshtml:
#model LetterModel
...
<div class="panel-body">
#await Html.PartialAsync("EditorTemplates/LetterAttachmentEditor", new LetterAttachmentUploadViewModel { IsBusy = false, LetterGuid = Model.IdCode.ToString() })
</div>
...
And finally, LetterAttachmentEditor.cshtml:
#model IList<SystemRoleModel>
#for (var i = 0; i < Model.Count; i++)
{
var index = i;
var title = Model[index].Name;
<div class="row">
<div class="col-lg-2 mt-3">
#Html.Label("LetterApprover[" + index + "]", title, new { #class = "control-label" })
</div>
<div class="col-lg-4">
#(Html.Kendo().DropDownList().Name("LetterApprover[" + index + "]")
.DataValueField(nameof(SystemUserModel.Id))
.DataTextField(nameof(SystemUserModel.EmployeeName))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsersByRoleId", "Api", new { roleId = Model[index].Id });
}).ServerFiltering(true);
})
)
</div>
<div class="col-lg-6">
<span asp-validation="" class="text-danger"></span>
#Html.ValidationMessage("LetterApprover[" + index + "]", $"An approver as a {title} is required", new { #class = "text-danger" })
</div>
</div>
}
Also, LetterModel.cs:
public class LetterModel
{
public LetterModel()
{
Approvers = new List<LetterApproverModel>();
}
// omitted for brevity...
public IList<SystemRoleModel> ApprovingRoles { get; set; } = new List<SystemRoleModel>();
}
Now, with that all out of the way, here is the final rendered dropdown (minus the kendo fluff):
<input id="ApprovingRoles_LetterApprover_0_" name="ApprovingRoles.LetterApprover[0]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_1_" name="ApprovingRoles.LetterApprover[1]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_2_" name="ApprovingRoles.LetterApprover[2]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_3_" name="ApprovingRoles.LetterApprover[3]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
If the user submits this form, I need to receive a list of selected IDs from this array of dropdowns. I followed an anti-pattern, so I'm hoping the MVC binding will do its magic here. I just need to figure out the name of the model property that I should add of type List<string>.
How about try to change the name into name="LetterApprover[0]" and name="LetterApprover[1]" and name="LetterApprover[2]" and name="LetterApprover[3]" .
Then you could bind to List<string> LetterApprover
Update
Name is auto-appended by MVC due to sub-editor
How about add js codes to change the input name when you submit the form?
I try it like below, I first add class="form-control" to dropdownlist, add id="save" to button, then:
<script>
var items = document.getElementsByClassName("form-control");
$('#save').click(function () {
for (var i = 0; i < items.length; i++)
{
items[i].setAttribute("name", "LetterApprover")
}
});
</script>
Then bind to List<string> LetterApprover.
I was able to bind the selected values to a model's property upon submission by modifying the prefix added by the MVC engine:
#using DACRL.Domain.Models.BusinessObjects
#model IList<DACRL.Domain.Models.BusinessObjects.SystemRoleModel>
#{
ViewData.TemplateInfo.HtmlFieldPrefix = "";
}
#for (var i = 0; i < Model.Count; i++)
{
var index = i;
var name = "SelectedApprover[" + index + "]";
var title = Model[index].Name;
<div class="row">
<div class="col-lg-2 mt-2">
#Html.Label(name, title, new { #class = "control-label" })
</div>
<div class="col-lg-4">
#(Html.Kendo().DropDownList().Name(name)
.Size(ComponentSize.Medium).Rounded(Rounded.Medium).FillMode(FillMode.Outline)
.HtmlAttributes(new { style = "width: 100%" })
.DataValueField(nameof(SystemUserModel.Identifier))
.DataTextField(nameof(SystemUserModel.EmployeeName))
.OptionLabel("Select " + title).Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsersByRoleId", "Api", new { roleId = Model[index].Id, sequence = index + 1 });
}).ServerFiltering(true);
})
.Height(500))
</div>
<div class="col-lg-6">
<span asp-validation="" class="text-danger"></span>
#Html.ValidationMessage(name, $"An approver as a {title} is required", new { #class = "text-danger mt-2" })
</div>
</div>
}
The line ViewData.TemplateInfo.HtmlFieldPrefix = ""; allowed me to control the naming and the binding started workinfg

Multi Select Values Not Saving on User Create

I am trying to save a multi select list on my user create in MVC 5, but the values are not saving. Values are saving only in edit. For some reason it's not working on create and it seems the issue is tied to the identity user. I have the same method implemented in a different controller for another entity and it's working fine.
I am trying to assign multiple health professionals to a user in the below code. I am not getting any errors or a break on save, it just doesn't save the values.
Can anyone please have a look at my code and give me a solution to this problem.
Here is my controller code relevant to creating a user:
public ActionResult Create()
{
PopulateDepartmentsDropDownList();
PopulateSuperiorsDropDownList();
// Show a list of available groups:
ViewBag.GroupsList = new SelectList(this.GroupManager.Groups, "Id", "Name");
var applicationUser = new ApplicationUser();
applicationUser.HealthProfessionals = new List<HealthProfessional>();
PopulateAssignedHealthProfessionals(applicationUser);
return View();
}
[HttpPost]
public async Task<ActionResult> Create([Bind(Exclude = "ProfilePicture")]RegisterViewModel userViewModel, ApplicationUser applicationUser, string[] selectedHealthProfessionals, params string[] selectedGroups)
{
if (selectedHealthProfessionals != null)
{
applicationUser.HealthProfessionals = new List<HealthProfessional>();
foreach (var healthProfessional in selectedHealthProfessionals)
{
var healthProfessionalToAdd = db.HealthProfessionals.Find(int.Parse(healthProfessional));
applicationUser.HealthProfessionals.Add(healthProfessionalToAdd);
}
}
if (ModelState.IsValid)
{
// To convert the user uploaded Photo as Byte Array before save to DB
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];
using (var binary = new BinaryReader(poImgFile.InputStream))
{
imageData = binary.ReadBytes(poImgFile.ContentLength);
}
}
var user = new ApplicationUser
{
UserName = userViewModel.Email,
FirstName = userViewModel.FirstName,
LastName = userViewModel.LastName,
Position = userViewModel.Position,
DepartmentID = userViewModel.DepartmentID,
SuperiorID = userViewModel.SuperiorID,
OfficeNumber = userViewModel.OfficeNumber,
CellNumber = userViewModel.CellNumber,
Email = userViewModel.Email
};
//Here we pass the byte array to user context to store in db
user.ProfilePicture = imageData;
var adminresult = await UserManager
.CreateAsync(user, userViewModel.Password);
//Add User to the selected Groups
if (adminresult.Succeeded)
{
if (selectedGroups != null)
{
selectedGroups = selectedGroups ?? new string[] { };
await this.GroupManager
.SetUserGroupsAsync(user.Id, selectedGroups);
}
return RedirectToAction("Users");
}
}
ViewBag.Groups = new SelectList(await RoleManager.Roles.ToListAsync(), "Id", "Name");
PopulateDepartmentsDropDownList(userViewModel.DepartmentID);
PopulateSuperiorsDropDownList(userViewModel.SuperiorID);
PopulateAssignedHealthProfessionals(applicationUser);
return View(applicationUser);
}
private void PopulateAssignedHealthProfessionals(ApplicationUser applicationUser)
{
var allHealthProfessionals = db.HealthProfessionals;
var userHealthProfessionals = new HashSet<int>(applicationUser.HealthProfessionals.Select(i => i.HealthProfessionalID));
var viewModel = new List<AssignedHealthProfessionals>();
foreach (var healthProfessional in allHealthProfessionals)
{
viewModel.Add(new AssignedHealthProfessionals
{
HealthProfessionalID = healthProfessional.HealthProfessionalID,
HealthProfessionalName = healthProfessional.Name,
HealthProfessionalSurname = healthProfessional.Surname,
Assigned = userHealthProfessionals.Contains(healthProfessional.HealthProfessionalID)
});
}
ViewBag.HealthProfessionals = viewModel;
}
Here is my create view:
#model MyApp.Models.RegisterViewModel
#{
ViewBag.Title = "Create User";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<link href="#Url.Content("~/Content/CSS/dropify.min.css")" rel="stylesheet" type="text/css" />
<div class="m-grid__item m-grid__item--fluid m-wrapper">
<div class="m-subheader ">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title m-subheader__title--separator">
Add User
</h3>
<ul class="m-subheader__breadcrumbs m-nav m-nav--inline">
<li class="m-nav__item m-nav__item--home">
<a href="#Url.Action("Dashboard","Home")" class="m-nav__link m-nav__link--icon">
<i class="m-nav__link-icon la la-home"></i>
</a>
</li>
<li class="m-nav__separator">
-
</li>
<li class="m-nav__item">
<a href="#Url.Action("Users","UserManagement")" class="m-nav__link">
<span class="m-nav__link-text">
Users
</span>
</a>
</li>
</ul>
</div>
<div>
</div>
</div>
</div>
#using (Html.BeginForm("Create", "UserManagement", FormMethod.Post, new { #class = "m-form m-form--fit m-form--label-align-right", role = "form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="m-content">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
User Details
</h3>
</div>
</div>
</div>
<div class="m-portlet__body">
<div class="m-form__section m-form__section--first">
<div class="row">
<div class="col-lg-4">
<div class="form-group">
<label>
Email Address
</label>
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label>
First Name
</label>
#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label>
Last Name
</label>
#Html.TextBoxFor(m => m.LastName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.LastName, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-lg-4">
<div class="form-group">
<label>
Position
</label>
#Html.TextBoxFor(m => m.Position, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Position, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label>
Department
</label>
#Html.DropDownList("DepartmentID", null, "Choose Department", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.DepartmentID, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label>
Superior
</label>
#Html.DropDownList("SuperiorID", null, "Choose Superior", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.SuperiorID, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>
Password
</label>
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>
Confirm Password
</label>
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.ConfirmPassword, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>
Office Number
</label>
#Html.TextBoxFor(m => m.OfficeNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.OfficeNumber, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>
Cell Number
</label>
#Html.TextBoxFor(m => m.CellNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.CellNumber, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label>
User Groups
</label>
<div class="m-checkbox-list">
#foreach (var item in (SelectList)ViewBag.GroupsList)
{
<label class="m-checkbox m-checkbox--success">
<input type="checkbox" name="selectedGroups" value="#item.Value">
#Html.Label(item.Text, new { #class = "control-label" })
<span></span>
</label>
}
</div>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label>
Health Professionals
</label>
<div class="m-checkbox-list">
#{
int cnt = 0;
List<MyApp.ViewModels.AssignedHealthProfessionals> healthProfessionals = ViewBag.HealthProfessionals;
foreach (var healthProfessional in healthProfessionals)
{
if (cnt++ % 3 == 0)
{
}
<label class="m-checkbox m-checkbox--success">
<input type="checkbox" name="selectedHealthProfessionals" value="#healthProfessional.HealthProfessionalID" #(Html.Raw(healthProfessional.Assigned ? "checked=\"checked\"" : ""))>
#Html.Label(healthProfessional.HealthProfessionalName, new { #class = "control-label" }) #Html.Label(healthProfessional.HealthProfessionalSurname, new { #class = "control-label" })
<span></span>
</label>
}
}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label>
Profile Picture
</label>
<input type="file" name="UserPhoto" id="fileUpload" accept=".png,.jpg,.jpeg,.gif,.tif" class="dropify" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="m-portlet__body">
<!-- Form Actions Start -->
<div class="m-portlet">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
Actions
</h3>
</div>
</div>
</div>
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions">
<input type="submit" class="btn btn-accent m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill" value="Save" />
#Html.ActionLink("Cancel", "Users", null, new { #class = "btn m-btn--pill m-btn--air btn-brand m-btn m-btn--custom" })
</div>
</div>
</div>
<!-- Form Actions End -->
</div>
</div>
}
</div>
<script src="#Url.Content("~/Scripts/jquery.min.js")"></script>
<script src="#Url.Content("~/Scripts/dropify.min.js")"></script>
<script>
$(document).ready(function () {
// Basic
$('.dropify').dropify();
// Translated
$('.dropify-fr').dropify({
messages: {
default: 'Glissez-déposez un fichier ici ou cliquez',
replace: 'Glissez-déposez un fichier ou cliquez pour remplacer',
remove: 'Supprimer',
error: 'Désolé, le fichier trop volumineux'
}
});
// Used events
var drEvent = $('#input-file-events').dropify();
drEvent.on('dropify.beforeClear', function (event, element) {
return confirm("Do you really want to delete \"" + element.file.name + "\" ?");
});
drEvent.on('dropify.afterClear', function (event, element) {
alert('File deleted');
});
drEvent.on('dropify.errors', function (event, element) {
console.log('Has Errors');
});
var drDestroy = $('#input-file-to-destroy').dropify();
drDestroy = drDestroy.data('dropify')
$('#toggleDropify').on('click', function (e) {
e.preventDefault();
if (drDestroy.isDropified()) {
drDestroy.destroy();
} else {
drDestroy.init();
}
})
});
</script>
Here is the controller for the edit function which works:
public async Task<ActionResult> Edit(int id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ApplicationUser applicationUser = db.Users.Include(h => h.HealthProfessionals).Where(h => h.Id == id).Single();
PopulateAssignedHealthProfessionals(applicationUser);
var user = await UserManager.FindByIdAsync(id);
if (user == null)
{
return HttpNotFound();
}
// Display a list of available Groups:
var allGroups = this.GroupManager.Groups;
var userGroups = await this.GroupManager.GetUserGroupsAsync(id);
var model = new EditUserViewModel()
{
Id = user.Id,
Email = user.Email,
FirstName = user.FirstName,
LastName = user.LastName,
Position = user.Position,
DepartmentID = user.DepartmentID,
SuperiorID = user.SuperiorID,
OfficeNumber = user.OfficeNumber,
CellNumber = user.CellNumber
};
foreach (var group in allGroups)
{
var listItem = new SelectListItem()
{
Text = group.Name,
Value = group.Id,
Selected = userGroups.Any(g => g.Id == group.Id)
};
model.GroupsList.Add(listItem);
}
PopulateDepartmentsDropDownList(user.DepartmentID);
PopulateSuperiorsDropDownList(user.SuperiorID);
return View(model);
}
private void PopulateAssignedHealthProfessionals(ApplicationUser applicationUser)
{
var allHealthProfessionals = db.HealthProfessionals;
var userHealthProfessionals = new HashSet<int>(applicationUser.HealthProfessionals.Select(i => i.HealthProfessionalID));
var viewModel = new List<AssignedHealthProfessionals>();
foreach (var healthProfessional in allHealthProfessionals)
{
viewModel.Add(new AssignedHealthProfessionals
{
HealthProfessionalID = healthProfessional.HealthProfessionalID,
HealthProfessionalName = healthProfessional.Name,
HealthProfessionalSurname = healthProfessional.Surname,
Assigned = userHealthProfessionals.Contains(healthProfessional.HealthProfessionalID)
});
}
ViewBag.HealthProfessionals = viewModel;
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Email,Id,FirstName,LastName,Position,DepartmentID,SuperiorID,OfficeNumber,CellNumber", Exclude = "ProfilePicture")] EditUserViewModel editUser, ApplicationUser applicationUser, int? id, string[] selectedHealthProfessionals, params string[] selectedGroups)
{
if (ModelState.IsValid)
{
// To convert the user uploaded Photo as Byte Array before save to DB
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase poImgFile = Request.Files["UserPhoto"];
using (var binary = new BinaryReader(poImgFile.InputStream))
{
imageData = binary.ReadBytes(poImgFile.ContentLength);
}
}
var user = await UserManager.FindByIdAsync(editUser.Id);
if (user == null)
{
return HttpNotFound();
}
var applicationUserToUpdate = db.Users.Include(h => h.HealthProfessionals).Where(h => h.Id == id).Single();
if (TryUpdateModel(applicationUserToUpdate, "",
new string[] { }))
{
try
{
UpdateUserHealthProfessionals(selectedHealthProfessionals, applicationUserToUpdate);
db.SaveChanges();
return RedirectToAction("Users");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
PopulateAssignedHealthProfessionals(applicationUserToUpdate);
// Update the User:
user.UserName = editUser.Email;
user.Email = editUser.Email;
user.FirstName = editUser.FirstName;
user.LastName = editUser.LastName;
user.Position = editUser.Position;
user.DepartmentID = editUser.DepartmentID;
user.SuperiorID = editUser.SuperiorID;
user.OfficeNumber = editUser.OfficeNumber;
user.CellNumber = editUser.CellNumber;
//Here we pass the byte array to user context to store in db
user.ProfilePicture = imageData;
await this.UserManager.UpdateAsync(user);
// Update the Groups:
selectedGroups = selectedGroups ?? new string[] { };
await this.GroupManager.SetUserGroupsAsync(user.Id, selectedGroups);
return RedirectToAction("Users");
}
ModelState.AddModelError("", "Something failed.");
PopulateDepartmentsDropDownList(editUser.DepartmentID);
PopulateSuperiorsDropDownList(editUser.SuperiorID);
return View();
}
It's something strange with parameters in your methods.
Best way is to pass user object as parameter.
https://stackoverflow.com/a/18005264/2114398
For quick fix you can update multi-select parameter manually, by removing selectedHealthProfessionals and selectedGroups parameters from method and then initialize them as local variables
[HttpPost]
public async Task<ActionResult> Create([Bind(Exclude = "ProfilePicture")]RegisterViewModel userViewModel, ApplicationUser applicationUser)
{
var selectedGroups = (Request.Form["selectedGroups"] ?? "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
var selectedHealthProfessionals = (Request.Form["selectedHealthProfessionals"] ?? "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
applicationUser.HealthProfessionals = new List<HealthProfessional>();
foreach (var healthProfessional in selectedHealthProfessionals)
{
var healthProfessionalToAdd = db.HealthProfessionals.Find(int.Parse(healthProfessional));
applicationUser.HealthProfessionals.Add(healthProfessionalToAdd);
}
if (ModelState.IsValid)
{
...

Ajax.BeginForm only displaying partial View instead of parent & partial view on return

I have a parent View & a child View.
When posing with the Ajax.BeginForm, I'm expecting back the entire parent view plus the results of the partial view updated. Only the results of the partial view is displayed.
In addition, the "OnSuccess" method doesn't seem to be getting hit as I'm debugging.
Can someone please tell me what I'm doing incorrecty?
Controller:
public class HomeController : Controller
{
private DAL db = new DAL();
public ActionResult Index()
{
ViewBag.Message = "Welcome to YeagerTech!";
return View();
}
// GET: Categories/Create
public ActionResult Create()
{
return View();
}
// POST: Categories/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(Category category)
{
if (ModelState.IsValid)
{
try
{
await db.AddCategoryAsync(category);
}
catch (System.Exception ex)
{
throw ex;
}
}
return View(category);
}
public PartialViewResult ShowDetails()
{
//string code = Request.Form["txtCode"];
Category cat = new Category();
//foreach (Product p in prodList)
//{
// if (p.ProdCode == code)
// {
// prod = p;
// break;
// }
//}
cat.CategoryID = 1;
cat.Description = "Financial";
return PartialView("_ShowDetails", cat);
}
}
Parent View
#model Models.Models.Category
#{
ViewBag.Title = "Create Category";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create Category</h2>
#using (Ajax.BeginForm("ShowDetails", "Home", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "div1",
InsertionMode = InsertionMode.Replace,
OnSuccess = "OnSuccess",
OnFailure = "OnFailure"
}, new { #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="body-content">
<h4>Category</h4>
<hr />
<div class="form-group">
<div class="col-offset-1 col-lg-11 col-md-11 col-sm-11 col-xs-11">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control", #placeholder = "Description" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-lg-11 col-md-11 col-sm-11 col-xs-11">
<button type="submit" id="btnCategoryCreate" class="btn btn-primary"><span class="glyphicon glyphicon-save"></span>Create</button>
</div>
</div>
</div>
}
<div id="div1">
</div>
#*<div>
#Html.ActionLink("Back to List", "Index")
#Html.Hidden("categoryCreateUrl", Url.Action("Create", "Home"))
</div>*#
#section Scripts {
<script>
$(document).ready(function ()
{
function OnSuccess(response)
{
$('#form1').trigger("reset");
}
//if (typeof contentCreateCategory == "function")
// contentCreateCategory();
});
</script>
}
Partial View
#model Models.Models.Category
<h1>Cat Details</h1>
<h2>
Cat Code: #Model.CategoryID<br />
Cat Name: #Model.Description<br />
</h2>
EDIT # 1
Parent & child view displayed (due to a missing JS file, thanks to the mention of Stephen), plus was able to programmatically clear out the form with the OnSuccess method.
I had thought since that was JS, it needed to go in the Scripts section, but did not recognize it there.
Here is the finished code.
#using (Ajax.BeginForm("ShowDetails", "Home", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "div1",
InsertionMode = InsertionMode.Replace,
OnSuccess = "OnSuccess",
OnFailure = "OnFailure"
}, new { #id = "frm1", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="body-content">
<h4>Category</h4>
<hr />
<div class="form-group">
<div class="col-offset-1 col-lg-11 col-md-11 col-sm-11 col-xs-11">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control", #placeholder = "Description" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-lg-11 col-md-11 col-sm-11 col-xs-11">
<button type="submit" id="btnCategoryCreate" class="btn btn-primary"><span class="glyphicon glyphicon-save"></span>Create</button>
<button type="reset" id="btnClear" class="btn btn-default"><span class="glyphicon glyphicon-eye-close"></span>Clear</button>
</div>
</div>
</div>
}
<div id="div1">
</div>
<script type="text/javascript">
function OnSuccess(response)
{
$('#frm1').trigger("reset");
}
function OnFailure(response)
{
alert("Whoops! That didn't go so well did it?");
}
</script>
A bit late for answer, but yet it might help someone else.
The issue might be that the javascript files required for Ajax.BeginForm are not loaded in your page.
Microsoft.jQuery.Unobtrusive.Ajax
Nuget package to search for
<package id="Microsoft.jQuery.Unobtrusive.Ajax" version="3.2.3" targetFramework="net45" />
of course that the version might differ.
Add reference to the page after your jQuery and it should work.

Uploading/Displaying Images in MVC 4

Anyone know of any step by step tutorials on how to upload/display images from a database using Entity Framework? I've checked out code snippets, but I'm still not clear on how it works. I have no code, because aside from writing an upload form, I'm lost. Any (and I mean any) help is greatly appreciated.
On a sidenote, why don't any books cover this topic? I have both Pro ASP.NET MVC 4 and Professional MVC4, and they make no mention of it.
Have a look at the following
#using (Html.BeginForm("FileUpload", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<label for="file">Upload Image:</label>
<input type="file" name="file" id="file" style="width: 100%;" />
<input type="submit" value="Upload" class="submit" />
}
your controller should have action method which would accept HttpPostedFileBase;
public ActionResult FileUpload(HttpPostedFileBase file)
{
if (file != null)
{
string pic = System.IO.Path.GetFileName(file.FileName);
string path = System.IO.Path.Combine(
Server.MapPath("~/images/profile"), pic);
// file is uploaded
file.SaveAs(path);
// save the image path path to the database or you can send image
// directly to database
// in-case if you want to store byte[] ie. for DB
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
byte[] array = ms.GetBuffer();
}
}
// after successfully uploading redirect the user
return RedirectToAction("actionname", "controller name");
}
Update 1
In case you want to upload files using jQuery with asynchornously, then try this article.
the code to handle the server side (for multiple upload) is;
try
{
HttpFileCollection hfc = HttpContext.Current.Request.Files;
string path = "/content/files/contact/";
for (int i = 0; i < hfc.Count; i++)
{
HttpPostedFile hpf = hfc[i];
if (hpf.ContentLength > 0)
{
string fileName = "";
if (Request.Browser.Browser == "IE")
{
fileName = Path.GetFileName(hpf.FileName);
}
else
{
fileName = hpf.FileName;
}
string fullPathWithFileName = path + fileName;
hpf.SaveAs(Server.MapPath(fullPathWithFileName));
}
}
}
catch (Exception ex)
{
throw ex;
}
this control also return image name (in a javascript call back) which then you can use it to display image in the DOM.
UPDATE 2
Alternatively, you can try Async File Uploads in MVC 4.
Here is a short tutorial:
Model:
namespace ImageUploadApp.Models
{
using System;
using System.Collections.Generic;
public partial class Image
{
public int ID { get; set; }
public string ImagePath { get; set; }
}
}
View:
Create:
#model ImageUploadApp.Models.Image
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm("Create", "Image", null, FormMethod.Post,
new { enctype = "multipart/form-data" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Image</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ImagePath)
</div>
<div class="editor-field">
<input id="ImagePath" title="Upload a product image"
type="file" name="file" />
</div>
<p><input type="submit" value="Create" /></p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Index (for display):
#model IEnumerable<ImageUploadApp.Models.Image>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.ImagePath)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ImagePath)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Ajax.ActionLink("Delete", "Delete", new {id = item.ID} })
</td>
</tr>
}
</table>
Controller (Create)
public ActionResult Create(Image img, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (file != null)
{
file.SaveAs(HttpContext.Server.MapPath("~/Images/")
+ file.FileName);
img.ImagePath = file.FileName;
}
db.Image.Add(img);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(img);
}
Hope this will help :)
<input type="file" id="picfile" name="picf" />
<input type="text" id="txtName" style="width: 144px;" />
$("#btncatsave").click(function () {
var Name = $("#txtName").val();
var formData = new FormData();
var totalFiles = document.getElementById("picfile").files.length;
var file = document.getElementById("picfile").files[0];
formData.append("FileUpload", file);
formData.append("Name", Name);
$.ajax({
type: "POST",
url: '/Category_Subcategory/Save_Category',
data: formData,
dataType: 'json',
contentType: false,
processData: false,
success: function (msg) {
alert(msg);
},
error: function (error) {
alert("errror");
}
});
});
[HttpPost]
public ActionResult Save_Category()
{
string Name=Request.Form[1];
if (Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
}
}

MVC3 - When using HttpPostedFileBase with large files, RedirectToAction is very slow

Okay, I have a situation that seems to make no sense. I have a controller thus:
public ActionResult Index()
{
return View(_courseService.ListAllCourses());
}
[HttpPost]
public ActionResult CreateNewCourse(CourseVDO course, HttpPostedFileBase CourseDataFile)
{
return RedirectToAction("Index");
}
And a View thus:
#using (Html.BeginForm("CreateNewCourse", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(false)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
Course Data File
</div>
<div class="editor-field">
<input type="file" name="CourseDataFile" id="CourseDataFile" />
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Visible)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Visible)
#Html.ValidationMessageFor(model => model.Visible)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
When I submit a file of around 200KB, it uploads to the server fast enough (it's local after all), but then takes 5 seconds to go from the "return RedirectToAction("Index"); " line back to the breakpoint on the "return View(_courseService.ListAllCourses());" line (not actually executing the ListAllCourses). This means it's entirely down to the internal plumbing. Worse, this delay scales with file size. What on earth is going on, and how can I stop it?
Thanks
I have never used that method before, and this is no direct answer, but maybe its a better solution:
// used when editing an item
public void UploadFiles(FormCollection form, NameValueCollection currentFiles, string folder, bool useTicks)
{
foreach (string file in Request.Files)
{
var hpf = Request.Files[file];
if (hpf.ContentLength == 0)
{
form[file] = currentFiles[file];
}
else
{
var filename = useTicks ? hpf.FileName
.Replace(" ", "_")
.Replace(".", RandomFileName() + ".") : hpf.FileName;
var myPath = Server.MapPath("~/Content/" + folder);
hpf.SaveAs(myPath + "/" + filename);
form[file] = filename;
}
}
if (Request.Files.Count > 0) return;
foreach (var file in currentFiles.AllKeys)
{
form[file] = currentFiles[file];
}
}
//used when creating a new item
public void UploadFiles(FormCollection form, string folder, bool useTicks)
{
foreach (string file in Request.Files)
{
var hpf = Request.Files[file];
if (hpf.ContentLength == 0)
{
form[file] = null;
}
else
{
var filename = "";
filename = useTicks ?
hpf.FileName.Replace(" ", "_").Replace(".", RandomFileName() + ".") :
hpf.FileName;
UploadFileName = filename;
var myPath = Server.MapPath("~/Content/" + folder);
hpf.SaveAs(myPath + "/" + filename);
form[file] = UploadFileName;
}
}
}
I use models so in my model item i use the UIHint("uploadbox")
here is the code inside views/Shared/EditorTemplates/UploadField.cshtml
#Html.TextBox("",null,new{type="File"})
here is an example of the usage of the upload feature:
public ActionResult AddFiles(FormCollection form, SomeModel myModel)
{
UploadFiles(form,"products", true);
myModel.pdfFile = form["pdffile"];
myModel.thumbnail = form["thumbnail"];
here is the code when editing the item, in case the file was not changed, but others items have
var existingFile = ctx2.modelname.SingleOrDefault(x => x.Id == id).Filename;
NameValueCollection myCol = new NameValueCollection();
myCol.Add("Filename", existingFile);
UploadFiles(form, myCol, "uploads/custom", true);
myModel.Filename = form["Filename"];
just a thought :-)

Resources