We are all familiar with using the embedded code block in the MVC framework views. They give us a powerful way to implement the functionality of the views without removing the separation between code and UI. One of the most common use is for generating UI of different controls through the use of HTML helpers.

But there is one significant limitation of that approach. All the code defined in a common embedded code block will be executed during the render stage of the page execution cycle.

But what if you had the following scenario: you register different css files in different parts of the view. Perhaps in different partial views and then you print them in the header section on top of the page. Something that would look like that:

<%@ Page ... %>
<html>
  <head>
    <title>CSS composite page</title>
    
    <% Html.MyExtension().RegisterCss("css/main.css") %>
    
    <%= Html.MyExtension().GetCss() %>
  </head>
  <body>
  
    <% Html.MyExtension().RegisterCss("css/specific.css") %>
  
    <% Html.MyExtension().RegisterCss("css/another.css") %>
  
  </body>
</html>

That would not work, because the two CSS files registered in the body section will not be available during the call to GetCss() method.

Here I would like to propose another approach for executing code blocks in OnInit, OnLoad or OnPreRender stages. The solution would look like this:

<%@ Page ... %>
<%@ Register TagPrefix="site" Namespace="MyNamespace" Assembly="MyAssembly"%>
<html>
  <head>
    <title>CSS composite page</title>
    
    <site:OnPageLoad runat="server" Call='<%#_=>Html.MyExtension().RegisterCss("css/main.css")%>' />
    
    <%= Html.MyExtension().GetCss() %>
  </head>
  <body>
  
    <site:OnPageLoad runat="server" Call='<%#_=>Html.MyExtension().RegisterCss("css/specific.css")%>' />
  
    <site:OnPageLoad runat="server" Call='<%#_=>Html.MyExtension().RegisterCss("css/another.css")%>' />
  
  </body>
</html>

Now the code passed to the Call() method will be executed in OnLoad stage while the GetCss() print statement will be run in the render stage. This way when you want to print the CSS includes they will all be available. You can do the same with OnInit or OnPreRender stages of the execution.

Finally the definition of the MyNamespace.OnPageLoad control in MyAssembly assembly would look like:

using System;
using System.Web.UI;

namespace MyNamespace
{
    public class OnPageLoad : Control
    {
        protected virtual void OnLoad(EventArgs e)
        {
            base.DataBind();
            if (this.Call != null)
                if (this.If == null || this.If(this.Page))
                    this.Call(this.Page);
        }

        public Predicate<Page> If { get; set; }
        public Action<Page> Call { get; set; }
    }
}

As you can see from the code you can also use conditions, for example:

<site:OnPageLoad runat="server" Call='
    <%#_=>Html.MyExtension().RegisterCss("css/another.css")%>' If='
    <%#_=>this.User.Identity.IsAuthenticated%>' />

Share this post:   digg     Stumble Upon     del.icio.us     E-mail

Commenting temporarily disabled