Validation Summary is not cleared after Ajax.Form successfully posted, MVC 3

My scenario is after the invalid form values are posted through ajax.form, and the validation summary is displaying on the view. After I filled in all the required fields and posted the form with valid values, the post back data is correctly displaying, but the validation summary is remaining on the page.

Here are some code snippets,

The view contains two date picker (textbox) which are required fields.

    @model ClosedTicketByProductReportViewModel
    @using (Ajax.BeginForm("ClosedTicketByProductReport", "Report", new AjaxOptions { UpdateTargetId = "closedTicketByProductGrid", LoadingElementId = "loadingcontainer" }))
        <div class="control-group">
            Date From
            <div class="controls">
                @Html.TextBoxFor(p =&gt; p.DateFromForClosedProduct, new Dictionary { { "class", "small" }, { "type", "date" }, { "data-datepicker", "datepicker" } })
        <div class="control-group">
            Date To
            <div class="controls">
                @Html.TextBoxFor(p =&gt; p.DateToForClosedProduct, new Dictionary { { "class", "small" }, { "type", "date" }, { "data-datepicker", "datepicker" } })

        Generate Report

Here is the view model I created for the view,

    public class ClosedTicketByProductReportViewModel

        [Required(ErrorMessage = "Please select Date From")]
        public DateTime? DateFromForClosedProduct { get; set; }

        [Required(ErrorMessage = "Please select Date To")]
        public DateTime? DateToForClosedProduct { get; set; }

        //report data
        public List Cases { get; set; }


After I click submit without entering any dates, it displays the error messages as expected.


Then I enter the dates, and click submit again. The post back data is retrieved from controller action, but the validation summary remains on the page. As you can see the validation errors on the textbox itself are gone. Ajax.Form is only lack of support on the validation summaries.


Here is my fix, I don’t think it is great, but it is a work around.

    @using (Ajax.BeginForm("ClosedTicketByProductReport", "Report", new AjaxOptions { OnSuccess = "HideValidationSummary", UpdateTargetId = "closedTicketByProductGrid", LoadingElementId = "loadingcontainer" }))
    { }

I created a javascript function and call it on OnSuccess = "HideValidationSummary, the javascript function just hide the validation summary div.

function HideValidationSummary() {

If anyone come across my blog post and has a better solution, please leave me a message. Much appreciated.


Using twitter bootstrap with bottom sticky footer

Nowadays, more website comprises 3 components. header, body and footer. With bootstrap, you can get it done even quicker. Here I created a sample start up project with most common layout in the world: Top fixed header, body and bottom sticked footer.

Here are some codes of the _layout.cshtml (if you are using MVC) or masterpages ( or any other languages whatever you call it.

For header section, use the bootstrap default “navbar” classes, you can set it to “navbar-fixed-top” or not, it is your choice. Set to top fixed, the header bar is always visible when you scrolling down.

    <div class="navbar navbar-fixed-top">
        <div class="navbar-inner">
            <div class="container">
                <a href="/" class="brand">Brand name</a>
                <ul class="nav">
                    <li><a href="">Home</a></li>
                    <li class="divider-vertical"></li>  
                    <li><a href="">Products</a></li>
                    <li class="divider-vertical"></li>
                    <li><a href="">FAQ</a></li>
                <ul class="nav pull-right">
                    <li><a href="">Register</a></li>
                    <li><a href="">Login</a></li>

For body section, I created a “wrap” div outside the “main” div, this is to make sure the footer stays after it. You will know what I mean after I show you the CSS

    <div id="wrap">
    <div id="main" class="container clear-top">
        <div class="row"> 
            <div class="span12">

For footer section, using <footer> is completely ok with modernizer, and I created a 3 columns with same size for your footer navigation links.

    <footer class="footer" style="background-color:#c2c2c2;">
        <div class="container" style="margin:0 auto;">
            <div class="row">
                <div class="span2 offset2">
                        <li><a href="">About Us</a></li>
                        <li><a href="">Contact</a></li>
                <div class="span2 offset1">
                        <li><a href="">Get help</a></li>
                        <li><a href="">FAQ</a></li>
                        <li><a href="">Support</a></li>
                <div class="span2 offset1">
                        <li><a href="" title="Facebook">Facebook</a></li>
                        <li><a href="" title="Twitter">Twitter</a></li>
                        <li><a href="" title="LinkedIn">LinkedIn</a></li>
                        <li><a href="" title="Google+">Google+</a></li>
                        <li><a href="" title="RSS">RSS</a></li>
                        <li><a href="" title="Blogs">Blogs</a></li>

Now let’s see the CSS,

/* styles for layout */

  min-height: 100%;  

    padding-bottom:150px; /* this needs to be bigger than footer height*/

    position: relative;
	margin-top: -150px; /* negative value of footer height */
	height: 150px;

Your footer is sticked to the bottom always.

To download the project sample, go to codeplex

Security configurations for MVC application & IIS 7

After Sony had been hacked earlier this year, they start taking security really serious now.

And recently I have been involved in a few Sony promotion projects that makes me learn a lot about how to make a website more securer from both web server configurations and application itself.

Go through a 50 pages configuration benchmark book is a pain, but there are some really simple steps people easily forget. Here are some highlights:

  1. Make sure web content is on non-system partition.
  2. Remove or rename well-known urls.
  3. Require a host headers on all sites. Don’t bind http:/*:80 to any site.
  4. Disable directory browsing
  5. Set default application pool identity to least privilege principal.
  6. Ensure application pools run under unique identities, and unique application pools for different sites.
  7. Config anonymous user identity to use application pool identity, this will greatly reduce the number of accounts needed for websites.
    open applicationHost.config and make sure you set the userName attribute of the anonymousAuthentication tag is set to a blank string.

    <system.webServer><security><authentication><anonymousAuthentication userName = ""/></authentication></security></system.webServer>
  8. Configure authentications,

    a. Ensure sensitive site features is restricted to authenticated principals only.

    <system.webServer><security><authorization><remove users="*" roles="" verbs="" /><add accessType="Allow" roles="administrators" />

    b. Require SSL in forms authentications and configure forms authentication to use cookies.

    <pre><system.web><authentication><forms cookieless="UseCookies" requireSSL="true" /></authentication></system.web></pre>

    c. Configure cookie protection mode for forms authentication.

    <pre><system.web><authentication><forms cookieless="UseCookies" protection="All" /></authentication></system.web></pre>

    d. Never save password in clear format!!

  9. configurations.

    a. Set deployment method to retail, modify machine.config

    <system.web>  <deployment retail="true" /></system.web>

    b. Turn debug off.

    <system.web><compilation debug="false" /></system.web></configuration>

    c. Ensure custom error messages are not off.

    <customErrors mode="RemoteOnly"/> or <customErrors mode = "On"/>

    d. Ensure failed request tracing is not enabled.

    – Open IIS.

    – Go to Connections pane, select server connection, site, application or directory.

    – In actions pane, click failed request tracing… make sure the checkbox is not checked.

    e. Configure to use cookies mode for session state in web.config

    <system.web><sessionState cookieless="UseCookies" /></system.web>

    f. Ensure cookies are set with HttpOnly attribute in web.config. This will stop client side script access to cookies.

    <configuration><system.web><httpCookies httpOnlyCookies="true" /></system.web></configuration>

    g. Set global .NET trust level. Open IIS, in the features view, double click .NET Trust Levels.

  10. Request filtering & restrictions in web.config, set maxAllowedContentLength, maxUrl, maxQueryStringallowHighBitCharacters (setting to dis-allow non-ASCII characters) & allowDoubleEscaping.
    <system.webServer><security><requestFiltering allowHighBitCharacters="false" allowDoubleEscaping = "false"><requestLimits maxAllowedContentLength="30000000" maxUrl="4096" maxQueryString="1024" /></requestFiltering></security></system.webServer></configuration>
  11. Disallow unlisted file extensions in web.config.
    <system.webServer><security><requestFiltering><fileExtensions allowUnlisted="false" ><add fileExtension=".asp" allowed="true"/>
    <add fileExtension=".aspx" allowed="true"/><add fileExtension=".html" allowed="true"/></fileExtensions></requestFiltering></security></system.webServer></configuration>

LabelFor html helper with htmlAttributes, MVC 3

The default LabelFor() html helper only comes with two overloads.

Html.LabelFor(Expression expression)

Html.LabelFor(Expression expression, string labelText)

Here is the extension came handy when you want to apply style sheet classes to the label.

public static class LabelForExtensions
        public static MvcHtmlString LabelFor(this HtmlHelper html, Expression<Func> expression, object htmlAttributes)
            return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
        public static MvcHtmlString LabelFor(this HtmlHelper html, Expression<Func> expression, IDictionary htmlAttributes)
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
                return MvcHtmlString.Empty;

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));


Call it in the view by using the following line of code.

@Html.LabelFor(a => a.Name, new { @class="field-label",title="Enter Username"})

The output is,


Integrate openID, oAuth to your site using JanRain

Integrate openID to your site using JanRain. It is definitely a time saver. My site is built in mvc3 and here are the steps how to do it.

1. You need to setup the widget and copy the generated js code to your site and update the “tokenUrl”.

<script type="text/javascript">(function() {    if (typeof window.janrain !== 'object') window.janrain = {};    window.janrain.settings = {};

    janrain.settings.tokenUrl = '__REPLACE_WITH_YOUR_TOKEN_URL__';

    function isReady() { janrain.ready = true; };    if (document.addEventListener) {      document.addEventListener("DOMContentLoaded", isReady, false);    } else {      window.attachEvent('onload', isReady);    }

    var e = document.createElement('script');    e.type = 'text/javascript'; = 'janrainAuthWidget';

    if (document.location.protocol === 'https:') {      e.src = '';    } else {      e.src = '';    }

    var s = document.getElementsByTagName('script')[0];    s.parentNode.insertBefore(e, s);})();</script>

2. Add your site url to the whitelist, here I put “” JanRain Integration JanRain Integration

3. I created a JanRainHelper to make the “auth_info” API call, and a class “JanRainData” for the de-serialization of the response data. (please forgive the naming conversions, I just copied all the return data fields from JanRain)

Don’t forget to copy your own “apiKey” and paste in the code below.

public class JanRainHelper{public static string AuthInfo(string token){string apiKey = "***************************";

WebRequest req = WebRequest.Create("");

((HttpWebRequest)req).UserAgent = "JanRainProServ/1.0(Automated)";req.Method = "POST";

string postData = "token=";postData += token;postData += "&apiKey=";postData += apiKey;

byte[] byteArray = Encoding.UTF8.GetBytes(postData);// Set the ContentType property of the WebRequest.req.ContentType = "application/x-www-form-urlencoded";// Set the ContentLength property of the WebRequest.req.ContentLength = byteArray.Length;// Get the request stream.Stream dataStream = req.GetRequestStream();// Write the data to the request stream.dataStream.Write(byteArray, 0, byteArray.Length);// Close the Stream object.dataStream.Close();

// Send the data to the webserverHttpWebResponse rsp = (HttpWebResponse)req.GetResponse();string content = "";using (StreamReader sr = new StreamReader(rsp.GetResponseStream())){content = sr.ReadToEnd();}return content;}}


[Serializable]public class JanRainData{public Profile profile { get; set; }public string stat { get; set; }}

[Serializable]public class Profile{public string identifier { get; set; }

public string providerName { get; set; }

public string displayName { get; set; }

public Name name { get; set; }

public string gender { get; set; }

public bool? genderBool{get{if (string.IsNullOrEmpty(gender))return null;else{if (gender.Equals("male")){return true;}else if (gender.Equals("female")){return false;}else{return null;}}}}

public string birthday { get; set; }

public DateTime? birthdayDateTime{get{DateTime dt;if (!string.IsNullOrEmpty(birthday) && DateTime.TryParse(birthday, out dt)){return dt;}else{return null;}}}

public string email { get; set; }

public string verifiedEmail { get; set; }

public string phoneNumber { get; set; }

public string photo { get; set; }

public Address address { get; set; }}

[Serializable]public class Name{public string givenName { get; set; }public string familyName { get; set; }public string formatted { get; set; }}

[Serializable]public class Address{public string formatted { get; set; }public string streetAddress { get; set; }public string locality { get; set; }public string region { get; set; }public string postalCode { get; set; }public string country { get; set; }}

4. Create an Action method for the “tokenUrl”, JanRain post back with a token, and you will need to use that token to call the auth_info API to retrieve the user info.

I am using the JavascriptSerializer to deserialize the response to a JanRainData object. Then you can do whatever you need to do, such as create a user in your database and authentication cookie, etc.

public ActionResult JanRainPostBack(string token){if (!string.IsNullOrEmpty(token)){string content = JanRainHelper.AuthInfo(token);JavaScriptSerializer s = new JavaScriptSerializer();

var data = s.Deserialize<JanRainData>(content);if (data.stat.Equals("ok") && !string.IsNullOrEmpty(data.profile.providerName) &&       !string.IsNullOrEmpty(data.profile.identifier)){var user = new User(){Email =};_repository.Save(user);return View();}elsethrow new Exception("response failed");}elsethrow new Exception("token is invalid");}

5. It is all done now. Please be aware you might only retrieve limited user information from different openID providers. Eg, twitter will not return an email address which I think it’s pretty lame. If email is required in your dbo.User table, you will need to enforce users to complete the registration.