Thursday, January 15, 2009

How to: Host ASP.Net MVC site under a SharePoint.


We had requirement to host simple asp.net site under SharePoint site. To host a simple asp.net website is SharePoint site is pretty straight forward. But as we were using ASP.Net MVC framework for our website, we faced few challenges as below:

  • APS.Net MVC uses its own view engine i.e.VirtualPathProviderViewEngine, this view engine uses the hosting site VirtualPathProvider. So in our case it was using sharepoint’s VirtualPathProvider. SP’s virtual path provider was not able to understand the MVC view’s path.
    To resolve this issue we created our own custom view engine dervied from MVC’s view engine. Now the problem was to tell the application to use our custom view engine. This is resolved by registering new view engines during Application_Start.

  • MVC uses its own http module and routing model (UrlRoutingModule), need to register this in the web.config of sharepoint site, so that all MVC views are handled by the MVC modules and handlers.

  • Cannot have session state, authentication in web.config of MVC application. As the MVC is application set as a subsite (new virtual dir under SP site) and not a website it will use session and authentication of its parent site hence our MVC application web config cannot have these keys.


And finally we were successful to host asp.net MVC site under sp site.Below are the steps to run your asp.net MVC site under SP site.
Steps to host a MVC site under SP site:

  1. In your MVC application create a class for your custom view engine (CustomViewEngine.cs)

  2. Derive CustomViewEngine class from VirtualPathProviderViewEngine and implement this abstrct class. Major changes to the view engine class as below:

    //Constructor of custom view engine
    public CustomViewEngine()

    {
     // This is where we tell MVC where to look for our files.
     // This says
     // to look for a file at "Views/Controller/Action.html"
     ViewLocationFormats = new[]
     {
       "~/MVCApp/Views/{1}/{0}.aspx",
       "~/MVCApp/Views/{1}/{0}.ascx",
      "~/MVCApp/Views/Shared/{0}.aspx",
      "~/MVCApp/Views/Shared/{0}.ascx"
     };
     PartialViewLocationFormats = ViewLocationFormats;
     //Add your master page location here..
     base.MasterLocationFormats = base.MasterLocationFormats;
    }

     //Method that fetches the path from general name. This is private method used by GetPath() method of the view engine.
     private string GetPathFromGeneralName(string[] locations, string name, string controllerName, ref string[] searchedLocations)
     {
      string result = String.Empty;
      searchedLocations = new string[locations.Length];
      for (int i = 0; i < locations.Length; i++)
      {
       string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName);
       searchedLocations = _emptyLocations;
       result = virtualPath;
      }
     return result;
     }

     //Method that fetches the path from specific name. This is private method used by GetPath() method of the view engine.
      private string GetPathFromSpecificName(string name, ref string[] searchedLocations)
     {
      string result = name;
      return result;
     }

     //Override the methods in VirtualPathProviderViewEngine.
     protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
     {
      return new WebFormView(partialPath, null);
     }

     protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
     {
      return new WebFormView(viewPath, masterPath);
     }



  3. Give strong name to your MVC application and put the dll in GAC.

  4. Create virtual directory under your SharePoint site.

  5. Point virtual directory to your MVC application.

  6. Copy httpHandlers, httpModules, assemblies from MVC configuration file to SP configuration file.

  7. Remove authentication, sessionState, customErrors from MVC configuration file.

  8. In global.asax of SP site add below code:


     void Application_Start(object sender, EventArgs e)
     {
      RegisterRoutes(RouteTable.Routes);
      ViewEngines.Engines.Clear();
      ViewEngines.Engines.Add(new CustomViewEngine());
     }

     public static void RegisterRoutes(RouteCollection routes)
     {
      Route MyRoute = new Route("MVCApp/{controller}/{action}/{id}", new MvcRouteHandler());
      MyRoute.Defaults = new RouteValueDictionary();
      MyRoute.Defaults.Add("controller", "Home" );
      MyRoute.Defaults.Add("action", "Index" );
      MyRoute.Defaults.Add("id", "");
      routes.Add(MyRoute);
     }
     MVCApp --> This is the name of your MVC virtual dir.


  9. Reset IIS and browse the application.


Appendix: Complete custom view engine class



 public class CustomViewEngine : VirtualPathProviderViewEngine
 {
  private static readonly string[] _emptyLocations = new string[0];
  public CustomViewEngine()
  {
   // This is where we tell MVC where to look for our files.
    // to look for a file at "Views/Controller/Action.html"
    ViewLocationFormats = new[] {
      "~/MVCApp/Views/{1}/{0}.aspx",
      "~/MVCApp/Views/{1}/{0}.ascx",
      "~/MVCApp/Views/Shared/{0}.aspx",
      "~/MVCApp/Views/Shared/{0}.ascx"
      };

    PartialViewLocationFormats = ViewLocationFormats;

   //Add your master page location here..
   base.MasterLocationFormats = base.MasterLocationFormats;
  }

  public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName)
  {
   if (controllerContext == null)
   {
    throw new ArgumentNullException("controllerContext");
   }
   if (string.IsNullOrEmpty(partialViewName))
   {
      throw new ArgumentException("Provide partial view name"
, "partialViewName");
   }
   string[] searched;
   string controllerName = controllerContext.RouteData.GetRequiredString("controller");
   string partialPath = GetPath(PartialViewLocationFormats, "PartialViewLocationFormats", partialViewName,controllerName, out searched);
   if (String.IsNullOrEmpty(partialPath))
   {
     return new ViewEngineResult(searched);
   }
   return new ViewEngineResult(CreatePartialView(controllerContext, partialPath), this);
  }

  public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
  {
   if (controllerContext == null)
  {
     throw new ArgumentNullException("controllerContext");
  }
   if (String.IsNullOrEmpty(viewName))
   {
     throw new ArgumentException("View name is missing", "viewName");
   }
   string[] viewLocationsSearched;
   string[] masterLocationsSearched;
   string controllerName = controllerContext.RouteData.GetRequiredString("controller");
   string viewPath = GetPath(ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, out viewLocationsSearched);
   string masterPath = GetPath(MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, out masterLocationsSearched);

   if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
   {
     return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
   }

   return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
  }

  private string GetPath(string[] locations, string locationsPropertyName, string name, string controllerName, out string[] searchedLocations)
  {
   searchedLocations = _emptyLocations;
   if (String.IsNullOrEmpty(name))
   {
    return String.Empty;
   }
   if (locations == null || locations.Length == 0)
   {
     throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICul ture, "Locations property name is missing", locationsPropertyName));
   }
   bool nameRepresentsPath = IsSpecificPath(name);
   return (nameRepresentsPath) ?
GetPathFromSpecificName(name, ref searchedLocations) :
GetPathFromGeneralName(locations, name, controllerName, ref searchedLocations);
  }

  private string GetPathFromGeneralName(string[] locations, string name, string controllerName, ref string[] searchedLocations)
  {
   string result = String.Empty;
   searchedLocations = new string[locations.Length];
   for (int i = 0; i < locations.Length; i++)
   {
     string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName);
     searchedLocations = _emptyLocations;
     result = virtualPath;
   }
   return result;
  }

  private string GetPathFromSpecificName(string name, ref string[] searchedLocations)
  {
    string result = name;
    return result;
  }

  private static bool IsSpecificPath(string name)
  {
    char c = name[0];
    return (c == '~' || c == '/');
  }

  protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
  {
    return new WebFormView(partialPath, null);
  }

  protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
  {
    return new WebFormView(viewPath, masterPath);
  }
 }

Tuesday, January 13, 2009

Improve performance of Regular expressions by using complied regular expressions


In one of our projects, we had convert given output file to a given specific format. Which included large nuumber fo string operations and number of regular expressions to execute over many different strings. Our project was completed functionally then later we faced huge performnace issues. As we were using complex regular expression to find the match and convert to given format and it was consuming huge time.


Then we came across the article which mentioned about the complied regular expressions. Using complied regular expressions the timings came to half of the original timings.
Lets see here what are and how to use complied regular expressions..


If an expression is not compiled, the regular expression engine converts the expression to a series of internal codes that are recognized by the regular expression engine; it is not converted to MSIL. As the expression runs against a string, the engine interprets the series of internal codes. This can be a slow process, especially as the source string becomes very large and the expression becomes much more complex.
Compiling regular expressions allows the expression to run faster.


There are two ways to compile regular expressions. The easiest way is to use the RegexOptions.Compiled enumeration value in the Options parameter of the static Match or Matches methods on the Regex class. And other is to precompile all of these expressions into their own assembly.


Lets go with first option:

We can use the RegexOptions.Compiled enumeration value in the Options parameter of the static Match or Matches methods on the Regex class, shown as below:


Match objMatch = Regex.Match(inputString, pattern, RegexOptions.Compiled);



There is one drwaback of this option that is: an in-memory assembly gets generated to contain the IL, which can never be unloaded. An assembly can never be unloaded from an AppDomain. The garbage collector cannot remove it from memory. If large numbers of expressions are compiled, the amount of heap resources that will be used up and not released will be larger. So use this technique wisely.


The second option is:

Precompiling all of these expressions into their own assembly.Compiling regular expressions into their own assembly immediately gives you two benefits. First, precompiled expressions do not require any extra time to be compiled while your application is running. Second, they are in their own assembly and therefore can be used by other applications.

To compile one or more expressions into an assembly, the static CompileToAssembly method of the Regex class must be used. To use this method, a RegexCompilationInfo array must be created and filled with RegexCompilationInfo objects. The next step is to create the assembly in which the expression will live. An instance of the AssemblyName class is created using the default constructor. Next, this assembly is given a name (do not include the .dll file extension in the name, it is added automatically). Finally, the CompileToAssembly method can be called with the RegexCompilationInfo array and the AssemblyName object supplied as arguments.

What is HttpModule..When and How to write own custom http module.

You might have heard of HTTP pipelines, HTTP Handlers and HTTP Modules in past but do we really know what they are? It was same with me a few months before. We make a web request n number of times in a day and rarely thing of what the number of stages the request has gone through since we often keep it as an abstraction. Finally when I realized importance of HTTP Modules I decided to write an article about how someone should go about this.
This article will start with a brief description of HTTP protocol and understanding what HTTP Modules are, where HTTP Module fit, then what HTTP Modules are and a brief description of when and how to use.

The ASP.NET HTTP Pipeline
To understand the role of HTTP modules in ASP.NET page life cycle, you need to understand how the HTTP protocol works. Once an HTTP request comes in over port 80 (the regular HTTP port or port 443 for HTTPS and the secure sockets layer), the request passes through a number of stages making up the HTTP pipeline before it's actually fielded by your application.

Request --> IIS --> ASPNET_ISAPI.DLL --> HttpApplication- (HttpModule)-> HttpHandler

IIS is the first participant in the chain. IIS is used to route the request to the ASP.NET runtime. IIS maps the ASP.NET file extensions to ASPNET_ISAPI.DLL - an ISAPI extension provided with ASP.NET. The job of ASPNET_ISAPI.DLL is to forward the request to the ASP.NET worker process, ASPNET_WP.EXE. From that point on, the request is wrapped up into an instance of HttpContext and piped through a number of ASP.NET classes.
The next step for the request is to pass through an instance of HttpApplication. This stage is useful for maintaining application-scope methods, data, and events.
After the HttpApplication object massages the request, it pushes the request through one or more HttpModule objects which play a role of providing pre- and post-processing on each request.
There are a number of system-level HTTP modules, providing services ranging from authentication to state management to output caching. The number of modules that get to intercept the request is based upon settings within the host machine's machine.config file and the application's web.config file. In classic ASP, this role of providing pre- and post-processing fell upon ISAPI filters. It turns out that ASP HTTP modules are more straightforward to write.
The final piece of the chain is the HttpHandler. If you've been working with ASP.NET for a while, you're familiar with the System.Web.UI.Page class. The Page class is an HttpHandler object, implementing the interface IHttpHandler. Classes implementing IHttpHandler can hook into the HTTP pipeline and service requests through the interface's ProcessRequest method.

HTTP Modules
One of ASP.NET's most useful features is the extensibility of the HTTP pipeline - the path that data takes between client and server. You can use them to extend your ASP.NET applications by adding pre- and post-processing to each HTTP request coming into your application. For example, if you wanted custom authentication facilities for your application, the best technique would be to intercept the request when it comes in and process the request in a custom HTTP module.
An HTTP module is simply a class that implements the System.Web.IHttpModule interface:




Public interface IHttpModule
{
void Dispose();
void Init(HttpApplication context);
}

When an HttpModule is hooked into the pipeline (via an entry in web.config), the ASP.NET runtime calls the module's Init and Dispose methods. Init is a window where the HTTP Module can initialize itself. These methods are invoked by the ASP.NET runtime when a module gets registered Init method gets executed and when unregister Dispose method gets executed. The Init and Dispose methods represent the module's opportunity to hook into a variety of events exposed by HttpApplication. These events include the beginning of a request, the end of a request, a request for authentication, and so forth. Notice the HttpApplication parameter passed in to the Init method. Usually, the Init method takes the HttpApplication object and maps event handlers to the desired events.
Following is a C# code for defining a simple custom HttpModule that attaches to an application's BeginRequest and EndRequest events to provide simple pre- and post-processing before and after each request.



namespace HttpModuleExamples

{

 public class CustomHttpModule : IHttpModule

 {

  // IHttpModule memberspublic

  void Init(HttpApplication httpApp)

  {

   httpApp.BeginRequest += new EventHandler(this.OnBeginRequest);

   httpApp.EndRequest += new EventHandler(this.OnEndRequest);

  }

  public void Dispose()

  {

   // Usually, nothing has to happen here...

  }

  // event handlers

  public void OnBeginRequest(object o, EventArgs ea)

  {

   HttpApplication httpApp = (HttpApplication) o;

   HttpContext ctx = HttpContext.Current;

   ctx.Response.Write("Beginning Request ");

  }


  public void OnEndRequest(object o, EventArgs ea)

  {

   HttpApplication httpApp = (HttpApplication) o;

   HttpContext ctx = HttpContext.Current;

   ctx.Response.Write("Ending Request ");

  }

 }

}


To wire this handler up into the processing chain, the web.config file simply declares the module within the httpModules section, as shown here:


<configuration>


 <system.web>

  <httpModules>

   <add type= "HttpModuleExamples.CustomHttpModule, HTTPModules" name="CustomHttpModule"
/>

  </httpModules>

 </system.web>

</configuration>

HTTP Handlers
HTTP handler’s process the request and are generally responsible for initiating necessary business logic tied to the request. Custom handlers must implement the System.Web.IHttpHandler interface. Additionally, a handler factory can be created which will analyze a request to determine what HTTP handler is appropriate. Custom handler factories implement the System.Web.IHttpHandlerFactory interface.
When to use Modules and Handlers
With all of the options available in ASP.NET, it is sometimes hard to determine what solution best fits your needs. Of course, it's always best to keep things simple; but, you still need to take evolutionary considerations and experience levels of current and future team members who have a potential of working on the project into account.
Consider what it is that you want to do within your module or handler. Some functions, such as authentication can be added within modules. Modules should be considered only when there is a need for pass-through and/or intercepting interaction with the request. Alternatively, handlers should be put in place when there is a need to direct functional actions to one or more parts of an application.

Conclusion
HTTP modules are very beneficial and can be complex but these can solve problems that could be very difficult to solve by any other way.