Has developers forgotten about this?

Old but great article, thought of reminding young minds.

http://www.asp.net/mvc/overview/performance/bundling-and-minification

Developers are busy with building the end product, poor performance of the application is realized after releasing it to production. These days end users won’t even use a system if its snail walking.

Above approach is a good way to reduce needless trafficking to your application and improve performance on the page load.

If you are not using it, then its time to start.

Dynamic URL in MVC – A CustomRouteHandler

Scenario: Your customers need to have their own name in your application URL.

eg. http://www.yourapp.com/GOODCUSTOMERNAME

Usually in MVC you have to define your route table, but to have a dynamic route table based on your customer names is not that easy. That is where the custom route handler comes in to play.

Step 1: Changes in Global.asax.cs

We pass all the calls through our CustomRouteHandler.

public static void RegisterRoutes(RouteCollection routes)
{
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   var b = new {controller = "Home", action = "Index", id = UrlParameter.Optional, area = ""};
   routes.Add("Default", new Route("{controller}/{action}/{id}", new RouteValueDictionary(b),
   new CustomRouteHandler()));
}

Step 2: Writing the CustomRouteHandler

Note: MyService is one of my business layer service to resolve the URLs. And I will send the resolved value to “Home/Index” with a parameter name called “name”. Cool! I have only one value to resolve.

public class CustomRouteHandler : MvcRouteHandler
{
   protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
   {
      string customerName= string.Empty;
      var controller = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
      if (string.IsNullOrWhiteSpace(controller))
      {
          controller = "Home";
          // The initial call sometimes does not carry the controller name
      }
       if (!string.IsNullOrWhiteSpace(controller))
       {
           customerName = controller;
           var s = MyService.ResolveUrl(customerName);
           //YOUR BUSINESS LOGIC TO RESOLVE THE URL GOES HERE, IF YOU HAVE MULTIPLE VALUES IN THE URL USE STRING MANIPULATION AS YOU WANT.
           if (s == null) // CANNOT RESOLVE, LEAVE THE CONTROLLER NAME ALONE
           {
               customerName= string.Empty;
           }
           else
           {
               controller = "Home";
               requestContext.RouteData.Values["name"] = customerName; //My Index method in HomeController is accepting a parameter called "name", that is the resolved customer name.
           }
       }
       requestContext.RouteData.Values["controller"] = controller; //Update the Controller Name
       var action = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
       if (string.IsNullOrWhiteSpace(action))
       {
           action = "Index"; //The initial call sometimes does not carry the action name
       }   
       //Since I don't have much to resolve in action name, I just pass the value. But if you have multiple resolution to the action (methods to refer), I think you can figure out how to change this code.
       requestContext.RouteData.Values["action"] = action;
       //At this moment you should have a correct/resolved values to the route data values, otherwise you will get a error page.
       return base.GetHttpHandler(requestContext);
    }
}

That is all, everything will be handled by the custom route handler. If you want more logics to resolve, just put them inside the handler.
Just keep in mind the actual controller classes must have a way to get the resolved values from the URL. Just like I have used the “name” parameter.
With this approach the URL entered in the browser would look more customer specific, and will not change, but the back end custom route handler resolve the URL for our app.

Pretty neat. eh!

NHibernate and Spring.net MVC

I recently started working on a project which I decided to use nHibernate and springframework for .Net with MVC. Though I had experience working with the springframework with ASP.NET, applying MVC had its issues.

Concerns at Deployment

Few things that you should keep in mind is that MVC projects works only under Integrated Pipeline mode. But the basic configuration for Springframework supports both modes Classic mode or Integreated. This conflict occurred as when I tried to deploy the project.
In order to solve that matter I had to assign the preCondition attribute in handlers. Such as,

<system.webServer>
   <validation validateIntegratedModeConfiguration="false"/>
   <modules runAllManagedModulesForAllRequests="true">
      <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web" />
      <add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate32" />
      <add name="SpringModule" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
   </modules>
   <handlers>
      <remove name="PageHandlerFactory"/>
      <remove name="ContextMonitor"/>
      <remove name="WebServiceHandlerFactory"/>
      <add name="PageHandlerFactory" preCondition="integratedMode" verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" />
      <add name="ContextMonitor" preCondition="integratedMode" verb="*" path="ContextMonitor.ashx" type="Spring.Web.Support.ContextMonitor, Spring.Web" />
      <add name="WebServiceHandlerFactory" preCondition="integratedMode" verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web" />
   </handlers>
</system.webServer>

After adding the above code in the web.config, web site started working fine. I forgot to mention about how to configure pipeline in IIS.

  1. Open IIS: type “inetmgr” in the Run command screen
  2. Expand the server node
  3. Go to the application pool
  4. Select the application pool that is selected for your web site
  5. Double click on the pool
  6. Change the value in “Managed pipeline mode” dropdown to “Integrated”

A common error

Then I got this error,

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

This is a very common error, but the main reason would be that, springframework can’t detect the hibernate session.

  • First check for the OpenSessionView module is existing in the web.config file. If it is not then add this in modules section
  • Secondly check whether the service layer calls are wrapped with a transaction attribute. It does not matter whether the call is read or write to the database.

I am telling this because I have a solution that have MVC Web Site and a windows application that uses the same data access library. All the configuration worked perfectly with the MVC after setting up as I have mentioned in the above of this post. But when it comes to the windows application it was throwing this error. Then I managed to get rid of it by specifying the “Transaction” attribute on the particular method that was called in the windows application.

I assume the reason behind this is windows applications are bound to maintain a dedicated session for the user, there’s no multiple session handling.

Transaction attribute

With the below configuration in your data access config file, transaction is enabled.

NOTE: WORDPRESS DOES NOT ALLOW ENTERING “Object” elements in anyway, so I have change that to “hobject”. when you use make sure to rename it back.

<hobject id="transactionManager"
       type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32">
    <property name="DbProvider" ref="DbProvider"/>
    <property name="SessionFactory" ref="NHibernateSessionFactory"/>
</hobject>

I assume you have the DbProvider and NHibernateSessionFactory objects defined. If not do as follows, Following is  the DbProvider object, if you look at the database connection details they are passed as parameters using ${db.user} as an example. This way you get to change the db config details even after deployment, otherwise you will have to do a release, as the config data is in the compiled data-access-config.xml file. How this is done I have explain in this post.

<db:provider id="DbProviderprovider="MySql.Data.MySqlClient" connectionString="server=${db.datasource}; User Id=${db.user};database=${db.database};password=${db.password};Persist Security Info=True"/>

<hobject id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate32">
   <property name="DbProvider" ref="DbProvider"/>
   <property name="MappingAssemblies">
      <list>
         <value>MyApp.DataAccess</value>
      </list>
   </property>
   <property name="HibernateProperties">
      <dictionary>
         <entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
         <entry key="dialect" value="NHibernate.Dialect.MySQLDialect"/>
         <entry key="hibernate.connection.driver_class" value="NHibernate.Driver.MySqlDataDriver"/>
         <entry key="hibernate.current_session_context_class" value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate32"/>
         <entry key="use_proxy_validator" value="false"/>
         <entry key="format.sql" value="true" />
         <entry key="show_sql" value="true" />
      </dictionary>
   </property>
   <property name="ExposeTransactionAwareSessionFactory" value="true" />
</hobject>

To support transaction in service layer add the following configuration in the service layer config.

<tx:attribute-driven/>

Then add the [Transaction] attribute on the methods declaration where you want to enable transaction in the service layer. And make sure that you use CurrentSession.Flush() method at the end of those methods to commit all changes to the database.

Happy coding!!!

(I am tired now 2 posts at a stretch ;-))

NameValueSectionHandler a handy value parser between config files

I am going to explain a feature that will definitely come in handy in configuration files. Its about the NameValueSectionHandler.

Add the following section to the <configsections> in your web.config file.

<section name=”databaseSettings” type=”System.Configuration.NameValueSectionHandler” />

Now you get your own section with the name of databaseSettings.

<databaseSettings>
   <add key="db.datasource" value="myservername" />
   <add key="db.user" value="root" />
   <add key="db.password" value="******" />
   <add key="db.database" value="Databasename" />
 </databaseSettings>

What happen here is making these key value pairs accessible in another config file. Same thing as AppSettings section except that AppSettings are been used in the application code itself, and this databaseSettings section I am going to use in another config file.

I am using springframework, so in my DataAccess layer I have a database-config.xml file, and that is the place where database configuration sections are available. If I had just placed the config values in the xml itself then it would be compiled at the time of deployment, and will not let me update later, unless I do a new release/compiled code.

With the help of above approach, I am able to do as follows,

<db:provider id="DbProvider" provider="MySql.Data.MySqlClient"
 connectionString="server=${db.datasource};User Id=${db.user}; database=${db.database}; password=${db.password}; Persist Security Info=True"/>

Now I have nothing to worry, the db configuration section is in the xml file and values are in the web.config file.

Syntax in accessing the variable is ${ PARAMNAME }

 

Happy coding!!!

GridView bound by SqlDataSource, RowDataBound event gets called twice

I had a grid view with the DataSourceId property is set to a SqlDataSource control. Also it have a RowDataBound event bounded to have custom data formatting. Then I noticed that the RowDataBound is getting fired twice, as if it binding data twice.

The reason for that behavior I figured out after some hours of debugging. The reason was I have some code that set the column headers which assign language specific header titles on Page_Load() event. When you alter the column specific properties after data binding through a Data Source control, it always tries to get the data set again from the source. But this happen only when there is a change in the newly assigned data.

Because I had some pages doing the same thing, but they were not having this issue. Then I realized that if the newly assigned data differs from what exists in the GridView, only then it tries to call for another data fetch.

This won’t happen if you had created the data set separately, and assign it into the DataSource property.

 

Hope I have saved someones time.

ondblclick event and onclick event in HTML controls

As you are aware of the mouse click events, it actually triggers multiple events in the process of a one single click.

Some explanation can be taken from here.

http://msdn.microsoft.com/en-us/library/ie/ms536921%28v=vs.85%29.aspx

  1. onmousedown
  2. onmouseup
  3. onclick – successful consequtive onmousedown and onmouseup event on the same control will trigger an onclick event
  4. ondblclick – two event cycles of onclick event has to trigger this event

If you find a situation where you have to use the CLICK event and DOUBLE CLICK event on the same control. Then you will see onclick event get fired twice and then afterward double click event is fired. Most of the time people demand such functionality on data grids or tables for Row Level (aka. <tr> tags)  event handling/behaviors.

Jquery site also explain that it is inadvisable to bind both handlers but world demands much more than limitations.

http://api.jquery.com/dblclick/

But if you wanted to fire only the double click event but not the click events when a double click is occurred, well… that’s not doable. But there are ways that you can tackle with it. That is using timing events in javascript.

Declare a global variable to assign the reference of the setTimeout() function. So that you can clear it later. I name the variable as “alreadyclickedTimeout”

$("#ctrlid").click(function(){
   if (alreadyclickedTimeout) clearTimeout(alreadyclickedTimeout);
   alreadyclickedTimeout = setTimeout(function(){ 
      clearTimeout(alreadyclickedTimeout);
      //write what you want to do on click event
   }, 300); //300ms is sufficient to delay the next click event before dblclick event is identified, but this is system/user dependent value
}).dblclick(function(){
   //Now first and foremost what you have to do is to stop the click event before it get fired
   clearTimeout(alreadyclickedTimeout);
   //Write what you want to do on dblclick event
});

Above is a pretty simple code to handle the issue, but remember that it might fail if the user have assign a larger value to the double click event interval. More information on how to change that value can be found here http://en.wikipedia.org/wiki/Double-click

Because 900 mili-seconds value is the maximum in windows OS (it might vary in other OSes), if user’s actual speed is 400ms for the dbl click and system setting is 900ms, by the time of second click is occurred, the first click event’s function will be executed already. Afterward the dblclick event will get fired.

I have written a complete solution to handle  this situation. The sample code is shared here.

I have considered 900ms as the click event trigger time.  If you want to consider a more worst case scenario in some other OS, you can change 900 to a slightly bigger value.

Note: Don’t increase more than 1000ms, you don’t want your users to feel a doubtfulness in your system whether it works or not.

Also I think 900ms won’t be a problem, because you are planning to use single click and double click on the same control, of course the behaviors on that control is going to be complex and users are aware of it and I expect them to be bit more advanced users.

Note: Don’t give these type of features in public sites, it confuses the users, rather better to use a row level button or anchor element. But for corporate applications, such requirements are fine.

Happy coding!

How to render HTML by passing it as a text in Javascript

I had message which is generated from the system and it consist of including a URL with an anchor tag in a Jquery model popup. I usually keep my strings/messages in resource files.  In this case it had a place holder to be replaced with the URL.

As an example,

“Please <a class=’link_color’ href='{url}?returnUrl={path}’>CLICK HERE</a> to Log in.<br/><br/>If you have not signed up <a class=’link_color’ href='{regurl}?returnUrl={path}’>CLICK HERE.</a>”

It was rendering above text as it is in the popup without rendering the HTML tags as hyperlinks,

When I checked the message that was assigned to the popup, its as follows,

“Please &lt;a class=’link_txt_color’ href=’/Account/LogOn?returnUrl=/Deal/4856/victorias-discount-bridal-service#.USIBq2dy18v’&gt;CLICK HERE&lt;/a&gt; to Log in.&lt;br/&gt;&lt;br/&gt;If you have not signed up &lt;a class=’link_txt_color’ href=’/Account/CreateNewUser?returnUrl=/Deal/4856/victorias-discount-bridal-service#.USIBq2dy18v’&gt;CLICK HERE.&lt;/a&gt;”

This is not what I expected to render in the popup.  So I created a div tag dynamically (with jQuery its very simple $(“<div/>”)) and assigned the above message as a HTML. Then I took the text rendered in the div, and assigned that to the popup. There you go, nicely rendered with anchor tags.

Sample code:

$("#popup").html($("<div/>").html(s).text());

s – is the altered message with actual URLs

Note that, in this way you can deal with any html tags. If the tags are rendered as text, get the text and assigned it back as HTML.

 

Could not load file or assembly Common.Logging,..

If you are getting the following error or something similar on finding difficulties in resolving the Common.Logging.dll, please use the NuGet to do so. http://nuget.org/packages/Common.Logging/
Could not load file or assembly ‘Common.Logging, Version=1.2.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

 

How easy it can be to just enter “PM> Install-Package Common.Logging” this in the console and enter… magic happens (kidding, it’s not magic).

NuGet packages are self resolving  many problems when they get installed. So try using them here onward for installation of plugins if its available, it’s not that difficult to use.

 

Have nice day!