Welcome to MSDN Blogs Sign in | Join | Help

Debugging ASP.NET generated code

Update 2/4/2010: changed Technique #2 to use Debugger.Break()

 

This post applies to any ASP.NET app that uses .aspx files, whether WebForms or MVC.

When you write an aspx/ascx/master file (I’ll just say aspx for here on, but it applies to all), it gets compiled dynamically by the ASP.NET runtime.  Note that this is true whether you use a Web Site or a Web Application Project (WAP).  While in a WAP, most of the code is built by Visual Studio, the aspx pages themselves are always built dynamically.

Normally, when you work with aspx files, you only need to worry about what you write in there, and the specifics of what ASP.NET generates under the cover are somewhat of an implementation details.  However, in some cases it’s pretty useful to look at the generated code, either to learn exactly what it does, or to make sense of tricky issues.

Note: one case where it’s particularly useful is if you’re implementing ProcessGeneratedCode in a ControlBuilder to generate custom code.  In that case, you really need to debug into the generated code if anything goes wrong.

For illustration, let’s take a really simple example page, and go through both how we can view the generated code, and then actually debug it.

Here is our lame little test page:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected void Button1_Click(object sender, EventArgs e) {
        Label1.Text = Server.HtmlEncode(TextBox1.Text);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="TextBox1" runat="server" />
        <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
        <asp:Label ID="Label1" runat="server" Text="Label" />
    </div>
    </form>
</body>
</html>
So you click on the button, and it puts the textbox’s text into the label.  I know, exciting stuff!  Now run the page and enjoy its rich feature set, then read on…

 

Looking at the generated code

Before we get into how to debug the generated code, let’s first discuss how we can simply look at it.  First, it’s a good idea to turn on the debug flag and turn off the batch flag when debugging issue.  This is done in web.config:

<compilation debug="true" batch="false">

Once you have that, there is a simple well known trick to see the generated code: deliberately add a compile error to the code.  e.g. change void to void2, or something like that.  Then when you run the page, you’ll get the familiar ASP.NET yellow error screen.  Near the bottom, you should see:

image

The first link can be useful on occasions to see what was passed to the compiler, but the real gold is in the second link, which displays the full generated code for the page.

e.g. here is an extract from it:

Line 293:          [System.Diagnostics.DebuggerNonUserCodeAttribute()]
Line 294:          private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1() {
Line 295:              global::System.Web.UI.HtmlControls.HtmlForm @__ctrl;
Line 296:              
Line 297:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 298:              @__ctrl = new global::System.Web.UI.HtmlControls.HtmlForm();
Line 299:              
Line 300:              #line default
Line 301:              #line hidden
Line 302:              this.form1 = @__ctrl;
Line 303:              
Line 304:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 305:              @__ctrl.ID = "form1";
Line 306:              
Line 307:              #line default
Line 308:              #line hidden
Line 309:              System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
Line 310:              
Line 311:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 312:              @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n    <div>\r\n        "));
Line 313:              
Line 314:              #line default
Line 315:              #line hidden
Line 316:              global::System.Web.UI.WebControls.TextBox @__ctrl1;
Line 317:              
Line 318:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 319:              @__ctrl1 = this.@__BuildControlTextBox1();
Line 320:              
Line 321:              #line default
Line 322:              #line hidden
Line 323:              
Line 324:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 325:              @__parser.AddParsedSubObject(@__ctrl1);
Line 326:              
Line 327:              #line default
Line 328:              #line hidden

It looks quite ugly and overly wordy, but it’s fairly easy to see what it does:

  • Creates the HtmlForm
  • Set its ID
  • Add a literal control with the start <div> tag to it (since <div> is not a server control here)
  • Create the TextBox and add it to the HtmlForm

If you try this on more complex pages that use fancier features link Bind() (aka two-way data binding), you can really get a good understanding of how those features work.

 

Debugging the generated code

So looking at the code is nice, but now we really want to actually debug this code.  This requires a few tricks, but is not too difficult.

First, let’s talk a little bit about the concept of line pragmas.  In the generated code above, you see all those lines that start with #line, e.g.

Line 318:              #line 17 "d:\tmp\WebSiteDebugGeneratedCode\Page.aspx"
Line 319:              @__ctrl1 = this.@__BuildControlTextBox1();

What this does is tell the compiler that the code following the #line pragma should be treated as if it were at line 17 of your aspx, rather that in the generated code.  This is very useful, as it allows compiler errors to point to your aspx file, which is what in most cases makes sense.  It also allows you to debug into the aspx page.

But although that’s very useful stuff, in this case it’s exactly what we don’t want, since our goal is to debug straight into the generated code!

The answer is simple: get rid of the line pragmas!  Luckily, there is a little known yet very simple directive that will do just that: LinePragmas="false".  So add that to your page:

<%@ Page Language="C#" LinePragmas="false" %>

Now run your page again.  Note that at this time, we still have the little syntax error that we introduced earlier (e.g. void2).  So you’ll get an error, but it won’t look quite the same.  First, it’ll say that the error is in the generated file, not the aspx file.  e.g. you’ll get something like this:

Source File: c:\Users\davidebb\AppData\Local\Temp\Temporary ASP.NET Files\websitedebuggeneratedcode\165e8896\2804a211\App_Web_page.aspx.cdcab7d2.qmy8q0k7.0.cs    Line: 46 

And then, if you expand the “Show Complete Compilation Source” link, you’ll see that the code no longer has line pragmas.  e.g. the code we looked at above now looks like this:

Line 121:          private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1() {
Line 122:              global::System.Web.UI.HtmlControls.HtmlForm @__ctrl;
Line 123:              @__ctrl = new global::System.Web.UI.HtmlControls.HtmlForm();
Line 124:              this.form1 = @__ctrl;
Line 125:              @__ctrl.ID = "form1";
Line 126:              System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
Line 127:              @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n    <div>\r\n        "));
Line 128:              global::System.Web.UI.WebControls.TextBox @__ctrl1;
Line 129:              @__ctrl1 = this.@__BuildControlTextBox1();
Line 130:              @__parser.AddParsedSubObject(@__ctrl1);

So same code, minus all the #line pragma.

Now let’s get back to our original goal of debugging our page’s generated code!  I’ll give you two different techniques to do this.

 

Technique #1: find the generated folder and open the file from there

Take the following steps.  It looks a little tricky, but nothing you can’t handle!

  1. Start by making sure you have LinePragmas="false" as discussed above.
  2. Copy the generated file’s folder path from above (in my case c:\Users\davidebb\AppData\Local\Temp\Temporary ASP.NET Files\websitedebuggeneratedcode\165e8896\2804a211), and open it in the windows shell.
  3. Remove the compile error we had put in earlier (e.g. void2)
  4. Run your page again.  This causes it to be recompiled, and it will execute normally.
  5. Now, look back a the generated file’s folder, and sort the files by Date Modified.
  6. The newest file should be named something like App_Web_page.aspx.cdcab7d2.q_hetksf.0.cs.  Drag it into VS to open it.
  7. Set a break point in there.  e.g. in the __BuildControlform1() we looked at.
  8. Hit F5 to debug your app, and it should hit your breakpoint!

You can now step through the code as if you wrote it!  Which you kind of did, indirectly :)

 

Technique #2: use a code break point to directly open the file for you.

This is a simpler technique as it doesn’t require you to hunt for the generated source file.  But it does require you to add a line of code to your page.

Start by making sure you have LinePragmas="false" as discussed above.  Now, remove our little compile error above (e.g. void2), and add a Page_Init method in your page that breaks in the debugger.  This can also go in Page_Load, or generally anywhere that executes during the page life cycle.  e.g.

void Page_Init() {
    System.Diagnostics.Debugger.Break();
}

Now hit F5 to debug your page, and boom, it should hit your break point, which has the great benefit of opening the generated file in the debugger!  Now you can set break point is other places, and go you’re all set.  Note that you’ll need to send a 2nd request to the page to debug methods like __BuildControlform1(), since they execute way before Page_Init.

Posted by davidebb | 7 Comments
Filed under: , ,

Use C# 4.0 dynamic to drastically simplify your private reflection code

Private reflection allows you to access private and internal members in other assemblies.  Generally, it’s considered to be a bad thing to do, as it ties you to undocumented implementation details which can later break you.  Also, it’s not usable in medium trust (and neither is the technique I describe in this post).

My purpose in this post is not to encourage anyone to use private reflection in situations where you would not have done it anyway.  Instead, my purpose is to show you how to do it much more easily if you decide that you need to use it.  Putting it a different way, I’m not telling you to break the law, but I’m telling you how to break the law more efficiently if that’s what you’re into!

Ok, that was my little disclaimer to avoid getting in trouble.  My lawyer made me do it!  Or would have if I had one. :)

The scenario

So let’s look at a sample scenario.  Say you’re using an assembly that has code like this:

public class Foo1 {    private Foo2 GetOtherClass() { ... }}internal class Foo2 {    private string SomeProp { get { .. } }}

And say you have an instance foo1 of the public class Foo1 and your evil self tells you that you want to call the private method GetOtherClass() and then get the SomeProp property off of that.

The solution using good old private reflection

Here is how you can write this code the old fashion way using private reflection.

object foo2 = typeof(Foo1).InvokeMember("GetOtherClass",    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,    null, foo1, null);PropertyInfo propInfo = foo2.GetType().GetProperty("SomeProp",    BindingFlags.Instance | BindingFlags.NonPublic);string val = (string)propInfo.GetValue(foo2, null);

Sure that works, but ouch, that’s ugly!

The dynamic solution

Now to be clear, C# 4.0 dynamic is not going to help you with this out of the box, because it doesn’t support private reflection (I suppose the C# designers didn’t want to encourage that).  So if you try to write:

string val = ((dynamic)foo1).GetOtherClass().SomeProp;

This will blow up with the error “RuntimeBinderException: 'LibraryWithPrivateMembers.Foo1.GetOtherClass()' is inaccessible due to its protection level”.

To get around this, we need to write our own DynamicObject implementation which will perform private reflection under the cover.  With that library, we can now write (after importing the PrivateReflectionUsingDynamic namespace):

string val = foo1.AsDynamic().GetOtherClass().SomeProp;

So we call AsDynamic() on our object (it’s an extension method), which gets us our special DynamicObject implementation.  Once we have that, we can happily write a tiny bit of nice looking dynamic code to replace the ugly reflection mess!

How does it all work

I attached a full VS2010 solution with unit test coverage, so I’m not going to show you the whole code here (it’s over 200 lines).  Instead, I’ll describe it at a high level.

I actually wrote a few other posts before where I wrote custom DynamicObject implementation (named PrivateReflectionDynamicObject).  The general idea is that you override various methods that get called by the dynamic engine when it needs to execute the code.  e.g. when it needs to get a property value, it calls your TryGetMember method.  To call a method, it calls your TryInvokeMember method.

The difference between my previous posts and what I did here is that PrivateReflectionDynamicObject is much more complete, because it’s trying to handle most of the things you might want to using private reflection.  Specifically, it handles:

  • Getting and setting properties
  • Getting and setting fields (note that properties and fields are the same thing in the dynamic world, but different in the reflection world)
  • Calling methods
  • Getting and setting values into arrays
  • Getting and setting values into indexed properties (e.g. string this[string s] { … })
  • Type conversions

The implementation of all this is simply to turn around and use private reflection.  So in the end, you’re executing mostly the same code as if you had done it manually, but with a lot less pain.

One interesting thing to note is that objects returned by this logic need to be themselves wrapped into a PrivateReflectionDynamicObject.  This is necessary in order to able to write foo1.AsDynamic().GetOtherClass().SomeProp.  Otherwise, GetOtherClass() would just return a Foo2 object, and you would not be able to access the SomeProp property.  In a twisted way, you might call that a fluent API.

And finally, then there is the AsDynamic extension method, which makes it easy to access this functionality.  It just has:

public static class PrivateReflectionDynamicObjectExtensions {    public static dynamic AsDynamic(this object o) {        return PrivateReflectionDynamicObject.WrapObjectIfNeeded(o);    }}

Usually, I’m hesitant to add extension methods to object, but in this case it seemed appropriate, since you can potentially do private reflection on any object.  Also, it’s in a specific namespace, so the method only shows up if you choose to import it.

You can unzip the attach solution and try it on VS2010.  I have a somewhat newer build, but I think it should run on beta 2.

Posted by davidebb | 8 Comments
Filed under: ,

Attachment(s): PrivateReflectionUsingDynamic.zip

Take your MVC User Controls to the next level

Note: this is based on ASP.NET MVC 2 RC, and will not work on earlier builds.

 

The quick pitch: make your User Controls as cool as built-in render helpers!

The goal of this post is to show you how to change the way MVC user controls are called from something like this:

<%= Html.Partial("~/Views/Shared/gravatar.ascx", new { Email = "foo@bar.com", Size = 80 }) %>

To something that looks just like a built-in render helper (like Html.TextBox(…)):

<%= Html.Gravatar("foo@bar.com", 80) %> 

 

The current model for User Controls in MVC

If you have used ASP.NET MVC, you probably know that you can use User Controls (.ascx files) to provide partial rendering.

For example, the default MVC app has a Site.Master and a LogOnUserControl.ascx under Views/Shared, and the Site.Master contains:

<div id="logindisplay">
    <% Html.RenderPartial("LogOnUserControl"); %>
</div>

As a slightly nicer alternative, you can change the RenderPartial call to:

<%= Html.Partial("LogOnUserControl") %>

 

What’s wrong with this pattern

While this pattern certainly works, there are some issues with it.  Let’s look at a few:

Hard coded paths with no intellisense

The first is that you need to refer to them by their path.  In the example above, the UC is in the same folder as the master, so you can use a relative path, but in the general case, you would have to refer to it as “~/Views/Shared/LogOnUserControl.ascx”, which gets ugly.  If you use T4MVC (plugging my other baby if you don’t mind!), it’ll get rid of the literal string and give you intellisense, but in essence it still works the same way: the View engine gets a literal string and tries to go from there.

Inconsistent with HTML render helpers

Another issue is that even though the UC is basically an HTML render helper, it doesn’t look like one when you call it.  Ideally, you really want to call it the same way you call ‘built in’ helpers.  e.g. since you can call Html.TextBox(), you should be able to call Html.LogOnUserControl().  In comparison, the RenderPartial call looks painfully complex.

Difficult to pass parameters

Suppose your UC needs to receive parameters from the caller.  With Partial/RenderPartial, you have to pass those through a model object, which is painful.  You can either rely on untyped data, or create a custom ViewModel type to encapsulate the data you need.  In either case, it looks nothing like a call to a render helper like Html.TextBox(…), which takes ‘natural’ parameters.

 

How we can make this better

The tools at our disposal

There are many little known gems in ASP.NET that allow us to put together a very nice solution that solves all those issues.

The first little known fact is that Web Applications can have an App_Code folder, where all its files get compiled into a single assembly that all pages reference.  Of course, the App_Code folder is very well known in Web Sites, but the fact that they can also be used in Web Application Projects (WAPs) is often overlooked.

The second little known gem is that user controls can go in App_Code!  Come on, admit it, you didn’t know that.  No one knows that! :)

The third one is that you can associate a control builder for an entire User Control (or page), and not just for controls within the page.

And finally, the fourth gem is the ControlBuilder.ProcessGeneratedCode method, which I blogged about a while back.  This method lets us modify the code generated for the User Control (or page), which opens up some very powerful possibilities.

What the end result looks like

Instead of giving you all the technical details here (the full sample is attached), let’s look at what the end result looks like.  In order to use it, you just need to add a reference to the MvcUserControlHtmlHelpers assembly in the sample (I know, lame name).

Then you can just move your User Control into App_Code, and make a small change to it.  e.g. in the example above, you would change the directive from

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

to

<%@ Control Language="C#" Inherits="MvcUserControlHtmlHelpers.UserControlHtmlHelper" ClassName="LogOnUserControl" %>

So basically you change the base type and give it a specific class name.

One you have that, the real fun begins, as you can change Site.master to just have

<div id="logindisplay">
    <%= Html.LogOnUserControl() %>
</div> 

You now have full intellisense, and the call looks just like a built-in helper.  Yeah!

 

So what about parameters?

Suppose you want to write a User Control that displays Gravatars.  You’d put in in App_Code, and write something like this:

<%@ Control Language="C#" Inherits="MvcUserControlHtmlHelpers.UserControlHtmlHelper" ClassName="Gravatar" %>

<script runat="server">
    // Declare the paramaters that we need the caller the pass to us
    public string Email;
    public int Size;
</script>

<%
    // Build hash of the email address
    // Note: in spite of its name, this API is really just a general MD5 encoder
    string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(Email.ToLower(), "MD5").ToLower();

    // Construct Gravatar URL
    string imageURL = String.Format("http://www.gravatar.com/avatar/{0}.jpg?s={1}&d=wavatar", hash, Size);
%>

<img src="<%= imageURL %>" alt="<%= Email %>" title="<%= Email %>" />

The key new concept here is that you declare the parameters that you want as public fields, and you just use them in your code.  Basically, think of this as declaring a method, but without a real method declaration.

And once you have that, things get really nice in your view, where you can now write

<%= Html.Gravatar("foo@bar.com", 80) %>

or if you prefer, you can write

<% Html.RenderGravatar("foo@bar.com", 80); %>

With the same distinction as between Partial() and RednerPartial().  Now for the fun, try hitting F12 (Go To Definition) on one of those methods.  You’ll get:

public static class GravatarExtensions {
    public static string Gravatar(this HtmlHelper htmlHelper, string Email, int Size);
    public static void RenderGravatar(this HtmlHelper htmlHelper, string Email, int Size);
}

What happened in that the special base generated some extension methods to allow you to call the User Control exactly as you would call a ‘built-in’ helper like Html.TextBox.

 

How does it all work

To pull this magic, it uses a combination of the various things I outlined above.  I won’t go into the details since the full source is attached and has enough comments to make it clear what it’s doing.  The file you want to look at is UserControlHtmlHelper.cs.  I warn you, I had to use a scary trick to get around a CodeDom limitation.  Also, there are some edge cases that don’t work yet but could be made to work.  At this point, this is just a sample!

Enjoy, and let me know what you think about this pattern.

Posted by davidebb | 16 Comments
Filed under: , ,

Attachment(s): MvcUserControlHtmlHelpers.zip

T4MVC 2.6.10: fluent route value API, shorter way to refer to action, and more

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

 

I just posted build 2.6.10.  There were also a few builds in between since I last blogged about 2.6, so this post describes some of those changes (full history here).

 

Fluent route value API

As you probably know, T4MVC uses a pattern where the route values are encapsulated using a pseudo-call to a controller action, e.g.

    Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID))

This adds the controller, the action and the method parameters to the route values in a convenient way with no hard coded strings.

But in some situation, you may need to add extra values to the route that don’t exist in the action method.  Now you can do it as follows:

Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID)
    .AddRouteValue("foo", 17))

You can add multiple values this way using a fluent approach, e.g.

Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID)
    .AddRouteValue("foo", 17)
    .AddRouteValue("bar", "abc"))

As an alternative for adding multiple values, you can write:

Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID)
    .AddRouteValues(new { foo = 17, bar = "abc"}))

Note that in some cases, you may want to omit the action method parameters from the route, possibly because they are meant to come from form data and not from the URL.  For those cases, you can always use the parameter-less override that T4MVC generates (that part is not new), e.g.

Html.ActionLink("Delete Dinner", MVC.Dinners.Delete()
    .AddRouteValues(new { foo = 17, bar = "abc"}))

 

The nice thing about this fluent approach is that it doesn’t require adding overloads to all the T4MVC helpers (e.g. Html.ActionLink is this case) to take in the extra route values.  Instead, it automatically applies to any method that uses the T4MVC pattern.

 

Shortcut to refer to controller actions from within the controller

Suppose you want to redirect to a different action in the same controller.  Normally, in MVC you write something like:

return RedirectToAction("Details", new { id = dinner.DinnerID });

With T4MVC, you’ve always been able to write:

return RedirectToAction(MVC.Dinners.Details(dinner.DinnerID));

And now you can simplify it a bit and write:

return RedirectToAction(Actions.Details(dinner.DinnerID));

So basically, ‘Actions’ is equivalent to MVC.Dinners when you’re within the Dinners controller.

Now some might be tempted to take it a step further and just write:

return RedirectToAction(Details(dinner.DinnerID));

But that would be horribly wrong, since you would end up actually calling your controller action directly, which is not what you want!  We’re only trying to make a pseudo call to it that captures the route values.

 

Small breaking change: Actions renamed to ActionNames

This is a result of the previous change.  Unfortunately, the token ‘Actions’ was already used as the way to get all the action names for a controller.  So I ended up renaming it to ActionNames, since Actions was the best name for the new feature above.

So if you’re currently using the pattern ‘MVC.Dinners.Action.Delete’ (to refer to the action name “Delete”), you’ll need to change it to MVC.Dinners.ActionNames.Delete.

Sorry for the little extra pain!

 

Generate full view paths to allow cross controller references

Previously, when you wrote something like MVC.Dinners.Views.Edit, it would evaluate to “Edit”.  This works fine as long as you are using it from the Dinners controller, which implies that this is the Dinners Edit view as opposed to another controller’s Edit view.

But in some cases, you may want to refer to another controller’s view, and just having the short name no longer works.  So T4MVC was changed to instead make MVC.Dinners.Views.Edit evaluate to the full "~/Views/Dinners/Edit.aspx", which removes all ambiguities.

As far as I know, it should not affect any scenarios that use it, as it never hurts to be more specific.  But let me know if you run into something…

 

Added way to get area name from both Area and Controller objects

T4MVC now makes the area name available, either from the Area and the Controller.  e.g. you can write MVC.MyArea.Name or MVC.MyArea.MyController.Area, both of which will evaluate to the area name (here “MyArea”).

Posted by davidebb | 7 Comments
Filed under: , ,

Passing anonymous objects to MVC views and accessing them using dynamic

First, I’ll start with a little disclaimer: this post is not about whether using dynamic is better/worse than static typing.  Instead, it’s about making it more convenient to use dynamic if you choose to go that route.  Clearly, some people dislike dynamic, as you can see in the comments in that post from Phil Haack, and for the most part, all the key arguments for/against have been made.

So anyway, let’s proceed… Recently, a few people have experimented with extending their view pages from ViewPage<dynamic>.  The idea is to then be able to access model data using the more convenient dynamic syntax.  e.g. check out this thread on StackOverflow, as well as Phil’s post I mention above.

One limitation that people are hitting is that you can’t easily pass an anonymous object as your model, because anonymous types are internal.

What we’re trying to write

e.g. Let’s say we’re trying to write this code in the controller:

public class HomeController : Controller {
    public ActionResult Index() {
        return View(
            new {
                Message = "Welcome to ASP.NET MVC!",
                Date = DateTime.Now
            });
    }
}

Note that we’re passing an anonymous object as the model.  The main reason to do this is to avoid the need to create an explicit ViewModel type.  Obviously, that’s controversial, but it should be viewed more as a simpler alternative to writing

ViewData["Message"] = "Welcome to ASP.NET MVC!";
ViewData["Date"] = DateTime.Now;
return View();

And then you’d change your view to have Inherits="System.Web.Mvc.ViewPage<dynamic>", which ideally would let you write something like this:

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%: Model.Message %></h2>
    <p>
        The date is <%: Model.Date %>
    </p>
</asp:Content>

 

Which is simpler than having to dig things out of the view data dictionary through string indexing.

But the default dynamic binder won’t let us!

Unfortunately, if you try to run this code, it’ll blow up with this error: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: '<>f__AnonymousType1<string,System.DateTime>.Message' is inaccessible due to its protection level

The reason for this is that the anonymous type being passed in the controller in internal, so it can only be accessed from within the assembly in which it’s declared.  Since views get compiled separately, the dynamic binder complains that it can’t go over that assembly boundary.

But if you think about it, this restriction from the dynamic binder is actually quite artificial, because if you use private reflection, nothing is stopping you from accessing those internal members (yes, it even work in Medium trust).  So the default dynamic binder is going out of its way to enforce C# compilation rules (where you can’t access internal members), instead of letting you do what the CLR runtime allows.

Solution: write our own!

I’m not sure why it was designed this way, but the good news is that it’s easy to work around by writing our own custom DynamicObject which binds through private reflection!  I’ve written a couple posts that make use of custom DynamicObjects (find them here), and the basic concept is the same: given the name of a property, write whatever code you want to produce its value.

Here, we’re not only going to write a custom Dynamic Object, but also a custom DynamicViewPage that uses it.  And doing all this takes surprisingly little code.  Here is the full implementation:

public class DynamicViewPage : ViewPage {
    // Hide the base Model property and replace it with a dynamic one
    public new dynamic Model { get; private set; }

    protected override void SetViewData(ViewDataDictionary viewData) {
        base.SetViewData(viewData);

        // Create a dynamic object that can do private reflection over the model object
        Model = new ReflectionDynamicObject() { RealObject = ViewData.Model };
    }

    class ReflectionDynamicObject : DynamicObject {
        internal object RealObject { get; set; }

        public override bool TryGetMember(GetMemberBinder binder, out object result) {
            // Get the property value
            result = RealObject.GetType().InvokeMember(
                binder.Name,
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                null,
                RealObject,
                null);

            // Always return true, since InvokeMember would have thrown if something went wrong
            return true;
        }
    }
}

As you can see there is not that much to it: when we need to look up a property value, we use private reflection and that’s the end of it.

And now it all works!

Once we have this, all that’s left to do is use it as our base class for the view, e.g.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="MvcHelpers.DynamicViewPage" %>

And we’re then able to write exactly what we wanted above in the controller and the view, without hitting any access issues.

The full VS2010 project is attached to this post.

Posted by davidebb | 21 Comments
Filed under: , ,

Attachment(s): MvcDynamicViewPage.zip

T4MVC 2.6: MVC 2 Areas support

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

 

One of MVC 2's major new features is the support for breaking up a large application into "Areas". This works by following a structure that looks like:

  • Root folder
    • Models
    • Views
    • Controllers
    • Areas
      • NerdDinner
        • Models
        • Views
        • Controllers
      • Blog
        • Models
        • Views
        • Controllers

So basically you still have your top level Models/Views/Controllers folders, and in addition to that you can have an arbitrary number of “Areas”, each having their own set of Models/Views/Controllers folders.

Starting with MVC 2.6, T4MVC lets you use areas in much the same way it lets you access top level items.  e.g. you can now write:

<%= Html.ActionLink("Delete Dinner", MVC.NerdDinner.Dinners.Delete(Model.DinnerID))%>

 

Note how we referred to the controller as MVC.NerdDinner.Dinners.

Optionally, if you set IncludeAreasToken to true in the settings file, this becomes:

<%= Html.ActionLink("Delete Dinner", MVC.Areas.NerdDinner.Dinners.Delete(Model.DinnerID))%>

 

Lots of headaches to find a good naming pattern for Areas in T4MVC

Surprisingly, one of the things that caused the most headaches in getting this working was finding a well working naming pattern.

Here are the patterns that were on the table:

  1. MVC.NerdDinner.Dinners
  2. MVC.NerdDinnerArea.Dinners
  3. MVC.Areas.NerdDinner.Dinners

#1 is the simplest and most concise, but breaks if you have a top level controller that has the same name as the area.

#2 appends ‘Area’ to the area name to solve the conflict we caused by #1.  But while it solves the conflict, you end up with a slightly quirky naming scheme.

#3 uses an extra Areas token before the area name to avoid the conflict.  The drawback here is that you end up with one more token, meaning one more thing to type through in intellisense.

I then polled twitter to see whether people preferred #2 or #3, and most went with the cleaner and more wordy #3.

Then Nikhil suggested using a hybrid of #1 and #2, where we only append ‘Area’ to the area name if we detect a conflict with a top level controller name.  Let’s call this #4!

So I ended up supporting both #3 and #4, based on the IncludeAreasToken switch in the settings file.

But frankly, I’m considering getting rid of #3.  In the twitter poll, people didn’t like #2 mostly because it’s weird to have that extra ‘Area’ suffix.  But with the hybrid #4 solution, this funky name only occurs exceptionally, making it much less of an issue.

To end this post, I’d like to thank Nathan Roe for helping out putting together this change!

Posted by davidebb | 14 Comments
Filed under: , , ,

T4MVC now has a real home and a dedicated forum!

Up until now, most things related to T4MVC were happening through my various blog posts about it.  And while that was sort of working ok for a while, it was also less than ideal for a couple reasons.

First, there was no single place to go to in order to get information about it.  You’d basically have to go through the various posts that describe the various features as they were added.  And as the number of posts grew, so did the pain involved in doing that.

The second issue is that there was no good place to discuss it, ask questions and report issues.  So all of those things were mostly just happening organically as comments in my various posts, which really doesn’t work so well.  Blog Post comments don’t support threading, and things ended up being spread all over the place.

To simplify this mess, I created two things:

New T4MVC Home Page: http://aspnet.codeplex.com/wikipage?title=T4MVC

This page contains everything you may want to know about T4MVC: where to get it, the complete documentation, and links to other relevant places.  And obviously, the idea is to keep this page up to date as new features are added.

New discussion forum: http://forums.asp.net/1215.aspx

This is a standard ASP.NET forum, much like the one used for MVC and other ASP.NET topics.  If you have any questions or comments about T4MVC, this is the place to go!

Hopefully, this will help make things a little less random :)

Posted by davidebb | 5 Comments
Filed under: , , ,

T4MVC 2.5.01: added support for Html.RenderAction and Html.Action

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

MVC 2 Beta introduces two nice helpers called Html.RenderAction and Html.Action.  Phil Haack described them in detail on his blog, so you may want to read through that before reading this post.

Basically, they’re two additional methods that follow the standard MVC pattern of passing the controller name and action name as literal strings, and the action parameters as anonymous objects.  e.g. Copying from Phil’s example, if you have an Action like this:

public ActionResult Menu(MenuOptions options) {
    return PartialView(options);
}

You can write this in your View:

<%= Html.Action("Menu", new { options = new MenuOptions { Width=400, Height=500} })%>

Note how the action name is hard coded, and the MenuOptions parameter is passed as an anonymous object.  With T4MVC, you can instead write:

<%= Html.Action(MVC.Home.Menu(new MenuOptions { Width=400, Height=500})); %>

Giving you full intellisense and type checking for the controller name, action name and parameters.

Another advantage is that normally, if you use an ActionName attribute, you’ll need to pass that name instead of the action method name.  Again from Phil’s blog:

[ActionName("CoolMenu")]
public ActionResult Menu(MenuOptions options) {
    return PartialView(options);
}

And you then have to pass “CoolMenu” instead of “Menu” when you make the call, which is pretty easy to get in trouble with.  But with T4MVC, the fact that you use a non-default Action Name is abstracted out, so you make the exact same Html.RenderAction(MVC.Home.Menu(...)) call.

Of course, all of this is nothing new if you’re used to using T4MVC.  It’s just the same pattern as we have everywhere else, applied to those couple new methods.  Maybe I’m just rehashing the same old benefits of strong typing and avoiding literal strings :)

On a separate note: I fixed a small bug that happened when you used a custom ActionResult without an explicit ctor.  See comments in previous post for details on the issue.

Posted by davidebb | 11 Comments
Filed under: , , ,

T4MVC 2.5.00 update: multiple output files and minified javascript support

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

T4MVC build 2.5.00 brings a couple of fun new features that I’ll describe in this post.  I can’t take too much credit for them as they came from users who suggested them to me, and helped out getting the code going.

Support for multiple output files

Up until now, T4MVC.tt has always generated a single file, which is the T4MVC.cs that you see get nested under it in VS.  And normally, this is the way T4 templates work: they just generate one file.  But last week I got an email from Stuart Leeks who pointed me to a new blog post from Damien Guard that describes a nice way to get around this limitation.  All of Damien’s logic is very nicely encapsulated in a class, making it pretty easy to add to an existing T4 template without having to make significant changes.

I was going to look into getting that in T4MVC, but Stuart went ahead and did it, so I didn’t have much to do myself.  Thanks to Stuart and Damien on this one!

But first I suppose we should discuss why generating multiple files is a good thing.  Quite simply, it keeps things more organized, and makes things cleaner when working with source control.  Since T4MVC can generate a fair bit of code, it is a good candidate to use this.  Specifically, T4MVC can now generate a different output file for each controller, making things more manageable.  Note that it still generated the ‘primary’ T4MVC.cs file, which contains all the top level things that don’t belong to any specific controller.

This behavior is on by default, but can be disabled in T4MVC.settings.t4:

// If true,the template output will be split into multiple files.
bool SplitIntoMultipleFiles = true;

I debated whether to make it the default, but in the end opted for it, as I didn’t see any serious drawbacks.  But I guess if you never plan to look at or deal with the generated files in any way, it doesn’t buy you a whole lot and you may choose to turn it off.

Warning if you’re using VS2010 Beta 2: Damien’s code uses the ITextTemplatingEngineHost interface, which got moved to a new Microsoft.VisualStudio.TextTemplating.Interfaces namespace in 2010 Beta 2.  So on 2010 Beta 2, you’ll need to add one extra import line to T4MVC.tt (the second line below):

<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating.Interfaces" #>

Support for Minified Javascript files

This one came from Matt Wicks.  Minified javascript files are alternate version of the files that makes them as small as possible, but using various strategies like removing white space.  e.g. in an MVC application’s Scripts folder, you’ll typically see both jquery-1.3.2.js and jquery-1.3.2.min.js.  Usually, you want to use the minified version at deployment time (to make your site load faster), but the regular version at development time, so you can more easily debug into it.

The new T4MVC support makes it automatic to use one vs. the other depending on the context.  T4MVC has been supporting script files for a while, letting you write:

<script src="<%= Links.Scripts.jquery_1_2_6_js %>" type="text/javascript"></script>

With this new feature, you don’t need to change anything to this line, but the token jquery_1_2_6_js will automatically point to either jquery-1.3.2.js or jquery-1.3.2.min.js depending on whether you’re running in production.  How does it know whether you’re in production?  It calls a method defined in T4MVC.settings.t4 which makes the decision.  By default, it looks at whether debugging is enabled:

    // Logic to determine if the app is running in production or dev environment
    public static bool IsProduction() { 
        return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled); 
    }
But you can easily change this logic if you have a different way of determining ‘production’.
Posted by davidebb | 9 Comments
Filed under: , , ,

Peter Blum’s new blog and his cool new data source controls

Peter Blum has been well known is the ASP.NET world for many years for writing a whole suite of powerful controls, which you can read all about on his site.  One thing that was missing on Peter’s resume is that he never had a blog.  Well he started one earlier this month, and is making up for the lost time in a big way, with already 11 posts!  And we’re not talking about small posts that just point to other people’s stuff (unlike this post I suppose!), but real with useful meaty content.  Make sure you check out his blog at http://weblogs.asp.net/peterblum/.  I hope he keeps the good stuff coming!

In particular, Peter has been working hard on some interesting data source controls that work with Visual Studio 2010.  He’s calling them the ‘Versatile DataSources’, and is making it all available for free on CodePlex.

The following posts on his blog describe the data source controls:

The simplest way to try out his controls is to download them from CodePlex.  The package contains a rich set of samples that you can directly run and play with.  You’ll need VS2010 Beta 2 to run this, so if you don’t already have it, get it from here.

I haven’t fully tried everything yet, but the one I played with the most is his POCODataSource, which is quite interesting.  The core idea is very simple: you give it a type and it makes it easy to put up a WebForms UI to fill up an instance of that type.  The UI supports full validation using standard model annotations supported by Dynamic Data.

The beauty is that it’s really quite easy to use.  The data source declaration looks something like this (borrowed from Peter’s samples):

   <poco:POCODataSource ID="POCODataSource1" runat="server" POCOTypeName="CEOEmailGenerator" />

 

For the actual UI, you can use any standard ASP.NET data control like DetailsView, FormView or some similar 3rd party control.  Then when an Update operation happens, you simply access the built instance from the data source using  POCODataSource1.POCOInstance.  At that point, you can do whatever you want with it.  In Peter’s sample, he ends up calling an action method directly on the object, e.g.

protected void FormView1_ItemUpdated(object sender, FormViewUpdatedEventArgs e) {
   if (Page.IsValid) {
      ((CEOEmailGenerator)POCODataSource1.POCOInstance).Send();
   }
}

But I don’t see anything that ties you to this pattern, and you could instead just call some helper method and pass the object if your object doesn’t have an action method itself.

Anyway, check it out in much more details on Peter’s blog!

Using C# Dynamic to simplify ADO.NET Data Access

Update (11/7/09): fixed Execute() method per Richard’s suggestion to wrap IDataRecord instead of Reader.

Recently, I started playing around with C# dynamic, and blogged how it could be used to call static class members late bound.  Today, I was talking to Phil Haack, who I think had talked to ScottGu, and he mentioned that it would be cool to use dynamic to simplify data access when you work directly with SQL query.  So I thought I’d play around with that, and it didn’t take much code to make it work nicely.

So the scenario is that you’re not using any fancy O/R mapper like LINQ to SQL or Entity Framework, but you’re directly using ADO.NET to execute raw SQL commands.  It’s not something that I would personally do, but there are a lot of folks who prefer this over the higher level data access layers.

So let’s look at an example of what we’re trying to improve.  Let’s borrow an MSDN sample about SqlCommand:

string commandText = "SELECT OrderID, CustomerID FROM dbo.Orders;";
using (var connection = new SqlConnection(Settings.Default.NorthwindConnectionString)) {
    using (var command = new SqlCommand(commandText, connection)) {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader()) {
            while (reader.Read()) {
                Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
            }
        }
    }
}

And now let’s assume that we’re only ever interested in making one select query at a time, which lets us abstract out some of the details about the SQL Connection.  By writing some nice little helpers that make use of dynamic, we’re able to write something much simpler:

string commandText = "SELECT OrderID, CustomerID FROM dbo.Orders;";
foreach (var row in SimpleQuery.Execute(Settings.Default.NorthwindConnectionString, commandText)) {
    Console.WriteLine(String.Format("{0}, {1}", row.OrderID, row.CustomerID));
}

A few things to note:

  • We pretty much just make one method call, and directly get back objects that we can work with.  Contrast this with having to deal with SqlConnection, SqlCommand and SqlDataReader.
  • We use a standard enumeration pattern, while SqlDataReader makes you call reader.Read() on every iteration, which looks ugly.
  • And the big one: we get to access the properties directly on the row object, thanks to dynamic!  e.g. we can write row.OrderID instead of reader[0] (or reader[“OrderID”])

So how does it all work?  First, let’s take a look at the SimpleQuery.Execute helper method:

public static IEnumerable<dynamic> Execute(string connString, string commandText) {
    using (var connection = new SqlConnection(connString)) {
        using (var command = new SqlCommand(commandText, connection)) {
            connection.Open();
            using (SqlDataReader reader = command.ExecuteReader()) {
                foreach (IDataRecord record in reader) {
                    yield return new DataRecordDynamicWrapper(record);
                }
            }
        }
    }
}

So it’s basically the same as the MSDN code, except that it wraps the reader that it returns in a DataRecordDynamicWrapper, which is what makes the dynamic magic work.  Also, note that the method returns IEnumerable<dynamic>, which is why we’re able to just use ‘var row’ in the test code (which I think looks nicer than ‘dynamic row’).

So now all that’s left to look at is DataRecordDynamicWrapper, which is incredibly simple:

public class DataRecordDynamicWrapper : DynamicObject {
    private IDataRecord _dataRecord;
    public DataRecordDynamicWrapper(IDataRecord dataRecord) { _dataRecord = dataRecord; }

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        result = _dataRecord[binder.Name];
        return result != null;
    }
}

All it does is index into the data record to get the value for a given property name.

I think what I did with static methods in my last post was probably a bit of an abuse of dynamic, because we were dealing with statically types objects, and there are alternatives that would have avoided the need for dynamic.  But here, it’s I think a more legitimate use, because we’re dealing with data record objects that are intrinsically untyped.  While dynamic of course doesn’t give us strong typing, it at least makes it more pleasant to deal with.

One last thing worth noting is that to make this real, we should add support for SQL parameters, which makes it easier to write SQL code that is not vulnerable to SQL-injection attacks.  That could easily be done by passing additional params to SimpleQuery.Execute.  This sample is more of a proof of concept and an excuse to mess around with dynamic :)

Zipped sample is attached to this post.

Posted by davidebb | 16 Comments
Filed under: ,

Attachment(s): DataReaderWithDynamic.zip

Using C# dynamic to call static members

By now, you’ve probably heard that C# 4.0 is adding support for the dynamic keyword, which introduces some aspects of dynamic languages to C#.  I had not had a chance to really try it, but recently I was reading Bertrand Le Roy’s post on the topic, and was sort of looking for a good opportunity to use it.

Today, I found a scenario which I thought it would work great for, but it turned out not to be supported out of the box!

The scenario is to call static class members using dynamic.  That probably sounds crazy, so let’s look at an example.  Say you have these two classes:

public class Foo1 {
    public static string TransformString(string s) { return s.ToLower(); }
    public static string MyConstant { get { return "Constant from Foo1"; } }
}

public class Foo2 {
    public static string TransformString(string s) { return s.ToUpper(); }
    public static string MyConstant { get { return "Constant from Foo2"; } }
}

Note that they are unrelated classes, but share some members with the same signature.  In a sense, you could say that they two classes share a duct tape signature.

Now here is the problem we’re trying to solve: given a System.Type object of either class (or any other random class that shares those members), how can you call those members?  Concretely, we’re trying to implement this method:

static void MakeTestCalls(Type type) {
    // Call TransformString("Hello World") on this type

    // Get the MyConstant property on this type
}

How can we implement this method? Ok, we can do it the old fashion way using reflection, e.g.

static void MakeTestCalls(Type type) {
    Console.WriteLine(type.GetMethod("TransformString").Invoke(null, new object[] { "Hello World" }));
    Console.WriteLine(type.GetProperty("MyConstant").GetValue(null, null));
}

That works, but it’s ugly.  These are the very type of things that dynamic is supposed to improve.  So my first naive attempt was to do this:

static void MakeTestCalls(Type type) {
    dynamic fooTypeDynamic = type;

    Console.WriteLine(fooTypeDynamic.TransformString("Hello World"));
    Console.WriteLine(fooTypeDynamic.MyConstant);
}

Basically, the theory was that when assigning a System.Type to a dynamic variable, it would let you call static members from it.  I didn’t really expect it to work, but I at least had to try! :)  And sure enough, it didn’t work, blowing up with: “Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.RuntimeType' does not contain a definition for 'TransformString'”.

So I then posted the question on our internal C# list, and got a reply from C# guru Eric Lippert, basically saying that it was a potentially interesting idea but was just not supported in C# 4.0.  Fair enough, this is only the beginning of C# dynamic, and it doesn’t do everything.

But I then went back to Bertrand’s post where he gives a great sample of how you can teach dymamic new tricks by implementing a custom DynamicObject.  And it turned out to be relative simple.  Here is the class I ended up with:

public class StaticMembersDynamicWrapper : DynamicObject {
    private Type _type;
    public StaticMembersDynamicWrapper(Type type) { _type = type; }

    // Handle static properties
    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        PropertyInfo prop = _type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (prop == null) {
            result = null;
            return false;
        }

        result = prop.GetValue(null, null);
        return true;
    }

    // Handle static methods
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
        MethodInfo method = _type.GetMethod(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (method == null) {
            result = null;
            return false;
        }

        result = method.Invoke(null, args);
        return true;
    }
}

The idea is pretty simple: when the runtime needs to call something, it basically asks you to do it.  It passes you the method (or property) name and the parameters, and you take it from there. And in this case, of course, we’re using reflection.

Once we have that, the real fun starts as we’re now able to call our static members using dynamic!

static void MakeTestCalls(Type type) {
    dynamic typeDynamic = new StaticMembersDynamicWrapper(type);

    // Call TransformString("Hello World") on this type
    Console.WriteLine(typeDynamic.TransformString("Hello World"));

    // Get the MyConstant property on this type
    Console.WriteLine(typeDynamic.MyConstant);
}

Note how we wrap the type into our custom DynamicObject is order to have the dynamic invocations go through us.

Now you might say that the scenario above where you have two classes with identical static members doesn’t seem like something that would actually occur commonly in real apps.  But once you start bringing in generics, it can actually be more common.  e.g. suppose you have something like:

public class Table<T> {
    public static IEnumerable<T> Records { get { [return records from database table T] } }
}

The idea is that the class is an abstraction for a database table.  So Table<Product>.Records returns an IEnumerable<Products>, and Table<Category>.Records returns an IEnumerable<Category>.  Now suppose you’re writing some table agnostic code that can work with the data from any table.  You have a System.Type for some Table<T>, and you need to get its Records property.  Even though it seems like it’s the same Records property coming for a base class, the reality is that it’s a completely different property for each T, and C# provides no simple way of making the call.  But with the technique above, you get to access the property with a much simpler syntax than with reflection.

The zipped sample is attached to this post.

Posted by davidebb | 15 Comments
Filed under: , ,

Attachment(s): DynamicCallsToStaticMembers.zip

T4MVC 2.4.04 update: MVC 2 support, new settings, cleanup, fixes

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

Though I haven’t blogged for a while about T4MVC, I’ve been making a few minor updates and only sent notification via Twitter.  Now, I have a few things that are worth discussing in a little more detail.  Note that you can see the complete list of changes from version to version in the readme.txt file that comes with it.  BTW, I used to have all this revision information directly in the .tt file, but it was getting a little long so I moved it to the readme.

The changes described below were added between version 2.4.00 and 2.4.04.

MVC 2 Preview 2 support

The most interesting things to many people is that I just made a fix to allow T4MVC to work on MVC 2 Preview 2 apps.  The reason is was not working is that the MVC team changed a number of their API’s to return MvcHtmlString instead of strings.

One challenge here is that I did not want to maintain two separate versions of T4MVC, just to account for this small difference.  Instead, I ended up adding logic in T4MVC which detects which version of ASP.NET MVC your app is using, and adapts what it generates accordingly.  The result is that the overall T4MVC experience is the same as before: you drop it into any MVC app and it should just work!

Detecting the version of MVC in use through the less-then-perfect VS DTE object model was a bit of a challenge in itself.  In case you’re curious, here is the logic I ended up with:

var vsProject = (VSLangProj.VSProject)Project.Object;

foreach (VSLangProj.Reference r in vsProject.References) {
    if (r.Name.Equals("System.Web.Mvc", StringComparison.OrdinalIgnoreCase)) {
        return r.MajorVersion;
    }
}

The fact that I had to cast Project.Object to a VSProject was far from intuitive.  But anyway, I digress, this post is not about the VS DTE model :)

So, back to MVC 2, please note that this new T4MVC does not add support for any of the new features.  It simply allows it to run without blowing up, but still only supports features that existed in MVC 1.  In particular, the one big obvious feature that would be worth supporting is Areas (Phil’s blog).  This is something I’d definitely like to add support for when I get some cycles (unless someone else does it first! :)).

Generate cleaner code that doesn’t make various tools complain

This came as various separate changes based of issues that several people mentioned.  Copying items from the revision list:

  • Put all the generated code in a T4MVC #region. This is useful to tell tools like ReSharper to ignore it.
  • Added <auto-generated /> comment to disable StyleCop in generated file
  • Added pragma to prevent compiler from complaining about missing Xml comments
  • Renamed generated classes to be CLS compliant

Generally, T4MVC is trying to be a good citizen with the various tools people are running.

New knobs in T4MVC.settings.t4

You can look at T4MVC.settings.t4 to see the list of things that are customizable.  In short, and again copying from the history list, the new knobs are:

  • Added a setting to turn off the behavior that always keeps the template dirty
  • Added a setting to set the namespace that Links get generated in
  • Added ProcessVirtualPath method to T4MVC.settings.t4 so user can write custom logic to modify client URL's

Cleanup

I made various cleanup to the template’s logic.  In particular, I greatly simplified the logic that locates the VS project that contains the T4 template, by using the FindProjectItem() method:

// Find the .tt file's ProjectItem
ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
Before, I was doing all kind of crazy things, mostly because I didn’t know about this method.  I’m learning the VS DTE model as I go along, as I had never used it before :)
Posted by davidebb | 8 Comments
Filed under: , , ,

C# method overload resolution can play tricks on you

While working on T4MVC, I ran into a very tricky C# compiler behavior that I thought I’d share.  T4MVC creates various overloads that allow you to avoid literal strings.  One such case is that you can replace:

routes.MapRoute(
    "UpcomingDinners", 
    "Dinners/Page/{page}", 
    new { controller = "Dinners", action = "Index" }
);

with

routes.MapRoute(
    "UpcomingDinners",
    "Dinners/Page/{page}",
    MVC.Dinners.Index()
);
This works because T4MVC adds its own MapRoute overload extension method (which it puts in the global namespace):
public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result);

And of course I had tested this out before publishing the template, and it worked perfectly well with NerdDinner, which I’ve been using as my little test app.

But then, a developer sends me an email telling me that while the template is generally working well for him, this one scenario is not.  Instead of it calling the T4MVC overload, it binds to the (less specific) overload in ASP.NET MVC (coming from the System.Web.Mvc namespace):

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults);

This was very puzzling, since the call was passing an ActionResult, and the more specific overload should ‘win’.  Eventually, we discovered that the only difference between my working app and his non-working app is that he was putting his ‘using’ statements inside the namespace, while I was putting them outside!

e.g. I had:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace NerdDinner {

    public class MvcApplication : System.Web.HttpApplication {

While he had:

namespace NerdDinner {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;

    public class MvcApplication : System.Web.HttpApplication {

Note that both ways are perfectly valid, and if you look at C# samples out there, you’ll find a mix of both.  It pretty much comes down to personal preference, and you would generally expect them to behave the same way.  So why the heck was that causing the C# binding behavior to change?!

It turned out that the root of the issue was that T4MVC was generating its overload in the global namespace (i.e. not in a namespace).  So it had to do with the way C# searched namespaces (see C# spec for details), causing it to find the System.Web.Mvc overload before it even considers the global namespace when the using statements are inside.  While when they’re outside, System.Web.Mvc and the global namespace are looked at together, letting the more specific overload take over.  Tricky stuff!

So what’s the moral from this story?  There are a couple:

Putting things in the global namespace is evil.  I was guilty of doing it in T4MVC.  I guess I had figured that being generated code, we just wanted it to be available everywhere without forcing the user to deal with namespaces, but it was a mistake.  I have since moved away from that, instead adding things to the System.Web.Mvc namespace.  This may be slightly questionable as well, since it’s adding to a framework namespace it doesn’t own, but given the nature of them T4 template, it’s acceptable.  Now it works equally well wherever the ‘usings’ are.

Overloads that take ‘object’ are pretty evil.  ASP.NET MVC makes common use of the anonymous object pattern to pass default values.  This is why their overload is typed as object, and lets you pass new { controller = "Dinners", action = "Index" }.  But while this is convenient, it really increases the odds of confusing the resolution rules, so I’m not a huge fan of them.  Some people will go as far as saying the method overloads are generally evil, but I think they are very useful when not abused.

Posted by davidebb | 5 Comments
Filed under: ,

T4MVC 2.4 updates: settings file, sub view folders, ActionName support and more

To get the latest build of T4MVC:

Go to T4MVC page on CodePlex

This post is a continuation of various previous posts on the T4MVC template for ASP.NET MVC:

I last blogged about version 2.2, and there have been a number of changes since that (you can get the full history at the top of the T4MVC.tt file).  This post describes some of those changes.

T4MVC now uses a separate settings file

Previously, if you wanted to customize T4MVC, you’d have to change T4MVC.tt directly.  This is fine until you want to grab the next build, and have to hand merge the changes.

Instead, it is now using a separate settings file called T4MVC.settings.t4.  The idea is that you can tweak some behavior by changing this file, without changing the main file.  Make sure that you copy both files when you grab 2.4 or later!

Note: it uses a .t4 extension instead of .tt, because we don’t want VS to process it directly.  Instead, it’s included by the main .tt file.  What’s nice is that the .t4 extension is also recognized by Clarius’ Visual T4.

Currently, it doesn’t support all that many settings, but it’s only a first step.  The idea is that as more customization scenarios come up, new things will appear there.  Of course, you may need some small hand merging of the settings files when you update to newer versions, but that’s a lot less painful than merging the main .tt file.

Here is what it contains in 2.4.00:

// The prefix used for things like MVC.Dinners.Name and MVC.Dinners.Delete(Model.DinnerID)
const string HelpersPrefix = "MVC";

// The folder under the project that contains the controllers
const string ControllersFolder = "Controllers";

// The folder under the project that contains the views
const string ViewsRootFolder = "Views";

// Folders containing static files for which links are generated (e.g. Links.Scripts.Map_js)
readonly string[] StaticFilesFolders = new string[] {
    "Scripts",
    "Content",
};

Support for views in sub folders

I have had a few users mention that they sometimes don’t put their views directly under Views\CtrlName, but instead put them in a subfolder.  e.g. you might have Views\Dinners\Sub\Details.aspx.

Previously, T4MVC was ignoring those.  Now, it finds them and makes them available using a matching hierarchy.

So when you have Views\Dinners\Sub\Details.aspx, you can refer to it as

MVC.Dinners.Views.Sub.Details

or if you’re within the Dinners controller, you can just write:

Views.Sub.Details

And this will evaluate to "Sub/Details".

Support for [ActionName] attribute

Suppose you have an action method that looks like:

public virtual ActionResult Details(int id) {

By default, the action name is just the method name: “Details”.  That is, this is what normally shows up in your URLs, e.g. /Dinners/Details/2.

But sometimes, you want your action name to be different from the method name, and that’s when you would use the MVC ActionName attribute.  e.g.

[ActionName("NewActionName")]
public virtual ActionResult Details(int id) {

And now your URLs start looking like /Dinners/NewActionName/2.

Except that previously, T4MVC was ignoring this attribute, causing it to still generate the old URL!  Now, it correctly locates and honors the attribute.

The beauty is that T4MVC completely shields your code from those changes.  Without it, you’d have written:

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

And you would have had to change “Details'” to “NewActionName”.  But with T4MVC, you just write:

<%= Html.ActionLink(dinner.Title, MVC.Dinners.Details(dinner.DinnerID)) %>

And it keeps on doing the right thing no matter what the ActionName is set to!

New parameter-less overload for all actions

Previously, T4MVC was only offering pseudo-action calls that had the exact same signature as the real action method.  This usually works well, but in some POST scenarios, the parameters comes from the form and not the URL.

To solve this, T4MVC now always generates a parameter-less overloads.  e.g. suppose your action looks like:

[AcceptVerbs(HttpVerbs.Post), Authorize]
public virtual ActionResult Edit(int id, FormCollection collection) {

Where both the id and the FormCollection are things that you don’t want to pass explicitly, you can write:

<% using (Html.BeginForm(MVC.Dinners.Edit())) { %>

So you still get the benefit of not hard coding the controller and action names (what T4MVC is all about), even though you’re not using the signature that matches your real action.

Support for placing T4MVC.tt below the root of the app

Previously, T4MVC.tt had to be at the root of the MVC web application.  Some users mentioned that they preferred to have it in some other folder, like ‘Templates’.  So I made a change so it can be anywhere under the project root.

Bug fixes

There are also a number of bug fixes that are not interesting enough to discuss individually.  Please see the history at the top of T4MVC.tt for details.

Posted by davidebb | 34 Comments
Filed under: , , ,
More Posts Next page »
 
Page view tracker