Validation failing when using multiple forms - asp.net-mvc

I'm using this construct to host multiple forms in the same view:
When I submit the first form without entering credentials, validation fails. The form reloads as a GET, with a URL of /home/signin, and the expected error messages don't display.
The controller's ModelState is invalid as expected, but I can't figure out why this state isn't passed back to the view.
What am I doing wrong? How can I get validation to work with multiple forms?
Here's my code:
Controller
Imports System.Threading.Tasks
Imports System.Web.Mvc
Imports Website.ViewModels.Home
Imports Microsoft.AspNet.Identity.Owin
Namespace Controllers.Home
Partial Public Class HomeController
<AllowAnonymous>
Public Function Index() As ActionResult
Dim oViewModel As SignInOrSignUp
oViewModel = New SignInOrSignUp
Return Me.View("Index", oViewModel)
End Function
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignIn) As Task(Of ActionResult)
Dim oViewModel As SignInOrSignUp
Dim eStatus As SignInStatus
Dim oAction As ActionResult
oViewModel = New SignInOrSignUp With {.SignIn = Model}
If Me.ModelState.IsValid Then
eStatus = Await Me.SignInManager.PasswordSignInAsync(Model.Username, Model.Password, isPersistent:=False, shouldLockout:=False)
If eStatus = SignInStatus.Success Then
oAction = Me.Redirect("www.domain.com")
Else
Me.ModelState.AddModelError("", "Invalid signin attempt.")
oAction = Me.View("Index", oViewModel)
End If
Else
oAction = Me.View("Index", oViewModel)
End If
Return oAction
End Function
End Class
End Namespace
ViewModel
Imports System.ComponentModel.DataAnnotations
Namespace ViewModels.Home
Public Class SignIn
<Required(ErrorMessage:="User Name is required.")>
<Display(Name:="User Name")>
Public Property Username As String
<Required>
Public Property Password As String
<Display(Name:="Remember Me")>
Public Property RememberMe As Boolean
End Class
End Namespace
View
#ModelType ViewModels.Home.SignInOrSignUp
#Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Website</title>
#Scripts.Render("~/scripts/bootstrap")
#Scripts.Render("~/scripts/jquery")
#Styles.Render("~/styles/bootstrap")
#Styles.Render("~/styles/home")
</head>
<body>
<div class="row">
<div class="wrapper">
<div class="section">
<h5>Sign in here</h5>
<div class="box">
<div class="titlebar">Sign In</div>
#Using (Html.BeginForm("signin", "home", FormMethod.Post, New With {.id = "SignInForm"}))
#Html.AntiForgeryToken
#Html.EditorFor(Function(M) Model.SignIn)
#<div class="button">
<input type="submit" value="Sign In" Class="button" />
</div>
#<div class="anchor">
Forgot your password?
</div>
End Using
</div>
</div>
<div class="section">
<h5>Or enter your City Code here</h5>
<div class="box">
<div class="titlebar">Sign Up</div>
#Using (Html.BeginForm("signup", "home", FormMethod.Post, New With {.id = "SignUpForm"}))
#Html.AntiForgeryToken
#Html.EditorFor(Function(M) Model.SignUp)
#<div class="button">
<input type="submit" value="Continue" Class="button" />
</div>
End Using
</div>
</div>
</div>
</div>
</body>
</html>
--EDIT--
I've been able to get unblocked in the meantime with a clunky workaround in my view:
#Code
If IsPost AndAlso Request.Path = "/home/signin" AndAlso Model.SignIn.Username.IsNothing Then
#Html.ValidationMessageFor(Function(Model) Model.SignIn.Username, "Username is required", New With {.class = "text-danger"})
End If
End Code
But I'd still like to use the in-built validation mechanism if it's possible to do so with multiple forms in the same view.

There are 2 things you can try:
1. Put validation summary on the page:
With this option you are not changing anything in your controller but you are putting error summary on your page. You will not get highlighted field but you will still be able to display all errors, like:
<body>
<div class="row">
<div class="wrapper">
#Html.ValidationSummary(false)
...
</div>
</div>
</body>
Not an elegant solution!
2. In controller use SignInOrSignUp as an input but from UI provide either SignIn or SignUp model:
With this approach you are not changing your vbhtml/cshtml file it will remain as it is only thing you are changing is type of argument on controller methods:
Namespace Controllers.Home
Partial Public Class HomeController
...
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
<HttpPost>
Public Async Function SignUp(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
End Class
End Namespace
unless there is some complex validation involved, this approach will work like a charm!

Related

Adding users to a list MVC

I have a form in which the user is supposed to enter Name and Wage and click a button Add. When the button "Add" is clicked, that user is supposed to be displayed on a list.
This is how I tried it.
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TimeIsMoney.Models;
namespace TimeIsMoney.Controllers
{
public class HomeController : Controller
{
List<UserModel> users = new List<UserModel>();
public ActionResult Index(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
public ActionResult AddUser(UserModel user)
{
users.Add(user);
return View(users);
}
}
}
View:
#model TimeIsMoney.Models.LoginModel
#{
}
#functions{
public string GetAntiForgeryToken()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
<div id="main-content" class="col-md-8 col-md-offset-2">
<div class="col-md-12 row">
<h1>Time is money my friend!</h1>
</div>
<div class="col-md-12 row">
<h2>1000kr</h2>
</div>
<div class="col-md-12 row">
<button class="btn" onclick="start()">Start</button>
<button class="btn" onclick="reset()">Reset</button>
</div>
<div class="col-md-12 row">
<form >
<input type="text" placeholder="Name" />
<input type="number" placeholder="Hourly wage" />
<input type="submit" value="Add" onclick="AddUser()" />
</form>
</div>
<div class="col-md-12 row">
<div class="col-md-3 col-md-offset-1">
<label>Name:</label>
<ul>
<li>Dave</li>
<li>Pete</li>
</ul>
</div>
<div class="col-md-4">
<label>Wage:</label>
<ul>
<li>500kr/h</li>
<li>500kr/h</li>
</ul>
</div>
</div>
<br />
<br />
</div>
Model:
namespace TimeIsMoney.Models
{
public class UserModel
{
[Required]
[DataType(DataType.Text)]
[DisplayName("Username")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Text)]
[DisplayName("Wage")]
public string Wage { get; set; }
}
}
Am I on the right path?
How can I move on from here?
UPDATE:
public ActionResult AddUser(UserModel user)
{
var list = Session["myUsers"] as List<UserModel>;
list.Add(user);
return View(list);
}
You're mostly on the right path excluding way you're trying to store your users list.
Since ASP.NET MVC controller instance is created for every request and disposed after view is rendered and passed to the browser - it will be new controller holding new List<UserModel> created on every request.
So you have to store it somewhere else (session variables, file on server's disk, database and so on). Usually database is best choice for this.
In the case you want to store it in session variable, you should add something like this into Global.asax:
protected void Session_Start(object sender, EventArgs e)
{
Session["myUsers"] = new List<UserModel>();
}
and then in your controller's methods you will be able to access this list as
var list = Session["myUsers"] as List<UserModel>;

i am getting errorin runnging my partial view

Hi i have just started MVC 4 in c#, i am having issue in rendering partial view.
i have created model for the partial view and controller action in which i am just
sending a single string for the testing reasons but when i try to render it.
it just show the following error.
[NullReferenceException: Object reference not set to an instance of an object.]
here is my controller class.
enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using my_photos.Models;
namespace my_photos.Controllers
{
public class DefaultController : Controller
{
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
return View();
}
public ActionResult About() {
ViewBag.Message = "About Page";
return View();
}
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return View(model);
}
}
here is model class for partial view
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace my_photos.Models
{
public class partial
{
public string Winner { get; set; }
}
}
here my partial view
#model my_photos.Models.partial
<div class="body">
<div class="content">
<div class="header">
<h1 class="nav-heading">Data</h1>
<p class="paragraph" > Winner :#Model.Winner.ToString() </p>
</div>
</div>
<div class="bottom">
<div class="header">
</div>
</div>
</div>
and here is my main layout in shared folder
#model my_photos.Models.partial
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>_Layout</title>
<link href="#Url.Content("~/Content/Style/Site.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/Style/Side_barnav.css")" rel="stylesheet" type="text/css" />
</head>
<body>
<header>
<h3> Photos app</h3>
<p> In this app my major concerns are with the <strong>theaming</strong>!</p>
<div class="nav">
<ul class="main-menu">
<li>#Html.ActionLink("Home","Index", "Default")</li>
<li>#Html.ActionLink("About","About", "Default")</li>
<li>#Html.ActionLink("Contact","Contact", "Default")</li>
</ul>
</div>
</header>
<section>
#RenderBody()
#Html.Partial("~/Views/Shared/_partial.cshtml")
</section>
<footer>
<div class="fotter-menu">
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("About","About","Default")</li>
<li>#Html.ActionLink("Contact","Contact","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Resources","Resources","Default")</li>
<li>#Html.ActionLink("Testimonial","Testimonial","Default")</li>
<li>#Html.ActionLink("Team","Team","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
</ul>
</div>
</footer>
</body>
</html>
when ever i try to get value form the model it give me the following error.
kindly help me through this.
[NullReferenceException: Object reference not set to an instance of an object.]
This is happening because your model is null, as you can see, in actions About and Index there is no model being passed. Also partial is a keyword in C#, it will be better to have a more signifiant name.
To solve this you have to pass a model to every view that uses that layout that is expecting this model. In your case is null and an error is thrown.
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
return View(model);
}
It is necesary to pass the model because on the below line of code the partial is rendered by default with the current view model.
#Html.Partial("_partial.cshtml", Model) #* Model is passed by default if there is no other parameter specified *#
I think what you really want to do is to call the _RightView action in your layout.
#Html.Action("_RightView", "Default")
Don't forget to modify the action to return a partial view and the passing of model in the other actions won't be necessary
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return PartialView("_partial", model);
}
hey this is not a big problem you are giving partial class reference to both layout and partial view.
so if you are access a _RightView Action it does't thrown a error because you are passing a object to view properly but when comes it partial view you are not passing object reference so just pass the model in
#Html.Partial("~/Views/Shared/_partial.cshtml",Model)
That's it

MVC4 Post form null value

I have a grid when the client click on Edit for one like a form is open. the User can Edit only some values (let the user to edit only the Shipping date for the current order) but when I send the Form the values of the non editable field are NULL on Post
When I display :
#Html.Display(model => model.Rep)
or :
#Html.TextBoxFor(model => model.ClientName, new { disabled = "disabled", #readonly = "readonly" })
the Values are displayed correctly but when I submit the form the Value are Null.
the View :
#model Models.Orders
#{
Layout = null;
}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="~/Content/pure-release-0.5.0/pure-min.css" rel="stylesheet" />
</head>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<body>
<form class="pure-form">
<fieldset>
<legend>A Stacked Form</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-3" aria-disabled="true" aria-readonly="true">
<label for="first-name">#Html.LabelFor(model => model.Rep)</label>
#Html.Display(model => model.Rep)
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-3" aria-readonly="true">
<label for="first-name">#Html.LabelFor(model => model.ClientName)</label>
#Html.TextBoxFor(model => model.ClientName, new { disabled = "disabled", #readonly = "readonly" })
</div>
</div>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
</body>
}
</html>
<script type="text/javascript">
$(document).ready(function () {
$(".Titre").click(function () {
$(this).next('.Contenu').slideToggle("slow");
});
$("#Model").prop('disabled', true);
});
</script>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}^
The model :
public class Orders
{
public int ID { get; set; }
public string Rep { get; set; }
public string ClientName { get; set; }
}
Controller :
When the User click on Edit on the Grid:
public ActionResult Edit(int id = 0)
{
Orders order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
}
On post:
[HttpPost]
public ActionResult Edit(Orders order)
{
if (ModelState.IsValid)
{
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(order);
}
When I debug I find theat the Values on order are NULL
I Thought that the problem was the waay that I sent data from my grid to the form but i change the easyui to Use GridMVC and still have the problem.
I used : in View TextBoxFor for readOnly + disabled as attribut but same problem
I tried :
in the Model : [ReadOnly(true)]
+ in the View : #Html.EditorFor(model => model.Rep) but I was able to edit Rep That I want to block
I tried to make the EditorFor readonly with Javascript but I was able to edit
Can you help me please, I tried all what I found but there is something missing in my code
Thanks
This is by design. Readonly values are not submitted to server (at least by modern browsers).
If you want to submit this value you can create a hidden field instead of a textbox:
#Html.HiddenFor(model => model.ClientName)
This will effectively submit your value to server
I ran into the same issue. Trying to short cut with the MVC CRUD template. I like what #PaulTaylor suggested:
Attribute [Bind(Exclude=“”)] fails to prevent over-posting
The problem is because you are using 2 forms: one nested to the other. You have to remove the second and add the css class to the first. The Html.BeginForm() will create another form.
You can try something like this:
#using (Html.BeginForm("Edit","controllerName",null,FormMethod.Post,{#class="pure-form"}))
{
#Html.ValidationSummary(true)
<body>
#Html.HiddenFor(model => model.ID)
<fieldset>
<legend>A Stacked Form</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-3" aria-disabled="true" aria-readonly="true">
<label for="first-name">#Html.LabelFor(model => model.Rep)</label>
#Html.Display(model => model.Rep)
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-3" aria-readonly="true">
<label for="first-name">#Html.LabelFor(model => model.ClientName)</label>
#Html.TextBoxFor(model => model.ClientName, new { disabled = "disabled", #readonly = "readonly" })
</div>
</div>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</body>
}
Your text box is disabled. The inputs with disabled attribute set do not get submitted with the form. You can verify this by using network tab of Chrome dev tool or your favorite browser. If you want the text boxes disabled, use just readonly and not the disabled. So, your text box should be as below:
#Html.TextBoxFor(model => model.ClientName, new {#readonly = "readonly" })
Afterwards, you can use jQuery and CSS to make them look like disabled by graying them out if you like but do not use disabled if you want the values to come through.

When I submit the partial view by either keeping the textbox filled/empty, in both cases full view is loading. How can I call Ajax to post it?

I have Area in MVC3 as mentioned below.
Model
public class AdminModule
{
[Display(Name = "MyName")]
[Required(ErrorMessage = "MyName is missing")]
public String MyName { get; set; }
}
I have Partial View with following code.
#model _1.Areas.Admin.Models.AdminModule
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "myForm" }))
{
#Html.LabelFor(i => i.MyName)
#Html.TextBoxFor(i => i.MyName)
#Html.ValidationMessageFor(i => i.MyName)
<p id="getDateTimeString">
</p>
<input type="submit" value="Click here" id="btn" />
}
View
#model _1.Areas.Admin.Models.AdminModule
#{
ViewBag.Title = "Index";
Layout = "~/Areas/Admin/Views/Shared/_LayoutPage1.cshtml";
}
<h2>
Index</h2>
<script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript">
</script>
<script type="text/javascript" src="/scripts/jquery.unobtrusive-ajax.js">
</script>
<div id="myForm">
#Html.Partial("_PartialPage1", Model)
</div>
Layout
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
</head>
<body>
<div>
#RenderBody()
</div>
</body>
</html>
Controller Actions
[HttpPost]
public ActionResult Index(AdminModule model)
{
return PartialView(model);
}
[HttpGet]
public ActionResult Index()
{
AdminModule model = new AdminModule();
model.MyName = "My Name";
return View(model);
}
Confusion
When I submit first time.
I get output like below
and form show like this. Question is - Why is index word coming two times?
When I click second time, form appearance remains same and output shows like below.
Question - Why is Jquery coming so many times ?
You could use an Ajax.BeginForm instead of a regular form. But first you should decide which section of your page you want to be updated after the AJAX call.
Let's suppose the following scenario: if the AJAX call is successful you want to update some section of your DOM with some result and if the AJAX fails you want to update the form and display the error message instead.
To implement this you could start by placing the form inside a partial (_MyForm.cshtml):
#model _1.Models.HomeModels
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "myForm" }))
{
#Html.LabelFor(i => i.MyName)
#Html.TextBoxFor(i => i.MyName)
#Html.ValidationMessageFor(i => i.MyName)
<input type="submit" value="Click here" id="btn" />
}
#if (Model.SomeResultProperty != null)
{
<div>#Model.SomeResultProperty</div>
}
and then you could have your main view reference this partial:
#model _1.Models.HomeModels
<div id="myForm">
#Html.Partial("_MyForm", Model)
</div>
The next step is to update your controller action that will handle the AJAX call:
[HttpPost]
public ActionResult Index(HomeModels model)
{
if (ModelState.IsValid)
{
// validation succeeded => we could set the result property
// on the model to be displayed:
model.SomeResultProperty = "this is the result";
}
return PartialView("_MyForm", model);
}
and finally you need to include the jquery.unobtrusive-ajax.js script to your page in order for the Ajax.BeginForm helper to work:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.unobtrusive-ajax.js")"></script>
Use Ajax.BeginForm instead.
Did you reference validation scripts in your page?

Asp.net mvc delete with AcceptVerbs HttpVerbs.Post method auto invoke problem

I'm new to Asp.net MVC.
I have an application that manages users. My problem is that when I click on a delete link of a user row, the delete method has [AcceptVerbs(HttpVerbs.Post)] annotation is called automatically after a render delete method invoked. Thus, the user with id is deleted before I click on the delete confirm button and the error has occurred afterward.
Everything worked fine before. So, I don't know why this happend.
My code:
// GET: /User/Delete/5
[Authorize]
public ActionResult Delete(int id)
{
return View(GetByUserId(id));
}
// POST: /User/Delete/5
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Users user)
{
//some process
}
The second method invokes automatically after the first one is called.
The view:
<h2>Delete</h2>
<p class="error"><%= Html.Encode(ViewData["messages"]) %></p>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>Fields</legend>
<div class="display-label">UserId</div>
<div class="display-field"><%= Html.Encode(Model.UserId) %></div>
<div class="display-label">UserName</div>
<div class="display-field"><%= Html.Encode(Model.UserName) %></div>
<div class="display-label">FullName</div>
<div class="display-field"><%= Html.Encode(Model.FullName) %></div>
<div class="display-label">Email</div>
<div class="display-field"><%= Html.Encode(Model.Email) %></div>
<div class="display-label">DayOfBirth</div>
<div class="display-field"><%= Html.Encode(String.Format("{0:MM/dd/yyyy}", Model.DayOfBirth))%></div>
<div class="display-label">Phone</div>
<div class="display-field"><%= Html.Encode(Model.Phone) %></div>
<div class="display-label">Active</div>
<div class="display-field"><%= Html.Encode(Model.Active) %></div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Delete" /> |
<%= Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>
You can create another view which will solve your purpose of confirmation delete.
Please find more details using following link.
http://forums.asp.net/t/1513258.aspx
Please find your modify code below.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Delete()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(RegisterModel ob)
{
return RedirectToAction("Index");
}
}
Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<h1>
#Convert.ToString(ViewBag.Delete)
</h1>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">
http://asp.net/mvc</a>.
<br />
<br />
#Html.ActionLink("Delete record", "Delete");
<br />
<br />
</p>
delete.cshtml
#model MvcApplication1.Models.RegisterModel
#{
ViewBag.Title = "Delete";
}
<h2>
Delete</h2>
<div>
Are you sure you want to delete this?</div>
#using (Html.BeginForm())
{
<p>
<input type="submit" value="Delete" />
|
</p>
}
Above code is same as your code and it's working fine. Please have a look.

Resources