Date format in ASP.Net (MVC)

Displaying a dates in the client culture format is as as easy as:

  • Use the DataType attribute to describe the type in your ViewModel – https://stackoverflow.com/questions/133671/format-date-on-binding-asp-net-mvc/4058891#4058891
public class Model 
{
  [DataType(DataType.Date)]
  public DateTime? Due { get; set; }
}
  • Add the Globalization element to your web.config file to respect the Culture and UICulture of the client: https://msdn.microsoft.com/en-us/library/ydkak5b9(v=vs.71).aspx
  <system.web>
    <globalization culture="auto:en-US" uiCulture="auto:en-US"/>
    <compilation targetFramework="4.6.1" debug="true" />
    <httpRuntime targetFramework="4.6.1" />
  </system.web>

 

  • Make certain that the browser is set to the correct language, which determines culture. In Chrome this means setting the default to the language and also prioritising that language by moving it to the top of the list.

At this point, your date will display in the culture as defined in the browser, with the fallback of en-US as specified in the Web.Config file.

 

ClientID? Grrr.

All too often we find ourselves in a situation where we need to update a web page on the client side, a page which is smack-bang full of server controls. Those controls may be in other containers or be on pages which are part of a nested master page set-up.

As you probably know, the id of the control on the client can be vastly different from the id you assigned it on the server. This is annoying, but necessary. The MSDN says we need to use the ClientID property of the control to use it on the client. I don’t like it; firstly because I don’t like embedding server-side script into client script with <%%>notation, and secondly, I have often been in situations where, well, it just doesn’t work. I could have spent time figuring out why it didn’t work in those situations, but I thought it better to come up with something which agrees with me and will always work, no matter what. I also wanted the solution to be very easy to re-implement across multiple projects and most importantly, to make it’s usage an absolute breeze – no work required.

There are a few intelligent solutions to this issue, all of which have merit and do work. So here’s my version – I hope it makes your life easier.

I thought it would make sense to emit a client script block which would take place for every page. This script block would describe the controls on the page and make those controls available on the client via a simple little object model.

In order to make the script available to each page, I implemented its generation as an HttpModule. The module generates the script in the PreRender event.

So the net effect is that on every page, all server controls are iterated and a JS object model script generated which represents those controls. That script is then pumped down to the client and is therefore available from any other script on the page. The object model is a simple facade which is responsible for returning a controls ClientID, without any complexity, and without having to hook anything up on each page. It just happens.

Here’s the HttpModule:

using System;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.UI;

namespace Web.HttpModules
{
  public class ClientIDModule : IHttpModule
  {
      #region IHttpModule Members

      ///
      ///Initializes a module and prepares it to handle requests.
      ///
      ///
      ///An  that provides access to the methods, properties, and events common to all application objects within an ASP.NET application 
      void IHttpModule.Init(HttpApplication context)
      {
          context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
      }

      private void context_PreRequestHandlerExecute(object sender, EventArgs e)
      {
          Page page = HttpContext.Current.CurrentHandler as Page;

          if (page != null)
              page.PreRender += new EventHandler(page_PreRender);
      }

      private void page_PreRender(object sender, EventArgs e)
      {
          //proc vars
          Page page = sender as Page;
          string theScript = String.Empty;

          //first we need to see if we have already cached the script
          Cache pageCache = HttpContext.Current.Cache;

          if (page != null)
          {
              #region Do the work to create the client script

              //is the script already in the cache? If not, go get it.
              if (pageCache[page.Request.Url.AbsolutePath] == null)
              {
                  //get the script
                  theScript = registerServerControlsOnClient(page);

                  //add it to the cache
                  pageCache.Add(page.Request.Url.AbsolutePath, theScript, null, Cache.NoAbsoluteExpiration, new TimeSpan(8, 0, 0), CacheItemPriority.Normal, null);
              }
              else //pull the script from the cache
              {
                  theScript = pageCache[page.Request.Url.AbsolutePath].ToString();
              }

              //register on page
              page.ClientScript.RegisterClientScriptBlock(page.GetType(), "ServerControls", theScript, true);

              #endregion
          }
      }

      ///
      ///Disposes of the resources (other than memory) used by the module that implements .
      ///
      ///
      void IHttpModule.Dispose()
      {
      }

      #endregion

      #region Implementation

      /// 
      /// Starts the creation of the JS "object" which will be accessible via script on any page.
      /// 
      /// The page which the script should be built for
      private string registerServerControlsOnClient(Page page)
      {
          //proc vars
          StringBuilder sb = new StringBuilder();
          string theScript = String.Empty;

          try
          {
              //build script
              sb.Append("/************************* START ServerControls Script *************************/n");
              sb.Append("function ServerControlsClass(){n");
              sb.Append(getAllServerControls(page.Controls));

              //build blank error object if there was no error
              if (sb.ToString().IndexOf("ClientIDGenerationError")  0)
                      sb.Append(getAllServerControls(control.Controls));
              }
          }

          //ret val
          return sb.ToString();
      }

      #endregion
  }
}

and here’s an example of the resulting script:


/************************* START ServerControls Script *************************/
function ServerControlsClass(){
this.form1 = function(){return "aspnetForm"};
this.ScriptManager1 = function(){return "ctl00_ScriptManager1"};
this.infoMessage = function(){return "ctl00_infoMessage"};
this.infoError = function(){return "ctl00_infoError"};
this.cphContentMain = function(){return "ctl00_cphContentMain"};
this.txtUserName = function(){return "ctl00_cphContentMain_txtUserName"};
this.txtPassword = function(){return "ctl00_cphContentMain_txtPassword"};
this.cmdLogin = function(){return "ctl00_cphContentMain_cmdLogin"};
this.ClientIDGenerationError = function(){return ""};
}
var serverControls = new ServerControlsClass();
/************************* END ServerControls Script *************************/

and here’s an example of the script being used:

var userName = $get(serverControls.txtUserName()).value;

And that’s it! Now you never have to worry about ClientID again.