2011-05-10

ASP.NET MVC: Where is the ClientID?

,

For those who are used to program in ASP.NET know this scenario. You have a textbox and you want to do some custom validation in Javascript. You have to be able to access the textbox from the Javascript. The first thing you need to know is the Id for that textbox. You can’t hard code it, because you are not sure how ASP.NET will generate the Id. If the control exists in an INamingContainer, the INamingContainer will add some prefix to the Id of the control.

That is where the ClientID property comes to the rescue. This property contains the Id that will be used in HTML. Take a look at this example.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">

    <script type="text/javascript" language="javascript">

        function ButtonClicked() {

            var element = document.getElementById('<%= MyTextBox.ClientID %>');

            alert('Value: ' + element.id);
        }
    
    </script>
   
   
   <asp:TextBox ID="MyTextBox" runat="server" />

   <button onclick="javascript:ButtonClicked()">Click Here</button>
</asp:Content>

In this example the Id of MyTextBox will be showed in a messagebox. Because MyTextBox is added in a Asp:Content control, the Id of this textbox will be prefixed with something. When we run the site and look at the source of the webpage, we will see it’s id.

<script type="text/javascript" language="javascript">
function ButtonClicked() {

var element = document.getElementById('MainContent_MyTextBox');

alert('Value: ' + element.id);
}
</script>

<input name="ctl00$MainContent$MyTextBox" type="text" value="dfd" id="MainContent_MyTextBox" />

<button onclick="javascript:ButtonClicked()">Click Here</button>

But how do we do this in ASP.NET MVC?


Take a look at this example. We use the TextBoxFor extension method to generate a textbox for our model. How do we figure out the Id that is used for the textbox?






@model MvcApplication2.Models.Person



@{

    ViewBag.Title = "Home Page";

}



<h2>@ViewBag.Message</h2>

<p>

   

   <script type="text/javascript" language="javascript">



       function ButtonClicked() {



           var element = document.getElementById("????");



           alert("Value: ??");

       }

   

   </script>





   @Html.TextBoxFor(m => m.Name);



   <button onclick="javascript:ButtonClicked()">Click Here</button>



</p>



You can hardcode the Id of the textbox ( “Name” ) in the javascript, but would it not be a lot  more beautiful or easier ( intellisense) if you could pas a lambda expression?


After looking in Reflector i saw that MVC uses this static class for generating an Id and it passes this Id to a static method of the TagBuilder class called “CreateSanitizedId”.




namespace System.Web.Mvc

{

    // Summary:

    //     Provides a helper class to get the model name from an expression.

    public static class ExpressionHelper

    {

        // Summary:

        //     Gets the model name from a lambda expression.

        //

        // Parameters:

        //   expression:

        //     The expression.

        //

        // Returns:

        //     The model name.

        public static string GetExpressionText(LambdaExpression expression);

        //

        // Summary:

        //     Gets the model name from a string expression.

        //

        // Parameters:

        //   expression:

        //     The expression.

        //

        // Returns:

        //     The model name.

        public static string GetExpressionText(string expression);

    }

}



Now that we know this, the only thing left to do is to create an HtmlHelper extension that will do exactly the same.





namespace System.Web.Mvc.Html

{

    public static class IdHtmlHelper

    {

        public static String GetIdFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)

        {

            return TagBuilder.CreateSanitizedId(ExpressionHelper.GetExpressionText(expression));

        }

    }

}



Now we can write our code like this:




@model MvcApplication2.Models.Person



@{

    ViewBag.Title = "Home Page";

}



<h2>@ViewBag.Message</h2>

<p>

   

   <script type="text/javascript" language="javascript">



       function ButtonClicked() {



           var element = document.getElementById("@Html.GetIdFor( m=> m.Name)");



           alert("Value: " + element.id);        

       }

   

   </script>





   @Html.TextBoxFor( m => m.Name)



   <button onclick="javascript:ButtonClicked()">Click Here</button>



</p>




When we render the page and look at the source, we can see that the Id is put in the getElementById method.

<p>

<script type="text/javascript" language="javascript">

function ButtonClicked() {

var element = document.getElementById("Name");

alert("Value: " + element.id);
}

</script>


<input id="Name" name="Name" type="text" value="John Doe" />

<button onclick="javascript:ButtonClicked()">Click Here</button>
</p>
Read more →

2011-05-03

ASP.NET MVC 3 and Unity using an IDependencyResolver

,

In this post i used a custom ControllerFactory for dependency injection. I created a custom ControllerFactory where i overrided the GetControllerInstance method. In this method i used the UnityContainer for creating instances of the requested controller.

In ASP.NET MVC 3 their is some build in abstraction for doing dependency injection ( IDependencyResolver ). I will change the example used in this post to use the IDependencyResolver.

the IDependencyResolver

The IDependencyResolver is a fairly easy interface. It contains only 2 methods:

  • object GetService (Type serviceType)
    • The GetService method is used to resolve a single registered service
  • IEnumerable<object> GetServices(Type serviceType)
    • The GetServices method resolves all registered services

In our case, we will create an UnityDependencyResolver. This implementation will accept an IUnityContainer and will use this container for resolving the requested types. If the DependencyResolver is unable to resolve a type, it should always return null for the GetService method and an empty collection for the GetServices method. That is why a try catch is used in the UnityDependencyResolver.

    public class UnityDependencyResolver : IDependencyResolver
    {
        IUnityContainer container = null;

        public UnityDependencyResolver(IUnityContainer container)
        {
            this.container = container;
        }

        #region IDependencyResolver Members

        public object GetService(Type serviceType)
        {
            try
            {
                return container.Resolve(serviceType);
            }
            catch
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return container.ResolveAll(serviceType);
            }
            catch
            {
                return new List<object>();
            }
        }

        #endregion
    }



Registering the UnityDependencyResolver

Now that we created this dependency resolver, we have to register it so that the MVC framework will use it. This is done in the Global.asax, in the Application_Start method.

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
            
            DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfigurator.GetContainer()));
        }

You could also register it inside a WebActivator.PreApplicationStartMethod.

Changing the UnityControllerFactory

In the UnityControllerFactory we now can use the IDependencyResolver that we registered to resolve the requested controllers. It doesn’t need to work with an IUnityContainer any more.

    public class UnityControllerFactory : DefaultControllerFactory
    {        
        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            IController result = null;

            if (null != controllerType)
            {
                result = DependencyResolver.Current.GetService(controllerType) as IController;
            }

            return result;
        }
    }

Changing the UnityConfigurator

As you might have noticed the Application_Start method of the Global.asax has changed a bit. The line for registering our UnityControllerFactory has been removed (see this post ) . The MVC 3 framework will use it’s current DependencyResolver to resolve a ControllerFactory, so we have to register our UnityControllerFactory with the IUnityContainer. Now the MVC 3 framework will use our UnityControllerFactory as it’s default ControllerFactory.

public class UnityConfigurator
{
    public static IUnityContainer GetContainer()
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<IControllerFactory, UnityControllerFactory>();
        container.RegisterType<ITitleRepository, TitleRepository2>(new HttpContextLifetimeManager<ITitleRepository>());

        return container;
    }
}

 

The result

If we run it, everything works just fine.

Read more →