I'm creating a webpage using MVC 5, Visual Studio, C#.
In my view I have a remark page which the user is allowed to make a remark in a text box and click "save" to save the remark in a database. However, it is saying that the value of the remark is invalid when it shouldn't be.
The error is
The value 'Testing Remark' is invalid
yet it should be valid
In my model, I have a class called Recall, which has a
public string Remark {get; set;}
In the view I have
#using (Html.BeginForm())
{
<div class="form-group">
#Html.LabelFor(model=>model.Remark, htmlAttributes: new {#class ="control-label col-md-2"})
<div class="col-md-10">
#Html.TextAreaFor(model => model.Remark, 5, 50, new { #class = "text-danger"})
#Html.validationMessageFor(model => model.Remark, "", new { #class = "text-danger"})
</div>
</div>
<div class="form-group">
<input type="submit" value="save" class="btn btn-default" />
</div>
}
In the controller
....
not putting the controller code here since it should have nothing to do with the error I'm getting.
You should use data type MultilineText if you are using a TextArea:
[DataType(DataType.MultilineText)]
public string Remark { get; set; }
Or just change the TextAreaFor to a TextBoxFor if you don't need multi line text:
#Html.TextBoxFor(model => model.Remark, new { #class = "text-danger"})
Related
I'm having some trouble with data being sent through my controller, here's a simplified example:
public ActionResult EditNote(NotesModel model)
{
model.Author = Session["UserName"].ToString();
model.Note = null;
model.Title = null;
return View(model);
}
On my views page the data shown from the model is the exact same as how it was received by the method and all changes are ignored, why?
Bigger picture:
I'm trying to have a user edit an existing note in the database, if they're the one who made it of course. based on whether or not they're the author they will either edit the existing note or create a new note, this is where the problem lies. The controller is supposed to set all the values of the model to null so that on the views page they will be empty.
Editing an existing note is no problem however emptying the model so the editing page is blank does not work.
EDIT
This is my view page:
#model WebsiteProject.Models.NotesModel
#{
ViewBag.Title = "";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Sidebar
{
<div id="sidebarheadericon" style="background-image: url('../Content/icons/apps.png')"></div>
<div id="headertext"><h1>Welcome</h1></div>
<hr id="seperator" />
<p class="psidebar">test</p>
<p>
#Html.ActionLink("Create New", "EditNote")
</p>
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h1>NotesModel</h1>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<p class="control-label">Note by #Session["UserName"].ToString()</p>
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Note, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Note, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Note, "", 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="largebtn" />
</div>
</div>
<p class="text-danger">#ViewBag.NoteViewError</p>
</div>
}
<div>
#Html.ActionLink("Back to List", "NoteApp")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here you can see the data that is received (dummy data)
Now here you'll see that the data of the model is changed
Yet on the website it is not changed
The biggest problem isn't the Note and Title not being changed because the user can do that, but the Id and Author, which the user cannot, and should not be able to change.
This is related to the fact that you are using EditorFor:
#Html.EditorFor(model => model.Note, new { htmlAttributes = ... })
It so happens that EditorFor not only uses the Model object, it also uses ModelState which keeps a copy of all values for all Model items that were received, parsed and validated, along with any validation errors that this may have produced.
As long as ModelState has a value for that model item, it will be shown by EditorFor. The reason is that user input may be invalid, like entering 12X for an int Model property. EditorFor will show 12X if the form is re-rendered, which is coming from ModelState, and which could never come from Model.
Unwanted values can be removed by calling Remove, like this:
ModelState.Remove("Note");
On a different note, the ViewModel class that you are using here is not suited to the needs of this action method. It may be better to create a dedicated ViewModel class for it, with fewer properties, which you can then convert to the ViewModel type that the View needs.
I think you want to tell the incoming notes model is a new one or an existing one, here is some code to try,
public ActionResult EditNote(NotesModel model)
{
if(model.Id > 0) //assuming existing notes has id or any other ways you want to check
{
//save data
return View(model);
}
else //if Id has a value <= 0, return a new model with only Author set, maybe the Id (depending on how you want to generate the Id)
{
var model = new NotesModel();
model.Author = Session["UserName"].ToString();
return Viwe(model);
}
}
I am currently trying to get the validation from the backend models to the razor view using resource files. I have 2 languages setup, (en, fr) but even though French is selected, the error message is always in English.
I have tried multiple online tutorial / looking at other people having similar problem but none of the fixes worked for me.
my viewmodel example:
[Required(ErrorMessageResourceName = "RequiredField", ErrorMessageResourceType = typeof(GlobalRes))]
[Display(Name = "Username", ResourceType = typeof(GlobalRes))]
public string Username { get; set; }
[Required(ErrorMessageResourceName = "RequiredField", ErrorMessageResourceType = typeof(GlobalRes))]
[DataType(DataType.Password)]
[Display(Name = "Password", ResourceType = typeof(GlobalRes))]
public string Password { get; set; }
Razor view:
<div class="form-group">
#Html.LabelFor(m => m.Username, new { #class = "col-md-12" })
<div class="col-md-12">
#Html.TextBoxFor(m => m.Username, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Username, "", new { #class = "text-danger"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-12" })
<div class="col-md-12">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password, "", new { #class = "text-danger" })
</div>
</div>
Inspecting the html in your browser after changing the language and submitting the form.
<input class="input-validation-error form-control" data-val="true" data-val-required="Ce champ est requis." id="Username" name="Username" type="text" value="">
<span class="field-validation-error text-danger" data-valmsg-for="Username" data-valmsg-replace="true">This field is required.</span>
<input class="input-validation-error form-control" data-val="true" data-val-required="Ce champ est requis." id="Password" name="Password" type="password">
<span class="field-validation-error text-danger" data-valmsg-for="Password" data-valmsg-replace="true">This field is required.</span>
What the expected results should be is, based on the language selected, the error message should be in french. If you inspect the input box, you can see the correct value being added in french. When submitting the form, you actually only get the english value instead of the expected one.
Thank you in advance!
I had this problem also but I find a simple way, I controller add this code.
if (ModelState.IsValid)
{
}
else
{
ModelState.Clear();
TryValidateModel(Model);
}
I was having the exactly same issue. For me putting the resource files in App_GlobalResources folder solved my problem!
If that folder does not exist already you can create it.
I am using localization on Asp.Net MVC application.
I cant seem to find the problem here. Really stuck and need help. Im using Html.BeginForm and inside i have editorFor - model.DOB. Used post method but somehow it doesnt send the property back to my controller. Do help. I have other string property fields which is sending fine to the controller. Only date property not sending. TQVM in advance.
---------Edit---------
Just found out that if i use Edge - i need to use dd/MM/yyyy format. Then it will saves fine. If i use MM/dd/yyyy, then it will give null on the controller.
On chrome
using dd/MM/yyyy - gives me 'The field must be a date' error
using MM/dd/yyyy - gives me null.
---------Edit---------
Model
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Date of Birth")]
public DateTime? PersonDOB { get; set; }
View
#model Models.CorporationModel
using (Html.BeginForm("Edit", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<div class="form-group">
#Html.LabelFor(model => model.PersonDOB, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PersonDOB, new { htmlAttributes = new { #class = "form-control", placeholder = "Format: 06/31/1998" } })
#Html.ValidationMessageFor(model => model.PersonDOB, "", 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" name="action:PersonalSave" />
<input type="submit" value="Reprocess" class="btn btn-default" onclick="return confirm('Are you sure?')" name="action:PersonalReprocess" />
</div>
</div>
</div>
}
Controller
[HttpPost]
[MultipleButton(Name = "action", Argument = "PersonalReprocess")]
public ActionResult PersonalReprocess(int id, CorporationModel corporationModel, HttpPostedFileBase postedResultFile, HttpPostedFileBase postedPersonalFile)
{
corporationModel.Verified = "Processing";
return UpdatePersonal(id, corporationModel, postedResultFile, postedPersonalFile);
}
If i remove the
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
Im getting the 'The field must be a date error'. If i switch between month and date manually, then it saves without problem. However, when it pulls from the db, it will start with dd/mm/yyyy and then clicking on save will gives out 'the field must be a date error' again, so need to switch it manually.
Here's the view which I'm using to enter the multiline article
I wish that you can also told me how to save the text properties such as bold italic too because it makes me very confused.
#model WEBSITI.Models.article
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm( "Create", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(model => model.bodyofarticle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.bodyofarticle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.bodyofarticle, "", new { #class = "text-danger" })
</div>
<input type="file" id="file" name="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>
}
When a form is submitted, the asp.met mvc framework will inspect the request body to see whether it has any potentially dangerous content as HTML markup(Think about script injection). If it detects any dangerous content,the Request Validation module will throw an error. This is by design
To explicitly allow the form posting with Html tags inside the property value, you may decorate your specific property with the AllowHtml attribute
public partial class article
{
[AllowHtml]
public string bodyofarticle { set; get; }
//other properties here
}
This will tell the framework to exclude this property from the above request validation.
I suggest you follow PascalCasing while writing C# code ( Ex : Article instead of article)
I've noticed something in the mvc default projects that made me wonder how it works. When I create a ddefault MVC Project with Individual User Accounts authentication, visual Studio scaffolds an AccountController with two "ResetPassword" Actions. One that accepts a string parameter via GET request. The Action looks like this:
// GET: /Account/ResetPassword
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
return code == null ? View("Error") : View();
}
And the View looks like this:
#model SISGRAD_MVC.Models.ResetPasswordViewModel
#{
ViewBag.Title = "Reset password";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Reset your password.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Code)
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Reset" />
</div>
</div>
I access the Action with the code in the URL, GET-style, and the view knows to initialize the model property from the URL. One point of interest is that this only works if I use #Html.HiddenFor(). How does this work, and how does the view know when to pull data from the URL, and when not to?
Because you method is
public ActionResult ResetPassword(string code)
the DefaultModelBinder will add the value of code to ModelState
The HiddenFor(m => m.Code) method uses values from ModelState rather that the values from the model if they exist so it will render
<input type="hidden" name="Code" id="Code" value="###" />
where ### is the value you passed to the method.
Your statement that the "view knows to initialize the model property from the URL" is not correct. The model is not initialized and is in fact null which you can test using
<div>#Model.Code</div>
which will throw an "Object reference not set to an instance of an object." exception, whereas
<div>#ViewData.ModelState["Code"].Value.AttemptedValue</div>
will display the correct value.
Side note: From your comments, the reason that DisplayFor(m => m.Code) does not show the value is that its is using the value in the ViewData (which is null because the model is null). The default display template uses the following code (refer source code)
internal static string StringTemplate(HtmlHelper html)
{
return html.Encode(html.ViewContext.ViewData.TemplateInfo.FormattedModelValue);
}
as opposed to HiddenFor(m => m.Code) which uses the following code (refer source code
default:
string attemptedValue = (string)htmlHelper.GetModelStateValue(fullName, typeof(string));
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(fullName, format) : valueParameter), isExplicitValue);
break;
Note also that if you define a route with url: "Account/ResetPassword/{code}" then you do not need to add the hidden input in your view. It will be added as a route value by default - the BeginForm() method will render
<form action="Account/ResetPassword/###" ... >