I am using WebForms and I am trying to perform Model Validation inside a Master-Page and for some reason the model is not picking up the values, meaning that after the validation fires if I enter a good value, the model keeps coming back empty hence triggering the validation over and over. If I put the code in page without Master-Page it works fine. I was able to put a very simple example and honestly, it's hard to believe that as common as MasterPages are, nobody has ran into this scenario so far. For the purpose of this example I embedded the Model in the Code Behind but having outside makes no different. Any idea will be greatly welcome. Thanks.
--Master-Page--
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="test.master.cs" Inherits="test" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
-- WebForm --
<%@ Page Title="" Language="C#" MasterPageFile="~/test.master" AutoEventWireup="true" CodeFile="test3.aspx.cs" Inherits="test3" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<div>
<asp:ValidationSummary ID="valSummary" runat="server" />
</div>
<div><label>First Name:</label></div>
<div><input type="text" id="FirstName" runat="server" /></div>
<div><label>Middle Name:</label></div>
<div><input type="text" id="MiddleName" runat="server" /></div>
<div><label>Last Name:</label></div>
<div><input type="text" id="LastName" runat="server" /></div>
<div>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" />
</div>
</asp:Content>
-- Code Behind --
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.ModelBinding;
using System.ComponentModel.DataAnnotations;
public partial class test3 : System.Web.UI.Page
{
public class testClass2
{
[Required()]
[MinLength(2)]
public string FirstName { get; set; }
public string MiddleName { get; set; }
[Required()]
[MinLength(2)]
public string LastName { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
testClass2 tc = new testClass2();
if (TryUpdateModel(tc, new FormValueProvider(ModelBindingExecutionContext)))
{
System.Diagnostics.Debug.WriteLine("test");
}
}
}
}
The problem is indeed caused by usage of the master page. When used outside of the data bound control (such as GridView
, FormView
, Menu
, etc.), FormValueProvider
expects to have the same keys in Request.Form
dictionary as property names in model object.
If you will take a closer look at generated HTML you will see that all input
tags in form with master page have name
attribute value set to something like ctl00$ContentPlaceHolder1$FirstName
, ctl00$ContentPlaceHolder1$LastName
, etc. while form without master page leaves name attribute intact and equal to the value of control's ID
property.
This is the way of how UniqueID
is generated to avoid name duplication (which should be avoided because in Web Forms we can have only one form
tag and thus have controls with same ID's
both on master page and form page).
And this is the cause why FormValueProvider
cannot get values for your testClass2
object, it just cannot find FirstName
, LastName
, MiddleName
values in posted form.
I found a solution.You can write a little front-end code to set the name
equal to id
and don't forget to set ClientIDMode
to Static
<script>
$("input[type=text]").each(function () {
var id = $(this).attr("id");
$(this).attr("name", id);
});
</script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With