List<string> Property Mapping is not working - c#

I have a List property (Mac) and I mapped it as follow:
View Model:
public class UserViewModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public virtual IList<string> Mac
{
get
{
return _Mac;
}
set
{
_Mac = value;
}
}
private IList<String> _Mac;
public string MacSerialized
{
get
{
return JsonConvert.SerializeObject(_Mac);
}
set
{
_Mac = JsonConvert.DeserializeObject<IList<string>>(value);
}
}
}
Razor View:
#model RouterManagement.Models.UserViewModel
#{
ViewBag.Title = "Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>Register</h3> <br />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group row">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
#Html.LabelFor(model => model.Email, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
#Html.LabelFor(model => model.Mac, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
<span class="add-new-icon glyphicon glyphicon-plus-sign" id="add_mac"> </span>
#*Html.EditorFor(model => model.Mac, new { htmlAttributes = new { #class = "form-control", #id = "mac_addr" } })*#
#Html.EditorFor(model => model.MacSerialized, new { htmlAttributes = new { #class = "form-control", #id = "mac_addr" } })
#Html.ValidationMessageFor(model => model.MacSerialized, "", new { #class = "text-danger" })
<!-- <input name="Mac" class="form-control" id="mac_addr" /> -->
</div>
</div>
<div class="form-group row new_mac_wrapper">
<div class="col-md-offset-3">
<div class="new_mac_container">
</div>
</div>
</div>
<div class="form-group row">
<div class="col-md-offset-2 col-sm-10 col-md-2">
<input type="submit" value="Register" class="btn btn-primary col-sm-offset-1" />
</div>
</div>
}
And Action:
[HttpPost]
public ActionResult Register(UserViewModel model)
{
CancellationTokenSource cancelToken = new CancellationTokenSource();
AccountRegistrationRequestMessage requerstMessage = new AccountRegistrationRequestMessage();
requerstMessage.FullName = model.Name;
requerstMessage.EmailAddress = model.Email;
requerstMessage.MacAddresses = model.Mac;
requerstMessage.RegistrationType = AccountRegistrationEnum.IndividualAccountRegistration;
Task<AccountRegistrationResponseMessage> response = _interactor.Handle(requerstMessage, cancelToken.Token);
UserViewModel viewModel = _presenter.Handle(response.Result, model, ModelState);
if (response.Result.ValidationResult.IsValid)
{
//return View("DetailView", viewModel);
}
return View(viewModel);
}
When I submit data I am getting the following error:
Rendered form is look like:
Here, extra field of Mac is being created with jquery. Whats wrong in my approach? Don't address me bad as I am new in ASP.Net. Thanks for your time.

Related

ASP.NET core all model values are null when passing a model to the view

Goal: I have a page that I want to have a return url passed through the model of the view so upon completion of the form, it will return to the previous url. The page is a address validation and add it to the account as a saved address.
Flow of the page: You are presented with an address form to fill out. on completion, you will have a button that will call to a controller method that will verify with FedEx via API, and then if valid, it will let you save the address.
Issue: once you press the Verify Address button, it seems to have an issue with sending the form data to the controller.
HTTPGET:
public ActionResult AddShippingAddress(string strReturnURL)
{
// get states
ViewBag.states = GetStates();
DeliveryAddressModel model = new DeliveryAddressModel();
model.strReturnAddress = strReturnURL;
return View(model);
}
AddShippingAddress.chshtml
#model EcommerceWebsite.Models.Home.DeliveryAddressModel
#{
ViewBag.Title = "Shipping Address";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br />
<div class="container">
<partial id="ValidateAddress"></partial>
#using (Html.BeginForm())
{
<h4>Shipping Address</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<h5>Name</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>Attention To</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strAttnTo, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strAttnTo, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>Street</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strStreet1, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strStreet1, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>Street 2</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strStreet2, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strStreet2, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>City</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strCity, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strCity, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#{
IEnumerable<SelectListItem> dataItems = ViewBag.states;
}
<div class="form-group">
<h5>State</h5>
<div class="col-md-10">
#Html.DropDownListFor(model => model.State.IntStateId, dataItems, "-- Select --", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.State.IntStateId, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<h5>Zip</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strZip, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strZip, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>Phone Number</h5>
<div class="col-md-10">
#Html.EditorFor(model => model.strPhoneNumber, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.strPhoneNumber, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<h5>Set as Default</h5>
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.blnIsDefault)
#Html.ValidationMessageFor(model => model.blnIsDefault, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="button" class="btn btn-primary" data-ajax-method="get" data-toggle="ajax-modal"
data-url="#Url.Action("GetValidationOnAddress", new { model = Model })">
Verify Address
</button>
</div>
</div>
}
</div>
<script>
$(function () {
var PlaceHolderElement = $('#ValidateAddress');
$('button[data-toggle="ajax-modal"]').click(function (event) {
event.preventDefault();
var url = $(this).data('url');
// get the form containing the submit button
var form = $(this).closest('form')
// serialize all the fields in the form
var model = form.serialize();
// the the request to the url along with the form (model) data
$.get(url, model).done(function (data) {
PlaceHolderElement.html(data);
PlaceHolderElement.find('.modal').modal('show');
//$('#ValidateAddress').modal('show');
})
})
})
</script>
Here is the partial:
#model EcommerceWebsite.Models.Home.DeliveryAddressModel
<div class="modal fade" id="ValidateAddress">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="ValidateAddressLabel">Validate Address</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
#using (Html.BeginForm("AddShippingAddressToUser", "Home"))
{
#Html.HiddenFor(x => x.strName)
#Html.HiddenFor(x => x.strAttnTo)
#Html.HiddenFor(x => x.strStreet1)
#Html.HiddenFor(x => x.strStreet2)
#Html.HiddenFor(x => x.strCity)
#Html.HiddenFor(x => x.State.StrStateCode)
#Html.HiddenFor(x => x.State.StrStateName)
#Html.HiddenFor(x => x.State.IntStateId)
#Html.HiddenFor(x => x.strZip)
#Html.HiddenFor(x => x.strPhoneNumber)
#Html.HiddenFor(x => x.blnIsDefault)
<div class="modal-body">
<form action="Create">
<div class="form-group">
#if (Model.ErrorMessage == null)
{
<h5>#Model.strName</h5>
#if (Model.strAttnTo != null)
{<h5>#Model.strAttnTo</h5>}
<h5>#Model.strStreet1</h5>
#if (Model.strStreet2 != null)
{<h5>#Model.strStreet2</h5>}
<h5>#Model.strCity</h5>
<h5>#Model.State.StrStateCode</h5>
<h5>#Model.strZip</h5>
<h5>#Model.strPhoneNumber</h5>
<div class="modal-footer">
<button type="submit" value="Save" class="btn btn-primary">Save</button>
<button type="button" value="Edit" class="btn btn-secondary" data-dismiss="modal">Edit</button>
</div>
}
else
{
<h4>#Model.ErrorMessage</h4>
}
</div>
</form>
</div>
}
</div>
</div>
</div>
When all is said and done and the get validation button is pressed, it's supposed to send all the data to the controller and Verify the address with FedEx. But everything is null..
Now something to note, when I change the return of the httpget to return View(); everything works except it doesn't send the URL.
Update:
The AddShippingAddressToUser() hasn't even been called yet. The error lies somewhere in lines 101 - 102. Inside the button or the line 618 on the home controller.
Update: Here's the Model
public class DeliveryAddressModel
{
//[Required]
//[Display(Name = "First & Last Name")]
public string strName { get; set; }
//[Display(Name = "Attention To")]
public string strAttnTo { get; set; }
//[Required]
//[Display(Name = "Street 1")]
public string strStreet1 { get; set; }
//[Display(Name = "Street 2")]
public string strStreet2 { get; set; }
//[Required]
//[Display(Name = "City")]
public string strCity { get; set; }
//[Required]
//[Display(Name = "State")]
public Tstate State { get; set; }
//[Required]
//[Display(Name = "Zipcode")]
public string strZip { get; set; }
//[Required(ErrorMessage = "You must provide a phone number")]
//[Display(Name = "Phone Number")]
//[DataType(DataType.PhoneNumber)]
//[RegularExpression(#"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", ErrorMessage = "Not a valid phone number")]
public string strPhoneNumber { get; set; }
public bool blnIsDefault { get; set; }
public string ErrorMessage { get; set; }
public string strReturnAddress { get; set; }
}
First thing, since your form's function isnt a retrieval operation and a creational operation, use the http verb POST and not GET. Replace the HttpVerb filter above your action from HttpGet to HttpPost.
Second add this:
#using (Html.BeginForm("AddShippingAddressToUser", "Home", FormMethod.Post))
Alternatively,
#using (Html.BeginForm("AddShippingAddressToUser", "Home", FormMethod.Get))
Before your model in the action add: [FromQuery]

Foreign key passing as NULL. ASP .NET MVC

I am try to work on simple School management system using ASP .NET MVC 5 and SQL Server 2012 with database first approach.
The entity of student is related with an entity class, as every student would be enrolled in a class. SO have a 'Class' type variable and FK to the Classes table as attributes of my student entity.
Create View of Student has a dropdown list that shows the classes a student can be enrolled in. The dropdown is getting populated finely enough, but when the student is created and is viewed at the Index view, its class is NULL. When I checked the FK of created Students in Server Management studio, i found that the FK is being passed as NULL.
Can someone please let me know what I am doing wrong here.
PS. I am new to ASP .NET and I am not using a viewmodel because the tutorial I followed didn't and also because I didn't feel the need of making one.
Here is my Student.cs
using System;
using System.Collections.Generic;
public partial class Student
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Student()
{
this.Attendences = new HashSet<Attendence>();
}
public int St_id { get; set; }
public string St_name { get; set; }
public string St_guardian_name { get; set; }
public string St_guardian_relation { get; set; }
public string St_guardian_contact { get; set; }
public string St_address { get; set; }
public System.DateTime St_dob { get; set; }
public Nullable<int> St_cl_fk_id { get; set; }
public int St_status { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Attendence> Attendences { get; set; }
public virtual Class Class { get; set; }
}
Here is my Create Action in the StudentsController. PopulateClassDropDown is a helper method.
private void PopulateClassDropDownList(object selectedClass = null)
{
var classQuery = from c in db.Classes
where c.Cl_status==1
select c;
ViewBag.classID = new SelectList(classQuery, "Cl_id", "Cl_name", selectedClass);
}
[Authorize]
// GET: Students/Create
public ActionResult Create()
{
PopulateClassDropDownList();
return View();
}
// POST: Students/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "St_id,St_name,St_guardian_name,St_guardian_relation,St_guardian_contact,St_address,St_dob,St_cl_fk_id.St_status")] Student student)
{
try
{
var temp = student.St_cl_fk_id;
if (ModelState.IsValid)
{
student.St_status = 1;
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
}
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.");
}
PopulateClassDropDownList(student.St_cl_fk_id);
return View(student);
}
And finally here is the Create View of Student.
#model GMASchoolProject.Models.Student
#{
ViewBag.Title = "Create";
}
<link rel="stylesheet" type="text/css" href="~/Content/Site.css">
<div class="row" style="margin-bottom:5px;">
<div class="col-lg-12">
<h1 class="page-header">Create New Student</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
Fill in Details
</div>
<div class="panel-body">
<div class="row">
<form class="col-lg-6" role="form">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_name, "Student Name", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_name, "Name of Guardian", htmlAttributes: new { #class = "control-label " })
<div>
#Html.EditorFor(model => model.St_guardian_name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_guardian_name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_relation, "Guardian's Relation", htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.St_guardian_relation, new[] {
new SelectListItem() {Text="Parents", Value="Parents" },
new SelectListItem() {Text="Other", Value="Other" }
},"Choose an option", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.St_guardian_relation, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_contact, "Guardian's Contact", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_guardian_contact, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_guardian_contact, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_address, "Student's Address", htmlAttributes: new { #class = "control-label" })
<div>
#Html.TextAreaFor(model=>model.St_address, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_address, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_dob, "Student's Date of Birth", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_dob, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_dob, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
<label class="control-label col-md-2" for="ClassID">Class</label>
<div>
#Html.DropDownList("classID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.St_cl_fk_id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px,0,15px,0;">
<div class="col-md-offset-5 col-md-2">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-danger" })
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Based on this, make these changes:
// classId implies a scalar value, this should be a list
ViewBag.classList = new SelectList(classQuery, "Cl_id", "Cl_name", selectedClass);
// Change your dropdown code:
#Html.DropDownList("St_cl_fk_id", (SelectList)ViewBag.classList, htmlAttributes: new { #class = "form-control" })
// or better yet:
#Html.DropDownListFor(m => m.St_cl_fk_id, (SelectList)ViewBag.classList, new { #class = "form-control" })
// remove this line - it should bind automatically
var temp = student.St_cl_fk_id;

Using a file uploader in an editor template

I'm working with documents. I've got working CRUD for DocumentViewModel - good so far. There will be other models that have documents as properties. I don't want to repeat myself, so I converted my Edit View of DocumentViewModel into an editor template.
Now I'm working on LeaseViewModel, which has a property LeaseDocument of type DocumentViewModel. The scaffolded Create view pulls the editor template in correctly. However, I get a problem in the POST Create method in the controller. All the simple LeaseViewModel properties are populated, and most of the sub-properties on the LeaseDocument property are populated, but DocumentUpload is null. Any thoughts?
View Models:
public class DocumentViewModel
{
#region Properties
public int? ItemID { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
public string Description { get; set; }
[Display(Name = "Version Number")]
public int Version_Number { get; set; }
// TODO: culture code?
[Display(Name = "Document")]
[DataType(System.ComponentModel.DataAnnotations.DataType.Upload)]
public HttpPostedFileBase DocumentUpload { get; set; }
...
}
public class LeaseViewModel
{
#region Properties
public int ItemID { get; set; }
[Display(Name = "Space")]
[Required]
public int SpaceID { get; set; }
[Display(Name = "Status")]
[Required]
public int StatusID { get; set; }
public string StatusText { get; private set; }
[Display(Name = "Type")]
[Required]
public int TypeID { get; set; }
public string TypeText { get; private set; }
public DocumentViewModel LeaseDocument { get; set; }
...
}
Controller:
[Authorize]
public class LeasesController : Controller
{
...
// POST: Lease/Create
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(true)]
public ActionResult Create(LeaseViewModel vm)
{
LeaseItem created = createLeaseVersion(vm);
if (created == null)
return View(vm);
else
return RedirectToAction("Index");
}
...
}
View:
#using CMS.CustomTables;
#using CMS.CustomTables.Types.Tenantportal;
#using CMS.DocumentEngine.Types.Tenantportal;
#model TenantPortal.Models.LeaseViewModel
#{
ViewBag.Title = "Documents";
var emptySpaceOpts = new SelectList(new List<CustomTableItem>(), "ItemID", "Identifier");
var tenantOpts = new SelectList(TenantProvider.GetTenants(), "ItemID", "Display_Name");
var statusOpts = new SelectList(CustomTableItemProvider.GetItems<LeaseStatusItem>(), "ItemID", "Name");
var typeOpts = new SelectList(CustomTableItemProvider.GetItems<LeaseTypeItem>(), "ItemID", "Name");
}
<h2 class="page-title">Create Lease</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.LeaseDocument)
<div class="form-group">
#Html.LabelFor(model => model.SpaceID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SpaceID, emptySpaceOpts, "(select Property)")
#Html.ValidationMessageFor(model => model.SpaceID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.StatusID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.StatusID, statusOpts)
#Html.ValidationMessageFor(model => model.StatusID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TypeID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.TypeID, typeOpts)
#Html.ValidationMessageFor(model => model.TypeID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExecutionDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExecutionDate)
#Html.ValidationMessageFor(model => model.ExecutionDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CommenceDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CommenceDate)
#Html.ValidationMessageFor(model => model.CommenceDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpirationDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpirationDate)
#Html.ValidationMessageFor(model => model.ExpirationDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CanViewCapBudget, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<label>
#Html.RadioButtonFor(model => model.CanViewCapBudget, "true")
Yes
</label>
<label>
#Html.RadioButtonFor(model => model.CanViewCapBudget, "false", htmlAttributes: new { #checked = "checked" })
No
</label>
#Html.ValidationMessageFor(model => model.CanViewCapBudget, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Editor Template for DocumentViewModel
#using TenantPortal.Models
#using CMS.DocumentEngine.Types.Tenantportal
#model DocumentViewModel
#{
var signedOpts = DocumentViewModel.GetSignedOpts();
var propertyOpts = new SelectList(PropertyProvider.GetProperties().Columns("ItemID", "Identifier"), "ItemID", "Identifier");
var tenantOpts = new SelectList(TenantProvider.GetTenants(), "ItemID", "Display_Name");
bool isEdit = ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString() == "Edit";
object uploaderAtts;
int version;
if (isEdit)
{
uploaderAtts = new { #type = "file", #class = "form-control" };
Model.Version_Number += 1;
version = Model.Version_Number;
}
else
{
uploaderAtts = new { #type = "file", #required = "required", #class = "form-control" };
version = 1;
}
}
#Html.HiddenFor(model => model.ItemID)
<div class="form-group row">
<div class="col-sm-12 col-md-6 field">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
<div class="col-sm-12 col-md-6 field">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
<div class="col-sm-12 col-md-6 field">
#Html.LabelFor(model => model.Version_Number, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Version_Number, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly", #Value = version } })
#Html.ValidationMessageFor(model => model.Version_Number, "", new { #class = "text-danger" })
</div>
<div class="col-sm-12 col-md-6 field">
#Html.LabelFor(model => model.DocumentUpload, htmlAttributes: new { #class = "control-label" })
#(isEdit ? Html.Raw(String.Format("<a href='{0}' download='{1}'>{1}</a>", Model.Document_Url, Model.Original_File_Name)) : new HtmlString(""))
#Html.TextBoxFor(model => model.DocumentUpload, uploaderAtts)
#Html.ValidationMessageFor(model => model.DocumentUpload, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
<div class="col-sm-12 col-md-4 field">
#Html.LabelFor(model => model.Signed, htmlAttributes: new { #class = "control-label" })
#Html.DropDownListFor(model => model.Signed, signedOpts, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Signed, "", new { #class = "text-danger" })
</div>
<div class="col-sm-12 col-md-4 field">
#Html.LabelFor(model => model.PropertyID, htmlAttributes: new { #class = "control-label" })
#Html.DropDownListFor(model => model.PropertyID, propertyOpts, "(none)")
#Html.ValidationMessageFor(model => model.PropertyID, "", new { #class = "text-danger" })
</div>
<div class="col-sm-12 col-md-4 field">
#Html.LabelFor(model => model.TenantID, htmlAttributes: new { #class = "control-label" })
#Html.DropDownListFor(model => model.TenantID, tenantOpts, "(none)")
#Html.ValidationMessageFor(model => model.TenantID, "", new { #class = "text-danger" })
</div>
</div>
If your form is sending a file, you have to set its enctype to multipart/form-data
e.g.
#using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
Hth...

Creating a subform to upload update another entity

this is driving me mad because it seems like such a basic thing, and yet I cannot for the life of me google it out...
I have Two Models in the Portfolio Part of my MVC website
public class PortfolioEntry
{
public int ID { get; set; }
[Display(Name="Project Name")]
public string Name { get; set; }
[Display(Name="Created for")]
public string Client { get; set; }
public string Description { get; set; }
[Display(Name ="Started at")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime Start { get; set; }
[Display(Name ="Ended by")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime End { get; set; }
[Display(Name ="Skills used")]
public string Category { get; set; }
[Display(Name ="GitHub Link")]
public string GitHubLink { get; set; }
[Display(Name ="Solution Screenshots")]
public virtual ICollection<ScreenShot> ScreenShots { get; set; }
}
And the second one:
public enum ScreenShotType
{
[Display(Name = "Use case Diagram")]
UseCase,
[Display(Name = "Behaviour Diagram")]
Behavior,
[Display(Name ="Class Diagram")]
ClassStructure,
[Display(Name ="Main View")]
MainPage,
[Display(Name = "Additional View")]
SomthingCool
}
public class ScreenShot
{
public int ID { get; set; }
public string Description { get; set; }
[Display(Name="Screenshot Type")]
public ScreenShotType Type { get; set; }
public string ImageURL { get; set; }
public int Sorting { get; set; }
public int PortfolioEntryID { get; set; }
}
}
Now what I want to do is create a subform that allows me to on the fly Upload a ScreenShot and create a new record in the database for it (you click browse..., select the photo, fill in the info for it and click "Upload").
Then return the "Main" form so I can either upload another one or just save the whole thing altogether.
How should I go about it? I Tried creating a new action in the controller:
public async Task<ActionResult> UploadPhoto([Bind(Include = "ID,Name,Client,Description,Start,End,GitHubLink")] PortfolioEntry portfolioEntry, HttpPostedFileBase uploadedFile, string description, int sorting)
{
if (uploadedFile!=null && uploadedFile.ContentLength>0 && uploadedFile.ContentType.Contains("image"))
{
string extension = Path.GetExtension(uploadedFile.FileName.ToString().ToLower());
string fileName = "PorfolioImage" + String.Format("{0:D5}", db.Photos.Count()) + extension;
var path = Path.Combine(Server.MapPath("~/Pictures/ScreenShots"), fileName);
uploadedFile.SaveAs(path);
var screenshotToAdd = new ScreenShot
{
Description = description,
Sorting = sorting,
PortfolioEntryID = portfolioEntry.ID,
ImageURL = fileName
};
await db.SaveChangesAsync();
}
return(View(portfolioEntry));
}
But:
1. It does not see the uploaded file
2. Even if it did see the file it does not seem to register the Entity from the Bind
I've seen one solution by: mkozicki but before I re-write the methods I'd like to know if it is the path I should take.
Adam
EDIT: As per the follow up adding the View:
#model KoscielniakInfo.Models.PortfolioEntry
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PortfolioEntry</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Client, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Client, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Client, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Start, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Start, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Start, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.End, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.End, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.End, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.GitHubLink, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GitHubLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GitHubLink, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<table>
<tr>
#{
int cnt = 0;
foreach (var category in ViewBag.Categories)
{
if (cnt++ % 3 == 0)
{
#Html.Raw("</tr><tr>")
}
#Html.Raw("<td>")
<input type="checkbox"
name="selectedCategories"
value="#category.Name"
#(Html.Raw(category.Selected ? "checked=\"checked\"" : "")) />
#category.Name
#Html.Raw("</td>")
}
#Html.Raw("</tr>")
}
</table>
</div>
</div>
<div class="form-group">
<div id="newCats" class="col-md-10 col-md-offset-1">
<div id="newCat">
<h5>
New Category
</h5>
<input type="text" name="newCategories" /><br />
</div>
</div>
<div class="col-md-10 col-md-offset-1">
<input id="clone" type="button" value="More Categories" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
#*=================================This is the form Group for adding the photo ============================================*#
<div class="form-group">
<div class="row">
<div class="col-md-offset-2 col-md-3">
Description:
</div>
<div class="col-md-7">
<input type="text" name="description" id="description" />
</div>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-3">
screenType:
</div>
<div class="col-md-7">
<input type="text" name="screenType" />
</div>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-3">
Sorting:
</div>
<div class="col-md-7">
<input type="number" name="sorting" id="sorting" />
</div>
</div>
<div class="row">
<div class="col-md-offset-2 col-md-3">
Image:
</div>
<div class="col-md-7">
<input type="file" name="uploadedFile" />
</div>
<input type="button" value="Create" onclick="location.href='#Url.Action("UploadPhoto", "PorfolioEntries")'" />
</div>
</div>
//=============================================Ends Here =========================================================================
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$('#clone').click(function () {
$('#newCat').last().clone().appendTo('#newCats')
})
</script>
}

Password value missing after POST

So here is some code:
Controller
[HttpGet]
public ActionResult GetSettings()
{
var save = new SettingsSaver();
var dto = save.GetSettings();
var model = new SettingsModel
{
Password = dto.Password,
Port = dto.Port,
Username = dto.Username,
Enabled = dto.Enabled,
Id = dto.Id,
IpAddress = dto.IpAddress,
};
return View(model);
}
[HttpPost]
public ActionResult GetSettings(SettingsModel viewModel)
{
if (ModelState.IsValid)
{
var dto = new SettingsDto
{
IpAddress = viewModel.IpAddress,
Password = viewModel.Password,
Port = viewModel.Port,
Username = viewModel.Username,
Enabled = viewModel.Enabled,
Id = viewModel.Id
};
var save = new SettingsSaver();
var result = save.SaveSettings(dto); //Saves correctly and updates in DB
if (result)
{
return View(); // Returns this
}
return View("Error");
}
return View("Error");
}
View (Default Edit View)
#model Dash.UI.Models.Settings.SettingsModel
#{
ViewBag.Title = "Settings";
}
<h2>Settings</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Settings</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.Enabled, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Enabled)
#Html.ValidationMessageFor(model => model.Enabled, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IpAddress, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IpAddress, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.IpAddress, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Port, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Port, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Port, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Username, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Username, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Username, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Password, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</div>
</div>
<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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So, what the problem is when I update the model and POST to GetSettings it all works correctly, updates in the db etc. but on the return View() it does not hit the GetSettings() action method, but it returns the view with all of the model filled in except the password.
Model
public class SettingsModel : BaseSettingsViewModel // Base contains ID and Enabled properties with no data annotations
{
[Required]
[DataType(DataType.Text)]
[DisplayName("IP Address")]
public string IpAddress { get; set; }
[Required]
[DisplayName("Port")]
public int Port { get; set; }
[Required]
[DataType(DataType.Text)]
[DisplayName("Username")]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Password")]
public string Password { get; set; }
}
Any advise/guidance would be much appreciated.
Upon returning the same view from a POST, the ModelState will fill in the controls (apart from the password fields) from the posted values.
So you need a Post-Redirect-Get pattern:
if (result)
{
return RedirectToAction("GetSettings");
}

Categories