#Html.ValidationMessageFor crashes when I try to edit an item - c#

Why is my #Html.ValidationMessageFo not working? When I run the application, nothing happens and it allows everything to be entered. And it also crashes when I try to edit an item in my edit view, which is below. I have the following:
<div class="editor-label">
#* #Html.LabelFor(model => model.Posted)*#
</div>
<div class="editor-field">
#Html.HiddenFor(model => model.Posted, Model.Posted = DateTime.Now)
#Html.ValidationMessageFor(model => model.sendinghome)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Cartypes)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Cartypes)
#Html.ValidationMessageFor(model => model.Cartypes)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.RegNum)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.RegNum)
#Html.ValidationMessageFor(model => model.RegNum)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Regprice)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Image)
#Html.ValidationMessageFor(model => model.Regprice)
</div>

Here is how validation works.
Let's say you have the following model:
public class MyModel {
[Required]
public string MyProperty { get; set; }
}
Note the Required attribute, it is a data annotation attribute that specifies that MyProperty is a required field.
MyModel is used by the following view (MyView.cshtml):
#model MyNamespace.MyModel
#using (Html.BeginForm("MyAction", "MyController")) {
#Html.LabelFor(m => m.MyProperty)
#Html.TextBoxFor(m => m.MyProperty)
#Html.ValidationMessageFor(m => m.MyProperty)
<input type="submit" value="Click me">
}
Then, when this form gets posted to the MyAction action of MyController, the validation of your model will be performed. What you have to do is check whether your model is valid or not.
It can be done using the ModelState.IsValid property.
[HttpPost]
public ActionResult MyAction(MyModel model) {
if (ModelState.IsValid) {
// save to db, for instance
return RedirectToAction("AnotherAction");
}
// model is not valid
return View("MyView", model);
}
If the validation failed, the view will be rendered again using the different errors that are present in the ModelState object. Those errors will be used and displayed by the ValidationMessageFor helper.

Exactly, Bertrand explains it right, you could also use jquery validation too and eliminate the calls to the server validating on the browser. (asp.net mvc takes care of validating the rules on your model automatically)

Related

Issue when creating a reference of a Model without using Html.EditorFor() asp.net mvc

I am facing an issue when trying to create a reference of my model Restriction:
public int RestrictionID
public string portefeuille
public int AssetID
public int SegmentID
public int SubAssetID
public int Min
public int Max
public string logic_op
public virtual Asset Asset
public virtual Segment Segment
public virtual SubAsset SubAsset
That is instead of using the normal template in create view with #Html.EditorFor I am using a dropdown list with a script behind to fill the dropdown depending on the previous selected item that's work well, but when submitting nothing happen no error no redirecting, and of course the reference is not added to the database.
Here is my Create view:
<div class="editor-label">
#Html.LabelFor(model => model.portefeuille)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.portefeuille)
#Html.ValidationMessageFor(model => model.portefeuille)
</div>
#Html.DropDownList("Asset", ViewBag.AssetID as SelectList, "Select a Asset Class", new { id="Asset" })<br />
<select id="Segment" name="segment"></select><br /> //Here I am not using Html.EditorFor as EF does
<select id="subAsset" name="SubAsset"></select><br />
<div class="editor-label">
#Html.LabelFor(model => model.Min)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Min)
#Html.ValidationMessageFor(model => model.Min)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Max)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Max)
#Html.ValidationMessageFor(model => model.Max)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.logic_op)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.logic_op)
#Html.ValidationMessageFor(model => model.logic_op)
</div>
and my RestrictionController: ( I omitted useless parts)
public ActionResult Create()
{
ViewBag.AssetID = new SelectList(db.Assets, "AssetID", "Asset_Name");
return View();
}
//
// POST: /Restriction/Create
[HttpPost]
public ActionResult Create(Restriction restriction)
{
if (ModelState.IsValid)
{
db.Restrictions.Add(restriction);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.AssetID = new SelectList(db.Assets, "AssetID", "Asset_Name", restriction.AssetID);
return View(restriction);
}
Can somebody help to find where is the problem ?
Thank you for your help!
Name of the property in the model a should be same as name of the element in the html in order to bind values after the post back.That is why the code below
<select id="Segment" name="segment"></select><br /> //Here I am not using Html.EditorFor as EF does
<select id="subAsset" name="SubAsset"></select><br />
should be replaced by.
<select id="Segment" name="SegmentID"></select><br /> //Here I am not using Html.EditorFor as EF does
<select id="subAsset" name="SubAssetID"></select><br />
Always look at the HTML generated by any technology. This will help you to understand how the things are working.

Loading a page with values from multiple tables using a ViewModel

What I want to do is to have a number of labels populate with information from 2 different tables. When the submit button is pressed, it will then hit my Post method and save the info the user typed in and the info automatically populated to the db, but I'm having issues with my Get method. My Get method in my controller looks like this:
[HttpGet]
public ActionResult AddOrganization(int peopleID = 1)
{
var peopleModel = db.People.Include("EmployeeContacts").Single(g => g.PeopleID == peopleID);
return View("../Setup/AddOrganization", peopleModel);
}
However, I've got a viewModel that looks like this and includes all the tables that will be needed for the Get and Post methods for this page:
public class AddOrganizationViewModel
{
public MusicStore.Models.Organizations Organizations { get; set; }
public MusicStore.Models.People People { get; set; }
public MusicStore.Models.OrganizationOptions OrganizationsOptions { get; set; }
public MusicStore.Models.EmployeeContacts EmployeeContacts { get; set; }
}
So when the view is first loaded, and the Get method above is called, I get an error saying
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.People_8080C33752A42A0C994331F5015BCCFCEB99B3ECD7AB8CA2BB11ABE67851B81B', but this dictionary requires a model item of type 'MusicStore.ViewModels.AddOrganizationViewModel'.
Here is my view also:
<h2>AddOrganization</h2>
#model MusicStore.ViewModels.AddOrganizationViewModel
#using (Html.BeginForm("Add", "AddOrganization"))
{
<fieldset>
<legend>CONTACT INFORMATION</legend>
<div class ="editor-label">
#Html.Label("Organization Name")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.Organizations.OrgName)
</div>
<div class ="editor-label">
#Html.Label("Phone Number")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.Organizations.OrgPhone)
</div>
<div class ="editor-label">
#Html.Label("Point of Contact")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.Organizations.OrgPointOfContact)
</div>
<div class ="editor-label">
#Html.Label("Office Location")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.Organizations.OrgOfficeLocation)
</div>
</fieldset>
<fieldset>
<legend>FIRST EMPLOYEE OF ORGANIZATION</legend>
<div class ="editor-label">
#Html.Label("Admin First Name")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.People.FirstName)
</div>
<div class ="editor-label">
#Html.Label("Admin Last Name")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.People.LastName)
</div>
<div class ="editor-label">
#Html.Label("Admin NID")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.People.NID)
</div>
<div class ="editor-label">
#Html.Label("Admin SID")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.People.SID)
</div>
<div class ="editor-label">
#Html.Label("Admin Email")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.EmployeeContacts.Email)
</div>
<div class ="editor-label">
#Html.Label("Admin Phone Number")
</div>
<div class ="editor-field">
#Html.TextBoxFor(Model => Model.EmployeeContacts.PrimaryPhone)
</div>
How do I send the needed information to the view via the Get method when it can only take a ViewModel type? Is there a way I can add this information to my ViewModel? Any help or shove in the right direction would great.
var peopleModel = db.People.Include("EmployeeContacts").Single(g => g.PeopleID == peopleID);
what is the type of peopleModel in this case?
Seeing as you are returning it directly from a database, it looks like it has not yet been 'converted' or 'projected' into the actual viewmodel that the view expects.
you will probably need to do something like this:
AddOrganizationViewModel vm = new AddOrganizationViewModel();
vm.Organizations = new Organizations()
{
someOrganizationProperty = peopleModel.SomeProperty,
};
vm.People = new People()
{
somePeopleProperty = peopleModel.SomeOtherProperty,
};
//etc for the other properties and types in your viewmodel
when all that data has been set, you can return the AddOrganizationViewModel.
var peopleModel = db.People.Include("EmployeeContacts").Single(g => g.PeopleID == peopleID);
This doesn't create an AddOrganizationViewModel object. Either add a Select clause at the end or use the data in that object to populate a new viewmodel.

The model item passed into the dictionary is of type 'System.String', but this dictionary requires a model item of type 'JFS.Data.Model.Address'

I am quite new to MVC but have been making steady progress however I have recently hit a problem that I can't seem to overcome despite reading a number of similar posts on similar topics.
I have a model as follows (simplified for brevity)
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Address Address { get; set; }
I have a strongly typed view as follows:
#model JFS.Data.Model.Supplier
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Supplier Address</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Address.AddressLine1)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address.AddressLine1)
#Html.ValidationMessageFor(model => model.Address.AddressLine1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Address.Country)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Address.Country)
#Html.ValidationMessageFor(model => model.Address.Country)
</div>
</fieldset>
And I have a shared EditorTemplate for the Country field as follows:
#model JFS.Data.Model.Address
#using System.Globalization
#Html.DropDownListFor(o => o.Country, GetCountries(Model), "Please select")
#functions
{
private static IEnumerable<SelectListItem> GetCountries(object country)
{
var regions = CultureInfo.GetCultures(CultureTypes.SpecificCultures)
.Select(cultureInfo => new RegionInfo(cultureInfo.LCID))
.OrderBy(r => r.EnglishName)
.Distinct()
.ToList();
return new SelectList(regions, "TwoLetterISORegionName", "EnglishName", country);
}
}
I understand the problem but not sure how best to overcome it, any advice would be very much appreciated.
Though your particular scenario was already answered by #ProNotion, I have had this issue before when you are passing null into your View or Templates. It may help someone else coming this way.
In your main view replace:
#Html.EditorFor(model => model.Address.Country)
with:
#Html.EditorFor(model => model.Address)
By the way if you are writing a shared editor template for an Address model you probably want to include the other properties as well such as AddressLine1 in this template.
You need to just pass the Address property:
#Html.EditorFor(model => model.Address)
You are trying to pass the Address properties which are strings, whereas the requirement of type is Address.

ModelState Errors not showing in view

I have an action that saves a record by calling my BLL entity's Save method. The entity takes care of its own internal validation and if a field is required but fails validation because a user didn't enter a value then the entity throws up an error. I'm catching that error in my action and returning the same view. The problem is the error isn't showing in my ValidationSummary.
Yes I realize I have view model validation by attibute with MVC but this entity is used elsewhere and must have redundant validation if the UI doesn't/can't do it, such as used in a batch service job.
Here is my action:
public ActionResult Edit(EntityModel model) {
if (ModelState.IsValid) {
var entity = new Entity(model.ID, model.Name, model.IsActive);
try {
entity.Save(User.Identity.Name);
return RedirectToAction("List");
}
catch (Exception ex) {
ModelState.AddModelError("", ex.Message);
}
}
return View(model);
}
Here is my View:
#model ELM.Select.Web.Models.EntityModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>DefermentTypeViewModel</legend>
#Html.HiddenFor(model => model.ID)
<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">
#Html.LabelFor(model => model.IsActive)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.IsActive)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Why wouldn't the error I add to modelstate be shown in my validationsummary?
Change your View code:
#Html.ValidationSummary(true)
to:
#Html.ValidationSummary(false)
As per the MSDN Reference on ValidationSummary(), here is the method definition:
public static MvcHtmlString ValidationSummary(
this HtmlHelper htmlHelper,
bool excludePropertyErrors
)
Notice that the bool parameter, if you set it to true (like you originally did) you will exclude property errors. Change that to false and that should get you what you want.

AllowHtml attribute not working

I have a model with this property:
[AllowHtml]
[DisplayName("Widget for Table")]
[StringLength(1000, ErrorMessage = "Maximum chars 1000")]
[DataType(DataType.Html)]
public object TableWidget { get; set; }
And here is the create methods in controller:
//
// GET: /Admin/Table/Create
public ActionResult Create(int id)
{
Season season = _seasonRepository.GetSeason(id);
var table = new Table
{
SeasonId = season.SeasonId
};
return View(table);
}
//
// POST: /Admin/Table/Create
[HttpPost]
public ActionResult Create(Table a)
{
if (ModelState.IsValid)
{
_tableRepository.Add(a);
_tableRepository.Save();
return RedirectToAction("Details", "Season", new { id = a.SeasonId });
}
return View();
}
And last here is my view:
#model Stridh.Data.Models.Table
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Fields</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">
#Html.LabelFor(model => model.TableURL)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TableURL) #Html.ValidationMessageFor(model => model.TableURL)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SortOrder)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SortOrder) #Html.ValidationMessageFor(model => model.SortOrder)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TableWidget)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TableWidget) #Html.ValidationMessageFor(model => model.TableWidget)
</div>
<div class="editor-label invisible">
#Html.LabelFor(model => model.SeasonId)
</div>
<div class="editor-field invisible">
#Html.EditorFor(model => model.SeasonId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
When I add a "normal" message without html everything is saved OK, but when saving it says A potentially dangerous Request.Form...
Another strange thing is that I got this [AllowHtml] to work in another model class. I cant find why this is causing me troubble. Need your help. :-)
The way you are using AllowHtml should work. Make sure that you are not accessing the HttpRequest.Form collection anywhere else in your code (controller, filter, etc) as this will trigger ASP.NET Request Validation and the error you are seeing. If you do want access to that variable then you should access it via the following code.
using System.Web.Helpers;
HttpRequestBase request = .. // the request object
request.Unvalidated().Form;
I get the same problem and i solve it with the help of this post.
If you are on .net 4.0 make sure you add this in your web.config
<httpRuntime requestValidationMode="2.0" />
Inside the <system.web> tags
I had the same problem. My model class is named "GeneralContent" and has the property "Content". In my action method i used attribute like this:
public ActionResult Update(GeneralContent content)
when i renamed content argument to cnt, everything works well. I think MVC is confused when some attribude of model class has the same name as the argument in action method.
I also had this issue. I could not get a model property marked with [AllowHtml] to actually allow HTML, and instead encountered the same error you describe. My solution ended up being to mark the Controller action that accepts the posted model with the [ValidateInput(false)] attribute.
The answer that #marcind put me on the right track but my issue was that I was passing the FormCollection into the Controller method, so changing this...
public ActionResult Edit(MyClass myClass, FormCollection collection)
To this...
public ActionResult Edit(MyClass myClass)
Solved the problem.
Subsequently, I was able to access the heck out of the form collection with code like this without issue.
foreach (var key in Request.Form.AllKeys)
{
...
}
So, it was the passing the form collection parameter that caused the problem, not merely accessing the form collection.

Categories

Resources