MVC Form Submit ModelState Invalid- - asp.net-mvc

I am wanting to further my MVC learning. I do not understand why my form won't validate; well, actually I can read the message and it is straightforward enough but I can't find where I'm slipping up.
I'm only including what is relevant to the error message.
My model is this:
[Validator(typeof(ExtForumValidator))]
public partial class ExtrnlSubsModel : BaseEntityModel
{
.....snip......
public int ExtForumBoardId { get; set; }
}
My Validator:
public ExtForumValidator(ILocalizationService localizationService)
{
RuleFor(x => x.ExtForumBoardId)
.NotEqual(0).WithMessage(localizationService.GetResource("ExternalForumBoards.Fields.AvailBoard.Required"));
}
Razor:
<td>
#Html.DropDownListFor(model => model.ExtForumBoardId, Model.AvailableForumBoards)
#Html.RequiredHint()
#Html.ValidationMessageFor(model => model.AvailableForumBoards)
</td>
On submit all my other elements check out except this one has the ModelState error. For attempted value it shows as a string array???? 0,11 or 0,12 or 0,4 etc. It always has a zero and a comma prepended. The second number is correct as that is the id of the item selected in the drop down.
For exception it says null and for error message it says...well it says what I have for the validation message.
So it seems to me that it is getting hung up on this string array 0, stuff and I am at a loss as for where it comes from to go looking for the fix.

Related

MVC5 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

Ive been working on converting a MVC4 project over to MVC5. The first day I ran into an 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' but was able to resolve it by starting my conversion over. I'm not sure what the fix was which is a bummer, because its happened again.
The Error occurs in _ExternalLoginsListPartial.cshtml when I load the Login.cshtml page. The error is thrown on line 15. (string action = Model.Action;)
#using Microsoft.Owin.Security
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
var authenticationDescriptions = loginProviders as AuthenticationDescription[] ?? loginProviders.ToArray();
if (!authenticationDescriptions.Any())
{
<div>
<p>There are no external authentication services configured. See this article
for details on setting up this ASP.NET application to support logging in via external services.</p>
</div>
}
else
{
string action = Model.Action;
string returnUrl = Model.ReturnUrl;
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
{
#Html.AntiForgeryToken()
<div id="socialLoginList">
<p>
#foreach (AuthenticationDescription p in authenticationDescriptions)
{
<button type="submit" class="btn btn-default padded-8 margin-8" id="#p.AuthenticationType" name="provider"
value="#p.AuthenticationType" title="Log in using your #p.Caption account">
<img src="#Url.Content("~/Content/Brands/"+p.Caption+".png")" alt="Microsoft" class="img-responsive" />
<br/>
<b>#p.Caption</b>
</button>
}
</p>
</div>
}
}
}
The error thrown is
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'Action'
The snapshot says
Message : object' does not contain a definition for 'Action'
Source : Anonymously Hosted DynamicMethods Assembly
Now this is double weird because when I set a breakpoint Model.Action is not null. I can see the value.
This is really frustrating. The app was working 5 min ago.. I had changed the html on a non related page.. and now it wont work.
Hackish Fix
I would rather know why this error is happening. That said, I have a quick fix in case anyone else comes across this (Because this is part of part of the default solution). The solution is to not use dynamics. Create your own viewmodel and pass that.
public class ExternalLoginViewModel
{
[Display(Name = "ReturnUrl")]
public string ReturnUrl { get; set; }
[Required]
[Display(Name = "Action")]
public string Action { get; set; }
}
#Html.Partial("_ExternalLoginsListPartial", new ExternalLoginViewModel { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
Check the views in the Account folder and for each one that has an explicit model, make sure the (view)model is in the right namespace. Mouse over the m parameter (m => m.UserName ... etc) and make sure it is referencing the correct (view)model.
In my case, I moved AccountViewModels to a different folder and the app broke as above. It appears the views are sort of "caching" the model from the original namespace. I used a silly fix (commented out the #model line and un-commented it back). Got warning that m is dynamic but when built and ran it worked. Looks like a glitch in VS 2013 RTM.
This bug is verified by Microsoft, and they are working on fixing it.
So anyone from the future who reads this: try updating visual studio 2013 to at least update 2.
https://connect.microsoft.com/VisualStudio/feedback/details/813133/bug-in-mvc-5-framework-asp-net-identity-modules
Found a solution for my own (mvc5) project after some experimenting.
I had a _ExternalLoginsListShoppingCartPartial.cshtml (from my mvc4 project) with #model ICollection<AuthenticationClientData> at the top. I commented it out and rebuild the solution and suddenly it works. I'm not even using that partial view in any view so it's a pretty nasty bug imo.
So check in your project. You may have some mvc4/simplemembership stuff that is messing up your mvc5 project.
I got the same error after replacing account models to another folder. When I double checked each view under the Account folder I found out my "Manage.cshtml" referenced to old namespace. I changed it to correct namespace for my models and the error fixed.
For me I had changed the contents of the ManageUserViewModel to add a property... I then started getting the error. When I changed the Manage.cshtml from not using an explicit model to using:
#model XYZ.Models.ManageUserViewModel
and removed the using statements, it started working again. One hour wasted!
I also hit this issue with VS 2013 U3. I had just added an email field to RegisterViewModel with the [EmailAddress] attribute, and it was crashing when I tried visiting the Register page. Commenting out the [EmailAddress] attribute fixed the issue. However, it continued working after I added the attribute back in, so this is probably a broader issue that could have to do with changes to the model classes.
yeah, I replaced the "else" code with the following and its working but still trying to see why it didn't work when using Model.Action ?
//string action = Model.Action;
//string returnUrl = Model.ReturnUrl;
//using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))

Disable 'The value 'xxx' is not valid for 'yyy' message

In my ASP.NET MVC application, I have a form and I'm using a ViewModel, so the ModelBinder can bind to my Strongly Typed Class. I'm using DataAnnotations for validation
public class FormViewModel
{
[Required]
public string SomeValue {get;set;}
[Range(0, 10, ErrorMessage="Enter a number between 0 and 10.")]
public byte? SomeOtherValue {get;set;}
}
This works great. The problem however is when the user doesn't enter a valid value for the SomeOtherValue (like abc), a standard MVC-error pops up: 'The value 'abc' is not valid for 'SomeOtherValue'. This is really annoying, as I can't customize this message. I know there are ways to Localize this message, but that just doesn't make sense (I don't want a general message, I want a value-specific value).
I tried applying a RegularExpression-attribute to the 'SomeOtherValue', which only allows byte-values, but probably the standard-validation 'overrides' this validation. Is there some way to apply a custom 'the value is not valid' message for a property, or otherwise disable the standard-message?
Here is a different (non-ideal way, IMHO) to fix it if the custom validation attribute is not working for you. In the controller:
if (!ModelState.IsValid)
{
string fieldName = "ThatFieldName";
var m = ViewData.ModelState[fieldName];
if (m != null && m.Errors.Count > 0)
{
ViewData.ModelState.Remove(fieldName);
ViewData.ModelState.AddModelError(fieldName, "You mucked that field up.");
}
}

MVC Entity Framework validation to prevent duplicate records

Hi i'm new to MVC and EF so this may be a really simple question but what is the best way to prevent the user from trying to enter duplicate records?
I have a simple look up table with one column which is the primary key. I'm creating a maintenance screen so admins can add extra items to the look up list. My controller looks like :
public ActionResult Index(string NewRow)
{
try
{
CaseType t = new CaseType { ID = NewRow };
if (ModelState.IsValid)
{
UOW.CaseTypes.Add(t);
UOW.Save();
}
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
}
return View(UOW.CaseTypes.All());
}
Which stops the duplicate records and stops the yellow screen of death but the message displayed is : "An error occurred while updating the entries. See the inner exception for details." which is no good for the users.
I was just wondering if there is a better way to catch the error.
For show validation error I use something like this:
MainEmail it's property from ViewModel
var mod = ModelState.First(c => c.Key == "MainEmail"); // this
mod.Value.Errors.Add("Row's shouldn't duplicates."); // this
if (ModelState.IsValid)
{
return RedirectToAction("Details");
}
return View(client);
Error will show's in this field in view:
<div class="editor-label">
#Html.LabelFor(model => model.MainEmail)
</div>
And for future, you must hide your error screen! You need to display a custom error page:
If you use asp-mvc-3, add to web.config such string:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error" />
...
And users will have /Shared/Error.cshtml page insted of page with exception message (which can show sequrity data).
ADD
About unique constraint creation was discussed here
Unique Constraint in Entity Framework Code First
than you can check about records duplication with your try code.
In my application I use code first and don't add unique constraint because it's lead to low testability. In that case use simple Find before saving changes.
First aproach is little bit faster.
Approach two is grow up testability.
If you want to get the inner exception you can do like this,
catch (Exception ex)
{
while(ex.InnerException!=null){
ex=ex.InnerException;
}
ModelState.AddModelError("", ex.Message);
}
no too sure about the syntax :)

In MVC, how can I make a field in a model non-required after a checkbox is checked?

I have a page written using .NET MVC. In the model for a Person called PersonModel I have this defined which requires the user to enter some text in the last name field:
<DisplayName("Last Name"), Required()> _
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
On the form, there is a checkbox that a user can check to do some other things. Is there a way, using JQuery preferablly, to change that Last Name field to be non-Required? If not using JQuery I am open to other suggestions but since I am doing alot of things when this check box is checked anyways, I was hoping I could add this logic in there. Here is some sample of what I am doing when this box is checked to demonstrate...
function doOwnerBusiness(event) {
if ($(this).is(':checked')) {
$('input[name="People_1__LastName"], label[for="People[1]_LastName"]').hide();​
$("#People_1__LastName").hide();
$("#People_1__LastName").val("");
$("#People_1__LastName :input").attr('disabled', true);
$('input[name="People[1]_Suffix"], label[for="People[1]_Suffix"]').hide();​
$("#People_1__Suffix").attr('disabled', true);
$('#People_1__Suffix')[0].selectedIndex = 0;
$('#People_1__Suffix').hide();
}
else {
$('input[name="People_1__LastName"], label[for="People[1]_LastName"]').show();
$("#People_1__LastName").show();
$('#People_1__LastName :input').attr('disabled', false);
}
}
Any help with this would be appreciated folks.
Thank you
William
Here is how I am declaring my checkbox and also part of the function where I am trying to check if it is checked or not...
<%=Html.CheckBoxFor(Function(model) model.FirstNameAsBusiness)%>
<%=Html.LabelFor(Function(model) model.FirstNameAsBusiness)%>
Function Nominate(ByVal m As NominationModel, ByVal captchaValid As Boolean) As ActionResult
If Not m.FirstNameAsBusiness.checked AndAlso String.IsNullOrEmpty(m.lastnametext) Then
ModelState.AddModelError("LastName", "Last Name field is required if you don't yada yada...")
Return View()
End If
Short answer: no. You can't bypass the DataAnnotation with a jQuery call.
Technically, the Last Name field isn't required. So, I'd remove the DataAnnotation for Required, and then on the backend, when the user submits the form, verify that a field value exists when the checkbox isn't checked. If the conditional doesn't pass, and an error to ModelState for that field, and redirect to the page. (apologies for the c#):
public ActionResult Index(HomeIndexModel form)
{
if (!form.Checked && string.IsNullOrEmpty(form.LastName))
{
ModelState.AddModelError("LastName", "Last Name field is required if you don't yada yada...");
return View();
}
//conditional requirement passed...
}
If you want to get a little fancier, you can check out this thread, though all of the suggestions here are also server-side:
ASP.NET MVC Conditional validation

xVal error messages appearing twice

I'm trying to setup xVal with an ASP.NET MVC 2 Preview 1 project. I'm basically following the example at http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/ to the letter (server-side only, so far).
I have annotated a BlogPost entity, and here is the Post action:
[HttpPost]
public ActionResult Index(BlogPost b)
{
try
{
_blogService.Insert(b);
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "");
}
return (View(b));
}
And here's the service method:
public void Insert(BlogPost post)
{
var errors = DataAnnotationsValidationRunner.GetErrors(post);
if(errors.Any())
{
throw new RulesException(errors);
}
_blogRepo.Insert(post);
}
(Note that the DataAnnotationsValidationRunner is verbatim from the example blog post). When I submit a totally invalid BlogPost form, I get this list of validation errors:
A value is required.
Please enter a title
Please enter a posted date
Please enter some content
Please enter a title
Please enter a posted date
Please enter some content
I don't even know what the first message is for, but as you can see, the other errors are appearing twice. What am I doing wrong? Or is this a problem with MVC V2?
Starting in ASP.Net MVC 2 Preview 1 we now get DataAnnotation validation support out of the box, so I guess your issue is that when the ModelBinder logic runs it is applying the DataAnnotation rules:
public ActionResult Index(BlogPost b) //Create BlogPost object and apply rules
and then with your XVal logic you are requesting the check again:
var errors = DataAnnotationsValidationRunner.GetErrors(post);
This is backed up by the fact they are repeated in the same order.
Your code would have worked fine in version 1 of MVC as public ActionResult Index(BlogPost b) would not have run the DataAnnotation rules. I have not read anywhere if it is possible to turn off the new DataAnnotation logic and just use XVal.
There is more information about this on Scott's post able preview 1
To find out what the first item is run debug and check what errors are on the ModelState, as this will tell you what property on the object the errors are related to.
[HttpPost]
public ActionResult Index(BlogPost b)
{
try
{
_blogService.Insert(b); //Add breakpoint here and check ModelState
}
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "");
}
return (View(b));
}

Resources