Wednesday 21 March 2012

Cross Browser CSS Done With Ease In MVC

As anyone meddling with CSS on a daily basis knows, one of the biggest headaches is how to handle the subtle differences in how different browsers like to render your pages. Naming no names but far the worst offenders seem to be the earlier versions of Internet Explorer... but every now and again other browsers have their moments too. And as more and more browser versions and devices are becoming available, this issue could still be around for a long time yet.

You can get a copy of the source code here.

Our site has just been through a redesign and this problem reared it's head once again so rather than try and get around issues with the different hacks people have written about before (prefixing IE specific CSS with an asterisk etc etc), I came up with a simple but reasonably elegant way of doing this, without the need for the browser to be requesting it's own style sheet to override the main style sheet.

First of all we need to determine the browser making the request. I chose to do this by creating an Html Extension Method so we can encapsulate all this logic behind a nice clean method to use in our Razor view.



The GetBrowserDetails method is a little messy but anyone who has messed around with the user agent string will know it's a little confusing and even though it looks like a browser can be one type, it's actually another (this is mainly around Safari for some reason). The main thing is it works across IE(6-9), Firefox, Chrome and Safari (including iPad and iPhone). It can obviously be amended and extended as anyone sees fit.

But essentially that is it, I just need to use the string returned as my class in my Razor views. I have added it right at the top to my <body> tag, this way it only needs to be used once and we can override anything in our page from here. So in my _Layout.cshtml...

And now when you browse your site your <body> tag should have a class relating to the browser you are using.

Now all that is left to do is override these styles to get the desired affect, for example if you wanted to change all the <h2> tags in your site to different colours according to it's browser type...

Obviously I would expect people would use this to help with more serious rendering issues (paddings and margins etc) but you get the point, I can target any element on the page and change it according to how I want a certain browser to render it. And once the simple foundations are in place, it's very easy to do in my CSS.

Not only that, but since it's all based around CSS selectors, you can now easily target browser specific elements in jQuery too, just in case you want to disable that pop out menu that doesn't work properly in IE 6!

You can get a copy of the source code here.

If you have any thoughts or comments then please let me know.

Thanks
Jason

Friday 3 February 2012

Issue - No parameterless constructor defined for this object using Ninject in MVC3

A recent issue that got me puzzled for a small while recently was this on the yellow screen of death...

Server Error in '/' Application.
No parameterless constructor defined for this object.

In the stack trace were the following key lines
[MissingMethodException: No parameterless constructor defined for this object.]

and

[InvalidOperationException: An error occurred when trying to create a controller of type 'JasonpDoherty.Controllers.TestController'. Make sure that the controller has a parameterless public constructor.]


This confused me at first as I hadn't made any changes to any constructors during this piece of work so why had it started to complain about this now? What was even more confusing was the fact every other controller could be constructed except for this one.

I have been using Ninject for my sites and I love it. It's pretty lightweight but at the same time gives you a solid dependency injection solution for MVC3. There are tonnes of tutorials to get you going once you have downloaded the package from Nuget.

The problem is that the whole point of using Ninject in my MVC projects is so I can inject dependencies into my controllers? So why am I being told that my controller need a parameterless constructor?

After applying a bit of hindsight I realised what had happened...

My controller constructor is made up like this



I have just created another service that IStockService depends on called IReservationService. This is injected into the IStockService via the constructor. I don't need to inject a concrete version manually because Ninject will do this for me.

And the problem lies here, I actually forgot to tell Ninject to bind IReservationService to anything concrete in my Global.asax, and because I forgot to do this, Ninject did not know how to create an instance of IReservationService, and therefore could not create an instance of IStockService which in turn could not create me an instance of my controller. So instead it tries to find a default constructor in the controller of which I don't have (or want) one.

The problem isn't always that obvious because you could be working way down at another level well away from your UI/Controller and yet the exception you see indicates something is wrong with the way you have created your controller. So it's something to watch out for.

I guess the fix is to create concrete versions of your Interfaces you intend to inject with Ninject, and bind these to your interfaces in your Global.asax straight after, even if they are stubbed ones whilst you are progressing through your work.

Let me know if you have any comments or queries.

Thanks
Jason