Validating multiple properties with FluentValidation

I really like Jeremy Skinner’s FluentValidation library and have used it on a couple of projects. Up until now though, I’ve only be using it to validate single properties in isolation.

The other day a colleague and I were trying to create a rule that validated two properties by querying the database and checking that the combination didn’t already exist. But we couldn’t seem to work it out.

I cheekily pinged @JeremySkinner and he helpfully pointed out that there are several ways of validating multiple properties:

  • if you want to do cross property comparison then RuleFor(x => x.Foo).GreaterThan(x => x.Bar) etc
  • you can also use Must: RuleFor(x => x.Foo).Must((instance, foo) => …)
  • usually those cover most scenarios. If not, then there’s also Custom, but that’s usually a last resort

The second option was what worked for us, and here is an example.

public class FooBarRequestValidator : AbstractValidator<FooBarRequest>
{
    private readonly IRepository repository;

    public FooBarRequestValidator(IRepository repository)
    {
        this.repository = repository;

        RuleFor(x => x.Foo)
		.Must(NotAlreadyHaveABar)
		.WithMessage("You already have a bar for this foo.");
    }

    private bool NotAlreadyHaveABar(FooBarRequest instance, string foo)
    {
        return !repository.GetAll<FooBar>()
		.Any(x => x.Foo == foo && x.Bar == instance.Bar);
    }
}

The trick is using the overload of Must() that takes a Func<T, TProperty, bool> predicate: that gives you access to the whole instance for your validating pleasure. Here, in NotAlreadyHaveABar() I can access Bar even though the rule is for the Foo property.

This works with FluentValidation v1.1 up to v2.0 Beta 1.

Controlling which address WCF uses for your service

In IIS you can have multiple bindings for a site. I’m not talking about WCF bindings. Rather, I’m referring what the IIS Manager calls “identities”.  Essentially, these allow you to have multiple addresses for a site, by specifying different host header names.

Setting up multiple addresses for a website in IIS

This can be quite useful. However, you hit a snag if you try to host a WCF service in that site because WCF only allows a single address. Navigate to the service in your browser and you get the following error:

This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.

Thankfully, in .NET 3.5 there is a very easy way of solving this problem. You can tell WCF which address to use by simply configuring a base address prefix filter in web.config.

<system.serviceModel>
  <serviceHostingEnvironment>
     <baseAddressPrefixFilters>
        <add prefix=”http://xyz.mysite.com”/>
    </baseAddressPrefixFilters>

  </serviceHostingEnvironment>
</system.serviceModel>

This config-only solution saved me from a real headache today as it meant that I didn’t have to recompile and redeploy. So, I thought I’d share it.

ASP.NET MVC scaffolding and multiple assemblies

I came across a bug in ASP.NET MVC Release Candidate 1 today, which meant that I couldn’t use the useful scaffolding feature, i.e. Add View.

image

When trying to add a strongly-typed view I got the following error:

System.TypeLoadException: Could not load type ‘MyMvcApp.Shared.ISomeInterface’ from assembly ‘MyMvcApp.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’.

The issue was that the model object implemented ISomeInterface, which was defined in a different assembly.

image

I think this is a reasonably common scenario: model objects often use attributes or implement interfaces from validation frameworks and the like – so I was surprised that this bug had slipped into the release candidate. However, A bit of experimentation showed that the problem doesn’t happen if the model object itself lives in the web app. So it’s only when the model object is in a separate assembly from the web app, and the dependency (in this case the interface) is in yet another assembly. Ok, so that makes it a little more of a fringe case. But I happen to be in this fringe!

Luckily for me, not only had the bug already been reported but someone had also posted a workaround: you can get it working by making the relevant assembly available to Visual Studio. All you need to do is find out where Visual Studio is looking.

The only problem with the proposed workaround is that it involved finding the temp folder Visual Studio is using, and that changes for each session, which is a bit of a pain.

Anyway, I ran up Process Monitor and found that one of the places Visual Studio was looking was:

%Program Files%\Microsoft Visual Studio 9.0\Common7\IDE\

Result! That location doesn’t change across Visual Studio sessions.

So all I had to do was copy the assembly (MyMvcApp.Shared.dll) to that folder and then it worked fine.

Hopefully this will be fixed in the eagerly anticipated RTM. But in the meantime this is a pretty good workaround.

Method not found: FluentNHibernate.Mapping.IdentityPart, etc

I’ve been banging my head over this error I was getting when constructing a FluentNHibernate PersistenceModel:

Method not found: ‘FluentNHibernate.Mapping.IdentityPart`1<!0> FluentNHibernate.Mapping.ClassMap`1.Id(System.Linq.Expressions.Expression`1<System.Func`2<!0,System.Object>>)’.

I thought I’d post the (annoyingly simple) solution so that someone else might be saved the agony.

In my case, the FluentNHibernate.dll in one of my projects was an old version. Yawn.

Using SQLite on Vista 64 bit

I’ve been using trying to use SQLite to test my NHibernate mappings and have been getting the following error:

NHibernate.HibernateException : Could not create the driver from NHibernate.Driver.SQLite20Driver, NHibernate, Version=2.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4.

The IDbCommand and IDbConnection implementation in the assembly System.Data.SQLite could not be found.

I had checked to make sure the System.Data.SQLite.dll was copied to the application dir, so what gives?

Well it turns out that the SQLite.dll I was using was compiled for x86. To solve the problem you can either

  1. Download the x64 version of System.Data.SQLite.dll, as suggested here, or
  2. Just change the platform target of your project to x86. 

    image

If the project really needs to take advantage of 64 bit then you’d go for option 1. However, option 2 is easier and, in my case, more pragmatic because it means the code will work on both x86 and x64 systems.

Hope this helps.

Silverlight “outside the browser”

The two PDC2008 keynotes were quite interesting. Sure, the first one about Windows Azure and cloud computing was a little dry, and while is quite hard to wow audiences with architecture, infrastructure and backend services, they could have done a much better job by regularly demonstrating the value to developers and end users (See Apple’s keynotes). However, the second keynote was a lot more exciting. Amongst other things, we got tastes of Windows 7, Office v.Next on the web, and all sorts of Live Mesh goodness.

But for me the highlight of the keynotes was when Scott Guthrie mentioned that Silverlight is jumping “outside the browser”

“Next year we will also then be shipping a major new release of Silverlight, which includes a bunch of new runtime features.

“We’ve already announced support for H.264 media, and you’ll see a lot more media features being announced in the months ahead. In a few minutes you’ll learn about how you can actually run Silverlight both inside the browser, and now, OUTSIDE the browser. (applause)

“Also, as part of the next Silverlight release we’re going to be adding much richer graphics support as well as much improved data support.”

Of course, “in a few minutes” probably referred to a session on Silverlight, and as I wasn’t at the conference I’m left wondering about the details for now. Silverlight outside the browser really would deliver on Silverlight’s former name “WPF Everywhere”. It pits Silverlight against Adobe AIR and really ups the ante in the Rich Internet Application (RIA) space.

image Of course, for this announcement to even mean anything, “outside the browser” must mean on both the Windows and the Mac desktop (and yes, the Linux desktops too although that’s technically ‘Moonlight’). After all, we already have Silverlight outside the browser on Windows – it’s full on WPF. So if Silverlight itself is jumping outside the browser I can only assume that this is the the long-awaited move to get the .NET Framework running on the Mac!

If this proves to be the case, it will have profound implications for technology choice on RIA projects, especially as offline capability starts to become more important. Silverlight will finally be a player – not just a media player.

Windows “Cloud” and Office everywhere

I attended a TechNet event in London today where Steve Ballmer gave the key note. The whole event was called “Technologies to Change Your Business: How Customers Are Implementing s Strategies” and while we were bombarded with Hyper-V, SQL Server 2008, Silverlight and WPF two tech tidbits that I took away with me were

  • The next version of Windows server – which Ballmer dubbed Windows “Cloud” for want of a better word – will take cloud computing to the next level.
  • When asked if MS will offer an Office-as-a-service product to compete with Google Apps, Ballmer said yes. However, he balked at using the term “compete” when talking about Google Apps, which he doesn’t regard as serious competition – and nor do I for what it’s worth. He said there would be a “click-to-run” Office Live type thing (I’m imagining Click-Once) as well as a cut-down, browser-only offering for when you want to do some “light editing at an internet café”.

The funniest thing was at the end of the keynote. Ballmer was asked if he would mind re-enacting his “monkey dance/developer, developer, developer” craziness. Being the good sport he is, he then lept about on the stage chanting “IT Pros, IT Pros, IT Pros…I LOVE IT PROS!!!!”.

The trip to the Southbank was worth it just for that.

Google Chrome is nice, but it doesn’t play nicely with Windows

I like Google Chrome: I like what Google is doing under the hood to improve performance, security, and stability, and I like some of the UI features. But it seems to me that in their rush to implement an innovative UI they opted to side-step some standard Windows application features.

For example, today I was doing some cross-browser testing and I wanted to have four different browsers open at the same time. The thing is, the browser windows were all over the place.

Cluttered browser windows

So, I wanted to tile them. You can do this by control-clicking all four taskbar items, right-clicking, and selecting “Tile Horizontally”.

Tiling multiple windows

The problem is, while Safari, FireFox and IE were happy to oblige, Google Chrome just wasn’t interested.

Google Chrome doesn't tile

Not exactly sure why this doesn’t work, although I suspect it’s down to Google wanting to keep the code base as cross-platform as possible and in the process some Windows-specific things have fallen through the cracks. Perhaps I should be brave like Scott Hanselman and actually dive into the Chrome source code to find out.

Manic Miner in Silverlight

Manic Miner and Jetset Willy are two ZX Spectrum games that were emblazoned into my hippocampus in the early to mid-eighties.

What joy to find that Pete McGann and Richard Costall have created a Sliverlight version of Manic Miner! Have a play here:

http://www.nxtgenug.net/manicminer/

Manic Miner screenshot

Setting default browser in Visual Studio

When I switched to Firefox 3.0 as my default browser, VS started launching Firefox for debugging. But for some crazy reason I wanted to keep IE as the debug browser.

Usually this wouldn’t be too difficult, except that I’m using ASP.NET MVC, and for some reason the normal method isn’t available.

The normal method is to select an ASPX file and choose to Browse With…

Choose Browse With... on an ASPX

VS then launches a dialog allowing you to select your default browser.

Browse With dialog

However, if you’re in an ASP.NET MVC project (Preview 3 at the time of writing), the “Browse With…” option isn’t there. One solution is to open a non-MVC project and do as above.

Another solution is to go directly to the file where VS stores this setting: “browsers.xml”. The file is in your user profile, mine was:

C:\Users\Stuart\App Data\Local\Microsoft Visual Studio\9.0\browsers.xml

Open the file in Visual Studio and then press Ctrl-K, Ctrl+D to format the document so that it is readable. Find the browser you want and set the <IsDefault> tag to True. Et voilà! Job done.

<?xml version="1.0"?>
<BrowserInfo>
  <Browser>
    <Name>Internet Explorer</Name>
    <Path>"C:Program FilesInternet Exploreriexplore.exe"</Path>
    <Resolution>0</Resolution>
    <IsDefault>True</IsDefault>
    <DDE>
      <Service>IExplore</Service>
      <TopicOpenURL>WWW_OpenURL</TopicOpenURL>
      <ItemOpenURL>"%s",,0xffffffff,3,,,,</ItemOpenURL>
      <TopicActivate>WWW_Activate</TopicActivate>
      <ItemActivate>0xffffffff,0</ItemActivate>
    </DDE>
  </Browser>
  <Browser>
    <Name>Firefox</Name>
    <Path>"C:Program FilesMozilla Firefoxfirefox.exe"</Path>
    <Resolution>0</Resolution>
    <IsDefault>False</IsDefault>
  </Browser>
  <InternalBrowser>
    <Resolution>0</Resolution>
    <IsDefault>False</IsDefault>
  </InternalBrowser>
</BrowserInfo>