Fluent Validation: How to check if the email already exists - blazor-server-side

I'm working on a Blazor application with fluent validation.
I'm working on a manage profile page where they can change their first name, last name, and email.
Here is my Razor:
<EditForm Model="Input" OnValidSubmit="#UpdateProfile">
<FluentValidator TValidator="InputModelValidator" />
<div class="form-row">
<div class="form-group col-md-6">
<h2>Manage Profile</h2>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="First Name" #bind-Value="Input.FirstName"></SfTextBox>
</div>
<div class="form-group col-md-4">
<SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="Last Name" #bind-Value="Input.LastName"></SfTextBox>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-4">
<SfTextBox FloatLabelType="FloatLabelType.Auto" Placeholder="Email Address" #bind-Value="Input.Email"></SfTextBox>
</div>
</div>
<div class="form-row btn-update">
<div class="form-group col-md-4">
<SfButton IsPrimary="true">Update</SfButton>
<SfToast ID="toast_customDupemail" #ref="#toastDuplicateEmail" Title="Invalid Email" Content="#toastDupEmailErrorMsg" CssClass="e-toast-danger" Timeout=6000>
<ToastPosition X="Center" Y="Top"></ToastPosition>
</SfToast>
</div>
</div>
</EditForm>
Here is my validator:
public class InputModelValidator : AbstractValidator<InputModel>
{
public InputModelValidator()
{
RuleFor(e => e.FirstName).NotEmpty().WithMessage("First name is required.");
RuleFor(e => e.LastName).NotEmpty().WithMessage("Last name is required.");
RuleFor(e => e.Email).NotEmpty().WithMessage("Email is required.");
RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.");
RuleFor(x => x.Email).Custom((email, context) => {
if (IsEmailValid(email) == false)
{
context.AddFailure("The email is not valid.");
}
});
}
private bool IsEmailValid(string email)
{
var userInfo = Task.Run(async () => await utilities.GetApplicationUser().ConfigureAwait(false)).Result;
if (string.Equals(userInfo.Email, email, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
return false;
}
}
I have the initial checks for empty, and valid email and such. Those work great!
I need to add a custom message to make sure the email is not already in use.
What is the proper way to talk to the database / asp.net identity UserManager within the validator class?
I'm tried to inject my dependencies, but they are coming in null when I try that.
Thanks.
UPDATE:
Per response that this needs to happen in the handler, is something like this possible?
public partial class ManageProfile
{
public InputModel Input { get; set; } = new InputModel();
private EditContext _editContext;
protected override async Task OnInitializedAsync() // = On Page Load
{
var userInfo = await utilities.GetApplicationUser().ConfigureAwait(false);
Input = new InputModel
{
FirstName = userInfo.FirstName,
LastName = userInfo.LastName,
Email = userInfo.Email
};
await InvokeAsync(StateHasChanged).ConfigureAwait(false);
}
private async Task<EditContext> UpdateProfile()
{
_editContext = new EditContext(Input);
var messages = new ValidationMessageStore(_editContext);
messages.Clear();
if (IsEmailValid(Input.Email) == false)
{
messages.Add(() => Input.Email, "Name should start with a capital.");
_editContext.NotifyValidationStateChanged();
return _editContext;
}
return _editContext;
}
private void ValidateFields(EditContext editContext, ValidationMessageStore messages, FieldIdentifier field)
{
messages.Clear();
if (IsEmailValid(Input.Email) == false)
{
messages.Add(() => Input.Email, "Name should start with a capital.");
editContext.NotifyValidationStateChanged();
}
}
private bool IsEmailValid(string email)
{
var userInfo = Task.Run(async () => await utilities.GetApplicationUser().ConfigureAwait(false)).Result;
if (string.Equals(userInfo.Email, email, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
return false;
}
}
public class InputModel
{
[Required]
[MaxLength(250)]
[Display(Name = "First Name", Prompt = "Enter first name")]
public string FirstName { get; set; }
[Required]
[MaxLength(250)]
[Display(Name = "Last Name", Prompt = "Enter last name")]
public string LastName { get; set; }
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
[Required]
[EmailAddress]
[Display(Name = "Email", Prompt = "Enter email")]
public string Email { get; set; }
}
public class InputModelValidator : AbstractValidator<InputModel>
{
public InputModelValidator()
{
RuleFor(e => e.FirstName).NotEmpty().WithMessage("First name is required.");
RuleFor(e => e.LastName).NotEmpty().WithMessage("Last name is required.");
RuleFor(e => e.Email).NotEmpty().WithMessage("Email is required.");
RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.");
}
}
UPDATE 3:
public class InputModelValidator : AbstractValidator<InputModel>
{
public InputModelValidator(UserManager<ApplicationUser> user)
{
RuleFor(e => e.FirstName).NotEmpty().WithMessage("First name is required.");
RuleFor(e => e.LastName).NotEmpty().WithMessage("Last name is required.");
RuleFor(e => e.Email).NotEmpty().WithMessage("Email is required.");
RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.");
//RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.").Must(IsEmailexist).WithMessage("{PropertyName} Is Already Exist.");
}
private async Task<bool> IsEmailexist(string Email)
{
return false;
}
}
I tried injecting UserManager<>, but I have this error:
Severity Code Description Project File Line Suppression State
Error CS0310 'InputModelValidator' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TValidator' in the generic type or method 'FluentValidator' C:...\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Areas_Identity_Pages_Account_ManageProfile_razor.g.cs 200 Active

checking for duplication is not property or value validation, it's better to check this validation in handler or control-action

checking email already exist in DB in middleware follow below process
public class InputModelValidator : AbstractValidator<InputModel>
{
private EditContext _editContext;
public InputModelValidator(EditContext editContext)
{
_editContext=editContext;
RuleFor(e => e.FirstName).NotEmpty().WithMessage("First name is required.");
RuleFor(e => e.LastName).NotEmpty().WithMessage("Last name is required.");
RuleFor(e => e.Email).NotEmpty().WithMessage("Email is required.");
RuleFor(e => e.Email).EmailAddress().WithMessage("Email is not valid.").Must(IsEmailexist).WithMessage("{PropertyName} Is Already Exist.");;
}
private bool IsEmailexist(string Email)
{
return _editContext.userInfo.where(em=>em.EmailId==Email).FirstOrDefault()!=null?true:false;
}
}

Please refer to this answer: https://stackoverflow.com/a/72848675/9594249
Summary: I needed to make a custom form validation that was seperate from FluentValidation.
<EditForm Model="#Input" OnValidSubmit="#UpdateProfile">
<FluentValidator TValidator="InputModelValidator" />
<UI.Models.Other.CustomFormValidator #ref="#customFormValidator" />
https://www.syncfusion.com/blogs/post/blazor-forms-and-form-validation.aspx

Related

EventCallback - is it a func delegate?

What does this mean?
public EventCallback<Trail> OnSelected { get; set; }
Does this mean OnSelected is a delegate (function paramter) that holds input parameter of type Trail and return parameter void?
Why is EventCallback used?
If I have to return a parameter of type string for this delegate how would this declaration look like?
will it look like ?
public EventCallback<Trail, string> OnSelected { get; set; }
EventCallback is a bound event handler delegate.
One of the most common scenarios for using EventCallback is to pass data from a child component to the parent component.
Here is a simple demo about how to pass the string value:
child component
<h3>TestChild</h3>
<input #onchange="UseEcb"/>
#code {
[Parameter]
public EventCallback<string> RecoverRequest { get; set; }
async Task UseEcb(ChangeEventArgs e)
{
await RecoverRequest.InvokeAsync(e.Value.ToString());
}
}
parent component
page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<h2>#result</h2>
<TestChild RecoverRequest="Test"></TestChild>
#code {
[Parameter]
public string result { get; set; }
private void Test(string a)
{
result = "Child Component value is "+a;
}
}
Demo
To answer your first three questions:
An EventCallback is a readonly struct. It's a wrapper for a delegate that supports async behaviour through EventCallbackWorkItem.
It looks like this (extracted from the AspNetCore source code):
public readonly struct EventCallback<TValue> : IEventCallback
{
public static readonly EventCallback<TValue> Empty = new EventCallback<TValue>(null, (Action)(() => { }));
internal readonly MulticastDelegate? Delegate;
internal readonly IHandleEvent? Receiver;
public EventCallback(IHandleEvent? receiver, MulticastDelegate? #delegate)
{
Receiver = receiver;
Delegate = #delegate;
}
public bool HasDelegate => Delegate != null;
internal bool RequiresExplicitReceiver
=> Receiver != null && !object.ReferenceEquals(Receiver, Delegate?.Target);
public Task InvokeAsync(TValue? arg)
{
if (Receiver == null)
return EventCallbackWorkItem.InvokeAsync<TValue?>(Delegate, arg);
return Receiver.HandleEventAsync(new EventCallbackWorkItem(Delegate), arg);
}
public Task InvokeAsync() => InvokeAsync(default!);
internal EventCallback AsUntyped()
=> new EventCallback(Receiver ?? Delegate?.Target as IHandleEvent, Delegate);
object? IEventCallback.UnpackForRenderTree()
=> return RequiresExplicitReceiver ? (object)AsUntyped() : Delegate;
}
You can see the above source code and other related code here - https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/EventCallback.cs
To answer your last two questions:
In your example Trail is what you return.
You would call an EventCallback that returns a string like this in the component:
<div class="row">
<div class="col-auto">
<input class="form-control" type="text" #bind="#this.enteredValue" />
</div>
<div class="col-auto">
<button class="btn btn-primary" #onclick=this.HandleSelect>Set Me</button>
</div>
<div class="col-auto">
<button class="btn btn-secondary" #onclick=this.SetSelect>Set Me To Hello</button>
</div>
</div>
<div class="p-2 m-2 bg-dark text-white">
Value: #this.Value
</div>
#code {
private string enteredValue = string.Empty;
[Parameter] public EventCallback<string> OnSelected { get; set; }
[Parameter, EditorRequired] public string Value { get; set; } = string.Empty;
private async Task SetSelect()
{
await OnSelected.InvokeAsync("Hello");
}
private async Task HandleSelect()
{
await OnSelected.InvokeAsync(enteredValue);
}
}
And consume it like this:
#page "/"
<h2>Test Page</h2>
<MyComponent Value=#this.textValue OnSelected=this.HandleValueChanged />
#code {
private string textValue = string.Empty;
private async Task HandleValueChanged(string value)
{
// Emulate some async activity like getting data
await Task.Delay(1000);
this.textValue = value;
}
}
If you want to return more complex data, create a struct or record to return.
For general usage see the MS-Docs article - https://learn.microsoft.com/en-us/aspnet/core/blazor/components/event-handling?view=aspnetcore-6.0#eventcallback.

Add section comments to my Details view

in my View I have something like this:
<div class="form-group">
<form asp-controller="Ticket" asp-action="Comment" method="post">
<label asp-for="Comment" class="control-label"></label>
<textarea asp-for="Comment.Content" class="form-control" placeholder="Add comment!"></textarea>
<span asp-validation-for="Comment.Content" class="text-danger"></span>
</form>
<input type="submit" value="Add comment" class="btn btn-default" />
This is in my Details View. Now I want to add comment to my model
public class TicketCommentViewModel
{
public Ticket Ticket { get; set; }
public Comment Comment { get; set; }
}
and Controller:
public async Task<IActionResult> Comment(TicketCommentViewModel model)
{
var ticket = await _context.Tickets.FirstOrDefaultAsync(u => u.TicketId == model.Ticket.TicketId);
var user = await GetCurrentUserAsync();
if(ticket == null)
{
return NotFound();
}
model.Comment.SendTime = DateTime.Now;
model.Comment.TicketID = ticket.TicketId;
model.Comment.Ticket = ticket;
model.Comment.UserId = user.Id;
model.Comment.User = user;
_context.Comments.Add(model.Comment);
ticket.Comments = await _context.Comments.ToListAsync();
return View();
}
I have problem with this -> How to go from first code (add Comment) to Controller, and add my Comment to DB.
Can someone help me with that ?
Thanks.
I am not sure what is the problem but I guess that when you click submit your data is not submitted. This is because your submit button is outside the <form>. Try move the submit button inside the <form>
//Two action methods in the controller
public ActionResult AddComment(int PageId, string name, string email, string comment)
{
Comment comment = new Comment()
{
PageID = PageId,
Name = name,
Email = email,
Comment = comment,
CreateDate = DateTime.Now
};
DbContext.Add(jobOffer);
return PartialView("ShowComments", DbContext.Where(c=> c.pageID == PageId));
}
public ActionResult ShowComments(int PageId)
{
return PartialView(DbContext.Where(c=> c.pageID == PageId));
}
//Add the script after the comment div in the View
<script>
function addComment() {
$.ajax({
url: "/Comment/AddComment/"+#Model.PageID,
type: "Get",
data: {
name: $("#txtName").val(), email: $("#txtEmail").val(),
comment : $("#txtComment").val() }
}).done(function(result) {
$("#offerList").html(result);
$("#txtName").val("");
$("#txtEmail").val("");
$("#txtComment").val("");
});
}
</script>

ASP.Net MVC - cannot set value of #Html.Checkbox after changing dropdownlist

I've looking all over for something similar, couldn't find nothing..
I'm using ASP.NET MVC 4. I'm building a page so the users in my app can manage the permissions associated with each role.
So i have a view with #htmlDropDownList to show all the available roles, and below, one #Html.CheckBox for each Permission of the role wich is selected above.
The first time the view is rendered, the checkboxes are all set to true or false, according to the permission of that role.All is fine, life is good :) . When the value of the drop is changed, i post the SelectedRoleId using $.ajax. Then, i fetch all the permissions of the new selected role.
While in debug, in the razor view, i can confirm the new values (true or false) inside the model are correct. The problem is that the checkboxes show the old values, before the role was changed..
This is my first question asked, so i'll have to apologize if the question is not being made the best way.
And thx in advance to all of you :)
So here's my Controller:
public ActionResult Index(int ? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1; // value 1 is the supervisor Role
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
//values for the dropdownlist of Roles
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
//gets all the permissions of the selected role
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
//Gets all the groups of Permissions
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
return View(model);
}
[HttpPost]
public ActionResult Index(FormCollection form) {
switch (form["SubmitButton"])
{
case "Save":
SavePermissions();
break;
default:
return RedirectToAction("Index", new RouteValueDictionary(new { controller = "ManagePermissions", action = "Index", SelectedRoleId = Convert.ToInt32(form["SelectedRoleId"]) }));
}
return View();
}
And here is my View:
'#model AML.Web.Models.ManagePermissionsViewModel
#using (Html.BeginForm("Index", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList("RoleId", Model.RoleList, new { id = "RoleId" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
#Html.CheckBox("Chk_Permisssion", permission.IsSet)
</h5>
}
}
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/JavaScript">
$(document).ready(function () {
$("#RoleId").change(function (e) {
e.preventDefault();
$.ajax({
url: "/ManagePermissions/Index",
cache: false,
type: "POST",
data: { 'SelectedRoleId': $(this).val() },
dataType: "json",
success: function (result) { console.log("Sucess!"); },
error: function (error) { console.log("Error!"); }
})
});
});
</script>
}
And my viewModel:
public class ManagePermissionsViewModel
{
public int? SelectedRoleID { get; set; }
public string SelectedRoleDescription { get; set; }
public SelectList RoleList { get; set; }
public List<Permission> EntirePermissionList { get; set; }
public List<PermissionGroup> ListPermissionGroups { get; set; }
}
public class Permission
{
public int IdPermission { get; set; }
public bool IsSet { get; set; }
public string PermissionDescription { get; set; }
public int PermissionGroupId { get; set; }
}
public class PermissionGroup {
public int Id { get; set; }
public string Description{ get; set; }
}
UPDATE 1 -
Well, i think i got it. Let me post my approach
In the View:
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList,null,
new { onchange = "document.location.href = '/ManagePermissions/Index?SelectedRoleId=' + this.options[this.selectedIndex].value;" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>
And in the Controller:
public ActionResult Index(int? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
ModelState.Clear();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1;
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
ModelState.Clear();
return View(model);
}
Now each time the Drop changes value, the permissions in the checkboxes are updated. I got it to work with the attribute on the drop, "on change = Document.location.hef = URL". Is this a good approach? Or should i use something like ajax request ?
UPDATE 2
The Controller:
public async Task<ActionResult> Index(int? SelectedRoleId)
{
if (SelectedRoleId == null)
{
SelectedRoleId = 1;
}
var model = await GetSelectedPermissions(SelectedRoleId);
return this.View("Index",model);
}
[HttpGet]
public async Task<ActionResult> GetPermissions(string Id)
{
var SelectedRoleId = int.Parse(Id);
var model = await this.GetSelectedPermissions(SelectedRoleId);
return PartialView("_ManagePermissions", model);
}
private async Task<ManagePermissionsViewModel> GetSelectedPermissions(int? SelectedRoleId)
{
ModelState.Clear();
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
model.SelectedRoleID = SelectedRoleId;
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = await (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToListAsync();
model.ListPermissionGroups = await (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToListAsync();
return model;
}
The View
<h2>Permissions - Ajax with Partial View</h2>
#using (Html.BeginForm("SaveData", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList, null, null)
<div id="target">
#Html.Partial("~/Views/Shared/_ManagePermissions.cshtml", Model)
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#SelectedRoleID").change(function () {
var SelectedRoleID = $("#SelectedRoleID").val();
$("#target").load('#(Url.Action("GetPermissions","ManagePermissions",null, Request.Url.Scheme))?Id=' + SelectedRoleID);
});
});
</script>
}
And the Partial View:
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>

(ModelState.IsValid) Property is not working properly in asp.net mvc4 with entity framework

I have tried simple user log in using asp.net mvc4. I have used this condition (ModelState.IsValid), It was workiing before two days. Now i am trying to execute this program, But that property is terminating the condition. Please anyone help me to rectify this problem.
This is my controller code
{
[HttpPost]
[AllowAnonymous]
public ActionResult LogIn(Project.Models.Tbl_Users user)
{
int userid = user.UserID;
var sessionid = Session["userid"];
Session["RoleId"] = user.RoleId;
Session["Username"] = user.UserName;
var sessionval = Session["Username"].ToString();
if (!ModelState.IsValid)
{
if (Isvalid(user.UserName, user.UserPassword))
{
var db = new Project.Models.EntitiesContext();
var userroleid = db.Tbl_Users.FirstOrDefault(u => u.UserName == user.UserName);
Session["RoleId"] = userroleid.RoleId;
int sessionroleid = Convert.ToInt32(Session["RoleId"]);
FormsAuthentication.SetAuthCookie(user.UserName, false);
string sessionusername = Session["Username"].ToString();
if (sessionroleid == 1)
{
return RedirectToAction("adminpage", "LogIn");
}
else
if(sessionroleid==2)
{
return RedirectToAction("teammanager", "LogIn");
}
else
{
return RedirectToAction("userpage", "LogIn");
}
}
return View(sessionval);
}
return View();
}
private bool Isvalid(string username, string password)
{
bool Isvalid = false;
using(var db = new Project.Models.EntitiesContext())
{
var user = db.Tbl_Users.FirstOrDefault(u => u.UserName == username);
var pass = db.Tbl_Users.FirstOrDefault(u => u.UserPassword == password);
if (username != null)
{
try
{
if (user.UserName == username)
{
if (pass.UserPassword == password)
{
Isvalid = true;
//Session["RoleId"] = user.RoleId;
//int sessionid = Convert.ToInt32(Session["RoleId"]);
}
}
}
catch
{
//Response.Write("Login Failed For The User");
Isvalid = false;
}
}
}
}
This is my model
{
[Required(ErrorMessage = "User Name is Invalid")]
[StringLength(200)]
[Display(Name = "User Name")]
public string UserName { get; set; }
[Required(ErrorMessage = "Password Field is Invalid")]
[StringLength(50, MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string UserPassword { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
This is my view code
{
<form method="post" id="signin" action="#Url.Action("LogIn", "LogIn")">
<body style="background-color: Gray;">
<div>
<div>
</div>
#if (!Request.IsAuthenticated)
{
<strong>#Html.Encode(User.Identity.Name)</strong>
#Html.ActionLink("Log Out", "LogOut", "LogIn")
}
else
{
<fieldset>
<div>#Html.LabelFor(u => u.UserName)</div>
<div>#Html.TextBoxFor(u => u.UserName)
#if (Request.IsAuthenticated)
{
#Html.ValidationMessageFor(u => u.UserName)
#*#Html Session["Username"] = #Html.TextBoxFor(u => u.UserName);*#
}
</div>
<div>#Html.LabelFor(u => u.UserPassword)</div>
<div>#Html.PasswordFor(u => u.UserPassword)
#Html.ValidationMessageFor(u => u.UserPassword)
</div>
<div>#Html.CheckBoxFor(u => u.RememberMe)
#Html.LabelFor(u => u.RememberMe, new { #class = "checkbox" })
</div>
<div>
#Html.ValidationSummary(true, "Login Failed")
</div>
<input type="submit" value="LogIn"/>
</fieldset>
}
</div>
</body>
</form>
}
please DEBUG your code.
past this code below, just above if(!ModelState.IsValid)
var propertiesWithErrors = ModelState.Where(state => state.Value.Errors.Any()).Select(state => state.Key);;
propertiesWithErrors will give you the list of properties that has validation errors.

MVC : System.NullReferenceException model when submit form

I've been trying to pass a model to a partial view with a form. Some of the model fields are already assigned in the GET request. When the form loads I can see the model fields values but after
submiting the form I get this error in this line: #Html.Hidden("From",Model.From):
Object reference not set to an instance of an object
Why these two fields are assigned with null on submit?
My controllers:
[HttpGet]
public ActionResult SendPrivateMessage(string from, List<string> to)
{
// two of the fields are already assigned
return PartialView("SendMessage", new MessageModel(from,to));
}
[HttpPost]
public ActionResult SendPrivateMessage(MessageModel m)
{
string fullname = "";
LoginModel loginData = (LoginModel)(Session["user"]);
if (Session["user"] != null)
{
fullname = loginData.LoginDS.Tables[0].Rows[0][loginData.LoginDS.Tables[0].Columns["fullname"].Ordinal].ToString();
}
m.fullname = fullname;
m.Send();
return PartialView("SendMessage");
}
The partial view:
#model HaifanetMobile.Models.MessageModel
<div id="contact_form">
<a id="back_contact" href="#" style="float:left">
<img style="height:20px; width:30px;" src="~/Images/back_btn.gif" alt="back" />.
</a>
<div id="contactus_title">
<div id="close_contactus" style="float:right"><img style="height:20px; width:20px;" src="~/Images/close_btn.gif" /></div>
</div>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<br />
<fieldset>
#Html.Hidden("From", Model.From) //this is where I get the error
#Html.Hidden("To", Model.To)//this is where I get the error
<div>
#Html.TextBoxFor(m => m.Subject, new { #class = "", placeholder = "subject:", id = "msg_subject", onfocus = "this.placeholder = ''", onblur = "this.placeholder = 'subject:'" })
#Html.ValidationMessageFor(m => m.Subject, "required")
</div>
<div>
#Html.TextAreaFor(m => m.Content, new { #class = "", id = "msg_textarea" })
#Html.ValidationMessageFor(m => m.Content, "required")
</div>
</fieldset>
<p>
<input type="submit" value="send" />
</p>
}
</div>
The Model:
public class MessageModel
{
public string From { get; set; }
public List<string> To { get; set; }
public string Subject {get; set;}
public string Content { get; set; }
public string fullname { get; set; }
public MessageModel(string from, List<string> to)
{
// TODO: Complete member initialization
this.From = from;
this.To = to; ;
}
public MessageModel() {
}
public void Send()
{
ServiceReference2.WebService1Soap ws = new ServiceReference2.WebService1SoapClient();
if (!ws.SendMessage(this.From, this.Content, this.Subject, this.To.ToArray() ,this.fullname))
throw new Exception();
}
}
Thanks in advance
You're forgetting to pass the model to your view.
When you return this view, instead of this:
return PartialView("SendMessage");
you must do this:
return PartialView("SendMessage", m);
Where m is your model. That's why the model is null inside your view.