How to add a interface to auto-generated classes

by Kenny Eliasson 17. November 2010 16:13

Even though I really dont like working with webservices or WCF, sometimes you got to swallow the bitter pill and create some.

There are alot of different ways to work with webservices, you can add them as references, you can use WSDL and generate proxy classes or maybe call them directly via HttpWebRequest (why you would do that I dont know :)).

I usually ended up with generating them and making a "facade"-class around the calls to the webservice.

But sometimes you don't really feel the need for yet another class just to "hide" the webservice. What I want to accomplish is slapping a interface on top of my auto-generated proxy classes when I add the service as a reference. You can't add the interface on the proxy class since that change would be lost the next time you update the service reference.

What I came up with is that you can create a partial class


namespace MyProject.Services
{
 public partial class MyService : IMySerivce
 { }
}


Notice that you must have the same namespace as your webservice.

This is one of the few reasons where I had to use partial classes.

This solution is kinda quick and dirty and I would reconsider to use a facade instead if you need to add logic for logging etc.

Tags:
Categories: C#

Performance of Html.RenderPartial

by Kenny Eliasson 27. October 2010 10:56

I was using Html.RenderPartial to loop out a Filestructure. (Parents have children that can have children ...).


<% foreach (var entry in Model) { %>
    <li>
        <span class="Clickable"><%=entry.Name%></span>
        <% if (entry.Children.Any())
                Html.RenderPartial("../FileEntry/Item.ascx", entry.Children); 
        %>
    </li>
    <% } %>
</ul>


This worked flawlessy on small data-amouns but when the tree contained over 500 entries the page took over 5-10 seconds to load.

My first thought was of course that the database query was slow, I fired up NHProf only to find out that the query took 50ms.

My memory then told me that I had read a blog post about the performance isnt all that good on Html.RenderPartial. I googled a bit but didnt really find a solution for it, so I tried to change the way I locate the view. I changed the Html.RenderPartial part of the code from

Html.RenderPartial("../FileEntry/Item.ascx", entry.Children);

to


Html.RenderPartial("~/Views/FileEntry/Item.ascx", entry.Children); 


and the page once again took under 1 second to load. Pretty impressive performance boost with a one-line change.

The culprit of the problem is probably when searching for the view on the current filesystem. It probably looks in the "Shared"-folders, dont find it, look somewhere else til it finds the correct one. Hitting the filesystem *is* expansive, especially over 500 times.

Categories: C# | MVC2

My first adventure with MongoDB

by Kenny Eliasson 19. April 2010 15:23

After all traction the NoSQL movement have been getting lately I wanted to check out document-,object-databases. Last week I got an interesting task we're we needed to able to query the cache. At the moment we use the built-in .NET cache which we want to replace to something that can expand over more servers. We've looked at Memcached before but i suggested that we should take a look at MongoDb instead. After some investigating and spikes we realized that MongoDb would solve alot of problems. We choosed to use NoRM as our provider. The objects we're caching are pretty deep and we needed to modify them slightly to make NoRM's serializer able to serialize them.

Getting up to speed with NoRM was really easy and I really enjoy the schema-less nature. The querying is done via Linq and is really fast and as I told earlier meet our criterias.

So after working with MongoDb and NoRM for one day, im really impressed and i've been able to replace our caching-logic complety. It even feels faster now ;) If you're looking for a good document-database MongoDb is absolutely worth a look!

Tags: , ,
Categories: C# | NoSQL

EditorTemplates and MVC2

by Kenny Eliasson 19. April 2010 15:10

Been upgrading our MVC-project at work to MVC2. A pleasant journey without much hassle. After upgrading I of course wanted to play around with the EditorTemplates.

I easily implemented my own EditorTemplates for Strings, Int32's, MultilineText, Bools and other "simple" types. I then realized that it would be sweet if all properties ending with "Color" would use my Color-template that included some Javascript for a color-picker. I remembered that i saw something like that in Tekpubs MVC-movies. What I needed to do was to create my own ModelMetadataProvider. Luckily enough yu can just inherit from the default DataAnnotationsModelMetadataProvider and override CreateMetaData().

My ModelMetadataProvider looked like this after my small tweak.

public class CustomMetaDataProvider : DataAnnotationsModelMetadataProvider
    {
        protected override ModelMetadata CreateMetadata(System.Collections.Generic.IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        {
            var metaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
            if(propertyName != null) {
                if (propertyName.EndsWith("Color")) {
                    metaData.TemplateHint = "Color";
                }   
            }
            return metaData;
        }
    }

After that we tell our MVC-app to use our Provider in Global.asax with 1 line.

ModelMetadataProviders.Current = new CustomlMetaDataProvider();

And as easy as that I've implemented my own convention! :)

Tags: , ,
Categories: C# | MVC2 | Templates

Easily add test-dependencies in debug-mode

by Kenny Eliasson 12. March 2010 11:15

Something I often want to do is to replace some implementations of my interfaces that touches external resources (like hitting the database or sending mails).

I've got a MailService class that i have a "debug-implementation" of that looks like this


public class DebugMailService : IMailService
{
    public void Send(MailMessage message)
    {
        Send(new List<MailMessage> { message});
    }

    public void Send(IEnumerable<MailMessage> messages)
    {
        foreach (var mailMessage in messages) {
            Debug.WriteLine(string.Format("Skickar mail till {0} från {1}", mailMessage.To[0].Address, mailMessage.From.Address));
        }
    }
}

Inside my IoC-container setup (in my case StructureMap) i checks to see if the I'm in debug with the preprocessor directive #if (DEBUG) and sets a private variable to true. Like below


    public class StructureMapSetup
    {
        private bool _isDebugMode;

        public void Execute()
        {
            #if (DEBUG)
                _isDebugMode = true;
            #endif
   
            ObjectFactory.Initialize(x =>
            {
                x.AddRegistry(new BootstrapperRegsitry());
                x.AddRegistry(new UnitOfWorkRegistry());
                x.AddRegistry(new AnalyticsRegistry(_isDebugMode));
                x.AddRegistry(new RepositoryRegistry());
                x.AddRegistry(new FluentMdxRegistry(_isDebugMode));

            });
      }



Later on in my Registry classes i can easily check if im in debug mode and add the correct concrete class I would like under debug-circumstances


if (isDebugMode) {
    For<IAuthenticationService>().Use<DebugAuthentication>();
    For<IMailService>().Use<DebugMailService>();
} else {
    For<IAuthenticationService>().Use<CIRAuthentication>();
    For<IMailService>().Use<QuicksearchMailService>();
}


Sweet, and I dont need to change one line of code when going to production or Q/A (since I build in release mode then).

 

Over 'n out

Tags:
Categories: C#

My project setup, Part 1 - Initialization

by Jakobsson 4. March 2010 19:14

A while ago I wrote a post about what tools and frameworks I use in my web applications. Now I thought I'd write a small series about how I use those tool. In this first part I'll write about the initial setup and how I use my ioc container.

A lot in my applications revolve around my ioc container. I try to make it take the heavy lifts to make my coding easier. I have created a base bootstrapper that doesn't depend on a specific container. That class looks like this:



    public abstract class BootstrapperBase : IBootstrapper
    {
        private readonly List<Assembly> assemblies = new List<Assembly>();

        protected BootstrapperBase(IEnumerable<Assembly> assemblies)
        {
            this.assemblies.AddRange(assemblies);
        }

        public virtual void Execute()
        {
            ExecuteCore();
            SetServiceLocator();
            ServiceLocator.Current.GetAllInstances<IInitializationTask>()
                          .ForEach(x => x.Execute());
        }

        protected IEnumerable<Type> GetAllTypesInAssemblies<T>()
        {
            return
                GetAssemblies().SelectMany(
                    x => x.GetTypes().Where(y => typeof(T).IsAssignableFrom(y) && typeof(T) != y));
        }

        protected abstract void ExecuteCore();
        protected abstract void SetServiceLocator();

        protected virtual IEnumerable<Assembly> GetAssemblies()
        {
            return assemblies.Distinct();
        }
    }


It's quite simple. It takes a list of all assemblies that should be searched when I initialize my ioc container. Then it has a Execute() method (from the IBootstrapper interface). This basicly calls the ExecuteCore() abstract method that will initialize the container. Then it calls the SetServiceLocator() abstract method that will set a servicelocator for the ioc I'm using. Then it uses the servicelocator to get all instances of IInitializationTask and call the execute method on them.

The IInitializationTask interface looks like this:



public interface IInitializationTask
{
    void Execute();
}



Very simple with just one method, Execute(), that will execute the task. Everything that I want to initialize at the start of the application implements this interface. This could be registering my routes, setting up automapper or anything else that you want to execute on application startup.

Now I need a implementation of my base bootstrapper for the ioc container I want to use. My favorite is structuremap. And here is my bootstrapper for structuremap:



public class StructureMapBootstrapper : BootstrapperBase
    {
        public StructureMapBootstrapper(IEnumerable<Assembly> assemblies)
            : base(assemblies)
        {

        }

        protected override void ExecuteCore()
        {
            ObjectFactory.Initialize(x =>
            {
                GetRegistries().ForEach(x.AddRegistry);

                x.Scan(y =>
                {
                    y.WithDefaultConventions();

                    GetAssemblies().ForEach(y.Assembly);

                    y.AddAllTypesOf(typeof(IInitializationTask));
                    y.AddAllTypesOf(typeof(IConsumer<>));
                });
            });
        }

        protected override void SetServiceLocator()
        {
            ServiceLocator.SetLocatorProvider(() => new StructureMapServiceLocator());
        }

        protected virtual IEnumerable<Registry> GetRegistries()
        {
            var types = GetAllTypesInAssemblies<Registry>();
            return types.Select(x => (Registry)Activator.CreateInstance(x));
        }
    }



The interesting part here is the ExecuteCore() method. It initializes structuremap and first it adds all the implementations of the structuremap Registry class that it can find in the assemblies of the application. Then it scans all applications and adds all classes that implements the interface IInitializationTask (that I described earlier). Then it adds all classes that implements the IConsumer<> interface. I use the IConsumer<> to subscribe to events that I can publish from my application. You can read how that is done in this post.

Now i just need a way of calling my bootstrapper in my application. For this I have first created a MvcApplicationBase class. This is a class that inherits from the HttpApplication class. It looks like this:



public abstract class MvcApplicationBase : HttpApplication
{
    private IBootstrapper bootstrapper;

    public IBootstrapper Bootstrapper
    {
        get
        {
            return bootstrapper ?? (bootstrapper = CreateBootstrapper());
        }
    }

    public void Application_Start()
    {
        Bootstrapper.Execute();
        OnStart();
    }

    public void Application_End()
    {
        OnEnd();
    }

    protected abstract IBootstrapper CreateBootstrapper();

    protected virtual void OnStart()
    {
    }

    protected virtual void OnEnd()
    {
    }
}



This is pretty simple. It has a abstract method, GetBootstrapper(), that I call to get the bootstrapper and executes it in the Application_Start() method.

Then I need a implementation of this class for my structuremap. This class looks like this:



public abstract class StructureMapMvcApplication : MvcApplicationBase
{
    protected StructureMapMvcApplication()
    {
        BeginRequest += delegate
                            {
                                ServiceLocator.Current.GetInstance<IEventPublisher>().Publish(new BeginRequest(this));
                            };
        EndRequest += delegate
                          {
                              ServiceLocator.Current.GetInstance<IEventPublisher>().Publish(new EndRequest(this));
                          };
    }

    protected abstract IEnumerable<Assembly> GetAssemblies();

    protected override IBootstrapper CreateBootstrapper()
    {
        return new StructureMapBootstrapper(GetAssemblies());
    }
}



Here I publish two events when a request begins and when a request ends (explained in the link I gave earlier). Then I override the GetBootstrapper() method and creates a instance of my StructuremapBootstrapper. I also have a abstract method, GetAssemblies(), that will return all assemblies I want to search when I initialize structuremap.

All the code from this post sits in a base assembly that I use for just about all my applications. It contains the basic generic stuff that I want to do in just about every web application. In my next post I will show you how this fits into the application and how I extend it with the application-specific initialization and how I set up nhibernate in my applications. Stay tuned.

Tags:
Categories: C#

Meet my new HtmlHelper extensions friends, ForEach and If

by Kenny Eliasson 20. February 2010 10:08

How many times have you written code like this in your MVC views?


<%
 int currentIndex = 0;
 foreach(var item in Model.Items) {
%>
    <% if(currentIndex == 0) {%>
       <div class="item first"><%= item.Name %></div>
    <% } else if(currentIndex == Items.Count()-1) { %>
       <div class="item last"><%= currentIndex + 1 %> <%= item.Name %></div>
    <% } else { %>
       <div class="item"><%= item.Name %></div>
    <% } %>
<%
 currentIndex++;
 }
%>

This is pure ugliness :(

What I missed was something like django for variables. They include both a Last and First variable on the loop.

After reading Phil Haacked's blog about "A code based repeater for .NET MVC" I decided to shamelessy take some parts of his code and write my own extension methods.

The first extension method I wrote was the Html.ForEach which gets me a index counter.

public static void ForEach<T>(this HtmlHelper html, IEnumerable<T> items, Action<T, int> render)

{

    if (items == null)

        return;

    int i = 0;

    items.ForEach(item => render(item, i++));

}

And to use it


<% Html.ForEach(Model.Items, (item, index) => { %>
    <div>#<%= index + 1 %> <%= item.Name %>
<% }); %>

Pretty slick and I dont need to have the counter variable in the view code. It uses lambda in way I didn't thought was possible before I read Haacked blog post.

I then decided to see if I could manage to check if I was on the first or last item in the loop.

I came up with this

public static void ForEachExtra<T>(this HtmlHelper html, IEnumerable<T> items, Action<T, ForLoop<T>> render)

{

    if (items == null)

       return;

    var loop = new ForLoop<T>(items);

    int i = 0;

    items.ForEach(item => { render(item, loop.Update(i)); i++; });

}

public class ForLoop<T>

{

    private readonly int _itemCount;
    public ForLoop(IEnumerable<T> items)

    {

        _itemCount = items.Count();

    }

    public int Counter { get; set; }

    public int Counter0 { get; set; }

    public bool First { get; set; }

    public bool Last { get; set; }

    public ForLoop<T> Update(int i)

    {

        Counter = i + 1;

        Counter0 = i;

        First = i == 0;

        Last = i == _itemCount-1;

        return this;

    }

 }

And to use this you will write

<% Html.ForEachExtra(Model.Templates, (template, loop) => {%>

   <% if(loop.First) { %> First! <% }%>">

   <div>#<%= loop.Counter %> - <%= template.Name %></div>

   <% if(loop.Last) { %> Last! <% }%>

<% }); %>

Starting to look impressive here! :) But I still think I can get it better, so onto my other new extension method, If()!

What I want is to have code that looks something like this


<% Html.ForEachExtra(Model.Items, (item, loop) => { %>
   <div class='item <%= Html.If(loop.First).Write("first").ElseIf(loop.Last).Write("last") %>
       #<%=loop.counter%> <%= item.Name %'
>
   </div>
<% }); %>

That would be awesome so off I went to write it.

public interface IConditionWrite

{

    IElseIfConditionBuilder Write(string output);

}

public interface IElseIfConditionBuilder

{

    IConditionWrite ElseIf(bool condition);

}

public class ConditionBuilder : IConditionWrite, IElseIfConditionBuilder

{

    private readonly IList<FluentHtmlCondition> _conditions;

    private FluentHtmlCondition _lastAddedCondition;

    public ConditionBuilder()

    {

        _conditions = new List<FluentHtmlCondition>();

    }

    public IConditionWrite AddCondition(FluentHtmlCondition condition)

    {

       _lastAddedCondition = condition;

       _conditions.Add(condition);

       return this;

    }

    public override string ToString()

    {

        foreach (var condition in _conditions) {

            if (condition.Fulfilled)

                return condition.Output;

        }

        return "";

    }

    public IConditionWrite ElseIf(bool condition)

    {

        AddCondition(new FluentHtmlCondition(condition));

        return this;

    }

    public IElseIfConditionBuilder Write(string output)

    {

        _lastAddedCondition.Output = output;

        return this;

    }

}

 

public class FluentHtmlCondition

{

    public readonly bool Fulfilled;

    public string Output;

 

    public FluentHtmlCondition(bool fulfilled)

    {

        Fulfilled = fulfilled;

    }

    public void Write(string output)

    {

        Output = output;

    }

 }

And in my Html-helper extension class i add

public static IConditionWrite If(this HtmlHelper html, bool condition)

{

    return new ConditionBuilder().AddCondition(new FluentHtmlCondition(condition));

}

And there you have it all, hope someone can have some use with it.

Categories: C#

How I do data-access

by Kenny Eliasson 1. February 2010 10:03

Over the years I've tested alot of different techniques for getting data from a database in a .NET application.

 

From the simple ADO.NET wrapper that executes raw sql or SP's and then returning a DataTable to the more specified "Repository" where each entity in my domain had a corresponding Repository for querying the data.

 

I then discovered ORM's, especially NHibernate and started using it with the "One repository for each entity" approach. This worked great but when my projects grew bigger and bigger the need to create a new Repository for each new entity was to cumbersome (and often the Repository would have an interface, so for each new entity I created 3 new classes).

 

I later implemented Linq2NHibernate and made it so that the most basic queries (i.e find by name, ordering etc) was made using it. More advanced queries I still shuffled into a entity-specific repository.

 

My interface at this time looked at this

public interface INHibernateRepository

{

    ICriteria ExecuteCritera(DetachedCriteria criteria);

    IQuery ExecuteCritera(string hql);

    IList ExecuteMultiCriteria(params DetachedCriteria[] criterias);

    void Delete(int id) where ENTITY : DomainObject;

    int Save(ENTITY entity) where ENTITY : DomainObject;

    IQueryable Query() where ENTITY : DomainObject; //Linq2Nhibernate

    ENTITIY Get(int id) where ENTITIY : DomainObject;

}

Pretty basic stuff for querying and fetching by Primary Key.

 

If i got a entity specific repository i would extend INHibernateRepository like this

public interface QuestionRepository : INHibernateRepository

{

    Question GetLatestInserted();

    //more question specific implementations

}

I then, of course, had implementing classes of these interfaces.

 

To use it in a MVC application I used Dependency Injection to wire up my controllers.

public class QuestionController(INHibernateRepository repository, IQuestionRepository questionRepository, IUserRepository userRepository /* etc */)

{

}

Some may say that I shouldn't inject repositories directly to my controller, but even if I broke it out to a domain-service, it would still need 3 dependencies.

 

So instead of using the approach above I have begun using Domain Queries. I've read abit about them before but I was when i read Implementing Domain Queries i realized how it would benefit me.

 

I started my refactoring spree by adding two new methods on my repository interface

public interface INHibernateRepository : IRepository

{

    IEnumerable Query(IDomainQuery query);

    T FindOne(IDomainQuery domainQuery);

    /* All other methods */

}

I then one by one extracted the more complicated queries to their own query-class.

 

During this process I didn't encounter a single problem and I could remove all of my entity specific repositories and use _one_ repository for all database calls.

 

So when I'm writing a query nowadays, I first and foremost try to use Linq, if that doesn't work I create a new query class instead of creating a whole new repository for a single entity.

Categories: C#

The template method pattern

by Kenny Eliasson 16. January 2010 10:01

 

One of my favorite patterns is the "Template method pattern".

 

Basically its about having a abstract class that defines common behaviour with points that can be customizable.

 

Yesterday I was refactoring alot of classes tha't didn't make use of the template pattern, but they all inherited from the same base-class. The base-class acted more like a common place for methods that all objects needed.

 

Let me show you some code that I had before the refactoring.

 

public class QuestionQuery : QueryBuilder {

 

public IFluentMdxQuery BuildQuery() {

  return new FluentMdxQuery(_context)

  .Get(x =>

  {

    x.Rowset.ForQuestion(_queryId).WithChildren();

    x.AddMeasure(DefaultMeasure.RespondentCount);

    x.AddMeasure(DefaultMeasure.RespondentShare);

 

    base.AddComparisonIndex(x);

    base.AddBreakdown(x);

    base.AddTimeBreak(x);

    base.SwapAxes(x);

  })

  .WithFilter(base.FilterManager)

  .Order.By(_properties.OrderBy)

  .TheMeasureIs(currentMeasure)

  .AscendingIf(_properties.OrderBy != OrderBy.Measure)

  .SetupWith(setup => {

    setup.HideTheseIds(q => q.AddRange(_properties.HiddenIds));

    setup.AddHighlight.OnMeasure(DefaultMeasure.RespondentShare);

  })

  .WithRules(rules => {

    rules.AddDefaultRules(_properties.ShowAllAnswers());

    foreach (var rule in base.AddedRules) {

      rules.Add(rule);

    }

    rules.Add(new MakeQuestionLevelTotalAndPlaceLastRule());

  });

Thats alot of base-method calls in there.

Now take into consideration that I've got somewhere between 5 to 10 more classes like this.

 

So yesterday I was assigned to add new functionality to the system which involved these classes. And because the classes are built as they are, I was forced to add the functionality to all classes, and that tingled my "bad code sense". I was duplicating code all over the place!

 

So I sat down and realized that the Template method would be a perfect pattern to implement here. Make all common calls in a base-class and add ways of overriding the certain parts of the creation.

 

So heres my new base class. (Some methods are missing since they not add any value besides of taking up space)

public IFluentMdxQuery BuildQuery(ISetupFluentFilterManager filterQueryManager)

{

 

  return new FluentMdxQuery(_context)

  .Get(x => {

    SetupDimensionCollector(x);

    AddComparisonIndex(x);

    AddBreakdown(x);

    AddTimeBreak(x);

    SwapAxes(x);

  })

  .WithFilter(AddFilter(filterQueryManager))

  .SetupOrder(SetupOrder)

  .SetupWith(AddSetupRules)

  .WithRules(ruleCollector => {

    ruleCollector.AddDefaultRules();

    foreach (var rule in _addedRules) {

      ruleCollector.Add(rule);

    }

    AddExtraRules(ruleCollector);

  });

}

 

  protected abstract void SetupDimensionCollector(IDimensionCollector dimensionCollector)

 

  protected virtual void SetupOrder(IFluentMdxSortCommand sortCommand)

  {

    sortCommand.UseDefault();

  }

 

  protected virtual void AddExtraRules(IRuleCollector ruleCollector) { }

 

Its almost looks the same as the old one, but this time I've added the metods to the base class, implemented the default behaviour and made them virtual so they can be overriden in the child classes. I also made some methods abstract to force the implementing classes to add them.

 

So, how did these changes affect my QuestionQuery class?

protected override void SetupDimensionCollector(IDimensionCollector dimensionCollector)

{

  dimensionCollector.Rowset.ForQuestion(_queryId).WithChildren();

  dimensionCollector.AddMeasure(DefaultMeasure.RespondentCount);

  dimensionCollector.AddMeasure(DefaultMeasure.RespondentShare);

}

 

protected override void SetupOrder(IFluentMdxSortCommand sortCommand)

{

  sortCommand.By(_querySettings.OrderBy);

  sortCommand.TheMeasureIs(GetCurrentMeasure());

  sortCommand.AscendingIf(_querySettings.OrderBy != OrderBy.Measure);

}

 

Damn! Only 2 methods needed to be overriden. Everything else was default behaviour. Of course not all my classes we're as simple as this, but they all got more to the point and I avoided alot of duplication.

 

These changes also make it easy for me to add functionality to all query classes easy, just add it to the base class and we're done :)

 

Categories: C#

Model binding i .NET MVC

by Kenny Eliasson 15. January 2010 09:46

(From now on I will try to write my posts in english)
I see alot of variations in how people do model-binding in .NET MVC.
Some guys use the old-school way using Request.Form directly in their Controller actions.

public ActionResult Create()

{

    Recipe recipe = new Recipe();

    recipe.Name = Request.Form["Name"];

    return View();

}

A better way is to pass a FormCollection to the action.

public ActionResult Create(FormCollection values)

{

    Recipe recipe = new Recipe();

    recipe.Name = values["Name"];      

    // ...

    return View();

}

The best way is of course to accept your entity directly.

public ActionResult Create(Recipe recipe)

{

    _repository.Save(recipe);

    return View();

}

This works great when dealing with simple objects.

But what happens when you have a rich domain model and your entities references other entities and so on..

 

Take this simple class for examle

public class Comment

{

 public int Id { get; set; }

 public string Message { get; set; }

 public Post Post { get; set; }

}

If Post is a reference to entity that's already saved in the database. How do you populate it nicely?

Either you can let the ModelBinder bind what it can, and in your action method do

public ActionResult Create(Comment comment)

{

    comment.Post = _repository.Load(Request.Post["PostId"]);

    _repository.Save(comment);

    return View();

}

This works, but I dont really like it :P

I return to a solution further down.

 

Another thing I often find irritating is the need to inject a repository into a controller only to read up a entity.

Instead of having to do like this

public class PostController : Controller

{

     private readonly IRepository _repository;

     public PostController(IRepository repository)

     {

          _repository = repository;

     }

     public ViewResult Details(int id)

     {

          return View(_repository.Get(id));

     }

}

 

I would instead like it to be like this.

public class PostController : Controller

{

     public ViewResult Details(Post post)

     {

          return View(post);

     }

}

 

Now this was a very simple case, but even then i think it has several advantages, one being that it's easier to unit-test this method and another being that we can hide alot of repetetive code.

How do I accomplish both binding to Details/Show-actions as well as binding more complex objects?

Answer: I wrote my own modelbinder ;)

public class GenericBinderResolver : DefaultModelBinder

    {

        private readonly ICanResolveDependencies _resolver;

        private static readonly Type BinderType = typeof(IModelBinder<>);

 

        private class ModelBindResult

        {

            public bool Success;

            public object BoundObject;

        }

 

        /// 

        /// Creates a new GenericBinderResolver. This should be used as the DefaultModelBinder

        /// 

        /// For easy testability of this class we created a new interface thats extracts out the "GetInstance" method from StructureMap.

        public GenericBinderResolver(ICanResolveDependencies resolver)

        {

            _resolver = resolver;

        }

 

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

        {

            //First look at the routes to see if we have any parameters named "Id", if we do load the entity from the database

            var result = TryBindById(bindingContext, controllerContext);

            if(result.Success) {

                return result.BoundObject;

            }

 

            //If there wasn't a Id in the route check if we have custom modelbinder for the type.

            result = TryBindWithCustomModelBinder(bindingContext, controllerContext);

            if (result.Success) {

                return result.BoundObject;

            }

 

            //If nothing works, do it the usual way.

            return base.BindModel(controllerContext, bindingContext);

        }

 

  private ModelBindResult TryBindById(ModelBindingContext bindingContext, ControllerContext controllerContext)

        {

            var result = new ModelBindResult();

 

            int entityId = 0;

            //Is the type we're binding to assignable to our base domain object.

            if (IsAssignableToDomainObject(bindingContext.ModelType))

            {

                if (EntityExistsInRoute(controllerContext.RouteData.Values, bindingContext.ModelName, out entityId))

                {

                    result.Success = true;

                    result.BoundObject = _resolver.TryGetInstance().Get(bindingContext.ModelType, entityId);

                }

            }

            return result;

        }

 

        private ModelBindResult TryBindWithCustomModelBinder(ModelBindingContext bindingContext, ControllerContext controllerContext)

        {

            var result = new ModelBindResult();

            Type genericBinderType = BinderType.MakeGenericType(bindingContext.ModelType);

            IModelBinder binder = _resolver.TryGetInstance(genericBinderType) as IModelBinder;

            if (binder != null) {

                result.Success = true;

                result.BoundObject = binder.BindModel(controllerContext, bindingContext);

            }

            return result;

        }

 

        private bool EntityExistsInRoute(RouteValueDictionary routeValueDictionary, string modelName, out int entityId)

        {

            entityId = TryParseRouteData(routeValueDictionary, "id");

            if (entityId > 0)

                return true;

 

            entityId = TryParseRouteData(routeValueDictionary, string.Concat(modelName, "id"));

            if (entityId > 0)

                return true;

 

            return false;

        }

 

        private int TryParseRouteData(RouteValueDictionary routeValueDictionary, string key)

        {

            if (routeValueDictionary.ContainsKey(key))

            {

                string id = routeValueDictionary[key].ToString();

                if (!string.IsNullOrEmpty(id))

                {

                    return int.Parse(id);

                }

            }

 

            return 0;

        }

 

        private bool IsAssignableToDomainObject(Type modelType)

        {

            return typeof(DomainObject).IsAssignableFrom(modelType);

        }

    }

 

Alot of code but the important things is that I inject a instance of ICanResolveDependencies which is a implementation of your favorite IoC-container. In my case StructureMap.

 

I then look at the route data for a key named "id" if the ModelBindingContext.ModelType is a DomainObject which happens to be my base-class for all entites.

So routes like "Post/Detail/5" would have a key named "id". I take the key and use it with to get the entity from the database. And whops i solved a problem.

 

Also important to note is that if the ModelType isn't is a DomainObject nothing happens and I will let the default model-binder do its work.

 

The next thing I do is to check if I have custom model-binder class for the ModelType. All my custom model-binders inherit from the same base-class which checks the Request.Form and Querystring dictionaries for a key named "id". If it finds a key named "id" and its greater than 0 it will call the abstract method "BindExisting(int originalId)" else it calls the abstract method "BindNew()".

 

A implementation of a custom model-binder can look like this

public class CommentBinder : ModelBinder

    {

        private readonly INHibernateRepository _repository;

  private readonly IUserContext _context;

 

        public CommentBinder(INHibernateRepository repository, IUserContext context)

        {

            _repository = repository;

             _context = context;

        }

 

        protected override Comment BindNew()

        {

   //Don't do more work then necessary, I have method on the base-class which does the default model-binding.

            var comment = base.DoDefaultModelBinding(); 

 

   //Since I use NHibernate, just get a proxy to the Post and don't hit the database.

   //The Get() method is within the base-class and just returns Request-data.

            comment.Post = _repository.Load(Get("PostId")); 

   comment.User = _context.User;

 

   return comment;

        }

 

  protected override Comment BindExisting(int entityId)

        {

            //load the entity and change the values

   _repository.Get(entityId);

 

            var comment = base.DoDefaultModelBinding(); 

 

   comment.Post = _repository.Load(Get("PostId")); 

   comment.User = _context.User;

 

   return comment;

        }

    }

 

(I left out the code for the base class, if you want too see it email me kennyeliasson at gmail dot com)

 

All I need to care about is how to handle existing and new objects.

This solution have worked out really nice for me WHEN i have more complex objects. Of course I use the default model-binding as often as i can, but sometimes it just isn't enough.

 

Categories: C#