I used to be fiddling with ASP.NET 4.5 and Visual Studio 2012 particularly with all the new Validation attributes and i identified they function great, specially the new unobtrusive validation, then I attempted to permit this sort of validation over a new Vacant Net Software, and that i identified that this just isn't out-of-the-box, you'll need to create some configurations to your Net Application.

You'll find a few ways to allow the unobtrusive validation over a Internet Software:

Through the web.config file

<configuration> 
  <appsettings> 
   <add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms"> 
  </add></appsettings> 
 </configuration> 

Via the Global.asax file

protected void Application_Start(object sender, EventArgs e)
{
   ValidationSettings.UnobtrusiveValidationMode = UnobtrusiveValidationMode.None;
}

On each page:

protected void Page_Load(object sender, EventArgs e)
{
   this.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.WebForms;
}

To disable the unobtrusive validation set the UnobtrusiveValidationMode property to None. Unobtrusive validation is actually enabled by default in ASP.Net 4.5.

We'll start with a simple example, create an Empty Web Application and add a MasterPage called Site.master and a content page for this master called Default.aspx.
Add the following code to the Default.aspx file:

<asp:TextBox runat="server" ID="txt" />
    <asp:RequiredFieldValidator ErrorMessage="txt is required" ControlToValidate="txt" runat="server" Text="*" Display="Dynamic" />
    <asp:Button Text="Send info" runat="server" />

If you try to run a simple ASPX page using a validator, the following exception will be thrown:

    "WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. Please add a ScriptResourceMapping named jquery(case-sensitive)". Before fixing this, let's disable the unobtrusive validation to see the result.

On the page:

protected void Page_Load(object sender, EventArgs e)
{
   this.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.None;
}

Now run the page and the validation will work as it used to work in ASP.Net 4.0 If you examine the rendered HTML, you will see that the gross inline script is rendered:

<script type="text/javascript">
//<![CDATA[
var Page_Validators =  new Array(document.getElementById("ContentPlaceHolder1_ctl00"));
//]]>
</script>

<script type="text/javascript">
//<![CDATA[
var ContentPlaceHolder1_ctl00 = document.all ? document.all["ContentPlaceHolder1_ctl00"] : document.getElementById("ContentPlaceHolder1_ctl00");
ContentPlaceHolder1_ctl00.controltovalidate = "ContentPlaceHolder1_txt";
ContentPlaceHolder1_ctl00.errormessage = "txt is required";
ContentPlaceHolder1_ctl00.display = "Dynamic";
ContentPlaceHolder1_ctl00.evaluationfunction = "RequiredFieldValidatorEvaluateIsValid";
ContentPlaceHolder1_ctl00.initialvalue = "";
//]]>
</script>


<script type="text/javascript">
//<![CDATA[

var Page_ValidationActive = false;
if (typeof(ValidatorOnLoad) == "function") {
    ValidatorOnLoad();
}

function ValidatorOnSubmit() {
    if (Page_ValidationActive) {
        return ValidatorCommonOnSubmit();
    }
    else {
        return true;
    }
}
       
document.getElementById('ContentPlaceHolder1_ctl00').dispose = function() {
    Array.remove(Page_Validators, document.getElementById('ContentPlaceHolder1_ctl00'));
}
//]]>
</script>

Now let's re-enable the unobtrusive validation. In order to fix the previous exception, we need to install the following Nuget packages: (I like to install jQuery first to get the latest version, although this is not required.)

  1. jQuery
  2. ASPNET.ScriptManager.jQuery
  3. Microsoft.AspNet.ScriptManager.MSAjax
  4. Microsoft.AspNet.ScriptManager.WebForms

At this point, if you run the application again, the exception will be gone =) how cool eh?. This is because the following Nuget packages automatically register the scripts needed with the ScriptManager control.

Let's examine the code added by these Nuget packages using ILSpy:

AspNet.ScriptManager.jQuery

public static class PreApplicationStartCode
    {
        public static void Start()
        {
            string str = "1.8.1";
            ScriptManager.ScriptResourceMapping.AddDefinition("jquery", new ScriptResourceDefinition
            {
                Path = "~/Scripts/jquery-" + str + ".min.js",
                DebugPath = "~/Scripts/jquery-" + str + ".js",
                CdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-" + str + ".min.js",
                CdnDebugPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-" + str + ".js",
                CdnSupportsSecureConnection = true,
                LoadSuccessExpression = "window.jQuery"
            });
        }
    }

Microsoft.AspNet.ScriptManager.MSAjax

public static void Start()
{
    ScriptManager.ScriptResourceMapping.AddDefinition("MsAjaxBundle", new ScriptResourceDefinition
    {
        Path = "~/bundles/MsAjaxJs",
        CdnPath = "http://ajax.aspnetcdn.com/ajax/4.5/6/MsAjaxBundle.js",
        LoadSuccessExpression = "window.Sys",
        CdnSupportsSecureConnection = true
    });
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjax.js", "window.Sys && Sys._Application && Sys.Observer");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxCore.js", "window.Type && Sys.Observer");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxGlobalization.js", "window.Sys && Sys.CultureInfo");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxSerialization.js", "window.Sys && Sys.Serialization");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxComponentModel.js", "window.Sys && Sys.CommandEventArgs");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxNetwork.js", "window.Sys && Sys.Net && Sys.Net.WebRequestExecutor");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxHistory.js", "window.Sys && Sys.HistoryEventArgs");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxWebServices.js", "window.Sys && Sys.Net && Sys.Net.WebServiceProxy");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxTimer.js", "window.Sys && Sys.UI && Sys.UI._Timer");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxWebForms.js", "window.Sys && Sys.WebForms");
    PreApplicationStartCode.AddMsAjaxMapping("MicrosoftAjaxApplicationServices.js", "window.Sys && Sys.Services");
}
private static void AddMsAjaxMapping(string name, string loadSuccessExpression)
{
    ScriptManager.ScriptResourceMapping.AddDefinition(name, new ScriptResourceDefinition
    {
        Path = "~/Scripts/WebForms/MsAjax/" + name,
        CdnPath = "http://ajax.aspnetcdn.com/ajax/4.5/6/" + name,
        LoadSuccessExpression = loadSuccessExpression,
        CdnSupportsSecureConnection = true
    });
}

Microsoft.AspNet.ScriptManager.WebForms

public static void Start()
{
    ScriptManager.ScriptResourceMapping.AddDefinition("WebFormsBundle", new ScriptResourceDefinition
    {
        Path = "~/bundles/WebFormsJs",
        CdnPath = "http://ajax.aspnetcdn.com/ajax/4.5/6/WebFormsBundle.js",
        LoadSuccessExpression = "window.WebForm_PostBackOptions",
        CdnSupportsSecureConnection = true
    });
}

As you can see these Nuget packages automatically register the scripts using the ScriptManager object (besides installing the required JavaScript files)

Run the application and examine the rendered HTML. You will note that it's much cleaner now, in this case the inline script has been moved to an external file that can be rendered using bundles to increase performance. The rendered script looks like:

<script src="Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js" type="text/javascript"></script>
<script src="Scripts/jquery-1.8.1.js" type="text/javascript"></script>

Much better right?. Notice how ASP.Net used HTML5 custom attributes:

<input name="ctl00$ContentPlaceHolder1$txt" type="text" id="ContentPlaceHolder1_txt" />
    <span data-val-controltovalidate="ContentPlaceHolder1_txt" data-val-errormessage="txt is required" data-val-display="Dynamic" id="ContentPlaceHolder1_ctl00" data-val="true" data-val-evaluationfunction="RequiredFieldValidatorEvaluateIsValid" data-val-initialvalue="" style="display:none;">*</span>
    <input type="submit" name="ctl00$ContentPlaceHolder1$ctl01" value="Send info" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl00$ContentPlaceHolder1$ctl01&quot;, &quot;&quot;, true, &quot;&quot;, &quot;&quot;, false, false))" />

The data-val-* are custom attributes used by the unobtrusive validation engine

If you click the button to trigger the validation you will be pleased to see that it works as expected...but we are not done yet =/

The settings we have applied won't work if you intend to use an UpdatePanel control (yeah the evil UpdatePanel again...). This is because this control requires a ScriptManager control on the page (or MasterPage) and we do not have any yet. So let's add a simple ScriptManager control to the master page and see what happens. Add the following code to the Site.master page right under the <form...

<asp:ScriptManager runat="server" ID="scriptManager">
        </asp:ScriptManager>

Run the page again and fire the validation... oops... the client validation has gone =( We only have server validation. I'm not sure why this happens but my best guess is that the just added ScriptManager control is overriding our code settings.

To fix it, change the declaration of the ScriptManager control on the Site.master page to:

<asp:ScriptManager runat="server" ID="scriptManager1">
        <Scripts>
            <asp:ScriptReference Name="MsAjaxBundle" />
            <asp:ScriptReference Name="jquery" />
            <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
            <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
            <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
            <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
            <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
            <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
            <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
            <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
            <asp:ScriptReference Name="WebFormsBundle" />
        </Scripts>
    </asp:ScriptManager>

Run the application and our little example will work again as expected

Sadly these new settings are the equivalent to the settings added by code and we need to add them to be able to use the traditional Microsoft AJAX controls.

There's one last thing we need to configure, this is because there's actually a bug with the ValidationSummary control.

To test it, update the Default.aspx page as follows:

<asp:ValidationSummary ID="ValidationSummary1" runat="server" />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <br />
    <asp:TextBox runat="server" ID="txt" />
    <asp:RequiredFieldValidator ErrorMessage="txt is required" ControlToValidate="txt" runat="server" Text="*" Display="Dynamic" />
    <asp:Button Text="Send info" runat="server" />

Now run the page again, scroll down until you can see the button and click it... woot your page jumped to the top... the workaround to solve this little bug is to add the following code to the Site.master

<script>
            window.scrollTo = function () {

            };
        </script>