Wednesday, January 25, 2012

FubuMVC Conventional Design List View

Coming from Asp.Net MVC I was so used to the structure expected, for example all controllers had to end in “Controller” and your controllers were separate from the Views etc.  Nothing wrong with this design, but coming into Fubu and having so much freedom to place files how ever you want them was a bit daunting at first.  What I want to cover over my next blog posts are the following conventional ways FubuMVC makes structuring your project easier, and how it does a lot of the heavy work for you out of the box.  This post assumes you have something similar to the configuration as this.

  1) Conventional List Views (this post)
  2) Conventional Create Views
  3) Conventional Edit Views
 

I chose these as they are the most commonly structured tree within a web application.  So this looks something like:

root
   - EntityFolder
       - List.spark
       - Edit.spark
       - Create.spark (or New.spark)

This is pretty common so it makes sense to target the 80% audience and hopefully someone gets something out of this.  To start off I’m assuming you use the following structure and that your entities use an interface like so:

public interface IEntity
{
    int Id { get; set; }
}


Note: Id can be int or Guid, doesn’t matter



Now going back to my Asp.Net experience, wanting a list view to render, the most common style was creating a Controller and then an ActionResult method named Index.  I could do this same thing in Fubu, however if my style of entity design is always going to be Create, Edit, and List then why not let Fubu perform this task for me conventionally.  To get started we will need to build up our convention, lets add a class and call it ListEntity<T> so that it accepts any of our entity classes.  This guy will be responsible for getting a collection of our objects and returning them.



public class ListEntity<TEntity, TList>

where TEntity: class, IEntity

where TList : IEntityList<TEntity>, new()

{
    private readonly IRepository _repository;  	
  	
    public ListEntity(IRepository repository)  	
    {  	
          _repository = repository;	  	
    } 
	  	
    public TList<T> Get(EntityList<TEntity> items)  	
    {
       return new TList<T>() {Items = _repository.All<TEntity>()};
    }	
}


Now lets create our Model that we will use to bind our list



public class EntityList<T> : IEntityList<T> where T : IEntity	  	
{  	
     public IEnumerable<T> Items { get; set; } 	  	
}


You see I’m using an IEntityList, that is nothing more than an interface requiring an IEnumerable<T> Items.  Now what we have here is the conventional piece that will be responsible for delivering EntityList<T> to our Model.  We need a class that takes in IActionSource and will be responsible for ensuring our convention is triggered which will call our ListEntity Get method.



public class ListEntityActionSource : IActionSource  	
{	  	
     private static readonly string MethodName = ReflectionHelper.GetMethod<ListEntity<IEntity, EntityList<IEntity>>>(a => a.Get(null)).Name;	  	
	  	
     public static MethodInfo GetExecuteMethod(Type action)  	
     {  	
         return action.GetMethod(MethodName);	  	
     }
	  	
     public IEnumerable<ActionCall> FindActions(TypePool types)
     {
	 return types.TypesMatching(type => type.IsConcreteTypeOf<IEntity>())
	  	.Select(t =>
	  	 {
	  	     var action = typeof(ListEntity<,>).MakeGenericType(t, getListType(t);
	  	     return new ActionCall(action, GetExecuteMethod(action));
	  	  });

}

 

private Type getListType(Type entity)
     {
            return _container
                .Model
                .DefaultTypeFor(typeof(IEntityList<>).MakeGenericType(entity));
     }

}


And now we need to generate a way to register this with fubu as well as set our route up



public class ListEntityEndpoints : IFubuRegistryExtension	  	
{	  	
     public static string ToRoutePattern(Type entityType)  	
     {	  	
        return "{0}/list".ToFormat(entityType.Name.ToLower());	  	
     }	  	
	  	
     public void Configure(FubuRegistry registry)	  	
     {	  	
         registry.Actions.FindWith(new ListEntityActionSource());	  	
         registry.ApplyConvention(new LambdaConfigurationAction(graph => graph.Actions().Where(x => x.HandlerType.Closes(typeof(ListEntity<,>))).Each(ModifyChain)));	  	
     }	  	
	  	
     public static void ModifyChain(ActionCall action)	  	
     {	  	
         var chain = action.ParentChain();  	
         var pattern = ToRoutePattern(action.HandlerType.GetGenericArguments()[0]);
         chain.Route = new RouteDefinition(pattern);	  	
         chain.Route.AddHttpMethodConstraint(action.Method.Name.ToUpper());	  	
     }	  	
}


Then to register your ListEntityEndpoints, simply import it into your FubuRegistry like so:



public class MyFubuRegistry : FubuRegistry
{
    ... 
    Import<ListEntityEndpoints>();
    
    ...
}


And now we add into our Registry a section informing Structuremap how to use our IEntityList types, since we are using a generic we have to implement a closing type otherwise spark may have issues:



public class WebRegistry : Registry
{
    public WebRegistry()
    {
        Scan(x =>
                 {
                     x.TheCallingAssembly();
                     x.WithDefaultConventions();
                     x.ConnectImplementationsToTypesClosing(typeof (IEntityList<>));
                 });
    }
}


This is so awesome how this works, now that I have configured my convention, all I have to do from now on for all my entities that I want a list view is to use IEntityList<T> or I can create a model that inherits EntityList<MyEntityClass> (EntityList inherits IEntityList) for the model of my spark view and voilĂ ! This works for your simplest case.  If you need additional behaviors for your list, this of course would need additional behaviors added.  But for the most part, if you need a view that renders a basic list of data then this covers your common list scenarios.  Fubu will wire this up automatically and you now have a list view, you do not require another Endpoint (Or Controller for Asp.Net MVC guys) from here on out.  Keep in mind this adds a List to all of your IEntity types (person/list, address/list, etc), the only difference is only entities that are wired up to a View will actually be chained to a View endpoint.



 



I tried pulling parts out of my codebase and we all know its difficult to get what is needed for a blog post only and exclude the rest of the sections, so if you have some issues getting started with this don’t hesitate to contact me gary.l.coxjr AT gmail.com



 



Happy Coding!

Monday, January 23, 2012

Getting Started with FubuMVC

With FubuMVC getting closer and closer to version 1.0, more and more developers are adopting it for its conventional design and the ability to control all aspects of its behavior.  I started using FubuMVC 4 months ago and ran into many road blocks as there wasn’t (And currently as of this post “isn’t”) very much documentation on how to get started and what you can do.  I would like to spend the next few weeks writing up posts on how to first get Fubu up and running, then how to use its conventional power and the underlying magic within.  I say magic because it is what it is, the framework is simply brilliant and I want to demonstrate it’s power little by little over each post.  There are currently two ways you can configure FubuMVC for a new project, one would be to download the Nuget package “FubuMVC”

image

 

This is basically the Starter package which will load all the references and get FubuMVC configured and Setup for you.  Im not going to cover that route as it’s pretty straight forward and easy for anyone to get started.  What I want to demonstrate is the manual approach to configuring FubuMVC.  For me its always better to get your hands dirty and really learn how to use your tools and what they truly do under the hood.  So lets begin.

Create a new ASP.NET Web project (Empty).

image

Next, right click on your references and select Manage NuGet packages, you should get the same screen as the NuGet image above.  Type in FubuMVC in the search and choose FubuMVC.References and FubuMVC.Spark.  This will load all the required references you need to get Fubu up and running.  Lets assume I created my project as MyFubu.  First step we need is to get Fubu bootstrapped and registered.  Create a class in your web project, for me I might call it MyFubuApplication keeping it named after my project.

public class MyFubuApplication : IApplicationSource
{
    public FubuApplication BuildApplication()
    {
        return FubuApplication
            .For<MyFubuRegistry>()
            .StructureMap(WebBootstrapper.BuildContainer);
    }
}







Now we need to create our registry class and our web bootstrap class.



public class MyFubuRegistry : FubuRegistry
{
    public MyFubuRegistry()
    {
        IncludeDiagnostics(true);
        Applies
            .ToThisAssembly();
        Actions
            .IncludeTypesNamed(name => name.ToLower().EndsWith("endpoint"));
        
        Routes
            .HomeIs<MyHomeEndpoint>(e => e.Index(null))
            .IgnoreControllerNamesEntirely();
        Views
            .TryToAttachWithDefaultConventions();
        this.UseSpark();
    }
}


and for our bootstrap class, this is where you educate Structuremap on where your Registry classes are:



public static class WebBootstrapper
{
    public static IContainer BuildContainer()
    {
        ObjectFactory.Initialize(x =>
        {
            x.AddRegistry<WebRegistry>();
        });
        return ObjectFactory.Container;
    }
}
public class WebRegistry : Registry
{
    public WebRegistry()
    {
        Scan(x =>
        {
            x.TheCallingAssembly();
            x.WithDefaultConventions();
        });
    }
}


As you can see in the FubuRegistry I set the route of HomeIs<MyHomeEndpoint>, what this is telling fubu is when the site loads to direct the user to the default landing page which is in MyHomeEndpoint.Index.  That class would look something like this:



public class MyHomeEndpoint
{
    public HomeViewModel Index(HomeViewModel input)
    {
        return input;
    }
}
public class HomeViewModel
{
    public string HelloWorld
    {
        get { return "Hello World";}
    }
}


Now all I would need is a spark file that uses my HomeViewModel as its model and FubuMVC will build a route to this view which would look something like MyHomeEndpoint/Index. Now this looks a bit tacky having the word endpoint in your url. Not a problem, Fubu allows you to control the way your routes display. To override the way FubuMVC creates your routes simply create a class that inherits IUrlPolicy, something like the following:



public class EndpointUrlPolicy : IUrlPolicy
{
    public bool Matches(ActionCall call)
    {
        return call.HandlerType.Name.EndsWith("Endpoint");
    }
    public IRouteDefinition Build(ActionCall call)
    {
        var routeDefinition = call.ToRouteDefinition();
        routeDefinition.Append(call.HandlerType.Namespace.Replace(GetType().Namespace + ".", string.Empty).ToLower());
        routeDefinition.Append(call.HandlerType.Name.Replace("Endpoint", string.Empty).ToLower());
        return routeDefinition;
    }
}


And register this in your FubuRegistry class



Routes.UrlPolicy<EndpointUrlPolicy>();


And that’s it, your new route policy is in effect and now our url is rendered as /MyHome/Index.  Further customization could be performed to remove the Index as well if desired.



This covers the setting up of FubuMVC portion, to make sure your routes are wired up correctly, run your application and go to localhost:YOURPORT/_fubu to see the advanced diagnostics.  Click on the Behavior Chains link and check that your routes (Mine would be MyHome/Index) are present.  You can also click on the Behavior chain link next to the route to see how Fubu wired it up.  The Advanced Diagnostics will quickly become your closest friend when working with Fubu as it informs you of any chains that are not correctly routed and helps you understand why they are not working as you desired them too.



This about sums it up for getting started, go check out FubuMVC for yourself and see what you think about it.



The FubuMVC Project



Happy Coding!

 
Creative Commons License
Blogged Information and Code is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.