No Free Time

Because my therapist says I need to let things out

Archive for the ‘mvc’ Category

Load ASP.Net MVC Routes dynamically at runtime from a repository

Posted by andrewmyhre on August 2, 2008

This article was written for a preview version of ASP.Net MVC and is now out of date.

Source for this example

Today I read Ian Suttle’s post about loading MVC routes dynamically from a SQL database. I think it’s a cool idea, and I wanted to see if I could do the same thing with XML or a configuration file. I also wanted to introduce the factory design pattern so that people can plug in their own route repositories.

My solution comprises the following classes:

  • MvcRoute – main route DTO
  • MvcRouteParam – route parameter DTO
  • IRouteService – interface defining a service which loads route data from a repository
  • RouteServiceBase – abstract class handles most common route service operations
  • ConfigRouteService – extends RouteServiceBase,  is responsible for reading configuration settings and constructing an IRouteService
  • DynamicRoutesConfigurationHandler and DynamicRoutesConfiguration – parse the configuration

A couple of caveats:

  • It’s not complete, it’s a proof of concept
  • It doesn’t handle ‘ignore’ routes

Settings your routes looks like this:

  

  

24 protected void Application_Start()

25 {

26 IRouteService routeService = new ConfigRouteService();

27 routeService.SetAppRoutes(RouteTable.Routes);

28 RegisterRoutes(RouteTable.Routes);

29 }

 

IRouteService is implemented thusly:

 

  

11 namespace DynamicRoutes

12 {

13 public interface IRouteService

14 {

15 List<MvcRoute> GetConfiguredRoutes();

16 RouteCollection ResetAppRoutes(RouteCollection RouteTable);

17 RouteCollection SetAppRoutes(RouteCollection RouteTable);

18 RouteCollection SetAppRoutes(RouteCollection RouteTable,

19 List<MvcRoute> ConfiguredRoutes);

20 }

21 }

 

 

Most importantly you have a method to get route data from your chosen repository (GetConfiguredRoutes) and a method to add the routes to your application RouteTable (SetAppRoutes).

 

The RouteServiceBase class implements all methods except GetConfiguredRoutes, and this should be the only method you need to implement yourself in order to set up a new route repository. For example, here’s the implementation for ConfigRouteService:

 

 

9 namespace DynamicRoutes

10 {

11 public class ConfigRouteService : RouteServiceBase

12 {

13 public override List<MvcRoute> GetConfiguredRoutes()

14 {

15 DynamicRoutesConfigurationSection configuration =

16 ConfigurationManager.GetSection(“dynamicRoutes”) as

17 DynamicRoutesConfigurationSection;

18

19 return configuration.Routes;

20 }

21 }

22 }

 

 

And here are the configuration handler classes:

 

 

7 namespace DynamicRoutes

8 {

9 public class DynamicRoutesConfigurationHandler : IConfigurationSectionHandler

10 {

11 public object Create(object parent, object configContext, System.Xml.XmlNode section)

12 {

13 DynamicRoutesConfigurationSection config = new DynamicRoutesConfigurationSection();

14 config.LoadRoutesFromConfig(section);

15 return config;

16 }

17 }

18 }

  

8 namespace DynamicRoutes

9 {

10 public class DynamicRoutesConfigurationSection : ConfigurationSection

11 {

12 public List<MvcRoute> Routes { get; set; }

13 public string TypeName { get; set; }

14 public void LoadRoutesFromConfig(XmlNode section)

15 {

16 Routes = new List<MvcRoute>();

17 TypeName = section.Attributes["type"].Value;

18 foreach (XmlNode node in section.ChildNodes)

19 {

20 if (node.Name == “route” && node.Attributes["type"].Value == “map”)

21 Routes.Add(new DynamicRouteConfiguration().LoadRouteMappingFromConfig(node));

22 }

23 }

24 }

25

26 public class DynamicRouteConfiguration

27 {

28 internal MvcRoute LoadRouteMappingFromConfig(XmlNode routeNode)

29 {

30 MvcRoute route = new MvcRoute();

31

32 route.routeName = routeNode.Attributes["name"].Value;

33 route.routePattern = routeNode.Attributes["pattern"].Value;

34 route.routeParams = new List<MvcRouteParam>();

35

36 foreach (XmlNode node in routeNode.ChildNodes)

37 {

38 if (node.Name == “param”)

39 route.routeParams.Add(LoadParamFromConfig(node));

40 }

41

42 return route;

43 }

44

45 internal MvcRouteParam LoadParamFromConfig(XmlNode paramNode)

46 {

47 MvcRouteParam param = new MvcRouteParam();

48

49 param.paramKey = paramNode.Attributes["key"].Value;

50 param.paramValue = paramNode.Attributes["defaultValue"].Value;

51

52 return param;

53 }

54 }

55 }

 

 

Finally, here’s what’s in my web.config to set up my default route:

 

 

11 <configSections>

12 <section name=dynamicRoutes type=DynamicRoutes.DynamicRoutesConfigurationHandler, DynamicRoutes/>

13 </configSections>

14

15 <dynamicRoutes>

16 <route type=ignore url={resource}.axd/{*pathInfo}/>

17 <route type=map name=Default pattern={controller}/{action}/{id}>

18 <param key=controller defaultValue=Home/>

19 <param key=action defaultValue=Index/>

20 </route>

21 </dynamicRoutes>

 

 

This all probably sounds like nonsense so download the complete source here.

Posted in mvc | Tagged: , | 10 Comments »

ASP.Net MVC: Giving MasterPages access to ViewData

Posted by andrewmyhre on July 3, 2008

If you want to include ViewData in the MasterPage UI, you can.

ASP.Net MVC MasterPages are System.Web.Mvc.ViewMasterPage – this is a generic type just like System.Web.Mvc.ViewPage. So you can type it with a ViewData object, like this:

public partial class MyTemplate : ViewMasterPage<SomeViewData>

As soon as you do this you’re saying that the SomeViewData class is the only ViewData object that can be used on any page using this template. Not a problem though, just create a base ViewData class.

public class SiteWideViewData
{
}

public class PageViewData : SiteWideViewData
{
}

This of course means no more default ViewData objects and no more return View(); I found the easiest way to deal with that is to create a static property on the base ViewData:

public class SiteWideViewData
{
public static SiteWideViewData Default { get { return new SiteWideViewData(); } }
}

Now I can do this:

public ActionResult MySimpleControllerMethod()
{
return View(SiteWideViewData.Default);
}

And that seems to work okay.

Posted in .net, mvc | Tagged: , | 3 Comments »

ASP.Net MVC Toolkit Download

Posted by andrewmyhre on June 29, 2008

Took me ages to find a link to download this sucker, so here’s the download link.

Download MVC Toolkit for MVC Preview 1

Note: As Simone noted in the comments, this toolkit is built against MVC Preview 1 and hence doesn’t work with Preview 2 or 3.

UPDATE:

I thought I needed it because there are so many MVC how-to articles referencing Preview 1, but it turns out much of the functionality is now rolled up into Preview 3. This assembly is now redundant, which is why it’s so hard to find. It’s *supposed* to be.

Posted in .net, mvc | Tagged: , | 4 Comments »

MVC Not Ready For TFS?

Posted by andrewmyhre on January 9, 2008

High expectations this year. I want to have at least a couple of commercial MVC website under my belt by 2009, and I want to be using Team Foundation 2008. Part of this will be to make use of Web Deployment Projects combined with Team Builds. What would be great is if I could have the team server spitting out nicely labelled development, staging and production builds of our sites, and if I could configure the config file changes using web deployment projects. Also I would like it to produce metrics around unit tests, integration test and interface tests, and anything else that would be useful (code metrics? haven’t explored this fully yet). I want our projects managers/testers to be able to know what build they’re looking at and easily get a summary of the changesets involved in that build.

So that’s the plan. We are currently running TFS 2005, but the documentation says that VSTS 2008 and TFS 2005 are compatible, so what I’m going to do first is set up a ‘Sandbox’ MVC project in it’s own Team Project space, for us to play with and try things out.

So started by creating a new Team Project, then a new ASP.Net MVC Web Application and Test project (makes sense – want to try out the built in unit testing functionality).

Then I choose the project in TFS I want to use as the repository.

At this stage everything is created and ready to check in, so I perform a solution check-in. All looks good, I can see padlocks next to all my files. But if I close and re-open the solution, I get the message:

The project ‘MvcApplicationTest’ is under source control. This version of Visual Studio .NET does not support source controlled projects. Any changes that you make to this project will not be propagated to source control.

Strange! And now the test project is no longer source-controlled. If I create a build to run these tests on the build server it won’t have any of the project files to compile and run.

To clarify, I’m using Visual Studio Team System 2008 RTM. Anyway, I’ve tried a couple of things, like deleting the test project and adding a new test project. Trouble is I can’t write tests against the MVC controllers due to some weird issue – I can’t add a reference to the version of System.Web.Extensions.dll referenced by the MVC project (3.6.0.0) to the test project. It’s in the GAC, but doesn’t appear in the components list (I see 3.5.0.0, the version that ships with VS 2008). So I can’t even create my own test projects.

Bit of a worry and I hope it gets addressed when MVC goes into full release…

Posted in .net, mvc, tfs | Tagged: , , | 1 Comment »