Monthly Archives: June 2009

New adventures under medium trust

Many web hosting companies only allow ASP.NET applications to run under medium trust. This has been a major drawback for Cuyahoga because it required full trust (or better: some libraries require full trust). This has already caused some nasty surprises when people deployed their site to the host to find out it would not run.

Well, I can finally say that Cuyahoga 2.0 will work under medium trust!

Castle DynamicProxy

Last week, someone mentioned on the Castle users list that DynamicProxy was supposed to work under medium trust and this immediately triggered me. DynamicProxy had always been the key part that prevented Cuyahoga, NHibernate, and lots of other software from running under medium trust because it generates assemblies on the fly and that’s not allowed (at least pre-NET 2.0 SP1).

So, I checked out a fresh version of the Castle trunk, built it with AllowPartiallyTrustedCallers and copied the assemblies to Cuyahoga that was set to run under medium trust.
Unfortunately, still no luck. The dreaded SecurityException showed its yellow screen, but instead of giving up immediately, I took a deep breath and started digging the DynamicProxy sources. The solution was a simple one: DynamicProxy calls AssemblyBuilder.DefineDynamicModule and used the overload that generates debug symbols. Changing that to not generate the debug symbols anymore made it work under medium trust! I send a patch to the Castle guys and lets hope it can be incorporated. This allows NHibernate to run under medium trust without turning off lazy-load on class mappings or using a special proxy generator.

One caveat: the Castle trunk requires .NET 3.5, so we can’t fix it for the 1.6.x branch of Cuyahoga which is .NET 2.0.

Lucene.Net

Second, Lucene.Net didn’t work under medium trust and boy, that was easy to fix: a single call was made to a relative file path, which is not allowed. Changed that to use the full path and it worked. Submitted a patch and I hope they will accept it.

Cuyahoga

So, with the libraries working under medium trust, I was ready to roll, at least I thought so. It appeared however that Cuyahoga also did some nasty things that are not allowed under medium trust, such as requesting a HttpModule instance from the appdomain and some file access outside the application root. Fortunately these were easy fixes and now I have everything working just fine under medium trust.

I think, I’ll leave medium trust turned on in the development version to signal issues in an early state.

The problem of data grids in your web application

I’m sure everybody who builds web applications uses grids to display data. There is nothing wrong with that per se, but you might not realize that you’re increasing the customers expectations to an unreachable level:

Yes, all very nice and well, but can’t you make that thing work like Excel?

My first thought is always something like: “sure, if you supply us with the budget that the Excel team has”, but in practice we’ll always end up buying one of those bloated grid components or hacking our own solution where the customers is never 100% happy (because it still doesn’t work like Excel).

The solution?

Don’t format the data in a grid, but in a nicely formatted list and stay away from anything that resembles column headers. Add some simple search and filter options and people are happy.

ASP.NET WebForms and MVC together in one project

This post briefly describes a solution to mix ASP.NET WebForms and MVC in one project. You can download a sample project that might be more useful than my ramblings. Download the sample here, unzip, open with VS 2008 SP1 and hit F5.

There are lots of ‘legacy’ ASP.NET WebForms applications out there in the wild. What if you want to create new functionality or rebuild an existing part with ASP.NET MVC, but you can’t (or won’t) create a separate new project?

The simple solution is to add the default MVC folders (Content, Controlllers, Scripts, Views etc.) to the root of the web project, add references to the MVC binaries, modify web.config and add the MVC GUID to the ProjectTypeGuids in the project file. A major drawback however is that it pollutes the root of your carefully structured application. This post will show you how you can logically separate the new MVC pieces from the existing WebForms app in a single project.

Isolate the MVC bits

webforms-mvc-solution  A simple requirement: I want that all my MVC folders reside in the folder /MyMvcApp and I also want that all urls of the MVC app start with /mymvcapp. No interference with my old WebForms app please.

Area’s

About a year ago, Phil Haacked showed a concept called area’s to partition an ASP.NET MVC application. After that, Steve Sanderson came up with an improved version of the concept.

Although designed to partition an MVC application, area’s are also useful when we want to isolate our MVC application from our existing WebForms app. The solution from Steve Sanderson almost completely fits our needs, follow the link for more technical details. The only thing I removed was the usage of an Areas subfolder in the project where all the individual MVC sub-applications. Simply didn’t need the extra subfolder and url of the MVC app is closer to the physical structure.

So, I implemented area’s with a specific AreaViewEngine that can lookup views based on the area name and added the extension to the RouteCollection class to add area information when mapping routes. This is how Global.asax.cs looks:

protected void Application_Start(object sender, EventArgs e)

{

    ViewEngines.Engines.Clear();

    ViewEngines.Engines.Add(new AreaViewEngine());

 

    // Routes

    RegisterRoutes(RouteTable.Routes);

}

 

public static void RegisterRoutes(RouteCollection routes)

{

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

 

    routes.CreateArea("mymvcapp", "WebFormsMVCDemo.MyMvcApp.Controllers",

        routes.MapRoute("mymvcapp-defaultroute", "mymvcapp/{controller}/{action}/{id}", new { action = "Index", controller = "Home", id = "" })

    );

}

With the ViewEngine and routes in place, we’re able to run the MVC app from the url /mymvcapp. To make sure the WebForms url’s still work, we just have to add some ignore statements in Global.asax.cs (in our case, exclude .aspx and .ashx from routing):

public static void RegisterRoutes(RouteCollection routes)

{

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.IgnoreRoute("{*allaspx}", new { allaspx = @".*\.aspx(/.*)?" });

    routes.IgnoreRoute("{*allashx}", new { allashx = @".*\.ashx(/.*)?" });

    routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

 

    routes.CreateArea("mymvcapp", "WebFormsMVCDemo.MyMvcApp.Controllers",

        routes.MapRoute("mymvcapp-defaultroute", "mymvcapp/{controller}/{action}/{id}", new { action = "Index", controller = "Home", id = "" })

    );

}

One caveat: when performing the request for /mymvcapp without controller name (and action), the Default.aspx that comes with the MVC projects was loaded, but area’s seem so cause a problem with the default one. Instead of rewriting the url from ‘default.aspx’ to ‘/’, I had to rewrite to url to ‘Home/Index’:

public partial class _Default : Page

{

    public void Page_Load(object sender, System.EventArgs e)

    {

        string pathToRewriteTo = Request.Path.ToLowerInvariant().Replace("default.aspx", "Home/Index");

        HttpContext.Current.RewritePath(pathToRewriteTo, false);

        IHttpHandler httpHandler = new MvcHttpHandler();

        httpHandler.ProcessRequest(HttpContext.Current);

    }

}

I’m under the impression that I’m missing something very simple, but couldn’t get my fingers behind it, so if you know it, please comment.

 

That’s it. I created a sample project with both WebForms and an MVC app in a subfolder. You can download it here.