HttpPostedFileBase ImageUpload is always null in asp.net mvc 5 - c#

I try to create a project in aps.net mvc 5, but I can't save an image in my local directory... The attribute: (HttpPostedFileBase ImageUpload) of my entity (Perfil), is always null translating to English: Profile = Perfil
Can someone help me please?
. My Entity:
[Table("Perfil")]
public class Perfil
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int idPerfil { get; set; }
[Required]
[ForeignKey("Usuario")]
public int idUsuario { get; set; }
[Required]
[ForeignKey("Genero")]
public int idGenero { get; set; }
[DisplayName("Descrição:")]
public string descricao { get; set; }
public string linkMultimidia { get; set; }
[DataType(DataType.ImageUrl)]
public string ImageUrl { get; set; }
[DataType(DataType.Upload)]
[NotMapped]
public HttpPostedFileBase ImageUpload { get; set; }
public virtual Usuario Usuario { get; set; }
public virtual Genero Genero { get; set; }
}
}
My Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "idPerfil,idUsuario,idGenero,descricao,linkMultimidia,fotoPerfil")] Perfil perfil)
{
var validImageTypes = new string[]
{
"image/gif",
"image/jpeg",
"image/pjpeg",
"image/png"
};
if (perfil.ImageUpload == null || perfil.ImageUpload.ContentLength == 0)
{
ModelState.AddModelError("ImageUpload", "This field is required");
}
else if (!validImageTypes.Contains(perfil.ImageUpload.ContentType))
{
ModelState.AddModelError("ImageUpload", "Please choose either a GIF, JPG or PNG image.");
}
if (ModelState.IsValid)
{
if (perfil.ImageUpload != null && perfil.ImageUpload.ContentLength > 0)
{
var uploadDir = "~/Imagens";
var imagePath = Path.Combine(Server.MapPath(uploadDir), perfil.ImageUpload.FileName);
var imageUrl = Path.Combine(uploadDir, perfil.ImageUpload.FileName);
perfil.ImageUpload.SaveAs(imagePath);
perfil.ImageUrl = imageUrl;
}
rep.IncluirPerfil(perfil);
return RedirectToAction("Index");
}
ViewBag.idGenero = new SelectList(db.Generos, "idGenero", "nomeGenero", perfil.idGenero);
ViewBag.idUsuario = new SelectList(db.Usuarios, "idUsuario", "nome", perfil.idUsuario);
return View(perfil);
}
My Create View:
<div class="form-group">
#using (Html.BeginForm("Create", "PerfilController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="col-md-10">
#Html.LabelFor(model => model.ImageUpload)
</div>
#Html.TextBoxFor(model => model.ImageUpload, new { type = "file" })
}
</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>
I tried other solutions, but continued null...

The submit button must be inside using block:
<div class="form-group">
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.AntiForgeryToken()
<div class="col-md-10">
#Html.LabelFor(model => model.ImageUpload)
</div>
#Html.TextBoxFor(model => model.ImageUpload, new {type = "file"})
<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>
Also add ImageUpload to Bind list:
public ActionResult Create([Bind(Include = "idPerfil,idUsuario,idGenero,descricao,linkMultimidia,fotoPerfil, ImageUpload")] Perfil perfil)
One more thing, You can use Exclude instead of Include in your case.

I solved!
Entity:
public string photoPath{ get; set; }
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "idPerfil,idUsuario,idGenero,descricao,linkMultimidia,photoPath")] Perfil perfil)
{
string filename = perfil.photoPath;
var uploadDir = "~/Imagens";
var imagePath = Path.Combine(Server.MapPath(uploadDir), filename);
var imageUrl = Path.Combine(uploadDir, filename);
perfil.photoPath = imageUrl;
if (ModelState.IsValid)
{
rep.IncluirPerfil(perfil);
return RedirectToAction("Index");
}
ViewBag.idGenero = new SelectList(db.Generos, "idGenero", "nomeGenero", perfil.idGenero);
ViewBag.idUsuario = new SelectList(db.Usuarios, "idUsuario", "nome", perfil.idUsuario);
return View(perfil);
}
Create View:
<div class="form-group">
#Html.LabelFor(model => model.photoPath, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.photoPath, new { type = "file" })
#Html.ValidationMessageFor(model => model.photoPath)
</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>

Related

Unable to send Model Data from Controller's GET Method to Controller's POST Method via View

I am sending the list of affiliates from the get method of controller to View via ViewBag(ViewBag.AffiliateData) and expecting to get the same list in controller's HTTP Post Method(myAffiliateList) but receiving value as null. Could you please help me to understand what am I doing wrong here?
NOTE: I am sending the data as hidden because it is not needed to be shown. So I am trying to get 2 values in HTTP-Post method, one
which is being selected and other the whole list that is being used to
populate the select box dynamically.
Model:
public class ModelOld
{
public string Aname { get; set; }
public string Acode { get; set; }
}
public class ModelNew
{
public string Acode { get; set; }
public IEnumerable<ModelOld> myAffiliateList { get; set; }
}
Controller: UserInvitation.cs
// GET Method
public ActionResult Import()
{
List<ModelOld> affiliateList = new List<ModelOld>();
ModelNew affiliateList1 = new ModelNew();
var affiliateMappingList = Configuration.GetSection("AffiliateMapping").GetChildren();
foreach (var KeyValuePair in affiliateMappingList)
{
affiliateList.Add(new ModelOld()
{
Aname = KeyValuePair.Key,
Acode = KeyValuePair.Value
});
}
affiliateList.Insert(0, new ModelOld { Acode = "", Aname = "--Select Your Affiliate--" });
affiliateList1.myAffiliateList = affiliateList;
ViewBag.AffiliateData = affiliateList1.myAffiliateList;
return View();
}
[HttpPost]
public async Task<ActionResult> ImportAsync(string Acode, IEnumerable<ModelOld> myAffiliateList)
{
//Some Code
}
View: Import.cshtml
#model ModelNew
<!DOCTYPE html>
<html>
<body>
#using (Html.BeginForm("Import", "UserInvitation", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<div class="form-group">
<div class="col-md-offset-3 col-md-10">
<label class="col-md-offset-3 col-md-2" title="Select Your Affiliate" style="font-size:large;"><b>Affiliate:</b></label>
<select id="affiliate" class="form-control" style="-webkit-appearance:listbox" asp-for="Acode" asp-items="#(new SelectList(ViewBag.AffiliateData,"Acode","Aname"))">
</select>
#Html.HiddenFor(m => m.myAffiliateList, htmlAttributes: new { #Value = ViewBag.AffiliateData })
</div>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<div class="col-md-offset-3 col-md-10">
<br />
<button type="submit" id="btnSubmitData" title="Click to Invite the Users" class="btn btn-info">
<i class="glyphicon glyphicon-upload"></i> Invite Users
</button>
</div>
</div>
</div>
}
</body>
</html>
Here is a whole working demo:
Model
public class ModelOld
{
public string Aname { get; set; }
public string Acode { get; set; }
}
public class AffiliateModel
{
public string Aname { get; set; }
public string Acode { get; set; }
}
public class ModelNew
{
public string Acode { get; set; }
public IEnumerable<ModelOld> myAffiliateList { get; set; }
}
View
#model ModelNew
#{
var data = TempData["AffiliateData"] as string;
TempData.Keep("AffiliateData"); //be sure add this to persist the data....
var list = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<ModelOld>>(data);
}
<!DOCTYPE html>
<html>
<body>
#using (Html.BeginForm("Import", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<div class="form-group">
<div class="col-md-offset-3 col-md-10">
<label class="col-md-offset-3 col-md-2" title="Select Your Affiliate" style="font-size:large;"><b>Affiliate:</b></label>
<select id="affiliate" class="form-control" style="-webkit-appearance:listbox" asp-for="Acode"
asp-items="#(new SelectList(list,"Acode","Aname"))"> #*change here....*#
</select>
</div>
</div>
</div>
<br />
<div class="row">
<div class="form-group">
<div class="col-md-offset-3 col-md-10">
<br />
<button type="submit" id="btnSubmitData" title="Click to Invite the Users" class="btn btn-info">
<i class="glyphicon glyphicon-upload"></i> Invite Users
</button>
</div>
</div>
</div>
}
</body>
</html>
Controller
[HttpGet]
public async Task<IActionResult> Index()
{
List<ModelOld> affiliateList = new List<ModelOld>();
ModelNew affiliateList1 = new ModelNew();
var affiliateMappingList = Configuration.GetSection("AffiliateMapping").GetChildren();
foreach (var KeyValuePair in affiliateMappingList)
{
affiliateList.Add(new ModelOld()
{
Aname = KeyValuePair.Key,
Acode = KeyValuePair.Value
});
}
affiliateList.Insert(0, new ModelOld { Acode = "", Aname = "--Select Your Affiliate--" });
affiliateList1.myAffiliateList = affiliateList;
//change here....
//or asp.net core 2.x,you could use NewtonSoft.Json -----JsonConvert.SerializeObject(affiliateList1.myAffiliateList);
TempData["AffiliateData"] = System.Text.Json.JsonSerializer.Serialize(affiliateList1.myAffiliateList);
return View();
}
[HttpPost]
public async Task<ActionResult> ImportAsync(string Acode)
{
var data = TempData["AffiliateData"] as string;
IEnumerable<AffiliateModel> myAffiliateList = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<AffiliateModel>>(data);
return View();
}

Capturing date time from the view into the database MVC

I created MVC application that has a text box posted to the database. When the text box is posted, I want to capture today's date from the view and store it into the table. How do I capture the date and time the view that posted and how do I pass this information into row Date within the database? Appreciate any help.
Controller
[HttpGet]
public ActionResult Pay(int accountNumber)
{
return View();
}
[HttpPost]
public ActionResult Pay(Payments payment )
{
if(ModelState.IsValid)
{
DB.Payment.Add(payment);
DB.SaveChanges();
var service = new Accounts(DB);
service.Updatepayee(payment.AccountNumber);
return RedirectToAction("Index", "Home");
}
return View();
}
Payments Class
public class Payments
public int Id { get; set; }
[Required]
[DataType(DataType.Currency)]
[DisplayFormat(ConvertEmptyStringToNull = false)]
public decimal Amount { get; set; }
[Required]
public int AccountNumber {get; set;}
[RegularExpression(#"(^$)|(^\d{2}/\d{2}/\d{4})|(^((\d{1})|(\d{2}))/((\d{1})|(\d{2}))/(\d{4})\s((\d{1})|(\d{2}))[:]{1}((\d{1})|(\d{2}))[:]{1}((\d{1})|(\d{2}))\s((AM)|(PM)))", ErrorMessage = "Invalid Date")]
public DateTime TransactionDate { get; set; }
//Navigation property to check the account
public virtual AccountNumber accountNumber { get; set; }
}
Pay View
#model Credits.View.Payments
#{
ViewBag.Title = "Pay"; }
<h2>Payments</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Transaction</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Amount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Amount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Amount, "", 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", "Home") </div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval") }
Couldn't you set it in the controller:
[HttpPost]
public ActionResult Pay(Payments payment )
{
if(ModelState.IsValid)
{
payment.TransactionDate = DateTime.Now.ToUniversalTime();
DB.Payment.Add(payment);
DB.SaveChanges();
[HttpPost]
public ActionResult Pay(Payments payment )
{
var d=DateTime.Now.ToUniversalTime();
if(ModelState.IsValid)
{
Payments p=new() Payments{
AccountNumber=p.AccountNumber,
Amount=payment.Amount,
TransactionDate=d
};
DB.Payment.Add(p);
DB.SaveChanges();

Display list of objects and set a value field for each input MVC

I have the following class defined as my ViewModel
public class CreateApplicationViewModel
{
public Step1ViewModel Step1 { get; set; }
public Step2StandAloneViewModel Step2StandAlone { get; set; }
public Step2ChildViewModel Step2Child { get; set; }
public Step3ViewModel Step3 { get; set; }
public Step4ViewModel Step4 { get; set; }
}
I'm trying to display items in the Step4ViewModel which consists of the following:
public class Step4ViewModel
{
public List<DataDetails> DataDetails = new List<DataDetails>();
}
public class DataDetails
{
public string GroupCode { get; set; }
public string GroupDesc { get; set; }
public decimal DetailSequence { get; set; }
public string DetailCode { get; set; }
public string DetailDesc { get; set; }
public string YesNoFlag { get; set; }
public string NumberFlag { get; set; }
public string ValueFlag { get; set; }
public string DateFlag { get; set; }
public string ListValuesFlag { get; set; }
public string CommentFlag { get; set; }
public string CalcRateFlag { get; set; }
public string ColumnSequence { get; set; }
public string TextFlag { get; set; }
public string CheckboxFlag { get; set; }
public string YesNoValue { get; set; }
public int NumberValue { get; set; }
public DateTime DateValue { get; set; }
public string ListValue { get; set; }
public string CommentValue { get; set; }
public string TextValue { get; set; }
public bool CheckboxValue { get; set; }
}
In my controller I populate the Step4ViewModel.DataDetails like so:
private Step4ViewModel GetCaseDataDetails(string caseType)
{
Step4ViewModel model = new Step4ViewModel();
List<DataDetails> data = new List<DataDetails>();
List<DataDetailsValues> values = new List<DataDetailsValues>();
var dataDetails = (from tb1 in db.DEFAULT_CASE_DATA_VW
join tb2 in db.CASE_DATA_DETAIL on tb1.CASE_DATA_GROUP_ID equals tb2.CASE_DATA_GROUP_ID
where tb1.BUS_CASE_CODE == caseType
orderby tb2.DETAIL_SEQUENCE
select new { tb1, tb2 });
foreach (var detail in dataDetails.ToList())
{
DataDetails i = new DataDetails();
DataDetailsValues j = new DataDetailsValues();
i.CalcRateFlag = detail.tb2.CALC_RATE_FLAG;
i.CheckboxFlag = detail.tb2.CHECKBOX_FLAG;
i.ColumnSequence = detail.tb2.COLUMN_SEQUENCE;
i.CommentFlag = detail.tb2.COMMENT_FLAG;
i.DateFlag = detail.tb2.DATE_FLAG;
i.DetailCode = detail.tb2.DETAIL_CODE;
i.DetailDesc = detail.tb2.DETAIL_DESC;
i.DetailSequence = detail.tb2.DETAIL_SEQUENCE;
i.GroupCode = detail.tb1.GROUP_CODE;
i.GroupDesc = detail.tb1.GROUP_DESC;
i.ListValuesFlag = detail.tb2.LIST_VALUES_FLAG;
i.NumberFlag = detail.tb2.NUMBER_FLAG;
i.TextFlag = detail.tb2.TEXT_FLAG;
i.ValueFlag = detail.tb2.VALUE_FLAG;
i.YesNoFlag = detail.tb2.YES_NO_FLAG;
data.Add(i);
}
model.DataDetails = data;
return model;
}
My thought process with the Step4ViewModel is that for every DataDetail I will display the DetailDesc as a label and then beside of it I will have an input for the NumberValue, YesOrNoValue, NumberValue, DateValue, ListValue, CommentValue, TextValue, or CheckboxValue depending on the control type and then post that data to server. I am able to successfully display each DataDetail.DetailDesc, but for each input, which also renders, the values I enter into the inputs never post back to the server. Here is what my view looks like:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => Model.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => Model.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
Controller to which post data
[HttpPost]
public ActionResult Step4(Step4ViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
I was thinking this could be due the grouping, which I do to separate each group into a separate HTML panel element, but my inputs are rendering with the index number in the name. Any help or suggestions on a better way to accomplish this would be greatly appreciated. Cheers!
UPDATE
Here is my updated post controller and view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
[HttpPost]
public ActionResult Step4(CreateApplicationViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
UPDATE 2
I am able to get the form input if I pass a FormCollection to the HttpPost controller. Any ideas as to why I can get these values as a FormCollection but not as the model?
You are posting list of complex objects. But MVC DefaultModelBinder can’t able to bind to your DataDetails object because Index must be in sequence when posting the form with list of complex objects. In your case due to nested for loop, this sequence is broken. So what you can do is take one separate variable and initialize with default 0 value like this - I have tried to modify your code.
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
Look at the hidden field i have added in the view. That do the trick to post your data even with the broken sequences. Hope this help you.
I was able to get the model back to the controller by taking the idea of using an index integer and incrementing it from the answer above and implementing the idea in a different way in my view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#Html.TextBoxFor(val => val.Step4.DataDetails[index].TextValue)
#Html.HiddenFor(val => val.Step4.DataDetails[index].GroupCode)
</div>
</div>
</div>
index++;
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
The above code in the view gives me the proper index of every element and allows me to post

ASP.NET MVC-5 sever side validation not working

I have ASP.NET MVC application and I am failing to Server-side and client-side validation for partial page. In the start of my application there is login page which validating correctly. so if I press submit with no values in form, app don't show any error messages
model class
public class CreateFunctionNavigation_SP_Map
{
public CreateFunctionNavigation_SP_Map()
{
}
//Function Table
[StringLength(250)]
[Required(ErrorMessage = "Required Function Title")]
[Display(Name = "Function Title")]
public string FunctionName { get; set; }
[Required(ErrorMessage = "Required Function Hierarchy; i.e Where Function Exists In Hierarchy Tree \n Top-Level Start From 1 ")]
[Display(Name = "Function Hierarchy Level")]
public int FunctionHierarchy_Level { get; set; }
//Controller Table
[StringLength(250)]
[Required(ErrorMessage = "Required Controller Title")]
[Display(Name = "Controller Title")]
public string ControllerName { get; set; }
//Action Table
[StringLength(250)]
[Required(ErrorMessage = "Required Action Title")]
[Display(Name = "Action Title")]
public string ActionName { get; set; }
// Hierarchy Table
[Required(ErrorMessage = "Required Function Parent - Child Relation ID \n Put 0 In Case Given Function doesn't Have Any Parent Function ")]
[Display(Name = "Function Parent's FunctionID")]
public int Function_ParentsFunctionID { get; set; }
}
controller method
#region CreateNewFunctionNavigation
[HttpGet]
public ActionResult CreateNewFunctionNavigation()
{
return PartialView("CreateNewNavigation_Partial");
}
#endregion
[HttpPost]
public ActionResult CreateNewFunctionNavigation(CreateFunctionNavigation_SP_Map obj )
{
try
{
if(ModelState.IsValid)
{
_FN_Services_a2.CreateFunctionNavigation(obj);
}
}
catch (DataException ex)
{
ModelState.AddModelError("", "Unable To Create New Function Navigation" + ex);
}
return RedirectToAction("SystemCoreHome");
} //end
view
#model App.DAL.Model.CreateFunctionNavigation_SP_Map
<div class="_Form_Block">
#using (Html.BeginForm("CreateNewFunctionNavigation", "SystemCore", FormMethod.Post, new { id = "NewFunctionNavigationForm" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(#model => #model.FunctionName, new { #class = "control-label col-md-2" })
<div class="form-group">
#Html.EditorFor(#model => #model.FunctionName)
#Html.ValidationMessageFor(#model => #model.FunctionName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(#model => #model.FunctionHierarchy_Level, new { #class = "control-label col-md-2" })
<div class="form-group">
#Html.EditorFor(#model => #model.FunctionHierarchy_Level)
#Html.ValidationMessageFor(#model => #model.FunctionHierarchy_Level)
</div>
</div>
<div class="form-group">
#Html.LabelFor(#model => #model.ControllerName, new { #class = "control-label col-md-2" })
<div class="form-group">
#Html.EditorFor(#model => #model.ControllerName)
#Html.ValidationMessageFor(#model => #model.ControllerName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(#model => #model.ActionName, new { #class = "control-label col-md-2" })
<div class="form-group">
#Html.EditorFor(#model => #model.ActionName)
#Html.ValidationMessageFor(#model => #model.ActionName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(#model => #model.Function_ParentsFunctionID, new { #class = "control-label col-md-2" })
<div class="form-group">
#Html.EditorFor(#model => #model.Function_ParentsFunctionID)
#Html.ValidationMessageFor(#model => #model.Function_ParentsFunctionID)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default _formButton" />
<input type="button" value="Cancel" class="btn btn-default _formButton" onclick="CancelPage();" />
</div>
</div>
}
</div> <!--End _Form_Block-->
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
instead of
return RedirectToAction("SystemCoreHome");
use
return PartialView("CreateNewNavigation_Partial", obj);
Ajax Form
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "TargetID" }))
{
...
}
<div class="_Form_Block" id="TargetID">
</div>
You need to handle this case.
Presently you are not doing anything in the event that the ModelState is invalid. Try the following:
public ActionResult CreateNewFunctionNavigation(CreateFunctionNavigation_SP_Map obj)
{
if (!ModelState.IsValid)
{
return View(obj);
}
// rest of method here
if(ModelState.IsValid)
{
_FN_Services_a2.CreateFunctionNavigation(obj);
}
else
{
return View();
}
Should do the trick.

Validation in ViewModel not working

I have ViewModel which contains some proprty of class. Code below.
public class ViewModel
{
public Doctor VmDoctor { get; set; }
public Patient VmPatient { get; set; }
public List<Visit> VmVisit { get; set; }
public List<Hours> hours { get; set; }
public List<Hours> hours2 { get; set; }
public Schedule schedule { get; set; }
public bool BlockBtn { get; set; }
public Test test { get; set; }
}
In this case important property is Patient VmPatient. This is a model which has been generated by Database Model First. He has validation.Code below.
public partial class Patient
{
public Patient()
{
this.Visits = new HashSet<Visit>();
}
public int PatientID { get; set; }
[Required(ErrorMessage = "Podaj imię.")]
public string name { get; set; }
[Required(ErrorMessage = "Podaj nazwisko.")]
public string surname { get; set; }
[Required(ErrorMessage = "Podaj pesel.")]
[RegularExpression(#"^\(?([0-9]{11})$", ErrorMessage = "Nieprawidłowy numer pesel.")]
public string pesel { get; set; }
[Required(ErrorMessage = "Podaj miasto.")]
public string city { get; set; }
[Required(ErrorMessage = "Podaj kod pocztowy.")]
public string zipCode { get; set; }
[Required(ErrorMessage = "Podaj e-mail.")]
[EmailAddress(ErrorMessage = "Nieprawidłowy adres e-mail")]
public string email { get; set; }
[Required(ErrorMessage = "Podaj telefon komórkowy.")]
[RegularExpression(#"^\(?([0-9]{9})$", ErrorMessage = "Nieprawidłowy numer telefonu.")]
public string phone { get; set; }
public virtual ICollection<Visit> Visits { get; set; }
}
and i have Main Index where return my ViewModel because, display two Models in the same View. Code below
public ActionResult Index(int id)
{
ViewModel _viewModle = new ViewModel();
schedule = new Schedule();
if(Request.HttpMethod == "Post")
{
return View(_viewModle);
}
else
{
idDr = id;
_viewModle.schedule = schedule;
_viewModle.BlockBtn = _repository.BlockBtn(schedule);
_viewModle.VmDoctor = db.Doctors.Find(idDr);
_viewModle.hours = _repository.GetHours();
foreach (var item in _viewModle.hours)
{
_viewModle.hours2 = _repository.GetButtonsActiv(item.hourBtn, item.count, idDr, schedule);
}
}
if (_viewModle == null)
{
return HttpNotFound();
}
return View(_viewModle);
}
inside View Index i display my objects and rendered partial _FormPatient.Code below.
#model Dentist.Models.ViewModel
<div class="container-select-doctor">
<div class="row">
<div class="text-left">
<div class="row">
<div class="content">
<div class="profileImage">
<div class="imageContener"><img style="margin:1px;" src="#Url.Content("~/Images/" + System.IO.Path.GetFileName(#Model.VmDoctor.image))" /></div>
</div>
<div class="profileInfo">
<div class="profileInfoName">#Model.VmDoctor.name #Model.VmDoctor.surname</div>
<div class="profileInfoSpeciality">#Model.VmDoctor.specialty</div>
</div>
</div>
</div>
</div>
#ViewBag.firstDay<br />
#ViewBag.lastDay<br />
<div class="text-middle">
<div class="content">
<div id="partialZone">
#Html.Partial("_TableSchedule")
</div>
</div>
</div>
<div class="text-right">
<div class="content">
#Html.Partial("_FormPatient")
</div>
</div>
</div>
</div>
and last step is form which has been rendered inside Main Index by #Html.partial.code below
#model Dentist.Models.ViewModel
#using (Html.BeginForm("Create","Patient"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<font color="red">#ViewBag.Pesel</font>
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.VmPatient.email, htmlAttributes: new { #class = "control-label col-md-2" }, labelText: "E-mail:")
<div class="col-md-10">
#Html.TextBoxFor(model => model.VmPatient.email, new { htmlAttributes = new { #class = "form-control" } })
#*<input class="form-control" id="email" name="email" type="text" value="">*#
#Html.ValidationMessageFor(model => model.VmPatient.email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VmPatient.phone, htmlAttributes: new { #class = "control-label col-md-2" }, labelText: "Telefon kom.:")
<div class="col-md-10">
#Html.TextBoxFor(model => model.VmPatient.phone, new { maxlength = 9 })
#*<input class="form-control" maxlength="9" id="phone" name="phone" type="text" value="" />*#
#Html.ValidationMessageFor(model => model.VmPatient.phone, "", 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>
}
Please pay attention that this form redirect to another Controller where data will be validate and save to database. Method where data from FORM will be validate and save. code below
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Patient pat)
{
ViewModel vm = new ViewModel();
DentistEntities db = new DentistEntities();
if (ModelState.IsValid)
{
db.Patients.Add(pat);
db.SaveChanges();
}
return RedirectToAction("Index", "Visit", new { id = VisitController.idDr });
}
Conclusion How can i get validation for this form! I have observed that,every time modelstate.isvalid return false.. I dont have any ideas so I would like to ask you for help.
Best regards.
I would suggest that you do this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Patient pat)
{
ViewModel vm = new ViewModel();
DentistEntities db = new DentistEntities();
if (ModelState.IsValid)
{
db.Patients.Add(pat);
db.SaveChanges();
}
vm.VmPatient = pat;
return View(vm);
}
Render the view again, but this time the validation error messages should appear on the page (via the ValidationMessageFor() calls in the view). That, at least you can see why the validation has failed.
Alternatively, you could interrogate the modelstate e.g.
foreach (ModelState modelState in ViewData.ModelState.Values) {
foreach (ModelError error in modelState.Errors) {
string error = error.ErrorMessage;
}
}

Categories