Stack Overflow DevDays in Washington D.C. on October 26th. The event is SOLD OUT with talks on Python, ASP.NET MVC, iPhone development, Google App engine, and jQuery. Something to learn for everyone!
Øredev! I’m looking forward to seeing Sweden again! There are 14 tracks covering everything from Java to .NET, and Agile Ways to Leadership. The list of great speakers include, but are in no way limited to, Douglas Crockford, Jim Coplien, Dan North, Neal Ford, Ola Bini, Tess “Debug Diag” Fernandez, Shawn Wildermuth, Julie Lerman, Stephen Bowlen, Amanda “F#” Laucher, and Bea “WPF” Stollnitz. There is also Bellware, Oren, Hanselman, and Mr. Neward. It’s going to be awesome.
EPiServer Meetup! I’ve been invited to fly into Stockholm while I am in Sweden to visit the awesome team at Nansen and talk at the EPiServer Meetup on November 4th. Watch the meetup page for more details.
DevConnections! I’m in the ASP.NET track and have a post-conference AJAX workshop on Friday with lots of tips and tricks. Looking forward to seeing guys like Rick Strahl, Markus Egger, Paul Litwin, and Miguel Castro again. Exciting!
Code Camp! The Central Pennsylvania .NET Users Group is having a Code Camp on December 5th. I hope to see you there!
LINQ! I’m giving a three day class on LINQ and LINQ related technologies in Waltham, MA on December 8th. If you want to take a deep dive into the technology and see how LINQ and functional programming can transform not only your data access code but your business logic and tests, then sigh-up now. I’m sure we’ll go off on some interesting tangents, too.
I’ve often felt that we treat relational databases as a hammer to use with every kind of nail, screw, bolt, rivet, metric nut, and wall anchor we encounter in software development. The modern relational databases is a marvelous piece of engineering, and we have centuries of collective experience in designing, optimizing, securing, and managing them, but they just aren’t the best fit for every scenario.
The last few months I’ve been keeping an eye on the growing No-SQL movement. I’d like to make room for the No-SQL conference (nosqleast – their motto is: select fun, profit from real_world where relational=false;), but I’ll just have to wait for a debrief from Matt P. Here are a couple great blog posts for background on the No-SQL thing:
I wanted to experiment with a document oriented database myself and chose MongoDB. From the FAQ:
MongoDB is an document-oriented DBMS. Think of it as a persistent object store. It is neither a relational database, nor even "table oriented" like Amazon SimpleDB or Google BigTable. If you have used object-relational mapping layers before in your programs, you will find the Mongo interface similar to use, but faster, more powerful, and less work to set up.
I chose MongoDB because it looked easy to setup and run with.
To talk to MongoDB I used mongodb-csharp. You can either download the source as a zip file, or use a Git client like Git on Windows to clone the github repository. Sounds difficult, but Git is easy once you’ve adopted to the terminology, and as a bonus, it’s screaming fast. There is a Visual Studio solution included with the sources, so you can open it, build it, and out pops a MongoDB.Driver assembly.
Connecting to a database looks like this:
var mongo = new Mongo(); mongo.Connect(); var db = mongo.getDB("movieReviews");
I’m running MongoDB on the local machine and it’s listening on the default port with no special security settings. That simplifies the code, but also notice I can ask for a database (movieReviews), and if it doesn’t exist MongoDB will create the database for me. I don’t need to create tables or schemas or setup primary keys. It just works. I’m thinking document oriented databases are to relational databases what dynamic languages are to static languages.
The next step is to get/create a collection and start adding documents to it.
var movies = db.GetCollection("movies"); var movie = new Document(); movie["title"] = "Star Wars"; movie["releaseDate"] = DateTime.Now; movies.Insert(movie);
A collection is somewhat analogous to a table in the RDBMS world, but instead of rows and columns a collection is a bunch of documents that internally are stored in a binary JSON format (BSON). The documents can contain anything – they are schemaless, but MongoDB understands how to index and query the documents.
var spec = new Document(); spec["title"] = "Star Wars"; var starWars = movies.FindOne(spec);
With a few more abstractions (and a little bit of LINQ), document oriented databases could be a huge hit in .NET. Although, they might be better aligned with a language that runs on the DLR…
In ASP.NET web forms I’ve used the “sub-web project” trick to break apart large web applications. It has some downsides, but generally works. ASP.NET MVC 2 will include built-in support for breaking apart a large MVC application into “areas”. To quote ScottGu:
Areas provide a means of grouping controllers and views to allow building subsections of a large application in relative isolation to other sections. Each area can be implemented as a separate ASP.NET MVC project which can then be referenced by the main application. This helps manage the complexity when building a large application and facilitates multiple teams working together on a single application together.
There is a detailed walkthrough on MSDN for creating an Areas application using multiple projects. You create a parent project (MvcAreasMultiProject) and two sub-projects (Accounts and Store).
Notice the “s” on the Accounts controller name – there is an Account controller and an Accounts controller in the application – we’ll come back to that.
Inside the parent project, use the AreaRegistration class to magically register all the routes in all child projects.
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); AreaRegistration.RegisterAllAreas(); routes.MapRoute( "Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" } ); }
The AreaRegistration class will scan assemblies looking for types derived from AreaRegistration. It will instantiate these types and execute a method to give the the child projects a change to register their own routes. For example, the Accounts sub-project registers it’s routes with the following code:
public class Routes : AreaRegistration { public override string AreaName { get { return "Accounts"; } } public override void RegisterArea( AreaRegistrationContext context) { context.MapRoute( "Accounts_Default", "Profile/{action}/{id}", new { controller = "Accounts", action = "Index", id = "" } ); } }
With routes in place you can now generate links that reach specific areas. The following snippet creates a link to the Accounts controller in the Accounts sub-project…
<%= Html.ActionLink("Accounts", "Index", "Accounts", new { area = "accounts" }, null)%>
… while this one links to the Account controller in the parent project…
<%= Html.ActionLink("Log On", "LogOn", "Account", new { area = "" }, null)%>
What happens if two of the projects have a controller with the same name? For instance, if both the parent project and the Accounts project have an AccountController (with no “s” on Account).
If you try to reach the AccountController inside the Accounts area - everything should work. This is because the AreaRegistrationContext used to register routes for the Accounts area is automatically adding a namespace value to restrict the controller search. It’s like using the following code:
namespace Accounts // ^^ // the namespace of the area registration type // is used by default when mapping routes { public class Routes : AreaRegistration { public override string AreaName { get { return "Accounts"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Accounts_Default", "Profile/{action}/{id}", new { controller = "Account", action = "Index", id = "" }, null, new string[] { "Accounts" } // ^ this is explicitly specifying // the namespace as "Accounts", // but "Accounts" is the // default, so this isn't needed ); } } }
Note that the AccountController doesn’t have to live in the root Accounts namespace. It can live further down the hierarchy (like Accounts.Controllers.AccountController) and the factory will still find it.
The child area is in good shape, but a problem can occur if you try to reach the AccountController in the parent project. If the routes for the parent project were not given a any namespace values (which they aren’t by default), then the default controller factory will become angry and throw an exception at runtime.
The controller name 'Account' is ambiguous between the following types:
MvcAreasMultiProject.Controllers.AccountController
Accounts.Controllers.AccountController
The easiest solution is to include the namespace(s) for your parent project controllers when registering routes in the parent area.
routes.MapRoute( "Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" }, null, // namespaces -> new string[] { "MvcAreasMultiProject" } );
Coming up next Tuesday, my answers to the following questions:
Health monitoring has been available in ASP.NET since v 2.0, and the health monitoring features can give you information you can’t find anywhere else. I was troubleshooting an MVC application recently and needed information about the application:
This is the type of information you can record with health monitoring in both Web Forms and MVC applications.
You’ll typically want to record health data into SQL Server for analysis. The first step is to create the ASP.NET “application services” database. You might already be using the database if you are using ASP.NET features like the SQL membership provider for forums authentication. If not, the aspnet_regsql tool will create the tables and procedures required for health monitoring in any database you choose.
Once the database tables are in place, you just need a bit of configuration in web.config. The following configuration is telling the health monitoring system to send application lifecycle events to a SQL Server provider.
<system.web> <connectionStrings> <add name="appDB" connectionString="data source=..." /> </connectionStrings> <system.web>
<healthMonitoring enabled="true"> <providers> <add name="sqlProvider" type="System.Web.Management.SqlWebEventProvider" connectionStringName="appDB" buffer="false" bufferMode="Notification" /> </providers> <rules> <add name="lifeCycle" provider="sqlProvider" eventName="Application Lifetime Events" /> </rules> </healthMonitoring>
The health monitoring system will start to populate the aspnet_WebEvent_Events table with detailed event information. There is no built-in feature to display the events, but you can always setup a simple display view, connect with Microsoft Excel, or connect with any SQL query tool. The information is fairly detailed.
Many people are using ELMAH for error logging. ELMAH is easier to use and configure compared to the built-in health monitoring features. ELMAH also includes a number of display options, including the ability to generate RSS feeds from logged events, and sending log events to Twitter. Hanselman has a great post on using ELMAH in an MVC application. ELMAH’s creator is Atif Aziz, who has a number of other interesting projects listed on his web site: www.raboof.com.
If you are already using ELMAH, you still might consider looking at health monitoring for some scenarios. ELMAH is a fantastic error reporting tool, but some of the information available from health monitoring is only available via health monitoring, since it has a close tie to the ASP.NET runtime. If you want to take the health monitoring events and publish them via ELMAH, than Eric Schoenholzer (@bluesware) has written an ElmahEventProvider you can download from the Files section of the ELMAH project site.
It’s a bug you’ve probably learned to avoid in .NET programming, it’s just not as obvious now.
var cities = new List<string> { "Baltimore", "Munich", "Copenhagen" }; var citiesToRemove = cities.Where(city => city.Length < 7); foreach (var s in citiesToRemove) { cities.Remove(s); }What goes wrong, and what’s an easy fix?
--
All links to my “What’s Wrong” series are here.
#3 (Bowling with Visual Basic)
#5 (Bowling with Joe the developer)
#6 (A distinct select problem)
#10 (Threading is hard; let’s go shopping)
#11 (ASP.NET application instances)
#12 (ASP.NET module instances)
#16 (So many ways to go wrong with JavaScript)
#21 (Closing around an answer)
#22 (If it hurts, don't do it)
Have you ever taken a step back and looked at all the funny characters we use in programming computers?
I did this yesterday. Sometimes, when you look at familiar things in just the right light, they seem so strange.
I use the period to terminate all my sentences. In many programming languages the period is more of a continuation character. It says: “I’m going to act on this thing, and here is what I want it to do”.
boss.MakeMeASandwhich();
That code uses a semicolon to finish a statement; in writing the semicolon joins independent clauses. If symbols are so powerful, how can we juggle the conflicting meanings in our mind? Maybe Perl and C++ had part of it right using –> as a dereferencing operator.*
Sometimes a symbol will mean different things depending on how many times you type it. Like & versus &&. Or the = in JavaScript:
var x = 3; // assignment if(x == "3") // check for equality if(x === "3") // check for equality and i really really mean // equality because i typed an extra = character
Then we use symbols that impart meaning due to their shape.
{
// i'm trapped inside a { } and I can't escape.
}
It’s really not a far stretch from using { } to creating ASCII art.
$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$'`$$$$$$$$$$$$$'`$$$ $$$$$$ $$$$$$$$$$$ $$$$ $$$$$$$ '$/ `/ `$' .$$$$ $$$$$$$$. i i /! .$$$$$ $$$$$$$$$.--'--' $$$$$$ $$^^$$$$$' J$$$$$$ $$$ ~"" `. .$$$$$$$ $$$$$e, ; .$$$$$$$$ $$$$$$$$$$$.' $$$$$$$$$ $$$$$$$$$$$$. $$$$$$$$ $$$$$$$$$$$$$ $by&TL$
In fact, I think you could get the above picture to compile into something useful in APL.
* It’s amusing that the Wikipedia entry for Dereference operator has a single “See also” link at this time, and that link points to Segmentation fault.