Invalidate (re-cache) Content on AWS CloudFront

This is a handy script I use to invalidate (re-cache) content on AWS’s CloudFront.

using System;
using System.Collections.Generic;
using System.Configuration;
using Amazon;
using Amazon.CloudFront.Model;
using Amazon.S3.Model;
 
namespace AwsConsoleApp1
{
  internal class Program
  {
    /// <summary>
    /// Invalidates only one file. e.g. /images/profile.gif
    /// </summary>
    /// <param name="file"></param>
    public static void InvalidateFiles(string file)
    {
      InvalidateFiles(new List<string>() { file });
    }
 
    /// <summary>
    /// Invalidates only one file. Enter bucket name and key (file in the bucket).
    /// </summary>
    /// <param name="bucket"></param>
    /// <param name="key"></param>
    public static void InvalidateFiles(string bucket, string key)
    {
      InvalidateFiles(new List<string>() { bucket + "/" + key });
    }
 
    /// <summary>
    /// Invalidates a list of files. e.g. /images/profile.gif, /home/index.html
    /// </summary>
    /// <param name="files"></param>
    public static void InvalidateFiles(List<string> files)
    {
      // AWS client. You always create one.
      var cfClient = AWSClientFactory.CreateAmazonCloudFrontClient();
 
      // Create paths to files we want to invalidate
      Paths invalidationPaths = new Paths();
      // invalidationPaths.Items = new List<string>() { "/images/dan1g.zip" };
      invalidationPaths.Items = files;
      invalidationPaths.Quantity = invalidationPaths.Items.Count;
 
      // Now... let's build the request...
      CreateInvalidationRequest invalidationRequest = new CreateInvalidationRequest();
      invalidationRequest.DistributionId = ConfigurationManager.AppSettings["DistributionID"];
 
      // ... and other required paramaters
      invalidationRequest.InvalidationBatch = new InvalidationBatch();
      invalidationRequest.InvalidationBatch.Paths = invalidationPaths;
      invalidationRequest.InvalidationBatch.CallerReference = Guid.NewGuid().ToString();
 
      // Execute the request and get back a response object.
      CreateInvalidationResponse response = cfClient.CreateInvalidation(invalidationRequest);
 
      // Starting
      System.Console.WriteLine("Initiated On: " + response.CreateInvalidationResult.Invalidation.CreateTime);
      System.Console.WriteLine("InvalidationID: " + response.CreateInvalidationResult.Invalidation.Id);
      System.Console.WriteLine("Status: " + response.CreateInvalidationResult.Invalidation.Status);
    }
 
    /// <summary>
    /// Check if a file exists on S3.
    /// </summary>
    /// <param name="bucket"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public static bool IsFileInBucket(string bucket = "", string key = "")
    {
      bool exist = true;
      var s3Client = AWSClientFactory.CreateAmazonS3Client();
      try
      {
        GetObjectResponse oResponse = s3Client.GetObject(new GetObjectRequest() { BucketName = bucket, Key = key });       
      }
      catch (Exception e)
      {
        Console.WriteLine("\n" + e.Message);
        exist = false;
      }
 
      return exist;
    }
 
    /// <summary>
    /// Main Caller.
    /// </summary>
    /// <param name="args"></param>
    public static void Main(string[] args)
    {
      if (args.Length == 2)
      {
        string bucketName = args[0];
        string key = args[1];
 
        if (args != null && IsFileInBucket(bucketName, key))
        {
          InvalidateFiles(bucketName, key);
        }
        else
        {
          Console.WriteLine("\n\nDone.");
        }
      }
      else
      {
        Console.WriteLine("\nUse:\n   S3-Invalidate BUCKETNAME KEY\n\ne.g.\n   S3-Invalidate images photo.gif\n");
      }
 
      // Console.ReadKey();
    }
  }
}

List All EC2 Instances

Been playing around a lot with the AWS API. Going to post a few handy snippets every once in a while.

Typically, you start EC2 instances by ID. In this case, we’re doing it by tags (e.g. the name of the instance).

namespace EC2_Instance
{
  class Program
  {
    public static void StartInstance(AmazonEC2Client c, string InstanceID)
    {
      StartInstancesRequest r = new StartInstancesRequest();
      r.InstanceId.Add(InstanceID);
      c.StartInstances(r);
    }
 
    public static void StopInstance(AmazonEC2Client c, string InstanceID)
    {
      StopInstancesRequest r = new StopInstancesRequest();
      r.InstanceId.Add(InstanceID);
      c.StopInstances(r);
    }
 
 
    public static void Main(string[] args)
    {    
 
      AmazonEC2Client ec2Client = new AmazonEC2Client();   
      var instancesRequest = new DescribeInstancesRequest();
 
      instancesRequest.Filter.Add(new Filter() { Name = "tag:Name", Value = new List<string> { "*" } });
 
      DescribeInstancesResponse statusResponse = ec2Client.DescribeInstances(instancesRequest);
 
      foreach (var item in statusResponse.DescribeInstancesResult.Reservation)
      {
        Console.WriteLine(item.RunningInstance.ElementAt(0).Tag.Where(x => x.Key == "Name").First().Value);
        Console.WriteLine(item.RunningInstance.ElementAt(0).InstanceId);
        Console.WriteLine("\n");
      }     
 
      Console.ReadLine();
      Console.WriteLine("\n\nDone.");
    }
  }
}

Immediate Window in VB.NET

If you’re in debugging a VB.NET execution in the Immediate Window, to view the value you use the question mark:

? strpassword

Otherwise you’ll get :

Property access must assign to the property or use its value.

Model Binding and Validation ASP.NET MVC Sample Project

I wanted to share this sample project I put together that demonstrates model-binding and validation of several form components, including complex ones such as dropdowns, checkboxes, and radio buttons. There are several aspects to think about when submitting a form:

  1. HTML form value has to map to the correct C# property/object via Model Binding.
  2. Value submitted has to be properly validated based on Attributes or logic in controller.
  3. If the form has invalid data, the form has to refresh itself and be populated with all the values the user previous attempted to submit.
  4. The appropriate error messages have to be displayed next. The error messages can be part of the set of attributes above the property or handled via ViewBag/ViewData object.

The following example has all that. It also uses a ViewModel (BankAccount.cs) to piece together the main Business Domain Models (e.g. Person).

Download the Sample Project

Here’s our classes in the project:

Model Binding to a Dropdown

Sample #1: Binding to a List<string>

There’s a few ways to model bind a collection to a dropdown using the DropDown HTML helpers in ASP.NET MVC. Let’s first look at a simple scenario, where we have a dropdown and we want to bind to a List of states.

For this example, we’re going to construct a class called Globalization that has the list of states. (I use an this object to hold look-up data sets.)

  public class Globalization
  {
    public List<string> States
    {
      get
      {
        return new List<string>() 
        {
          "NY", "NJ", "IL", "TX", "FL"
        };
      }
    }

Now let’s create our model:

public class Person
{
  [Required(ErrorMessage="Please choose a state!")]
  public string State { get; set; }
}

And follow up with our Controller:

  public class HomeController : Controller
  {
    Globalization global = new Globalization();
 
    public ActionResult Index()
    {
      return View();
    }
    Globalization global = new Globalization();
 
    public ActionResult Index()
    {
      return View();
    }
 
    [HttpPost]
    public ActionResult Index(Person ba, FormCollection form)
    {      
      // Let's check if the state form field exists in the Global State list...
      if (global.States.Exists(s => s == form["State"] ? true : false))
      {
        // Clear the errors from the state property of the modelstate
        ModelState["State"].Errors.Clear();
      }      
 
      // Let's put it in the ViewBag so we can retain the user's form state when 
      // the page is refreshed and the forms are repopulated with what the user
      // previously put in.       
      ViewBag.selectedState = form["State"];
 
      if (ModelState.IsValid)
      {
        // Run further server-side business logic from private methods.
        // DoFurtherStuff();
        return (RedirectToAction("Success"));
      }
 
      return View(ba);
    }
 
    public ActionResult Success()
    {
      return View("Success");
    }
  }

Now let’s do the View:

@model MvcApplication10.Models.Person
@using MvcApplication10.Models;
@{
  ViewBag.Title = "BankAccount";
  Html.EnableClientValidation(false);
  Html.EnableUnobtrusiveJavaScript(false);
}
 
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "mvcform" }))
{    
  <fieldset>
    <legend>BankAccount</legend>
 
    <div class="editor-field">      
      @{ 
        SelectList slStates = new SelectList(new Globalization().States, ViewBag.selectedState); 
      }
      @Html.DropDownList("State", slStates.OrderBy( x => x.Text ), "")
      @Html.ValidationMessageFor(model => model.State)
    </div>
 
    <p>
      <input type="submit" value="Create" />
    </p>
  </fieldset>
}
<div>
  @Html.ActionLink("Back to List", "Index")
</div>

So with this app, if we don’t pick a value from the dropdown, we get an error:

Now, let’s look at the HTML code generated:

<select id="State" name="State">
  <option value=""></option>
  <option>FL</option>
  <option>IL</option>
  <option>NJ</option>
  <option>NY</option>
  <option>TX</option>
</select>

Notice that the option elements don’t have explicit values, so they’ll be set to the text inside the option elements. So that’s equivalent to:

<select id="State" name="State">
  <option value=""></option>
  <option value="FL">FL</option>
  <option value="IL">IL</option>
  <option value="NJ">NJ</option>
  <option value="NY">NY</option>
  <option value="TX">TX</option>
</select>

We leave the first one blank so the user has to select a value. So what if we want to bind the dropdown to a key/value pair collection like Dictionary? Like this for example:

<select id="State" name="State">
  <option value="4523">FL</option>
  <option value="6345">IL</option>
</select>

To do the above, refer to the next section…

Sample #2: Binding to a List<SelectListItem>

Now let’s visualize a different scenerio:

Where the HTML generated is:

<select class="input-validation-error" id="CategoryModel_StatusID" name="CategoryModel.StatusID">
  <option selected="selected" value=""></option>
  <option value="1">Approval Code</option>
  <option value="2">More Info Requested</option>
  <option value="3">Rejected</option>
  <option value="4">Deleted</option>
  <option value="5">Approved</option>
</select>

and we have to populate it with the data from the db (Status table):

Where the schema is:

CREATE TABLE [dbo].[Status](
	[StatusID] [tinyint] IDENTITY(1,1) NOT NULL,
	[Name] [varchar](50) NOT NULL
 CONSTRAINT [PK_Status] PRIMARY KEY CLUSTERED 
(
	[StatusID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

So we write the C# code a little different for this scenario. I’ve found that for this, it’s helpful to use the helper @Html.DropDownListFor(), which accepts an IEnumerable, which you’ll have to construct.

First let’s create our Model class:

public class Category
{		
    [Required(ErrorMessage = "Status is required.")]
    public Byte StatusID { get; set; }
}

For convenience, let’s also create a ViewModel class that uses Category. We’re also using Dapper here, which makes db connection a snap. Check out the tutorial for more details.

  /// <summary>
  /// We create his class so we can map data from Dapper.
  /// </summary>
  public class StateSelectListItem
  {
    public string Name { get; set; }
    public byte StatusID { get; set; }
  }
 
  /// <summary>
  /// This is the ViewModel for the Category Create Form
  /// </summary>
  public class CategoryViewModel
  {
    public Category CategoryModel { get; set; }
 
    public List<SelectListItem> ListStatusCodes
    {
      get
      {
        // We're putting an empty SelectListItem so that the first item in the drop down
        // is blank. 
        List<SelectListItem> selectList = new List<SelectListItem>() { new SelectListItem() { Text = "", Value = "", Selected = false } };
 
        using (SqlConnection conn = new SqlConnection("Data Source=NARUTO;Initial Catalog=GalaxyM33;Integrated Security=True"))
        {
          conn.Open();
 
          // Let's map the results (using Dapper) to the list of StateSelectListItem
          IEnumerable listStatus = conn.Query<StateSelectListItem>("select StatusID, Name From [Status]");
 
          // We're adding SelectList objects to the List...
          foreach (StateSelectListItem item in listStatus)
          {
            selectList.Add(new SelectListItem() { Text = item.Name, Value = item.StatusID.ToString() });
          }
 
          conn.Close();
        }
        return selectList;
      }
    }
  }

Here’s the controller:

    public ActionResult Create()
    {
      CategoryViewModel viewModel = new CategoryViewModel();    
      return View(viewModel);
    }
 
    [HttpPost]
    public ActionResult Create(CategoryViewModel viewModel)
    {      
      return View(viewModel);
    }

Now for the View:

@model ViewModels.CategoryViewModel
@{
  ViewBag.Title = "Create";
  Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
  @Html.ValidationSummary(true)
  <fieldset>
    <legend>Category</legend>
    <div class="editor-field">      
      @Html.DropDownListFor(m => m.CategoryModel.StatusID, Model.ListStatusCodes)
      @Html.ValidationMessageFor(model => model.CategoryModel.StatusID)
    </div>       
    <p>
      <input type="submit" value="Create" />
    </p>
  </fieldset>
}
<div>
  @Html.ActionLink("Back to List", "Index")
</div>

That should do it.

Download Sample 1

Dapper – A C# Micro ORM Library Makes Data Access a Snap – Part 1

I’ve recently gotten a chance to try out Dapper – a micro ORM library by Sam Saffron, which originally spawned from StackOverflow’s codeset. If you’re looking for an extremely light-weight library to access your SQL Server, I highly recommend it. It focuses more on convention than configuration. It also does not have the overhead that EntityFramework or NHibernate have, and it emphasizes speed and ease-of-use.

Dapper is a collection of Extension Methods that enhance the Connection object (or rather extends the IDbConnection interface). It also embraces the use of inline SQL in your code, which is useful when retrieving sets that are less trivial. With its buddy, Dapper-Extensions by Thad Smith, it makes DB interaction even easier.

Both of these libraries can be downloaded from NuGet, and you’ll need them to run the following code.

There’s really just one thing that I found irritating about the Dapper project: the documentation. While there is documentation found at its Google Code home page, I find it very lacking.

Anywhoot, to get started first we need to create our table. Once we have that and add some data, we’ll use the Dapper to extract the data and map to objects.

----------------------------------------
-- Customer Schema
----------------------------------------
CREATE TABLE [dbo].[Customer](
[CustomerID] [uniqueidentifier] NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[Age] [int] NULL,
[IsAllowed] [bit] NULL,
[DateRegistered] [datetime] NULL,
[AdditionalDetails] [nvarchar](max) NULL,
CONSTRAINT [PK_Customer_1] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
 
ALTER TABLE [dbo].[Customer] ADD  CONSTRAINT [DF_Customer_CustomerID]  DEFAULT (newid()) FOR [CustomerID]
GO
 
----------------------------------------
-- Data
----------------------------------------
INSERT INTO [dbo].[Customer]([CustomerID], [FirstName], [LastName], [Age], [IsAllowed], [DateRegistered], [AdditionalDetails])
  SELECT N'5458dff8-cea2-4bdb-9431-1dea56f109f8', N'Bruce', N'Wayne', 31, 1, '20080604 08:13:44.000', N'I am Batman' UNION ALL
  SELECT N'1767bc57-af03-4b17-891f-2aa9af244180', N'Peter', N'Parker', 25, 1, '20120103 12:22:28.000', N'I am Spider-Man' UNION ALL
  SELECT N'dc2bf42d-045b-4189-bd6b-8bf1bf120291', N'Eddie', N'Brock', 34, 0, '20040123 02:45:41.000', N'We are Venom'

OK, so this is what we have so far:

Because Dapper focuses more on convention over configuration, it’s important to note that when you create your class:

  • The name of your class must match the name of the table, otherwise an exception is thrown.
  • All column names must match all class property names, otherwise an exception is thrown.
  • If a column is not used (in NOT written out in the SELECT statement) and the class property exists, it will set to NULL or assign a default value – more on this later.

Now that we’re aware of these points, let’s see the code to get started:

using System;
using Dapper;
using System.Data.SqlClient;
 
class Customer
{
  public Guid CustomerID { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public int Age { get; set; }
  public bool IsAllowed { get; set; }
  public DateTime DateRegistered { get; set; }
  public string AdditionalDetails { get; set; }
}
 
class Program
{
  private static void Main()
  {
 
    using (SqlConnection conn = new SqlConnection("Data Source=NARUTO;Initial Catalog=TESTDATABASE;Integrated Security=True"))
    {
      conn.Open();
 
      // Put dapper code here.
 
      conn.Close();
    }
 
    Console.ReadLine();
  }
}

OK, so there’s nothing out of the ordinary here. We’re creating the class we want to map our data to, creating a Connection object, opening, closing, and then disposing (via using). Now let’s suck up some data within our Main() method:

private static void Main()
{
  using (SqlConnection conn = new SqlConnection("Data Source=NARUTO;Initial Catalog=TESTDATABASE;Integrated Security=True"))
  {
    conn.Open();
 
    IEnumerable customers = conn.Query("SELECT * FROM Customer");
 
    foreach (Customer c in customers)
    {
      Console.WriteLine("CustomerID: " + c.CustomerID);
      Console.WriteLine("FirstName: " + c.FirstName);
      Console.WriteLine("LastName: " + c.LastName);
      Console.WriteLine("Age: " + c.Age);
      Console.WriteLine("IsAllowed: " + c.IsAllowed);
      Console.WriteLine("DateRegistered: " + c.DateRegistered);
      Console.WriteLine("AdditionalDetails: " + c.AdditionalDetails);
      Console.WriteLine("-----------------------------------------------");
    }
 
    conn.Close();
  }
 
  Console.ReadLine();
}

As we see, the Query extension method pulls in the data based on the select statements. The Query method returns a strongly-typed list of Customer. You should see the following:

Now what if we want to get the number of records in the table? Well, because Query returns an IEnumerable, we cannot use the Count property. To do so, we convert to a List:

List<Customers> customers = (List<Customers>)conn.Query("SELECT * FROM Customer");
Console.WriteLine(customers.Count);

That should give us the count. To see how the data types were mapped, we can take a look at the Dapper source code, SqlMapper.cs inside the static method SqlMapper(). For reference, you can take a peek at these two sources to understand SQL Server/CLR/.NET framework data types:

http://stackoverflow.com/questions/425389/c-sharp-equivalent-of-sql-server-2005-datatypes

http://msdn.microsoft.com/en-us/library/ms131092.aspx

For our example though, we saw that the data types were mapped:

Mismatches and Nulls

In the query that we ran, we were making the assumption that all columns in the db match all the properties in the class. What if we have a mismatch? What if we have this?

IEnumerable customers = conn.Query("SELECT LastName FROM Customer");

Notice that we’re only retrieving the LastName, while we have other properties in our Customer class. Well, this is what you would see:

So from the above, we notice that Dapper will handle Nulls by:

  • Setting strings as Nulls
  • Setting a Guid to 00000000-0000-0000-0000-000000000000
  • Setting an int to 0
  • Setting bool to false
  • Setting a DateTime to 1/1/0001 12:00:00 AM

Which will all happen when Dapper cannot find a class property to map to from the column value. Also, if you column name that DOES NOT match a property, it will throw a SqlException of “Invalid Column Name”.

Parameterization

What if we want to pass a parameter into our SQL? Let’s pass a parameter:

IEnumerable customers = conn.Query("SELECT * FROM Customer WHERE AGE &gt; @Age", new { Age = 30 } );

Notice that I’m passing in an anonymous object. I could also have done:

Customer someCustomer = new Customer {
Age = 33,
FirstName = "Clark Kent"
};
 
IEnumerable customers = conn.Query("SELECT * FROM Customer WHERE AGE &gt; @Age", someCustomer );

Which yields:

The property in someCustomer (FirstName = “Clark Kent”) is silently ignored because it’s not used in the SELECT statement.

When the above is run, SQL Server Profiler shows that the following is run:

exec sp_executesql N'SELECT * FROM Customer WHERE AGE &gt; @Age',N'@Age int',@Age=33

So we know it’s parameterized.

To call a stored procedure and map it to objects, we do, assuming we have the following sproc:

CREATE PROCEDURE GetCustomers
(
@IsAllowed BIT
)
AS
BEGIN
 
SELECT * FROM Customer
WHERE IsAllowed = @IsAllowed
 
END

We do:

// The second @ token does not have to be named "@IsAllowed" and can be named anything as
// long as the C# property in the anonymous object is named the same thing.
IEnumerable customers = conn.Query("GetCustomers @IsAllowed = @IsAllowed", new { IsAllowed = 33 } );

Also accepted:

IEnumerable customers = conn.Query("GetCustomers @IsAllowed = @Allow", new { Allow = 33 } );

Or you can be more explicit by specifying the command type (StoredProcedure):

IEnumerable customers = conn.Query("GetCustomers", new { IsAllowed = 33 }, commandType: CommandType.StoredProcedure );

Or writing it a more secure way:

DynamicParameters parameters = new DynamicParameters();
parameters.Add("@IsAllowed", 'f', dbType:DbType.Int32);
 
IEnumerable customers = conn.Query("GetCustomers", parameters, commandType: CommandType.StoredProcedure );

To insert data, we do as follows:

Customer customer = new Customer{
  FirstName = "Mazinger",
  LastName = "Z",
  Age = 40,
  IsAllowed = true,
  DateRegistered = DateTime.Now,
  AdditionalDetails = "Metallic defender"
};
 
conn.Execute(@"INSERT INTO Customer
                                  ( FirstName ,
                                  LastName ,
                                  Age ,
                                  IsAllowed ,
                                  DateRegistered ,
                                  AdditionalDetails
 
                   )
                   VALUES  ( @FirstName ,
                                 @LastName ,
                                 @Age ,
                                 @IsAllowed ,
                                 @DateRegistered ,
                                 @AdditionalDetails
                               )"
                 , customer);

This ends part 1 of the tutorial. I will post the 2nd part soon.

Validating Rich TextArea in ASP.NET MVC 3

There’s a few things to consider when validating data from a rich textarea. After setting it up (here’s a blog post about that), we have to allow the property to accept HTML, otherwise, you’ll get this:

Which would normally be good a thing for normal textboxes to avoid XSS. However, here we have to accept it. So assuming we have a property in our model called message, we add the AllowHtml attribute:

  [AllowHtml]
  public string Message { get; set; }

This is all great and dandy, however, once you do that, it won’t allow other validations, like Range(). So what we have to do is create our own attribute. To do this, we just create a class that inherits ValidationAttribute:

class AllowHtmlRangeLength : ValidationAttribute
{
  public override bool IsValid(object value)
  {
    string property = (string)value ?? "";
    if (property.Length >= 3 && property.Length <= 2000)
    {
      return true;
    }
 
    return false;
  }

In this case, we’re only accepting (to attempt to validate) a string from 3 to 2000 characters. Then we use it like this in our model:

  [AllowHtml]
  [AllowHtmlRangeLength(ErrorMessage="Please have at least 3 to 2000 characters."]
  public string Message { get; set; }

The problem with this set up is that we don’t want HTML tags to count as characters. So we need to parse out HTML. Because parsing data with just one regular expression can be error-prone, it’s best to use a library like HTML Agility pack – get it from NuGet:

Once you have it installed in your project, we can reuse the sample code parse out HTML from its CodePlex site.

For simplicity’s sake, I made the class and its methods static. Additionally, I added the following method to add additional scrubbing logic:

    public static string ConvertHTMLToCleanText(string html)
    {
      HtmlDocument doc = new HtmlDocument();
      doc.LoadHtml(html);
 
      StringWriter sw = new StringWriter();
      ConvertTo(doc.DocumentNode, sw);
      sw.Flush();
 
      // let's clean the string + Remove double spaces.
      string clean = Regex.Replace(sw.ToString().Trim(), @"\s{2,}", "");
 
      return clean;
    }

Once we have that set up, let’s now tweak our AllowHtmlRangeLength attribute we started out with to use this new ConvertHTMLToCleanText method (from above):

  class AllowHtmlRangeLength : ValidationAttribute
  {
    public int minHtmlLength { get; set; }
    public int maxHtmlLength { get; set; }   
 
    public override bool IsValid(object value)
    {
      string property = (string)value ?? "";
 
      if (HtmlToText.ConvertHTMLToCleanText(property.ToString()).Length >= minHtmlLength && HtmlToText.ConvertHTMLToCleanText(property.ToString()).Length <= maxHtmlLength)
      {
        return true;
      }
 
      return false;
    }
 
    public override string FormatErrorMessage(string s)
    {
      return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, minHtmlLength, maxHtmlLength);
    }
  }

We’re overriding the FormatErrorMessage method so we can customize the error message to show the min and max values of the range. Also, we need to set min and max as public properties so we can use it as arguments as part of the AllowHtmlRangeLength attribute. So this is how it’s called now:

    [AllowHtml]
    [AllowHtmlRangeLength(ErrorMessage="Please have at least {0} to {1} characters.", minHtmlLength=3, maxHtmlLength=255)]
    public string Message { get; set; }

So let’s see. This throws an error, even though there’s HTML that bolds, underlines, and adds a heading of 1.

The following has no error:

The following has 3000 chars and it fails.

Check out the source files.

Companies Who Use ASP.NET

During a job hunt, I compiled a list of companies that use ASP.NET. Most of them, without a surprise, are big corporate ones. Also, not all of them use ASP.NET exclusively for their entire site/business. Many of these sites have subsites for their many divisions, so a mix of technologies are used.

I’m going to keep updating as I find more.

Microsoft Amazon
 

Getting Started with the MongoDB C# Driver

Here’s my attempt on writing a super-barebones tutorial for using the MongoDB C# Driver. It’s a very hands-on tutorial-by-example, showing you the basics of the driver by creating console apps.

I’m assuming you’ve installed the official MongoDB C# driver and read the intro. Heads up on how you set up the driver. The .msi sets it up in the GAC. The zip file has the assemblies that can just be referenced in your project.

After you’ve done those two things, you can proceed. 🙂

Dependencies

In projects, you have the option of utilizing the following namespaces:

using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Bson.Serialization.Options;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using MongoDB.Driver.Wrappers;

The most commonly used are Bson, Driver, Serialization, and Serialization.Attributes. This tutorial will use these four in all code samples, so make sure you include them in your app, even if I don’t have it in the code samples. You can learn more about the API/namespaces by checking out the docs.

Connecting to a MongoDB Database

Connecting is pretty simple. Once you include the C# driver assemblies, you connect as follows:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
    }
  }
}

That’s pretty much all you need to connect. Of course, I recommend putting the connection string in the Web.config, or some initializer.

Inserting a document on MongoDB

There are tons of ways to do this, but one of the simplest ways is to create a class, create an instances of that class, and pass it into a MongoDB object that serializes that object into BSON and submits it to your database.

So for this example, before inserting a document into the database from C#, one has to do two things (aside from the establishing a connection and choosing which db to write to):

  1. Create a Generic Collection object. In this case, it’s a MongoDB collection.
  2. Create a class that’s to be used by the Generic Collection.

Those two go together.

Also, note that while working with MongoDB in C#, the word “collection” may be thrown around loosely. In MongoDB you have a “Collection” that’s comparable to a Table in a traditional ER database. A MongoDB “Collection” holds “documents,” which is comparable to a “record” in a traditional ER database. On the opposite side, in C#, a collection is a data structure that unlike an Array, can be resized dynamically and is more flexible as far as functionality.

The MongoDB Generic Collection is a C# collection that can hold any type of object, but it has to know what type of object it’s holding. You let it know what kind of type by creating a class, and then when you create a collection, you specify the name of the class. So for example, this is the syntax for creating a Generic Collection that has Car objects (where person is defined in a class):

After that line of code, you populate the vehicles object (remember it’s a MongoDB Generic collection that holds Cars objects), by calling the method “GetCollection” from the Cars object we creating in the last section “Connecting to a MongoDB database”:

In the above statement, if MongoDB does not find a collection on the database called “vehicles,” it will create it for you.

What does that Cars class look like? Pretty simple:

  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
  }

Then of course, before sending it to the MongoDB database, you create an object and set the values of the object:

      Cars newCar = new Cars();
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;

And then insert it in MongoDB:

vehicles.Insert(newCar);

To put it in perspective, here’s the entire program:

namespace ConsoleApplication1
{
  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
  }
 
  class Program
  {
    static void Main(string[] args)
    {       
 
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection vehicles;
 
      vehicles = Cars.GetCollection("vehicles");
 
      Cars newCar = new Cars();
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;      
 
      vehicles.Insert(newCar);
    }
  }
}

The insert method should serialize the Cars object (newCar) and create the MongoDB document, mapping the properties of the Cars class to MongoDB document key-pair values.

Let’s see how this got created in our database:

Run:

db.vehicles.find()

(e.g. ignore the lname property. This was removed in the source code)

Inserting Complex Objects in MongoDB

Let’s try inserting an object with a more complex data structure. Let’s assume we have the following class:

  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }

Now let’s declare the class and its properties:

      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;
 
      newCar.history = new Hashtable();   
      newCar.history.Add("2010-08-14", "Puss 'N Boots");
      newCar.history.Add("2011-12-01", "Puff the Magic Dragon");
      newCar.history.Add("2009-03-07", "Fraggle Rock");      
 
      newCar.magicNumbers = new int[3];
      newCar.magicNumbers[0] = 60;
      newCar.magicNumbers[1] = 186000;
      newCar.magicNumbers[2] = 1440;
 
      newCar.complex = new Hashtable();
      newCar.complex.Add( newCar.magicNumbers[1], newCar.history );
      newCar.complex.Add( System.Guid.NewGuid().ToString(), newCar.history);

It outputs the following (formatted for better reading):

{
  "_id": "a07513c8-9cb5-46cd-a9cb-425cabc0dd76",
  "brand": "Honda",
  "lname": null,
  "miles": 186000,
  "age": 1,
  "history": 
  {
    "2010-08-14": "Puss 'N Boots",
    "2009-03-07": "Fraggle Rock",
    "2011-12-01": "Puff the Magic Dragon"
  },
  "complex": 
  [
    ["eb7b3d4d-87b1-43c1-9fe7-5a5e4b5b79de",
    {
        "2010-08-14": "Puss 'N Boots",
        "2009-03-07": "Fraggle Rock",
        "2011-12-01": "Puff the Magic Dragon"
    }],
    [
    186000,
    {
        "2010-08-14": "Puss 'N Boots",
        "2009-03-07": "Fraggle Rock",
        "2011-12-01": "Puff the Magic Dragon"
    }]
  ],
  "magicNumbers": [60, 186000, 1440]
}

Now let’s look at the entire code for all this:

namespace ConsoleApplication1
{
  public class Cars
  {     
    public string _id { get; set; }   
    public string brand { get; set; }  
    public string lname { get; set; }  
    public Int32 miles { get; set; }  
    public int age { get; set; }
 
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }
 
  class Program
  {   
    static void Main(string[] args)
    {
 
      MongoServer  server = MongoServer.Create("mongodb://work2");          
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection<Cars> vehicles;
 
      vehicles = Cars.GetCollection<Cars>("vehicles");
 
      Cars newCar = new Cars();
 
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;
 
      newCar.history = new Hashtable();   
      newCar.history.Add("2010-08-14", "Puss 'N Boots");
      newCar.history.Add("2011-12-01", "Puff the Magic Dragon");
      newCar.history.Add("2009-03-07", "Fraggle Rock");      
 
      newCar.magicNumbers = new int[3];
      newCar.magicNumbers[0] = 60;
      newCar.magicNumbers[1] = 186000;
      newCar.magicNumbers[2] = 1440;
 
      newCar.complex = new Hashtable();
      newCar.complex.Add( newCar.magicNumbers[1], newCar.history );
      newCar.complex.Add( System.Guid.NewGuid().ToString(), newCar.history); 
 
      vehicles.Insert<Cars>(newCar);         
 
      Console.ReadLine();                
    }     
  }
}

Reading the 1st MongoDB document from the database

Before you query the database, you must make sure the class and member types match the values/objects that the MongoDB connection will return.

Let’s try to fetch the 1st document. To see what we’re expecting, let’s fetch it via the console first:

db.vehicles.find().limit(1)

which returns:

{
  "_id" : ObjectId("4d95f30058430000007a5943"),
  "ObjectId" : ObjectId("000000000000000000000000"),
  "brand" : "Ford",
  "lname" : null,
  "miles" : 2500,
  "age" : 1
}

Now that we know what it returns, let’s make sure we have the class in place that will handle the kind of key-value pairs in the MongoDB collection:

  public class Cars
  {
    public MongoDB.Bson.ObjectId _id { get; set; }
    public MongoDB.Bson.ObjectId ObjectId { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    // Complex Properties
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }

Notice that the properties history, complex, and magicNumbers are not part of the MongoDB document we queried. That’s OK. The MongoDB C# drivers are smart enough to map to to a null value when deserializing from MongoDB to a C# object.

Now how do you map values from a MongoDB connection to a C# object? Like so:

    Cars car = vehicles.FindOne();

The FindOne() method will return the first document. Now let’s add some context to this line of code, by adding MongoDB connection code (that we established before), writing it to the screen, and checking for nulls in the complex properties:

namespace ConsoleApplication1
{
  public class Cars
  {
    public MongoDB.Bson.ObjectId _id { get; set; }
    public MongoDB.Bson.ObjectId ObjectId { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    // Complex Properties
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }
 
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection vehicles;
      vehicles = Cars.GetCollection("vehicles");
 
      Cars car = vehicles.FindOne();
 
      Console.WriteLine(car._id);
      Console.WriteLine(car.ObjectId);
      Console.WriteLine(car.brand);
      Console.WriteLine(car.lname);
      Console.WriteLine(car.miles);
      Console.WriteLine(car.age);
 
      if (car.history == null)
        Console.WriteLine("history was null");
      else
        Console.WriteLine(car.history);
 
      if(car.complex == null)
        Console.WriteLine("complex was null");
      else
        Console.WriteLine(car.complex);
 
      if (car.magicNumbers == null)
        Console.WriteLine("magicNumbers was null");
      else
        Console.WriteLine(car.magicNumbers);                  
 
      Console.WriteLine("ha made it this far!");
      Console.ReadLine();
    }
  }
}

This will print the following on to the screen:

Read All Documents from a MongoDB Collection

Let’s try to output all the documents from a collection. We’re going to create a new MongoDB collection under the Cars database. Through the MongoDB client, we’ve created four documents. Let’s read them from the console first:

db.bankaccount.find()

The four documents look like:

{ "_id" : ObjectId("4d9650301b6e000000004116"), "name" : "Batman" }
{ "_id" : ObjectId("4d9650391b6e000000004117"), "name" : "Spider-Man" }
{ "_id" : ObjectId("4d96503f1b6e000000004118"), "name" : "Superman" }
{ "_id" : ObjectId("4d9650431b6e000000004119"), "name" : "Spawn" }

So the first thing is to create a class that represents each MongoDB document:

public class BankAccount
  {
    public MongoDB.Bson.ObjectId _id;
    public string name;
  }

The class is used to create an object that will contain the data that is deserialized (from MongoDB to a C# object).

Here’s the code to query all documents, iterating through them and showing them on the screen:

      MongoCursor cursor = BankAccountCollection.FindAll();
 
      foreach (BankAccount ba in cursor)
      {
        Console.WriteLine(ba._id);
        Console.WriteLine(ba.name);
        Console.WriteLine("=============================");
      }

Looks straightforward enough. What is a cursor? We can think of a MongoDB Cursor as a DataSet in .NET. Later, we’ll see MongoDB Queries, which resemble a SqlCommand object in .NET. Queries are configurable objects to search for document data. The Query object is then passed into the a find method (there are several) of the MongoCollection. The find method then typically returns a Cursor, which is then iterated through. (More about this later.) Also note that a Cursor is not “populated” with documents until the there’s an attempt to retrieve the first result from the server.

Let’s see the entire program in action.

namespace ConsoleApplication1
{
  public class BankAccount
  {
    public MongoDB.Bson.ObjectId _id;
    public string name;
  }
 
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase BankAccountDatabase = server.GetDatabase("Cars");
 
      MongoCollection BankAccountCollection;
      BankAccountCollection = BankAccountDatabase.GetCollection("bankaccount");
 
      MongoCursor cursor = BankAccountCollection.FindAll();
 
      foreach (BankAccount ba in cursor)
      {
        Console.WriteLine(ba._id);
        Console.WriteLine(ba.name);
        Console.WriteLine("=============================");
      }      
 
      Console.WriteLine("\n\nha made it this far!");
      Console.ReadLine();
    }
  }
}

The above program outputs the following:

If we wanted to retrieve a specific query, rather than doing this (from the above code):

 MongoCursor cursor = BankAccountCollection.FindAll();

We would do:

      var query = Query.EQ("name", "Batman");
      var cursor = BankAccountCollection.Find(query);

One last thing to mention about the Find() method, as stated from docs:
The Find method (and its variations) don’t immediately return the actual results of a query. Instead they return a cursor that can be enumerated to retrieve the results of the query. The query isn’t actually sent to the server until we attempt to retrieve the first result (technically, when MoveNext is called for the first time on the enumerator returned by GetEnumerator). This means that we can control the results of the query in interesting ways by modifying the cursor before fetching the results.

Get only key-value pairs from a collection

In this example, we’re going to try to do something like this in SQL:

SELECT Column1, Column2
FROM  TABLE

We’re also going to be using the collection “bbu”. Let’s try to translate this query:

db.bbu.find({},{whichAPI:1}).limit(10)

Which would return the following:

{ "_id" : ObjectId("4d90fbd85843000000004359"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435a"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435b"), "whichAPI" : "SIT" }
{ "_id" : ObjectId("4d90fbd8584300000000435c"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435d"), "whichAPI" : "SL" }

First, we’re going to define the class. We’re going to establish all the properties that are needed for a class, but then only query and populate two colums from the class.

Define the class and all of its properties.

public class BBU
  {
    public MongoDB.Bson.ObjectId _id;
    public int counter;
    public string whichAPI;
  }

Now the actual program:

  class Program
  {
    static void Main(string[] args)
    {    
 
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase BBUDatabase = server.GetDatabase("bbu");
 
      MongoCollection BBUCollection;
      BBUCollection = BBUDatabase.GetCollection("bbu");
 
      MongoCursor cursor = BBUCollection.FindAll().SetFields("id","whichAPI").SetLimit(5);
 
      foreach (BBU ba in cursor)
      {
        Console.WriteLine(ba._id + "----" + ba.whichAPI);
        Console.WriteLine("=============================");
      }      
 
      Console.WriteLine("\n\nha made it this far!");
      Console.ReadLine();                        
 
    }
  }

In the example above, SetLimit(5) will only return the top 5 documents.

Conclusion

I hope you got a good a sense of the basics of using the MongoDB C# driver. I’ve only scratched the surface of the API. I’ll be discussing more advanced topics in future posts.

For the meantime, I point you to the MongoDB Google Group: http://groups.google.com/group/mongodb-user?pli=1 where you’ll get informative responses, usually very quickly.

I also recommend you following the following folks on Twitter and these blogs/sites:

Lastly, I recommend you check out the MongoDB video presentations using the C# Driver and working in a Microsoft environment.