find a location for property in a new city

Thursday 23 December 2010

3 things that changed ASP.NET development in 2010

As 2010 draws to a close I thought about how I was writing code last year. I realised how much development has changed in just one year. I want to look at how my work has evolved during 2010.

Entity Framework 4

I really like using Entity Framework. I wasn't quite sure about it in its first version, however, since the release of Entity Framework 4 in April I fully adopted it. It solves so many problems that I feel exist in modern web development.

I like stored procedures, I know a lot about using and optimising them but there is something seriously wrong with their concept - you have business logic in your database! When you think open mindedly about what a logical architecture should be you realise just how ridiculous that is. Entity Framework takes the last remaining strand of business logic back to the web developer.

Aside from the improvement in architecture, the other benefits I love about it is that speed you can develop with, deferred querying that improves reuse of queries, strong typing of Linq to Entities, Intellisense when writing queries, no more mapping, no more writing tedious POCOs, lack of tedious code in general.

Its hard to believe only a year ago I was writing stored procedures.

ASP.NET MVC 2

Again, I had a look into this when it was in its first version but was carried by the hype around v2. I fully adopted the use of MVC in April too and what a joy it has been to use.
A lot has changed over the last 10 years of web development such as increasing expectations of performance and web standards, popularity of unit tests and agile development, ubiquity of AJAX.

Now, I wouldn't go so far as to say there is anything wrong with ASP.NET Webforms I just feel that ASP.NET MVC has been a superb reaction to these changing trends in what web developers want to produce.

Whilst all of the above concerns can be answered by Webforms, like turning off view state to remove bloat, moving logic out of code behind to unit test, improved web standards in ASP.NET 4 etc you still feel as though you are swimming up stream some what.

I much prefer to get down and dirty with ASP.NET MVC. It's refreshing to get involved in HTML and HTTP again in a way that was abstracted out of your hands with web forms. It makes you feel like a real developer again, omnipotent! Of course the framework and templates do a lot of the tedious work for you but let's keep that quiet ay... Omnipotent! Remember that, yeah.

It's hard to think only a year ago I was using web forms.

Contribution

This has obviously been around for some time but I think only during 2010 has Microsoft's commitment to open source and code contribution has really shone through. It had been displayed, proven and truly adopted by the community. Look at how much there is to gain from MVC contrib.

I would like to think this is why frameworks such as Entity Framework and ASP.NET MVC are evolving so quickly and more importantly in the right direction. Microsoft is really listening to the community now. Forums and polls about what you would like to see in the next version of Entity Framework for example.

It is not just direct listening either, I'd be extremely surprised if Microsoft weren't reading blogs, browsing stackoverflow and stalking twitter to gain insight into what the community love and what they are crying out for.

It's hard to think last year I didn't have a blog or a twitter account or contribute on stackoverflow or publish any code.

Follow britishdev on Twitter

Wednesday 15 December 2010

WCF Data Services for using Entity Framework over REST web services

I spent some time looking into WCF Data Services 4.0 (AKA ADO.NET Data Services & Astoria) as a way to expose our Entity Data Model (EDM) over an easy to create set of RESTful / OData web services. I decided to document my findings.

WCF Data Services 4.0 is service that provides a way of exposing an EDM over RESTful (OData) web services using WCF. It means that if you have an EDM already built, the work is essentially done. The EDM can be exposed using WCF Data Services so that it can be queried directly by the client.

How to begin

I successfully set up some WCF Data Services to expose a Comment part of my model. This helped me. I did find difficulty due to our use of POCOs instead of raw Entity Framework's generated code but I found a post that helped which told me about a weird hack that overrides the CreateDataSource into the Data Service:
public class CommentsService : DataService<SocialEntities>
{
    protected override CommentingEntities CreateDataSource()
    {
        var context = new CommentingEntities();
        var tracestring = context.CreateQuery<Comment>("CommentingEntities.Comments").ToTraceString();
        return context; 
    }
}

Consuming the web services

A client can now access the data by requesting URLs. E.g. http://api.mysite.com/CommentsService.svc/Comments to get a list of messages or http://api.mysite.com/CommentsService.svc/Comments(413L) to get the message with ID 413 (the L is for long since I use long instead of int)

The querying gets a lot more complicated than that too. See how to use your browser to query the data model

There are many SDKs out there to begin developing against your WCF Data Services from a number of popular platforms since it is simply using the OData protocol (e.g. JavaScript, PHP, Ruby, Java, Objective-C, .NET).

Restricting use

You can restrict the number of results to return when returning a list of entities to, say 5, so the client can't overload the server/bandwidth.

You can also restrict access to select parts of your EDM to calm your security nerves too:
public static void InitializeService(DataServiceConfiguration config)
{
    config.SetEntitySetAccessRule("Comments", EntitySetRights.AllRead);
}

Evaluating when to use WCF Data Services

So it does look like a great way to use the existing EDM to instantly have a set of RESTful web services to consume. However I think I would only use this if the developers of the web service client were have knowledge of the data and are expecting to get stuck into some code when consuming our data services.

If were internally designing our own Silverlight apps then this is great. However, expecting an external user to write sometimes complex queries to get to our data using all of our business rules (e.g. IsDeleted = false && SiteID = 21) is a little much to be expected I feel.

Conclusion

So great when providing RESTful web services to a handful of specific clients who have knowledge of your data and business logic. Not so great for making a friendly API for the masses based on a complex EDM as you cannot expect them to understand your business rules as well as you do.

I am not claiming authority on this topic. I am just discussing my findings so far in the hope that you may find this useful. If you have anything you think I have missed please feel free to comment.

Follow britishdev on Twitter

Thursday 2 December 2010

What motivates developers?

It concerns itself with the surprising truth of motivating people who's job requires cognitive skill (I'm taking that to include developers). It is very different from what you might you expect and explains why Linux and other open source exists.



Interesting indeed. What do you think?

Follow britishdev on Twitter

Monday 22 November 2010

Adding service reference gives the system cannot find the path specified error

I got an "The system cannot find the path specified." error box pop up when I tried to add a WCF web service reference to my web project. Problem with Service References?

Every time I tried to add the service reference to another WCF service I had set up in another web project I kept getting "The system cannot find the path specified." pop up in an alert box in Visual Studio 2010.

Solution

Somewhere along the line I had deleted the "Service References" folder from the project folder I was trying to add the reference to. It is simply solved by creating an new folder (in Windows Explorer) in the correct location called "Service References". Problem solved

Follow britishdev on Twitter

Thursday 18 November 2010

How to host multiple secure sites in IIS

I have two sites: www.site1.com and www.site2.com. Both have pages that are served securely and so need a binding for https on port 443.

The problem is that only one site can be bound to the https protocol and if I disobey that rule I get strange behaviour such as requests for site1 actually serving the page from site1.

How to host multiple secure sites on your local IIS

First, you should know that sites resolve which site to bind to based on:
  • Host header e.g. local.www.site1.com
  • Port e.g. 443
  • IP adress

In this scenario I really just want to change the host headers of the two https bindings for the different sites but IIS won't let me. But I have ways of persuading it...

Step 1:
Navigate your way to C:\Windows\System32\inetsrv\config where you may or may not see applicationHost.config. This is a very mysterious file, it's there but not, sort of. I've found that it can be edited in NotePad (but nothing else(?))

Step 2:
Ctrl+F your way to "443:" and you should find your attempted 443 http bindings. In my case there are two and they both look like <binding protocol="https" bindingInformation="*:443:" /> (Oh yeah they are exactly the same, lets change that.

Step 3:
Change them to <binding protocol="https" bindingInformation="*:443:local.www.site1.com" /> and <binding protocol="https" bindingInformation="*:443:local.www.site2.com" /> respectively.

Job done

If you check in your IIS UI you will notice that you host headers have indeed been set and your sites should now be able to discriminate between the two.

Follow britishdev on Twitter

Static Membership helper class causing problems with MembershipProvider

I was having a problem where after a user changes their password using my custom MembershipProvider it was being updated in the database but didn't seem to be propagating to my application. So if they tried to log in they would be expected to provide their old password even though there was a new password in the database.

It is almost as if Membership didn't particularly care what has changed in the database and it kept on just doing its own thing.

Almost as if Membership is a static class... oh right it is

I thought the Membership was acting as if it was a singleton or something and never going through its constructor which sets a new UserService() to the UserService property (the service which ultimately gets the users' data). Maybe it is something to do with the fact that MEMBERSHIP IS A STATIC CLASS! Of course.

Membership was using my MembershipProvider but only ever instantiating it once due to its static nature so the UserService was keeping the old version even if the data had been edited. My fix was to make sure that the MembershipService property returned a new MembershipService() each time it is called.

So for context I changed this code in MyMembershipProvider:
public MyMembershipProvider()
{
    UserService = new UserService();
}

public UserService UserService { get; set; }

To this:
public MyMembershipProvider() {}

public UserService UserService
{
    get { return new UserService(); }
}

Follow britishdev on Twitter

Wednesday 3 November 2010

Allow self closing tags in TinyMCE

I needed to make a tag self-close when using TinyMCE. It wouldn't allow it though, it kept opening them up again for me even after I edited them in HTML. How difficult can it be to add a tag to this allow self-closing tags list.

Answer: Not very. Even still though it took me a ridiculous amount of time to find out how to allow a new self closing tag. So I thought I'd share my discovery in case anyone else is struggling to find the answer.

I was trying to type in <source src="myVideo.m4v" /> but TinyMCE kept changing it to <source src="myVideo.m4v" ></source>.

Closed setting allows new self-closing tags

Turns out there is a little know closed setting you can set on tinyMCEs init method. I added my source tag to the list like so:
closed: /^(br|hr|input|meta|img|link|param|area|source)$/

Now any source tags are automatically self closing.

Notice I added a load more like img. The others are there by default in the core TinyMCE code so if I were to just put in source, the others (like img) would stop being self-closing. Not cool.

Follow britishdev on Twitter

Wednesday 27 October 2010

Set an identity seed back after delete in SQL

When deleting from a table in SQL the seed of the identity column or primary key will not be forgotten. It would be nice to truncate the selected rows(?). This is a little annoying but there is a way around it.

If you want to quickly remove all rows from a table and begin the table from scratch TRUNCATE is the best approach. It is quicker too since it logs nothing (so beware).

TRUNCATE is only for destroying all data in a table though. What if you want to remove only the last few rows and then begin the seeding off from the last primary key?

Use CHECKIDENT to reseed

You can delete the rows you want and after you can reset the SEED of the table to what you desire using the following line:
DBCC CHECKIDENT('myTable', RESEED, 10)

Note: the 10 is a seed so you would set this to be the current maximum identity. So if you reseed with 10 the next insert will yield 11 as the primary key.

Follow britishdev on Twitter

Thursday 14 October 2010

How to set up the Repository pattern using Unity

Recently moved from Spring.NET to Unity 2.0 over here in the London based lovemoney.com. We were already using the Repository pattern and Unit of Work pattern with Entity Framework. Now all there is to do is scrap Spring.NET and bring in Unity. Easy right?

I actually found it very difficult to plagiarise this work off some documentation so I thought I'd help the cause by spilling how I managed it. I'm not going to talk about how to set up the Repository pattern, Unit of Work pattern, or Unity in general. Just how to make a delicious combination of all three.

In my inventory of classes to wire up I have:
  • ContentEntities - this is my ObjectContext
  • UnitOfWork - this is my implementation of IUnitOfWork (Google that for guidance)
  • EntityRepostory<T> - this is my implementation of IRepository<T> where T:class (again for guidance on this pattern Google it)
  • ContentService - This has a dependency property for the ContentRepository of type IRepository<Content>

To wire these all up for the RepositoryPattern to be correctly implemented so that the UnitOfWork is reused correctly I used the following code in my Application_Start() method:
//new container
var container = new UnityContainer();

//set up the unit of works to use the singleton pattern (AKA ContainerControlledLifetimeManager)
container.RegisterType<IUnitOfWork, UnitOfWork>("contentUow", new ContainerControlledLifetimeManager(), new InjectionConstructor(new SocialEntities()));
//get the instance (i have named it to disambiguate in the event of having multiple UOWs (quite likely))
var contentUow = container.Resolve<IUnitOfWork>("contentUow");

//now we have the reference start up a new container
container = new UnityContainer()
//content repository (any other repositories within the model can use this same contentUow instance)
.RegisterType<IRepository<Content>, EntityRepository<Content>>(new InjectionConstructor(contentUow))
.RegisterInstance(typeof(ContentService));

Note I used the ContainerControlledLifetimeManager for the UnitOfWork. There are more for you to choose from, I decided from the description that this is the best for me. Check here for a full list of LifetimeManagers.

This is interesting reading if you are interested in what happens when you ignore the UnitOfWork part of the Repository pattern. Bad things!

Follow britishdev on Twitter

Don't fuck with the repository or unit of work pattern

I am one for not taking patterns as gospel so I have a tendency to use the bits I want and discard the bits I don't. Today I discovered I don't necessarily know best.

At lovemoney.com I have just started using Unity 2.0 to replace Spring.NET as our dependency container. This has meant that I have had to reimplement some of the wiring of the dependencies. This includes our implementation of the Repository pattern for use with Entity Framework.

Now, my problem with the Repository pattern is that I have always struggled to see the point in the UnitOfWork part of the pattern. Just extra typing for me with no/little benefit. I decided that (as with most things I don't understand) they should prove their worth. Reading didn't help their cause so I went for the more drastic way of not using and see what goes wrong. Well, nothing did! So there it is I will never use the Unit of Work pattern again.

Until today that is.

Here is a snippet from my EntityRepository:
public ObjectContext Context { get; private set; }
//in an orthodox implementation this would accept a UnitOfWork instead of an ObjectContext
public EntityRepository(ObjectContext context)
{
    Context = new UnitOfWork(context).Context;
}

And here is the wiring in my Unity configuration:
var container = new UnityContainer();

//content repositories
container.RegisterType<IRepository<LoveContent>, EntityRepository<LoveContent>>(new InjectionConstructor(new ContentEntities()))

Something just wasn't right. I first noticed it when I created a new item and added it to the repository and then tried to delete it. Well deleting the item wasn't the problem, it was the repository knowing what had happened. I deleted the item and it was gone, gone from the database, gone from the data returned from the database but not gone from the Repository when it came to display the results on the page.

So, I figured this was something to do with my bastardisation of the Repository and Unit of Work pattern. I configured Unity correctly to implement this pattern and lo it worked as expected.

So I won!

Well, sort of. I know I thought best, it turned out I didn't, then I came crawling back to convention. But I think I am better off for it. If I had just done what all of the blogs had told me I wouldn't have understood why I was doing it.

Being a curious chap I like to understand everything I use and this has helped me. Hopefully it will help you too if you are scratching your head at the Unit of Work pattern.

But seriously, how do you solve it?

If you are/were struggling with this I have written another blog post that will tell you how to set up the repository pattern with Unit of Work using Unity 2.0.

Follow britishdev on Twitter

Wednesday 6 October 2010

ASP.NET Authentication cookie not persisting across servers and subdomains

Recently some internal users have started complaining about being sporadically logged out and having to log in again when accessing a different server or different sub domain. It seems like the ASP.NET security cookie is not being persisted between live production servers and development servers.

I noticed a pattern to the seemingly spurious logging out and having to log in again:

  • Log in on live or if you are already logged in. Fine.
  • Log in on your development machine. (Oh that's weird, I thought I was logged in... but okay maybe I wasn't). Fine.
  • Refresh your page on the live site and I need to login again.

Why won't my cookie persist?! Why am I being logged out?

This has started happening since the recent ASP.NET security fix was put on our servers. Apparently it is something to do with changing the necessary authentication cookie. I guess in case you were already exploited before the security fix went out. Anyway, if you are swapping between non-patched development servers and patched production servers you're cookie will NOT persist and you will be asked to log in again if authentication or authorization is demanded by your page.

So either:
  1. Install the patch on all servers as per the ASP.NET team's advice
  2. OR be content with the fact that your customers won't have the problem. (Unless you have both patched and non-patched servers in your web farm)

Follow britishdev on Twitter

Friday 1 October 2010

ASP.NET MVC IsAjaxRequest() not recognising request from jQuery $.ajax()

If you are finding that an AJAX request from, say, a piece of jQuery AJAX code such as $.ajax() $.get() or $.post() or you own custom AJAX code (you legend) is not registering as an AJAX request when using the IsAjaxRequest() then the problem is probably to do with X-Requested-With.

I used .NET Reflector to have a look at how IsAjaxRequest() works and it is something like this:
return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest")));

So that means you need to have a header of "X-Requested-With" set to "XMLHttpRequest" which is usually the case when you are using AJAX libraries like ASP.NET's or jQuery's. You can see if this is the case using Fiddler.

However, interestingly you can also set this as either part of your form POST or even a GET querystring! Such as www.example.com?x-requested-with=XMLHttpRequest (case sensitive). This will also make IsAjaxRequest() return true.

Follow britishdev on Twitter

Thursday 23 September 2010

Get all month names from DateTime in C# programatically

I needed to have a drop down list of all the months but I don't want to be writing all of that out. So is there a way to list all the months programmatically in C#. Hell yeah there is

I knew there would be a way to do it and I knew it would be something to do with the CultureInfo of the session.

Here is a method I wrote to return a set of key values for each month:
public IEnumerable<KeyValuePair<int, string>> GetAllMonths()
{
 for (int i = 1; i <= 12; i++)
 {
  yield return new KeyValuePair<int, string>(i, DateTimeFormatInfo.CurrentInfo.GetMonthName(i));
 }
}

Just to demonstrate, I used it in my ASP.NET MVC app:
<%: Html.DropDownListFor(model => model.DobMonth, new SelectList(Model.GetAllMonths(), "Key", "Value", Model.DobMonth)) %>

Which outputs the following HTML:
<select id="DobMonth" name="DobMonth">
<option selected="selected" value="1">January</option> 
<option value="2">February</option> 
<option value="3">March</option> 
<option value="4">April</option> 
<option value="5">May</option> 
<option value="6">June</option> 
<option value="7">July</option> 
<option value="8">August</option> 
<option value="9">September</option> 
<option value="10">October</option> 
<option value="11">November</option> 
<option value="12">December</option> 
</select>

Follow britishdev on Twitter

Bet you didn't know about: C# Numerical suffixes

I love learning new things and you probably do too. So how about this one... I found a way to make a long, double, unsigned int etc without having to use casting or having to explicitly declare the type.

Instead of using explicit declarations and casting like this:

long l = 12;
var d = (double)12;
float f = 12.0; //compilation error
var u = (UInt32)12;
decimal m = 12;
ulong ul = 12;

You can use the numerical suffixes like this:

var l = 12L;
var d = 12D;
var f = 12.0F;
var u = 12U;
var m = 12M;
var ul = 12UL;

So there we are. Interesting? Or maybe everyone already knew that and I've only just found it.

Follow britishdev on Twitter

Wednesday 15 September 2010

Using Application State as early as possible in ASP.NET MVC

I'm working on a new website that will run off the same architecture as lovemoney.com. To distinguish one site from the other I am using a variable stored in ApplicationState. However I was running into problems when trying to access this variable.

The problem was that I was setting the Application variable in Application_Start() of Global.asax. I was accessing this variable in the contructor of my base Controller (that all my Controllers inherit from).

This was too early. Not too early for the Application_Start() event, obviously. Just too early to be able to access it I assume.

So how early can I access ApplicationState?

I found I could access it without problem on the Initialize method of my BaseController:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);
    //only here is the application state finally ready to be set
    SiteID = (int)requestContext.HttpContext.Application["SiteID"];
}

Problem is I really want to be able to access it during construction of my BaseController though since I will be implementing DI shortly. So in the end I used AppSettings in the config instead which can be accessed in the constructor. Still, this will still be useful I'm sure.

Follow britishdev on Twitter

Monday 6 September 2010

How to force clients to hard refresh their browser cache

We had this problem when we removed our style sheets and put them into a HttpHandler to serve them all in one single request. The problem was that due to some caching problem, users' needed to refresh their page to receive the updated CSS files. This resulted in confused users looking at a non-styled site featuring trendy black Times New Roman font on a original white background with blue and purple retro links? old skool...

We (as developers) nonchalantly refreshed the page and happily continued, others didn't and we quickly realised that "Oh, they just need to refresh the page" wasn't good enough.

Solution

We needed a way to make the users refresh their browser caches, but how since we have no control over their browsers?

I came up with a bit of JavaScript that will do a hard refresh of the page and use cookies to record that it has been refresh and ensure that it only happens once and doesn't go into an infinite loop.

Here is some code I came up with:
//jquery plugin for cookies
<script type="text/javascript" src="/js/jquery/jquery.cookies.2.0.1.min.js"></script>
<script type="text/javascript">
//give it a new name each time you need to do this
var cookieName = 'refreshv1';
//check client can use cookies
if ($.cookies.test()) {
    //get the cookie
    var c = $.cookies.get(cookieName);
    //if it doesn't exist this is their first time and they need the refresh
    if (c == null) {
        //set cookie so this happens only once
        $.cookies.set(cookieName, true, { expires: 7 });
        //do a "hard refresh" of the page, clearing the cache
        location.reload(true);
    }
}
</script>
Feel free to work with this code but please do not use it without testing or ensuring it is right for your situation. It is merely an idea that worked for me.

Follow britishdev on Twitter

Thursday 19 August 2010

Generate lowercase URLs with T4MVC templating tool

I noticed that my URL paths that are being generated using using T4MVC's excellent MVC templating were coming out in title case. This is a problem since we try to keep all URLs lower case since Google deems URL in different cases showing the same result as duplicate content.

I looked through a lot of the code that is generated by the tool and traced the problem all the way to the MyController.generated.cs file:
public class ActionNamesClass {
    public readonly string Index = "Index";
    public readonly string Edit = "Edit";
    public readonly string Create = "Create";
}

Great now I have to edit the way the code is generated... or do I?

Solution

Turns out David Ebbo has thought of everything! There is a setting in the T4MVC.settings.t4 file specifically for that, which I just need to set to true:
// If true, use lower case tokens in routes for the area, controller and action names
const bool UseLowercaseRoutes = true;

Now when I look at the generated code in my MyController.generated.cs file I can see:
public class ActionNamesClass {
    public readonly string Index = ("Index").ToLowerInvariant();
    public readonly string Edit = ("Edit").ToLowerInvariant();
    public readonly string Create = ("Create").ToLowerInvariant();
}

Lovely.

Follow britishdev on Twitter

Thursday 12 August 2010

Remove HTTP response headers to hide your framework

There are a number of infrastructure details that are passed with your HTTP response headers when serving a page. The security conscious developers out there will be aware that hackers and other malicious people will enjoy learning that information to target their exploits for that framework. If you want to remove the HTTP response headers of Server, X-Powered-By, X-AspNet-Version, X-AspNetMvc-Version or any others I will show you how.

I will show you the less hacky ones first. I.e. the ones where it is designed for you to remove them easily:

X-AspNet-Version

This can be removed simply using the enableVersionHeader attribute of the httpRuntime section of system.web section of your web.config:
<system.web>
  <httpRuntime enableVersionHeader="false" />
  <!-- other settings -->
</system.web>

X-AspNetMvc-Version

In your Global.asax.cs you can add the following to your Application_Start method:
protected void Application_Start(object sender, EventArgs e)
{
    MvcHandler.DisableMvcResponseHeader = true;
    // RegisterRoutes etc... and other stuff
}

X-Powered-By

Instead of removing this I have decided to change it to something different so as not to cause suspicion to a potential hacker:
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <remove name="X-Powered-By"/>
      <add name="X-Powered-By" value="PHP 5.2 Ubuntu"/>
    </customHeaders>
  </httpProtocol>
  <!-- other stuff -->
</system.webServer>

Server

This one is harder since you can't actually do it anywhere else. Of course you could have changed all the other Headers here too but it feels messy doing it this way so I opted to change the others using the intended way.

First, make an HttpModule (essentially a class inheriting from IHttpModule) like this:
namespace HttpModules
{
    public class SecurityModule : IHttpModule
    {
        public void Dispose()
        {
            //intentionally do nothing
        }

        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders);
        }

        private void context_PreSendRequestHeaders(object sender, EventArgs e)
        {
            var context = ((HttpApplication)sender).Context;
            context.Response.Headers.Set("Server", "Apache 2.0");
        }
    }
}
Note: I have gone for lying about the server over removing it (which is also possible) since I'd rather fool hackers than annoy them.

Next you just need to register that module in your web.config:
<system.webServer>
  <modules>
    <add name="SecurityModule" type="HttpModules.SecurityModule, HttpModules" />
  </modules>
</system.webServer>

Now use Fiddler to have a look at your Response Headers. Hopefully wonderfully deceptive like this:

If you have more to remove/change you can do it in much the same way as X-Powered-By (using web.config) or if not the Server one (using the Security HttpModule).

Follow britishdev on Twitter

Wednesday 4 August 2010

IntelliSense for jQuery in Visual Studio 2010

I read this morning in Steve Sanderson's Pro ASP.NET MVC 2 Framework book that it is possible to get IntelliSense when using the popular JavaScript library, jQuery.

Microsoft have decided to implicitly support jQuery by including some of its libraries in their sample MVC project. This is as well as their own AJAX library that comes with a lot of support for ASP.NET Web Forms specific features, which of course you won't be needing in ASP.NET MVC.

Part of their support translates into working with them to provide IntelliSense support to Visual Studio. It is not entirely integrated so will need a touch of set up and here's how to do it:

Let's do it!

First, you need to get the jquery-1.4.1-vsdoc.js file. I got mine by creating a new ASP.NET MVC2 sample web application. You will find it at /Scripts/jquery-1.4.1-vsdoc.js. Copy it from here and put it in your application somewhere sensible.

Then you simply reference the file like so:
<% /* %><script type="text/javascript" src="/js/jQuery/jquery-1.4.1-vsdoc.js"></script><% */ %>

Now you can enjoy such delights as this:

Note

  • You may want to put that reference in your MasterPage so it will work for all pages that use it. It will not work in miscellaneous pages or user controls (unless you add your own reference in those pages).
  • Also note the syntax I used so that users will not download the file as part of their request.
  • This works for VS2010. For VS2008 you may need to download a path that allows Visual Studio to find *-vsdoc.js files automatically

Follow britishdev on Twitter

Friday 30 July 2010

Developers' guide to search engine optimisation

Search engine optimisation (SEO) is quite a dark art because it is kept somewhat secret by the guys who write the search algorithms. In fact you can make a career out of SEO but that's not you is it. You're a developer and you just want to know roughly the SEO concerns that you should consider when developing a site. No? Oh... well you should. Here is your guide

Status codes and SEO

If you are a developer worthy of gracing the work place you will be well accustomed with 500's and 404's but I notice a lot of interviewees can't tell me what a 301 is. Understanding how different status codes affect SEO is an important start.
301 Permanent redirect
The URL you requested is wrong and should never be used again. Here is the new one. A user won’t see it but a search engine will make a note and be sure to move all its current indexing and value for the old page to the new one.
302 Temporary redirect
The URL has moved somewhere else for now. Search engines will not re-index their page to this new one so will continue to send people to the old page. Your site then 302's them to the new place. This is used for when it is not usual behaviour (e.g. submit new post and you get redirected to that post). Also if you want www.mysite.com?lang=enGB to appear like www.mysite.com on Google this is the one for you.
404 Not Found
Not cool because Google will thing you are an unreliable joke of a site.
500 Internal server error
Not cool because Google will thing you are an unreliable joke of a site. A sneaky Pete will issue a 503 instead.
503 Service unavailable
Means your server is down for some reason. May be maintenance. May be a crash. Whatever it is Google feels sorry for you and will return later to see if it's back. So make an HttpModule that chews up 500's and returns a HttpStatusCode of 503.

Duplicate content

Google despises you for this. If you had a page here: http://www.mysite.com/socks that just contains a list of your favourite socks for example, that's fine. If you also had the exact same list located at http://www.mysite.com/list-of-socks search engines would penalise you for duplicate content. Fair enough really because you are deliberately trying to have more pages about socks on your site by copy and pasting the same page.

But there are more subtle variations that if Google finds will tick you off for duplicating content. The following are variations on http://www.mysite.com/socks that do in fact count as duplicate content (unless the content is entirely different of course):
Actionless querystring
E.g. http://www.mysite.com/socks?source=email . Say you were logging the source for analytics and the source had no affect on the content. This URL would be marked as duplicate content to http://www.mysite.com/socks
Mixed casing
E.g. http://www.MySitE.com/sOcks. I know IIS is case insensitive but there are web servers that are not so Google counts the different casing as a different page and therefore duplicate content.
Secure pages
E.g. https://www.mysite.com/socks. The different protocol makes search engines count this URL as a different one from the original.
What to do?
To resolve all of these things you should look into using canonical URLs. Essentially if you put <link href="http://www.mysite.com/socks" rel="canonical" /> in the <head> section search engines will take that as the URL for the page and attribute any value for pages that include that canonical link to that particular URL.

SEO Friendly URLs

I did believe that friendly URLs are not only user friendly but also good for SEO too. Dan Atkinson pointed out that Google do not add weight to a site based on URL. However, another post from Google suggests that site hierarchies are infact used. (If Google aren't looking at URLs for SEO I wonder why they rewrite all their blog posts...)

Regardless of your leaning I would still recommend that clean URLs are considered even if it is only for the benefit of the user. A URL like http://www.mysite.com/articles/price-of-socks-plumets will have more chance of being linked to or being the URL of choice to click from some search engine results than http://www.mysite.com/articles.aspx?a=9031. Of course you will have to do a database look up based on that string rather than the ID so maybe you may prefer to use http://www.mysite.com/articles/9031/price-of-socks-plumets instead.

To make cleaner URLs you should look into URL Rewriting or ASP.NET 4's Routing engine.

SEO Friendly content

Basic stuff really, make sure you have filled the <title> with the title of the page. All your headings are within <h1>'s, <h2>'s and <h3>'s etc. Make sure you have a <meta content="Everything about socks" name="description"/> and a <meta content="socks, clothing, accessories" name="keywords"/> can't hurt either.

In ASP.NET 4 you can set easily using Page.MetaDescription and Page.MetaKeywords

Follow britishdev on Twitter

Tuesday 27 July 2010

The specified value is not an instance of type 'Edm.Int64' Parameter name: value. When inserting an object with Entity Framework

When trying to insert an object into my entity data model (i.e. myObjectContext.SaveChanges()) using Entity Framework 4, I got the most confusing error that said "The specified value is not an instance of type 'Edm.Int64' Parameter name: value".

What made it more confusing was that another repository that uses the same entity data model inserted fine. What made it even more confusing was that if I went back to the page that displays the inserted items they were in fact there no matter how many times I refreshed. What made it even more confusing was that they weren't actually in the database!

Mysterious solution

Beware: you won't leave this blog feeling enlightened. What I did worked but made no sense but fixed it:

Given that there is clearly some sort of caching happening I decided to refresh the Application pool for my application. This cleared out all those phantom items that existed on the page but not in the database. Cool...

Then I tried to insert a new item again for a laugh. It worked! It seemed as though recycling the app pools (AKA giving the server a kick up the arse) suddenly made it start working again.

Step 2: Back away slowly from the code and hope it doesn't happen again.

Update: Concrete solution

The problem was I am using Spring.NET for dependency injection and by default it is set to make the references singletons. So I had to change
<object name="MyRepository" type="MyAssembly.MyNamespace.MyRepository, MyAssembly"/>
to
<object name="MyRepository" type="MyAssembly.MyNamespace.MyRepository, MyAssembly" singleton="false"/>
and it all now works as expected.

Follow britishdev on Twitter

Wednesday 21 July 2010

Test your LINQ quickly and easily without recompiling

Tired of writing some LINQ then building, then attaching the debugger, then refreshing the page, then waiting for it to compile then see the results, but they're wrong so you detach the debugger then make changes then build then...

Here's a cool little tool that lets you run LINQ queries against you DB or Entity Framework or... well, quite a lot of things actually. The great thing is that you can skip the cycle of editing building etc. It's pretty much direct.

You can even swap between the result set, Lambda expression, SQL and Intermediary language (for some reason):

Download it here: http://www.linqpad.net/

Follow britishdev on Twitter

Monday 19 July 2010

System.Data.Entity not referenced when using Entity Framework

I started getting a compilation error telling with a message telling me "CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'". This really confused me since the solution built fine but the error only occurred at run time.

Obviously, it is all about adding a reference to System.Data.Entity to my Web project right? I checked and it is already there. Removed it re-added it. Checked for the correct version but still it doesn't like it! Why?

This came about when I used an existing Models project from a different solution in a brand new MVC 2 web application. So I checked the differences between the working solution and the new solution. Both had the same reference in the Web project so what's wrong?

Solution

Finally, I found that I had to add the System.Data.Entity assembly in the web.config too! See line 6 below:
<compilation debug="true" targetFramework="4.0">
  <assemblies>
    <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </assemblies>
</compilation>

This miraculously made my page start working as expected again.

Follow britishdev on Twitter

Friday 2 July 2010

SQL Server 2008 Prevent saving changes that require the table to be re-created

I got this notification when I changed a table's column to NOT NULL and tried to save: "Saving changes not permitted. The changes you have made require the following tables to be dropped and re-created. You have either made changes to a table that can't be re-created or enabled the option Prevent saving changes that require the table to be re-created."

This is because the script generated would contain a DROP TABLE statement. Of course it would have saved everything in a temp table before being dropped and re-created the table so nothing would have actually been lost.

Even still, it is probably a nice little safe guard for those who maybe aren't that used to SQL Server but I am so: how to get round it?

Solution

If you are confident that you are a legend with your SQL skills and you just want to be left alone you can disable this warning.

Go Tools » Options...

Go Designers » Table and Database Designers and then uncheck "Prevent saving changes that require table re-creation"

Job done - enjoy at your peril!

Follow britishdev on Twitter

Thursday 24 June 2010

Entity Framework MetadataException: Unable to load the specified metadata resource

I got a "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation" error with a description of "System.Data.MetadataException: Unable to load the specified metadata resource. at System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources".

This occurred when I was trying to move my Models out of my main MVC web application assembly. The main web dll is called Web and within that project is a folder called Models that is used to store all my *ahem* Models and entity data models etc. I decided to move everything in the Models folder out into its own Models assembly. I edited all the namespaces and everything built okay.

However, I was getting a runtime MetadataException when trying to view the page. What the hell is going on?!

Solution

The problem is that the connection string was incorrect. It wasn't immediately obviously with that error message but when you think about it, it makes sense.

My connection string was: connectionString="metadata=res://*/Models.Messaging.MessagingObjects.csdl|res://*/Models.Messaging.MessagingObjects.ssdl|res://*/Models.Messaging.MessagingObjects.msl;....etc"

Just so you know the metadata represents this metadata=res://{assembly}/{namespace}.{filename}.csdl|res://{assembly}/{namespace}.{filename}.ssdl|res://{assembly}/{namespace}.{filename}.msl;

Since I have moved the models around and the namespace is now different I needed to make it connectionString="metadata=res://*/Messaging.MessagingObjects.csdl|res://*/Messaging.MessagingObjects.ssdl|res://*/Messaging.MessagingObjects.msl;

Just for further understanding I could have replaced the asterix with Models since that is the name of the dll that contains my Messaging models.

Follow britishdev on Twitter

Monday 21 June 2010

MVC pass ViewMasterPage a Model

I have some data that I would like to display on every page on an MVC site. So my PartialView needs to go in the ViewMasterPage with data passed to it, but how is it possible to pass and then access a ViewModel or Model in a ViewMasterPage.

I found quite a cunning way of doing this by using the ViewMasterPage<T> class instead of ViewMasterPage to model and use the data I need.

Solution

I made a new class called BaseViewModel. This will be the class that all ViewModels should now inherit from. The class looks like this:
namespace Web.ViewModels
{
    public class BaseViewModel
    {
        public string MyProperty { get; set; }
    }
}

I now need to make my ViewMasterPage inherit from the generic version of ViewMasterPage%lt;%gt; taking in my new BaseViewModel by making the top line look like this:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<Web.ViewModels.BaseViewModel>" %>

Now I simply make the ViewModel I was using originally for my View inherit from BaseViewModel and I am ready to start passing data to the ViewMasterPage via MyProperty. The View that used the now modified ViewModel is unaffected and the ViewMasterPage now has access to the new data like so:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<Web.ViewModels.BaseViewModel>" %>
<%: Model.MyProperty %>

Further

This is all great (and very clever and amazing!) but what about when I am not passing a ViewModel to my View I am just sending a Model? I don't want to have to make a new ViewModel containing this model just for the sake of making it inherit from BaseViewModel.

Well, I made a new class that inherits from BaseViewModel that has a Generic constructor that allows me to pass in my Model. This class looks like this:
namespace Web.ViewModels
{
    public class BaseViewModel : BaseViewModel
    {
        public BaseViewModel() { }
        public BaseViewModel(T innerModel)
        {
            InnerModel = innerModel;
        }

        public T InnerModel { get; set; }
    }
}

I will need to change the type that is passed to the View in the Controller from this:
return View(message);
to this:
return View(new BaseViewModel<Message>(message));

I will then have to change the corresponding View so that it inherits from the new ViewModel and references the InnerModel property instead of just Model:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/RootMvc.Master" Inherits="System.Web.Mvc.ViewPage<Web.ViewModels.BaseViewModel<Web.Models.Social.Message>>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="RootContent" runat="server">
    <%: Model.InnerModel.Title %>
</asp:Content>

Now your ViewMasterPage is still getting a ViewModel of type BaseViewModel and your main View still has strongly-typed IntelliSense access to your original Model.

Follow britishdev on Twitter

Thursday 17 June 2010

Update minor change to database in your Entity Data Model

I added a new column to a table in the database and couldn't seem to get these changes reflected in my Entity Data Model using Entity Framework 4. There is a function I can use in the context menu called "Update Model from Database..." but that seems overkill. I just want one new column mapped in my entity data model.

I didn't want to use the 'Update Model from Database' since it will update every table and view in my model, reverting all the entity and property names to the database naming convention and breaking all my referencing code. Too much pain for what should be quite a simple change? Yes, I think so.

Solution

As an example let's say you have added a varchar(50) column called MyDbColumn to MyDbTable that currently has an entity modelled called MyEntity that hasn't recognised this column which you want to be called MyProperty.

Let's also say you have added MyProperty of type String with MaxLength set to 50 to your MyEntity entity. If not, do that. Now the tough bit: Mapping it to the database without a full update.

Time to leave the comfort of the UI.
  1. Right click your edmx file in the Solution Explorer
  2. Select 'Open With...'
  3. Select 'XML (Text) Editor' and click OK (you may be asked to close any open instances of the edmx file)
  4. Search for where is says <EntityType Name="MyDbTable">
  5. Add the property <Property Name="MyDbColumn" Type="varchar" MaxLength="50" />
  6. Search for <EntitySetMapping Name="MyEntity">
  7. You can find all your other mapped properties within a 'MappingFragment' element.
  8. Add your new mapped column <ScalarProperty Name="MyPropertyName" ColumnName="MyDbColumnName"/>
  9. Save & Build

If you now re-open your edmx file in the designer and take a look at the Mapping Details for MyEntity you will see that MyProperty is mapped to MyDbColumn in MyDbTable. Lovely stuff!

Follow britishdev on Twitter

Tuesday 15 June 2010

Cross database joins in Entity Framework4

Quite new to Entity Framework 4 I really struggled with the concept of not being able to make an Entity Data Model containing entities of tables that live across different multiple databases. I am still really quite disappointed that EF4 cannot support this and the team behind it doesn't even seem to think that cross database entities are an issue worth considering despite how long this forum has been asking for them.

Anyway, there is a cheeky little way that it can be done. I will use the example of a forum to illustrate this. I need to display posts alongside the username and email address of the contributor of that post. The problem is that the user information lives in a separate database from the post information.

Time to unleash my MS Paint skills to illustrate:

Solution

I got around this by creating a View inside the ForumDB like so:
USE ForumDB
CREATE VIEW dbo.vUserDetails
AS 
 SELECT
  u.UserID,
  u.UserName,
  c.Email
 FROM
  UserDB.dbo.UserNames u
 INNER JOIN
  UserDB.dbo.ContactInfo c ON c.UserID = u.UserID
GO


With this new View in the database I can now create an entity of it in the EDM. Go to your edmx file, right click the background and select 'Update Model from Database...'

Select the data connection to the ForumDB. Then when you are on the Choose Your Database Objects step, make sure you are on the Add tab and select Views and check the vUserDetails view:


You now have access to all your user data. You add an association to link the UserID from the Posts table (Post entity) to the UserID in your new view.


Further

You now have SELECT access to this user data but you cannot currently INSERT/UPDATE/DELETE users. In this scenario this is okay, however if you have a different objective you can still achieve this using stored procedure in the Entities to run on INSERT functions etc.

Follow britishdev on Twitter

Monday 14 June 2010

Entity Framework OptimisticConcurrencyException

I got an OptimisticConcurrencyException error with description of "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries." when trying to insert into a table using the Entity Framework 4.

I found that the table I was working on had an INSTEAD OF INSERT on it. This was doing a few things and then returning (0 row(s) affected). Entity Framework wasn't happy with this since it looked as though nothing was being inserted and so threw the confusing OptimisticConcurrencyException error.

Workaround

I've been trying to get this to work for a fancy workaround so a drop will be the order of the day:

DROP TRIGGER [dbo].[trg_PITA]

Job done. The main problem was finding this trigger in the first place since it is not something you normally look at and almost impossible to debug.

Better workaround

Almost 3 years later! Rachel Peirson has come up with a workaround to this problem that also allows you to keep your trigger in place. Please see her comments below for details.

Follow britishdev on Twitter

Make Form Postbacks work with MVC pages inside a WebForm MasterPage

I recently wrote about how I nested an MVC site with in a WebForms MasterPage and it how it all worked perfectly ;) However, I avoided the quite inevitable problem of POSTing not working as expected in your WebForm master page, mainly because I hadn't worked out how. Well I have now found a way and have explained it here:

Problem 1.

You may notice that any inputs above your MVC placeholder will work and any form inputs below your MVC placeholder will not POST.

The problem is that traditional ASP.NET web forms applications work off the principle of having only one form. MVC does not. However, if you look at the rendered HTML you may notice you have more than one form. ASP.NET will cope with the first form up until the first closing form tag (</form>).

Solution
Remove all form tags from your MVC pages that are causing the nested forms. This way there will only be one form per page and should therefore POST correctly. Your MVC pages will continue to POST as expected.

Problem 2.

So now your WebForms MasterPage and MVC page performs postbacks wherever there is a submit button as expected. The problem now is that you are going to have to handle that post back within your MVC page.

Solution
Make a base Controller class that all Controllers in the solution should inherit for. (I deliberately didn't end the class name with Controller so that MVC doesn't try and use it on its own).

Here is the main part of my ControllerBase:
using System.Web.Mvc;
namespace Web.Controllers
{
    public class ControllerBase : Controller
    {
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //if there is a form being posted
            if (Request.Form != null && Request.Form.Count > 0)
            {
                //iterate though all form keys
                for (var i = 0; i < Request.Form.Count; i++)
                {
                    //get the value of the form key/value in question
                    var value = Request.Form[i];
                    //if this is the key/value form pair i want and it is not blank
                    if (Request.Form.Keys[i].EndsWith("txtSiteSearch") && !string.IsNullOrWhiteSpace(value))
                    {
                        //do something (this redirects to a page with the search value in the query string
                        Response.Redirect("/search/?q=" + value);
                    }
                }
            }
            base.OnActionExecuting(filterContext);
        }
    }
}

This will run on every request just before the selected ActionMethod is encountered.

I am essentially looking for a particular form field to check if the user typed into the MasterPage's site search text box (with ID="txtSiteSearch") before clicking a form submit button. If they have I send them to the search page with the search text in the querystring.

Obviously, this example is specific to my needs but if you need the form to use a service or other methods, these are all possible too.

Follow britishdev on Twitter

Tuesday 8 June 2010

Use WebForms MasterPage in MVC project

Want to avoid having to duplicate your MasterPage design that you made in your ASP.NET WebForms project in you new MVC project? There is a simple way to share your master page across the ASP.NET web forms and MVC projects. Here's how:

Make a new "MVC 2 View Master Page" in your /Views/Shared folder and add the content:
<%@ Master Language="C#" MasterPageFile="~/MasterPages/Root.Master" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewMasterPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="RootTitle" runat="server">
    <asp:ContentPlaceHolder ID="RootTitle" runat="server" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="RootContent" runat="server">
    <asp:ContentPlaceHolder ID="RootContent" runat="server"/>
</asp:Content>

Replace the URL with the destination of your web forms MasterPage and the ContentPlaceHolderIDs with the respective ones you used in your original web forms master page.

You can then go on to use your new MVC master page as you would before but it will inherit all the content from your web forms master page.

Note

Any form post controls on your web forms master page will not work on your MVC pages. I have found a way though which I explained in my post about making form posts work in a webform master page nested MVC page if that sort of thing interests you.

Follow britishdev on Twitter

Friday 4 June 2010

Don't use runAllManagedModulesForAllRequests="true" when getting your MVC routing to work

It seems to be common advice to make your modules section of your web.config say <modules runAllManagedModulesForAllRequests="true">. In fact this is quite a drastic thing to do to solve the routing problem and has global effects that could CAUSE ERRORS.

You need a module that goes by the name of UrlRoutingModule-4.0 to be running through IIS. Now, since your MVC URLs are likely to end without .aspx these will not be picked up by IIS and run through the intergrated pipeline and therefore you will end up with 404 not found errors. I struggled with this when I was getting started until I found the <modules runAllManagedModulesForAllRequests="true"> workaround.

This highly recommended fix can cause other problems. These problems come in the form of making all your registered HTTP modules run on every request, not just managed requests (e.g. .aspx). This means modules will run on ever .jpg .gif .css .html .pdf etc.

This is:
  1. a waste of resources if this wasn't the intended use of your other modules
  2. a potential for errors from new unexpected behaviour.

Better solution

Fine, so the ranting about <modules runAllManagedModulesForAllRequests="true"> is over. What is a better solution?

In the modules section of your web.config, you can add the UrlRoutingModule-4.0 module in with a blank precondition meaning it will run on all requests. You will probably need to remove it first since it is most likely already registered at machine level. So make your web.config look like this:
<modules>
  <remove name="UrlRoutingModule-4.0" />
  <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
  <!-- any other modules you want to run in MVC e.g. FormsAuthentication, Roles etc. -->
</modules>

Note: the modules element does NOT contain the runAllManagedModulesForAllRequests="true" attribute because it is evil!

Follow britishdev on Twitter

Thursday 27 May 2010

MVC2 deploy - Could not load file or assembly 'System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.

A new MVC 2 project worked on my local machine but when it was deployed to the test server it gave the error 'Could not load file or assembly 'System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.' I have the full Visual Studio 2010 installed on my local machine but just the .NET 4 framework installed on the test servers. It seems the MVC assemblies do not come with .NET 4 framework itself so how to make MVC 2 work on the test servers?

Update This was written for difficulties with deploying an MVC 2 app. I have written a new blog post about deploying an ASP.NET MVC 3 web application to keep you up to date with the new technologies.

When I installed Visual Studio 2010 on my local machine it came with all the fruit included (.NET4 framework, MVC2 etc) so the System.Web.Mvc.dll can be found in my machine's GAC (C:\Windows\assembly). However, since there is no need to bloat the web servers only the plain old .NET4 framework has been installed on the test servers. This does NOT include the MVC assembly and that is why it cannot be found by the web application.

You need this assembly to be on your web servers that you are deploying to but you want to avoid having to copy them into the GAC manually and doing all that gacutil mess or maybe you don't have access to your servers if they are hosted by godaddy or something.

Solution

You need to make the System.Web.Mvc assembly bin deployable... okay that doesn't sound easy but here is how to do it for the necessary MVC references:

Simply right click the reference and select 'Properties':

Then change 'Copy Local' to 'True':

Note

If your server has .NET 3.5 sp1 installed the new(ish) assemblies System.Web.Routing and System.Web.Abstractions will already be in the GAC. If you had previously deployed an MVC 1 application to a .NET 3.5 server you may remember having to deploy the other two assemblies too. Since MVC2 requires at least .NET 3.5 sp1 you will not need to worry about these assemblies, just System.Web.Mvc.

Update

There is an easier way to do this if you are using Visual Studio 2010 Service Pack 1 and using Web Deploy as your publish action when publishing. You can add deployable dependencies to your ASP.NET MVC project that will choose the necessary assemblies for you. Even easier!

Follow britishdev on Twitter

Wednesday 26 May 2010

How to add an ASP.NET MVC 2 project to an existing ASP.NET Web forms application

In this 'how to' I will demonstrate how to integrate an ASP.NET MVC 2 project to an ASP.NET WebForms application that already exists. There are many weird ungoogleable issues and extra tips that haven't been covered elsewhere. I hope this guide helps you get started.

Update: I have written an updated blog post for the slightly different details of adding to a web forms project with an ASP.NET MVC 3 project.

1. Add references

Right click on your web root project in Visual Studio (2010 in my case) and add the following references:
  • System.Web.Routing
  • System.Web.Abstractions
  • System.Web.Mvc

2. Configuration

Make your web.config look like this. Obviously not exactly like this, don't just paste this over the top of your glorious web.config. I'm just highlighting the necessary points that need to be fitted into your existing web.config:
<system.web>
  <compilation debug="true" targetFramework="4.0">
    <assemblies>
      <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Abstractions,Version=4.0.0.0, Culture=neutral,PublicKeyToken=31BF3856AD364E35"/>
      <add assembly="System.Web.Routing,Version=4.0.0.0, Culture=neutral,PublicKeyToken=31BF3856AD364E35"/>
    </assemblies>
  </compilation>
  <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
    <namespaces>
      <add namespace="System.Web.Mvc"/>
      <add namespace="System.Web.Mvc.Ajax"/>
      <add namespace="System.Web.Mvc.Html"/>
      <add namespace="System.Web.Routing"/>
    </namespaces>
  </pages>
</system.web>
<system.webServer>
  <modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
  </modules>
</system.webServer>
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Update: I have changed my recommendation against using <modules runAllManagedModulesForAllRequests="true"> in favour of adding the UrlRoutingModule-4.0 module with a blank precondition as I explain in my article Don't use runAllManagedModulesForAllRequests="true" for MVC routing.

3. Routing

You will need to add a global.asax file to your web application if you haven't already got one. Right click > Add > Add New Item > Global Application Class:


Now in your global.asax add these usings:
using System.Web.Mvc;
using System.Web.Routing;

Now add these lines:
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    //ignore aspx pages (web forms take care of these)
    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");

    routes.MapRoute(
        // Route name
        "Default",
        // URL with parameters
        "{controller}/{action}/{id}",
        // Parameter defaults
        new { controller = "home", action = "index", id = "" }
        );
}

protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

4. Add some standard folders to the solution

Add a folder named 'Controllers' to your web project.
Add a folder named 'Views' to your web project.
Add a folder named 'Shared' to that Views folder.
Add a web configuration file to the Views folder (web.config).
Open this web.config in the Views folder and ensure make its contents as follows:
<?xml version="1.0"?>

<configuration>
  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

5. Get Visual Studio 2010 to recognise your MVC skills

If you right click the Controllers folder and select Add, you'll notice there is no Controller class to add. You need to make a change to your web project file.

Using Windows Explorer find the web project file (Web.csproj in my case) and open it in a text editor. You will need to add "{F85E285D-A4E0-4152-9332-AB1D724D3325};" to the ProjectTypeGuids element.

E.g. mine now looks like this:
<ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

6. Optional: Add a Controller (for a laugh)

Back to Visual Studio 2010 and right click the Controllers folder > Add > Controller... call it HomeController.

using System.Web.Mvc;

namespace Web.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Message"] = "This is MVC";
            return View();
        }
    }
}

7. Optional: Add a View (just to show off)

Right click where it says return View(); and select Add View... then click Add.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
        <%: ViewData["Message"] %>
    </div>
</body>
</html>

8. Optional: Try it (just to self-indulge your skills)

Now run you site and go to http://{localhost}/home

I hope this saved you the hours it took me! Please comment if you have any feedback. It would be much appreciated

More reading here if you would like to use an existing WebForms MasterPage in your new MVC project.

Follow britishdev on Twitter

Thursday 13 May 2010

Getting started with ASP.NET MVC2

About to start a new project using ASP.NET MVC 2 and Entity Framework 4. Where to get started?

I worked through the Nerd Dinner example before which was great but was MVC 1. I found this brilliant code sample and walkthrough of creating a music store using MVC 2 and Entity Framework 4 with this MVC 2 Sample Application.

I have looked over this briefly and am impressed. So I would like to share it with you. Enjoy.

Follow britishdev on Twitter

Friday 7 May 2010

How to upgrade to ASP.NET4

If you want to know how to upgrade your existing ASP.NET solution to target the ASP.NET 4 framework there are a number of steps you need to take to ensure a smooth upgrade of your website. ASP.NET 4 is a brand new framework, it is not just an extension of ASP.NET 3.5. This means there are a number of steps you need to know to know how to successfully upgrade to the new .NET4 runtime smoothly.

Here is a list of challenges I encountered whilst upgrading the lovemoney.com solution to ASP.NET 4 from ASP.NET 3.5. I hope you find this an important reference or guide if you come to do the same thing:

1. Set your application pool to use .NET 4
2. Changing the browser definitions
3. Running .NET 4 application as a child under a .NET 3.5 root parent site in IIS 7
4. Targeting ASP.NET 3.5 with MSTest
5. Potentially dangerous request validation
6. MembershipUser and other System.Web.Security types have moved namespace
7. Publishing a project with missing files


1. Set your application pool to use .NET 4

You may run into an error saying "Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive." with a description of "An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately."

This is indicating that your solution is targeting the .NET 4 framework but is still using the .NET 2 framework. To fix this you need to:
  1. Go to IIS
  2. Find the Application Pool you are using
  3. Right click it and select Basic Settings
  4. Change the target framework to .NET Framework v4 as illustrated

More info on unrecognized targetFramework attribute in ASP.NET 4


2. Changing the browser definitions

You could receive an error message of "The browser or gateway element with ID 'Safari1Plus' cannot be found." and a description of "An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately."

This is because the browser definitions have been updated for ASP.NET 4 from the 5 year old ASP.NET 2 browser definitions.

If you have not added to your browser definitions in any way your site should work okay but be aware that some browsers may be identified more (or maybe less) accurately. If you added to your browser definitions prior to the .NET4 upgrade (i.e. there are files in your App_Browser folder) you may recieve errors. These errors will be immediately apparent runtime errors.

If you are getting these runtime errors you can fix them in one of two ways:
  • Remove the browser definitions you have in the web root's App_Browsers folder
  • Copy the old browser definition files from the old location of C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers to C:\Windows\Microsoft.NET\Framework\v4.0.[whatever]\Config\Browsers (you will also need to do the same for the Framework64 version if you have one) and then run the Aspnet_regbrowsers.exe command-line tool.

More info on browser or gateway element not being found in browser definitions


3. Running .NET 4 application as a child under a .NET 3.5 root parent site in IIS 7

You get the error of "The requested page cannot be accessed because the related configuration data for the page is invalid." and a config error of "There is a duplicate 'system.web.extensions/scripting/scriptResourceHandler' section defined"

This is because your web.config of your child site or application is inheriting from you parent application or site. This would happen if you have made an ASP.NET 4 application a child of an ASP.NET 2 or 3.5 site.

A (filthy) workaround for this problem would be to:
  1. Move the whole <configSections> section into the machine level web.config at C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\
  2. stop the web.config inheritance to wrap the whole configuration section in a <location inheritInChildApplications="false">

This feel very messy and personally I am not a fan of changing machine level configs, I went for upgrading the root site.
If you want more detailed info than this please feel free to bore dive into ASP.NET 4 Child Applications Fail to Start When Under ASP.NET 2.0 or ASP.NET 3.5 Applications - (and good luck!)

More info on duplicate section defined in a child .NET 4 application


4. Targeting ASP.NET 3.5 with MSTest

You may run into an "attempted re-targeting of the project has been cancelled. You cannot change the specified .NET framework version or profile for a test project" error when you try to target the ASP.NET 3.5 framework in a Microsoft Unit Test project.

Seriously, that is the end of this step. You just can't do it. Deal with it. This comes from Microsoft's mouth too (slightly more elegantly, I will concede). But, the fact remains: You cannot use Visual Studio 2010 AND target ASP.NET 3.5 AND use MS Test.

You will either have to exclude the Unit Test project from your solution or not use VS2010!

More info on changing the specified .NET framework version or profile for a test project


5. Potentially dangerous request validation

You can find yourself with an error of "A potentially dangerous Request.Form value was detected from the client" on a page which is set to ValidateRequest="false".

Previously putting ValidateRequest="false" in the Page declaration solved this problem. In .NET4 this is not the case. Simple work around though. You simply need to stick the following code in your web.config:
<system.web>
    <httpRuntime requestValidationMode="2.0" />
    <!-- everything else -->
</system.web>

This will set the request validation back to how you are used to. However, why not use this opportunity to solve this potential security properly? Or maybe use a <location inheritInChildApplications="false"> to wrap this code so that it is only relevant to the specific page that needs it?

More info on potentially dangerous request in ASP.NET 4 upgrade


6. MembershipUser and other System.Web.Security types have moved namespace

You could get a build time error of "The type name 'MembershipProvider' could not be found in the namespace 'System.Web.Security'. This type has been forwarded to assembly 'System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' Consider adding a reference to that assembly. ASP.NET4." after upgrading.

To fix this you just need to add a reference to the erroring project(s).
  1. Right click the References folder
  2. Click Add Reference...
  3. Under the .NET tab find and select System.Web.ApplicationServices

You may now need to resolve the references to MembershipUser (or other types) but you should be good to go.

More info on Membership provider not being found in System.Web.Security


7. Publishing a project with missing files

It seems like Visual Studio 2010 is a lot less forgiving when it comes to the project file referencing a file (static (e.g. an image) or otherwise) that does not actually exist when publishing.

You will have to go about your solution excluding all of these dud references. One by one too! Publish then exclude, publish, exclude, publish, exclude etc. until it published okay and stops complaining.

Summary and more...

This is a list of the complications I encountered during the upgrade process and how to solve each one. There are other complications too that I didn't personally encounter which you can read a white paper on ASP.NET 4 breaking changes from Microsoft themselves.

Hope this helps - if it did please link to this guide.

Good luck!

Follow britishdev on Twitter

Thursday 29 April 2010

Error in Silverlight application code: 2104 Could not download the Silverlight application. Check web server settings

Setting up a Silverlight application for the first time I got a JavaScript error of "Unhandled Error in Silverlight Application Code: 2104" with an accompanying message "Could not download the Silverlight application. Check web server settings"

Being new to this and largely just experimenting with Silverlight for the first time wasn't 100% what to do. At least it pointed me in the right direction with its "Check web server settings" comment at the end.

I checked the MIME types for my site. Sure enough there was no mention of the .xap extension. Yes, that would be the problem.

Solution

I added a MIME type with extension ".xap" and MIME type of "application/x-silverlight-app" and it all worked pleasantly.

I thought this was a bit weird that it didn't come pre-registered but oh well, hope you find this useful.

Follow britishdev on Twitter