Browse by Tags

All Tags » ASP.NET MVC (RSS)

Looking Forward to 2010

Yes, the first month of 2010 is almost gone and I'm just now getting around blogging about the past year and the year ahead.  I guess time management should be on my to-do list for this year? The CodeMash Website One of the coolest projects I've worked on in 2009 was the CodeMash website .  Brian Prince and Jim Holmes asked SRT if they wanted to help design a new website for CodeMash.  Brian will be the first to admit that he's an evangelist first, a developer second and a web developer third.  They gave us pretty much free reign to come up with a new idea as well as the freedom to implement the solution however we wanted. We worked with a Inner Circle Media to help plan the new look and feel of the site.  They deserve kudos for the new look.  On the back-end, I used ASP.NET MVC 1.0 along with SQL Server, Linq2SQL and Castle Windsor for my IoC container.  We also integrated with the existing Sharepoint installation for sponsor maintenance, news and session submissions.  User registration was all done in SQL. This was a great learning project.  Registering for a conference is usually a simple process (from the registrants standpoint).  On the back-end, when you're dealing with varying registration costs (based on the current date), discount codes, PayPal, and other things, it can get pretty complicated.  A large suite of unit tests helped us catch a lot of stuff in the beginning, but a few bugs slippped through.  Luckily, nothing major! I want to also thank fellow SRT developers Marina Fedner and Ben Barefield .  Marina helped me out on the user registration portion and Ben was responsible for the REST feed that we all used for our mobile CodeMash applications . Stepping Down from GANG After being involved with the Great Lakes Area .NET Users Group (GANG) for many, many years (webmaster, VP and this last year as President), I did not run for re-election.  There were some other projects I was taking on and last year's vice president David Giard was willing to take the reigns of the group.  Dave did an amazing job last year as VP and is continuing to do great things with GANG in 2010 .  I'll still be around to help out from time to time, but Dave is the man in charge now! VSM's C# Corner After helming Visual Studio Magazine's C# Corner for a number of years, Bill Wagner decided he wanted to devote his time to other things.  He offered my name as a possible successor!  I talked it over with him and VSM Editor in Chief Michael Desmond.  Everything fell into place and I'm now honored to be following in Bill's footsteps as a VSM author.  My first column has been published ( Interface-Based Programming in C# ) and I've got some positive feedback so far.  My next article is in-process and I have to have the first draft done by February 1st or I'll be on someone's naughty list (and it won't be Santa's!). Microsoft C# MVP I was pleasantly surprised on January 1st to receive an email from Microsoft telling me I've received an MVP award for my C# and community work in 2009.  Thanks to Microsoft and other community members I work closely with! 2010 Plans One of the big conferences for 2010, CodeMash , has already come and gone.  It was a great conference and you CAN NOT beat the price.  The amount of content and learning available is unheard of for the price you pay.  I'm already looking forward to CodeMash 2.0.1.1. In February, I'll be attending the MVP Summit in Redmond.  A great chance to get in touch with new technologies, talk with Microsoft reps and mix it up with other MVP's. Michael Eaton is already planning this year's Ann Arbor Give Camp .  I've offered my assistance again this year and will post more on this even as it gets closer. Speaking: I'd like to do more speaking this year.  While I usually get compliments on my presentations, I'm very hard on myself.  I may be a good speaker, but I want to be a great speaker.  That will come with practice.  I've got some idea's for presentations on topics I'm passionate about (specifically, Inversion of Control and Mocking). I'm really looking forward to 2010! Technorati Tags: SRT , MVP , CodeMash , 2010

Using Windsor to inject dependencies into ASP.NET MVC ActionFilters

I'm using Windsor as my IoC container for an ASP.NET MVC application .  To get dependency injection in my controllers, I'm using a slightly modified WindsorControllerFactory from Andre Loker's post earlier this year .  It works great and allows me to easily test my controllers. I've got some custom ActionFilter s that would benefit from dependency injection.  Unfortunately, ActionFilters are attributes on controllers and methods and their instantiation is controlled by the framework.  There is no extension point to allow custom creation of the ActionFilters.  So I can't do constructor dependency injection.  However, I can do the next best thing – property dependency injection! Custom Method Invoker The ASP.NET MVC framework has an extensibility point when it comes to actually invoking actions on controllers.  The default ControllerActionInvoker does everything we need.  We need to modify it's behavior just a little bit to allow us to inject property dependencies. There's a method on ControllerActionInvoker that is used whenever an action with filters is going to be executed.  It's appropriately named "InvokeActionMethodWithFilters".  This method is passed a collection of ActionFilters that have already been created by the framework (see, this is why we can't use constructor injection).  Thanks to Simone Chiaretta for blogging about his custom Ninject-based ActionInvoker , I was able to convert his to a Windsor-based invoker with relative ease: public class WindsorActionInvoker : ControllerActionInvoker { readonly IWindsorContainer container;   public WindsorActionInvoker(IWindsorContainer container) { this .container = container; }   protected override ActionExecutedContext InvokeActionMethodWithFilters( ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary< string , object > parameters) { foreach (IActionFilter actionFilter in filters) { container.Kernel.InjectProperties(actionFilter); } return base .InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters); } } As you can see, it's pretty straightforward.  All we do is loop through all of the ActionFilters and inject any dependant properties.  Those of you familiar with Windsor will realize that the IKernel doesn't have an "InjectProperties" method.  I grabbed that from Jeremy Skinner's post about using AutoFac to inject properties into ActionFilters .  He created an extension method that uses reflection to resolve property dependencies: public static class WindsorExtension { public static void InjectProperties( this IKernel kernel, object target) { var type = target.GetType(); foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (property.CanWrite && kernel.HasComponent(property.PropertyType)) { var value = kernel.Resolve(property.PropertyType); try { property.SetValue(target, value , null ); } catch (Exception ex) { var message = string .Format( "Error setting property {0} on type {1}, See inner exception for more information." , property.Name, type.FullName); throw new ComponentActivatorException(message, ex); } } } } } Now that we have the plumbing, let's hook it up! Changes to WindsorControllerFactory My current implementation of WindsorControllerFactor.GetControllerInstance looks like this: protected override IController GetControllerInstance(Type controllerType) { if ( controllerType == null ) { return base .GetControllerInstance(controllerType); } var controller = container.Resolve(controllerType) as Controller;   return controller; } I just need to add a few lines of code to add my custom WindsorActionInvoker (which is registered inside Windsor!): protected override IController GetControllerInstance(Type controllerType) { if ( controllerType == null ) { return base .GetControllerInstance(controllerType); } var controller = container.Resolve(controllerType) as Controller;   // new code if (controller != null ) { controller.ActionInvoker = container.Resolve<IActionInvoker>(); }   return controller; } Using Property Injection with ActionFilters So now lets look at how this can be used to add common data to every page.  The oft-used example of populating a list of sponsors just happened to be the exact scenario I was facing when I researched this solution.  With the WindsorActionInvoker in place, I can now create an ActionFilter to load my sponsor information into ViewData: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class LoadSponsorsAttribute : ActionFilterAttribute { public ISponsorRepository SponsorRepository { get; set; }   public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.Controller.ViewData[ "sponsors" ] = SponsorRepository...

Strongly Typed Session Variables in ASP.NET MVC

This post was originally going to be a comment on Jarret@Work's blog post about " Using Extension Methods for Session Values ", but I decided to make a full blog post out of it.  Jarret employed extension methods such Bar()/SetBar() and Foo()/SetFoo() to have strongly-typed session data.  While his method certainly works, I've taken a different approach that I think is a bit more flexible and reads better. Like Jarret, I maintain a "SessionKeys" class – there is no easier way to ask for trouble than using a magic string buried across 4 or 5 web pages.  But I expose my session data in a base class that all controllers in my application derive from.  Here's a sample from my post on unit testing ASP.NET MVC controllers : public abstract class BaseController : Controller { protected SpeakerInfo SpeakerInfo { get { var info = Session[SessionKeys.SpeakerInfoKey] as SpeakerInfo; if ( info == null ) { info = new SpeakerInfo(); }   return info; } set { Session[SessionKeys.SpeakerInfoKey] = value ; } } } Now all of my controllers inherit from BaseController and they can easily access the data stored in the Session by utilizing the SpeakerInfo property.  I like this over Jarret's implementation for two reasons: Properties make the code more readable than get/set methods (in my opinion). I can change where/how SpeakerInfo is stored without affecting the rest of my code (perhaps to use a database instead of Session). To be fair, #2 is also possible with Jarret's implementation.  He can change the code in his get/set methods.  But his code would still read "Session.Bar()" and "Session.SetBar()" when (if the implementation was changed to use a database), it wouldn't really be using the Session. Technorati Tags: ASP.NET MVC
Posted by Patrick Steele's .NET Blog
Filed under: ,

Handy Extension Methods for ASP.NET MVC's UrlHelper

Mickael Chambaud posted three extension methods he created for UrlHelper: Image(), Stylesheet() and Script().  They make it pretty easy to keep your images, stylesheets and scripts organized in a single location – without the need for you to remember where they are placed.  And if you need to move things around for some reason, you only have to change the extension methods. Technorati Tags: ASP.NET MVC , Extension Methods

ASP.NET MVC + MVC Contrib + Unit Testing

One of the key benefits of the MVC (Model View Controller) pattern is a separation of concerns that leads to better testability.  Microsoft recognizes this and will automatically create a separate MS Test project when creating a new ASP.NET MVC solution.  While this gives you a nice head start, there's room for improvement.  While actions in the MVC pattern are simply methods on a class that can easily be called by MSTest (or any unit testing framework), most web applications have interactions with supporting objects such a Request (query string, form parameters, etc…), Response (cookies, content type, headers, etc…), Session, and more.  In a live environment, these objects come as a result of the HTTP request being processed by IIS.  In a test environment, you're isolating just your controllers and actions and you don't have IIS and an entire HTTP pipeline. We can use mocking to provide "pretend" implementations of all of these objects, but there's a lot to mock.  This is where the MVC Contrib project on CodePlex can really come in handy! MVC Contrib Test Helper The MVC Contrib project gets a lot of praise for the many benefits it brings when developing for ASP.NET MVC – numerous UI helpers, Model Binders, Controller factories, etc…  But it also contains a TestHelper library that makes unit testing your controllers much easier.  By utilizing Rhino.Mocks , the MVC Contrib TestHelper can create and initialize your controller with mocked instances of: HttpRequest HttpResponse HttpSession Form HttpContext and more! In this article, I'll utilize the MVC Contrib TestHelper library to fully unit test a simple ASP.NET MVC controller.  As with many small demos, it's totally contrived, but helps illustrate the principals. Scenario We're building an ASP.NET MVC project that has to accept submissions from speakers.  We'll be doing this in a "wizard-like" fashion.  The prospective speaker will first enter their personal information (first name and last name).  The next step will have them enter their submission information.  There will be a final review point and finally, the actual submission.  Since some speakers want to submit multiple talks, we'll re-display the speakers personal information if they start the wizard up again after submitting a talk. Design In this article, we're only going to deal with the first step: collecting the speakers personal information (first name and last name).  We'll save this information in the Session object and pull it back out if the speaker returns to the beginning of the wizard after submitting a talk.  Both the speakers first name and last name are required – the user can not continue if they aren't both filled in.  The action on the controller is the "Speaker" action.  The next step in the wizard is the "SessionDetails" action. Using the information above, we have 5 test scenarios to cover: If we run the "Speaker" action with nothing in the Session: The result should be a ViewModel which has no speaker first name/last name and we should return a "View" result to ASP.NET MVC. If we run the "Speaker" action with a first name/last name in the Session: The result should be a ViewModel which as the first name/last name from the Session and should return a "View" result to ASP.NET MVC. If we run the "Speaker" action and only send in a first name: We should save the first name to the Session, but we'll also add an error for the missing last name to the ModelState and return a "Redirect" result so ASP.NET MVC will go back to the "Speaker" action and give the user the chance to enter their missing last name. Do the same test as above, but for the last name. If we run the "Speaker" action and send both a first name and a last name: The first and last name should be saved to the Session object and a "Redirect" result should be returned that tells ASP.NET MVC to go to the "SessionDetails" action. Set Up Start up a new ASP.NET MVC project and make sure you select the option to create unit tests.  The default ASP.NET MVC project comes with a Home controller.  For simplicity's sake, we'll add our actions to that controller and add our tests to the HomeControllerTests class. First, let's create a class to maintain our speaker information.  Sure, it's only two pieces of information, but this is a sample.  In the real world, we'd probably have more than this and therefore, we'll use a class: public class SpeakerInfo { public string FirstName { get; set; } public string LastName { get; set; } } Test #1 We start by writing our failing test (red), we'll throw together enough production code to get the test to pass (green), then we'll implement our actual logic and make sure...

Know Your Environment!

This is probably one of the most embarrassing things I've admitted to in public (well, maybe not – but close).  I really had to think about whether I wanted to post this.  The mentor in me said "You need to post this.  Others may run into this situation and this will help them."  But the rest of me was saying "You can't admit to that!" The mentor in me won out and I'm posting this in the hopes it may save someone else a few hours of headaches. So I developed a small web site using ASP.NET MVC for a client.  Everything installed fine.  There were a few parameters in global.asax.cs they could tweak if they needed to.  So after some initial testing, they tweaked said parameters and when viewing the website, they still got the old data.  Hmmm…  Ok, so I recycled the app pool that the site was using.  Still seeing old data.  Ok, let's just do an iisreset.  Still seeing old data!  So I play around for an hour or so checking out permissions and finally get frustrated enough that I just reboot the machine. After a reboot, I viewed the site and WAS STILL SEEING THE OLD DATA!  Whoa!  I was blown away.  How can I get IIS to pick up the new values?  They don't even exist in the global.asax.cs file any more – where could they be coming from? After a couple more frustrating hours, I suspected that there was a problem in one of my DLL's – or something weird like that.  As soon as I looked at the bin directory and saw the list of files, it hit me: ASP.NET MVC is a totally compiled environment.  You can't just change a .cs file that is sitting on your website and let the worker process recompile the website. I had tweaked code-behind .cs files so often in webforms it was just natural to do it.  Need to do a quick change on the client's machine?  No problem -- just pull up the code-behind in Notepad and make the tweak.  On the next view of the website it's all re-compiled and you're good to go.  But MVC is different.  The code-behind stuff is all compiled into a DLL and placed in the bin directory.  No matter what change you do to the code-behind files (like global.asax.cs!), the site will continue to use the compiled DLL. Needless to say, I did a quick refactor so the parameters the client may want to change are now in web.config.  A change in that still causes the worker process to re-cycle and pick up the changes. So make sure you don't carry-over any old habits from webforms into your MVC development.  Your sanity will thank you! Technorati Tags: .NET , ASP.NET MVC , MVC
Posted by Patrick Steele's .NET Blog
Filed under: , ,

Lansing Day of .NET 2009

Last Saturday (August 1st) was Lansing's Day of .NET.  The guys organizing this did a great job and I had a really fun time.  I gave my "Intro to ASP.NET MVC" presentation.  I got some great questions during the presentations as well as good feedback.  I did have a few questions that I wanted to follow up on: Using WebForms Controls in ASP.NET MVC I mentioned that it should be possible to re-use ASP.NET Webforms controls if they don't rely on ViewState .  I've never done it before, but knowing how web forms controls do their rendering, I thought it would be quite possible to re-use WebForms controls as simply generators of HTML.  I did a few Google searches and found out it's incredibly easy. All you need to do is register the assembly that contains the user control.  In this example, I registered the System.Web assembly and the System.Web.UI.WebControls namespace so I could access the WebForms <asp:Table> control.  I used the tag prefix of "wc" to indicate a WebForms control: <%@ Register Assembly="System.Web" Namespace="System.Web.UI.WebControls" TagPrefix="wc" %> Now using the controls in the System.Web.UI.WebControls namespace is as easy as it was in WebForms.  Here's a sample for one of my MVC views:     <wc:Table runat="server" id="wfpan">         <wc:TableRow>             <wc:TableHeaderCell>Hdg1</wc:TableHeaderCell>             <wc:TableHeaderCell>Hdg2</wc:TableHeaderCell>         </wc:TableRow>         <wc:TableRow>             <wc:TableCell>Cell Data</wc:TableCell>             <wc:TableCell>More Cell Data</wc:TableCell>         </wc:TableRow>     </wc:Table> Again, if the control relies on ViewState for any behaviors, this probably won't work too well.  But you can at least utilize it as a simple HTML generator. Eliminating "magic strings" Many people who first see ASP.NET MVC code notice redirect code like this: return RedirectToAction("Index"); This redirects to the "Index" method of the current controller.   The problem is that if you rename your Index method, this string will not get updated (well, this assumes you're not using ReSharper which would fix the string too – but that's a different story).  If you hate magic strings as much as I do, check out the MvcContrib project on CodePlex.  They've got some extension methods that let you use lamdas to express your redirects: return this.RedirectToAction(c => c.Index()); If you need to redirect to a different controller, you can specify a controller type in the call: return this.RedirectToAction<AccountController>(c => c.LogOn()); Very cool!  No more magic strings!  For more information, see the MvcContrib project and this blog post . Sample Project Code Finally, I've had a few people asking for the sample code I wrote during the presentation.  Since I didn't get into as much detail as I wanted during the presentation, I'll ZIP up a reference project I used to create the presentation and make that available for download.  It should be up by end of day today. Technorati Tags: Lansing , Day of .NET , DODN

ASP.NET MVC and Resolving Controllers with Windsor

Last week, while working on an ASP.NET MVC app, I wanted to plug in Windsor and use IoC to resolve my controllers.  A couple of Google searches and I came across Andre Loker's blog where he describes step-by-step how to achieve this – and it was just about a week ago!  What timing! If you read the full article, you'll see at the end he has a "More Simplifications" section which I recommend you implement.  It makes things even, uh, simpler!  Thanks Andre. Technorati Tags: ASP.NET MVC , Windsor , IoC

ASP.NET MVC Goodness!

Last week at AADND , I gave a presentation on MonoRail , the Castle Project's MVC implementation on ASP.NET.  The MVC pattern is so popular (and productive!) among web developers, I'm sure you're aware that Microsoft is working on ASP.NET MVC – which is now up to RC1. If you're interested in learning more about ASP.NET MVC, Josh Holmes has a great series on building a simple photo gallery in ASP.NET MVC.  It starts with the basics and adds more and more features with each post.  Check it out: Building a Simple Photo Gallery in ASP.NET MVC Framework Returning Thumbnails With the MVC Framework Adding Lighbox.js to the Simple Photo Gallery Adding Paging to the Simple Photo Gallery Technorati Tags: ASP.NET MVC , Photo Gallery

Playing around with ASP.NET MVC

As I'm a big fan of Castle Project's MonoRail , I often get asked my opinion of the ASP.NET MVC stuff Microsoft is working on. And I always have the same answer -- I've seen some demos but haven't actually played around with it. So I took some time tonight and installed it. Installation You can download the ASP.NET MVC Preview 5 release here . Double-click on the MSI and you get the usual welcome screen. As always, there's a EULA to accept. After that, you're ready to install. And then you're done! Painless and easy. My First Project After installation completed, I started up Visual Studio 2008. At this point, the GhostDoc configuration screen appeared. I had to repeat my GhostDoc set up. That was weird! Don't know if that had anything to do with the ASP.NET MVC install, but I hadn't done anything else with my VS2008 installation recently. You'll now have a new Web project type called "ASP.NET MVC Web Application". After selecting this I was asked if I wanted to add a unit test project as well. Very nice! Obviously, I selected "Yes". :) My solution was now all set up and ready to go: Notice the project is pre-populated with folders for my controllers, models and views. The web.config is also fully configured. At this point, I clicked "Run" to see what would happen. By default, the web.config is not set up for debugging. I took the default and let VS.NET set up my config for debugging. And now my first ASP.NET MVC project was up and running! Comparison to MonoRail Now I started poking around the directory structure. I noticed that instead of a "layouts" folder they place their master pages ("layouts" in MonoRail) inside a "shared" folder. Sounds similar to MonoRail's shared views. I noticed that the view pages are still ASPX pages and contain a code-behind file. This seems kind of odd to me as I'm accustomed to MonoRail's view files (mostly NVelocity) -- a single file that contains everything needed to render the view; no more, no less. I could see that without discipline, the code-behind files could be bloated with business logic when it should only contain view logic. Be careful! Poking around the pre-built pages I noticed most of the "ViewData" (PropertyBag for you MonoRail people) output was wrapped in Html.Encode. It would seem to me that you'd want to, by default, always HTML encode your output (like MonoRail does). I think raw output of view data is the exception rather than the rule. Others think it should be this way too. Again, be careful! Adding a New View So it's time to start adding a little bit of my own code to this sample app. I started with adding a new view. When you do this, make sure you add a new "MVC View Page" and not the usual "Web Form": The page popped up and I noticed something right away: There's no way to pick your master page when creating a new MVC View Page. I'm sure this is just one of those things that don't exist yet. I know that this selection step is available for web forms so it's probably just a matter of time before the ASP.NET MVC stuff supports this. But, since it doesn't, you'll need to add the MasterPageFile attribute yourself as well as any ContentPlaceholder tags. I grabbed them from one of the sample pages. So now I just dumped some code real quick into the view. As I typed, I noticed the Visual Studio was complaining about what I was typing: It didn't like my "Html.Encode" nor my "ViewData" references. I copied these right from another page?! What was I missing? An import perhaps? Nope, the imports on the sample pages are the same as mine. Then it hit me -- these view pages (like web forms pages) inherit from a base class. That base class probably exposes the Html and ViewData objects. Since I just created this page (and haven't compiled), the intellisense wasn't picking up the proper settings. So even though I had the red squiggle's, I hit the build button. Everything built fine and my page errors went away. I put a line of code in one of the controllers to stick my name in the ViewData. Then I added my new page (action) to the menu: I ran the project and clicked on my link: Ok -- I admit it. Not too exciting! And it barely scratches the surface of what you can do with ASP.NET MVC. But I think I've showed it's pretty easy to install it and start using it right away -- even if you're not familiar with the MVC pattern. I'll continue to use MonoRail for my web projects as it's more mature than the ASP.NET MVC stuff. But I'll definitely be coming back to this stuff from time to time and playing around with it. I think Microsoft has made the right decision in creating a whole new architecture for implementation of the MVC pattern and not trying to jam it into the Web Forms engine. That would have been a huge mistake! Technorati tags: MonoRail...