Monday, March 28, 2011

Presenter Discovery Strategy WebformsMVP

[Update: As per comment posted by Anonymous, Get at least the changeset from March 29th (http://webformsmvp.codeplex.com/SourceControl/changeset/changes/8d76d88f629e) for the following code to work]

Fearing the start of a flame war, I do like the WebformsMVP framework. It's opinionated and it's works well. That's not to say I don't like Asp MVC, I do but I don't believe it's the only weapon in the .Net web developers arsenal. That's like saying I should always use a hammer to drive in a nail, what happens if the nail weighs 5kg.... you need a sledgehammer. While that certainly is drawing an extremely long bow (Being a guy the true answer if you can use a big electric tool use it, if not use a 20 pound sledgehammer or gaffer tape anyhow...) You should use the correct tool for the right job, for instance if I require a rich internet application I will use MVC, otherwise I will use Webforms.In saying the above Webforms certainly can be a pretty rich client experience.Anyhow enough of the ranting and onto the real purpose of this blog post.Previous to version 1.0 of the WebformsMVP project the only way to override the default behaviour of presenter discovery was by using Attributes such as

[sourcecode language="csharp"]
[PresenterBinding(typeof(ProductsAdminPresenter))]
public partial class ProductsAdmin : MvpUserControl, IProductsAdminView
[/sourcecode]

With the release of version 1.0, if you don't like the default Presenter discovery strategy you can now roll your own because the Presenter discovery strategies are now pluggable.Let's say, for instance, that my Presenter classes are in the namespace MyProjectName.Core.Presenters. To allow for custom presenter discovery I can create a new class inheriting from the type ConventionBasedPresenterDiscoveryStrategy.
[sourcecode language="csharp"]
public partial class CustomPresenterDiscoveryStrategy: ConventionBasedPresenterDiscoveryStrategy
{
public override CandidatePresenterTypeFullNameFormats
{
get{new[]{"{namespace}.Core.Presenters.{presenter}"};}
}
}
[/sourcecode]
If the code is trying to resolve the presenter for the ProductsAdmin partial class the above code will tell the PresenterBinder to look for MyProjectName.Core.Presenters.ProductsAdminPresenter.To plug the custom implementation into the framework in the Application_Start method of the Global.asax file (or where ever you do Bootstrapping)
[sourcecode language="csharp"]
protected void Application_Start(object sender, EventArgs e)
{
PresenterBinder.DiscoveryStrategy = new CompositePresenterDiscoveryStrategy( new AttributeBasedPresenterDiscoveryStrategy(), new CustomPresenterDiscoveryStrategy());
}
[/sourcecode]

By including the AttributeBasedDiscoveryStrategy class you can still use attribute overrides for tasks such as using shared presenters, but it'll fall through to your custom strategy for everything else.

Sunday, March 27, 2011

NuGet Packages and Dependencies

I admit that I've always liked the Ruby package management system, RubyGems. Until a few months ago I never even thought about a similar mechanism for the .Net Developer then along came NuGet. NuGet has the potential to really help push open source on the .NET platform and at the same time make the rigor of managing packages somewhat easier.

I am not saying NuGet isn't with it's pain points at times, but overall it's a fantastic tool.

One pet peeve I do have from time to time is dependencies within a package.

For instance Fluent NHibernate when installed through NuGet references NHibernate, Version=3.0.0.2001. I always try to use the latest and greatest versions of Libraries I work with. Whenever I build a web project referencing FluentNHibernate I get the following error bubbled up from StructureMap

StructureMap configuration failures:
Error: 170
Source: Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=2.6.2.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
Unable to find the exported Type's in assembly BasilBee.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. One or more of the assembly's dependencies may be missing.

Could not load file or assembly 'NHibernate, Version=3.0.0.2001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
System.IO.FileLoadException: Could not load file or assembly 'NHibernate, Version=3.0.0.2001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'NHibernate, Version=3.0.0.2001, Culture=neutral, PublicKeyToken=aa95f207798dfdb4'
at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes)
at System.Reflection.RuntimeAssembly.GetExportedTypes()
at StructureMap.Graph.TypePool.c__DisplayClass2.b__0(Assembly assembly) in c:\code\structuremap\Source\StructureMap\Graph\AssemblyScanner.cs:line 24


Luckily NuGet has a command for just this scenario which I discovered at David Ebbo's blog.

First you need to build your project and from the package manager console type:
PM> Add-BindingRedirect


This will add the minimal set of binding redirects to config to get everything working.

Once I ran the command my project starting running as expected.

Personally I think this is a great addition to the NuGet commands. Package Managers certainly can't be always up to date with the latest package references.[UPDATE]No longer relevant with the release of version 1.2