Friday, January 29, 2010

Getting Mongo with MongoDB

Having a few hours to kill I went off on a tangent and decided to investigate a schema-free, document-oriented database called MongoDB.  The reason was because I’ve heard so much about them on Floss Weekly.

Getting it setup

First you’ll need the database software which can be downloaded from the site. For windows this will bring down a ZIP file which can simply be up packed onto your hard drive.  Create a “data” directory within the MonoDB folder and create a simple batch file called “monodb_start.bat” which starts the server and passed in a location for the database files.

@echo Off
echo -----------------------------------------
echo .    Starting the MongoDB instance
echo -----------------------------------------
.\bin\mongod --dbpath=./data

From the command line just type “mongodb_start” and you should get a command window appear.

image

The next step is to get the Database Driver for C#.  I’ve found the one listed on the site worked fine.  You can get this from Git Hub and click the Download Source link in the top right of the screen.  Once you get the Source open it in Visual Studio and compile the project to give you “MongoDB.Driver.dll”.

Finally you’ll need something that will read the JSON which is exported from database queries.  You can get a good Json.NET library from codeplex. Again download the ZIP file and extract the version you require.

Creating a project and query the database

Open up a new solution in Visual Studio and create a new class library called “mongoTest”.  I’m going to create an NUnit project which will allow us to do basic queries.  Add the references you’re going to need; MongoDB.Driver, Newtonsoft.Json, nunit.framework and log4net.

Now create a new class file called “DevelopmentAdvisors” which has the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using MongoDB.Driver;
using Newtonsoft.Json;

namespace mongoTest
{
    [TestFixture]
    public class DevelopmentAdvisors
    {

        private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType);
        Database _mongoDB = null;
        IMongoCollection _daCollection = null;

        [TestFixtureSetUp]
        public void mongo_SetupDatabase()
        {
            log4net.Config.XmlConfigurator.Configure();
            var mongo = new Mongo();
            mongo.Connect();
            _mongoDB = mongo.getDB("MyDB");
            _daCollection = _mongoDB.GetCollection("DevelopmentAdvisors");
        }
}

This code will allow us to connect to a database called “MyDB” and connect to a “collection” (or table in any normal db) called “DevelopmentAdvisors”.

You’ll also need to create an App.config file so you can get the output. the contents of that is shown below:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>

  <log4net>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n"/>
        <param name="Footer" value="[Footer]\r\n"/>
        <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
      </layout>
    </appender>
    <root>
      <level value="Debug"/>
      <appender-ref ref="ConsoleAppender"/>
    </root>
  </log4net>

</configuration>

Now that al the basic setups are out of the way we can do our first inserts.

[Test(Description="Insert a bunch of random record")]
[TestCase("Joe", "Smith", null, null)]
[TestCase("Joe", "Murphy", "Mr.", null)]
[TestCase("Paddy", "O'Brien", "Mr.", "Dublin")]
[TestCase("Fred", "Smith", "Mr.", "Eastwall, Dublin")]
[TestCase(null, "Martin", "Miss.", "Carlow")]
public void mongoTest_InsertNewDA(string firstName, string secondName, string title, string address)
{
    Document da = new Document();
    if(!String.IsNullOrEmpty(firstName))
        da["FirstName"] = firstName;
    if(!String.IsNullOrEmpty(secondName))
        da["SecondName"] = secondName;
    if(!String.IsNullOrEmpty(title))
        da["Title"] = title;
    if(!String.IsNullOrEmpty(address))
        da["Address"] = address;
    _daCollection.Insert(da);
    // find if the records were added
    ICursor cursor = _daCollection.FindAll();
    Assert.IsTrue(cursor.Documents.Count() > 0, "No records found");
}

Ok, here we go starting the project using NUnit GUI will give us the following:

image

Click Run and we should get a bunch of Green lights!

image

If you notice your MongoDB command window now has a new connection listed.

image

OK so that inserts records with different layouts into the collection. But there is no point in doing this if we can get the data out so we create a new test.  Using the code below we use the built in function called FindAll() to extract all the information from the database.

[Test(Description = "Search collection for results")]
public void mongoTest_SearchForResults()
{
    ICursor cursor = _daCollection.FindAll();
    Assert.IsTrue(cursor.Documents.Count() > 0, "No values found!");
    foreach (Document doc in cursor.Documents)
        _log.DebugFormat("Record {0};", doc.ToString());
}

Clicking run will present the records we’ve added in the last run.

image

The console shows that the database is returning JSON strings for each record item.

Lets get more professional with this

Dealing with Document and var objects is not really good enough to deal with when we code, so the best thing to do it create a class which holds that information.  Create a new class called “DAClass” and paste in the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using Newtonsoft.Json;
using mongoTest.ExtensionMethods;

namespace mongoTest
{
    /// <summary>
    /// Interface for the Entity
    /// </summary>
    public interface IMongoEntity
    {
        Document InternalDocument { get; set; }
    }

    /// <summary>
    /// Class holding the DA information
    /// </summary>
    sealed class DAClass : IMongoEntity
    {
        /// <summary>
        /// Gets or sets the first name.
        /// </summary>
        /// <value>The first name.</value>
        public string FirstName
        {
            get { return InternalDocument.Field("FirstName"); }
            set { InternalDocument["FirstName"] = value; }
        }

        /// <summary>
        /// Gets or sets the name of the second.
        /// </summary>
        /// <value>The name of the second.</value>
        public string SecondName
        {
            get { return InternalDocument.Field("SecondName"); }
            set { InternalDocument["SecondName"] = value; }
        }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>The title.</value>
        public string Title
        {
            get { return InternalDocument.Field("Title"); }
            set { InternalDocument["Title"] = value; }
        }

        /// <summary>
        /// Gets or sets the address.
        /// </summary>
        /// <value>The address.</value>
        public string Address
        {
            get { return InternalDocument.Field("Address"); }
            set { InternalDocument["Address"] = value; }
        }

        /// <summary>
        /// Gets the list of items
        /// </summary>
        /// <typeparam name="TDocument">The type of the document.</typeparam>
        /// <param name="whereClause">The where clause.</param>
        /// <param name="fromCollection">From collection.</param>
        /// <returns></returns>
        public static IList<TDocument> GetListOf<TDocument>(Document whereClause, IMongoCollection fromCollection) where TDocument : IMongoEntity
        {
            var docs = fromCollection.Find(whereClause).Documents;    
            return DocsToCollection<TDocument>(docs);
        }

        /// <summary>
        /// Documents to collection.
        /// </summary>
        /// <typeparam name="TDocument">The type of the document.</typeparam>
        /// <param name="documents">The documents.</param>
        /// <returns></returns>
        public static IList<TDocument> DocsToCollection<TDocument>(IEnumerable<Document> documents) where TDocument : IMongoEntity
        {
            var list = new List<TDocument>();
            var settings = new JsonSerializerSettings();
             foreach (var document in documents)
             {
                 var docType = Activator.CreateInstance<TDocument>();
                 docType.InternalDocument = document;
                 list.Add(docType);
            }
            return list;
        }

        /// <summary>
        /// Gets or sets the internal document.
        /// </summary>
        /// <value>The internal document.</value>
        public Document InternalDocument { get; set; }
    }
}

Here we have a property for each data item, which is generated from the JSON Document string.  Here I’ve added a new extension method to the Document type called “Field” which gets round the problem of having nulls in the dataset as a plain old ToString() will crash out.  The extension method is simply a new class file called “DocumentExtensions” and paste in the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;

namespace mongoTest.ExtensionMethods
{
        //Extension methods must be defined in a static class
        public static class DocumentExtensions
        {
            /// <summary>
            /// Fields the specified in the document being passed
            /// </summary>
            /// <param name="doc">The document</param>
            /// <param name="fieldName">Name of the field to be found</param>
            /// <returns></returns>
            public static string Field(this Document doc, string fieldName)
            {
                return (doc[fieldName] == null ? null : doc[fieldName].ToString());
            }
        }
}

Now back in our DevelopmentAdvisors class file we’re going to do some searching.

[Test(Description = "Search the da records for results")]
private void mongoTest_SearchForOneDA()
{
    Document spec = new Document();
    spec["Title"] = "Mr.";
    IList<DAClass> das = DAClass.GetListOf<DAClass>(spec, _daCollection);
    Assert.IsTrue(das.Count > 0, "No values found!");
    _log.DebugFormat("Name: {0} {1}", das[0].FirstName, das[0].SecondName);
}

This method will find all DA’s with a title of “Mr.” and return that information into the IList.

Finally here is a method that uses a bit of Linq to order the results.

[Test(Description = "Use Linq query")]
private void mongoTest_SearchForAllDAsAndOrder()
{

   ICursor cursor = _daCollection.FindAll();
    var orderedList = from da in DAClass.DocsToCollection<DAClass>(cursor.Documents)
                      orderby da.SecondName
                      select da;
    foreach (DAClass da in orderedList)
        _log.DebugFormat("Name: {0} {1}", da.FirstName, da.SecondName);
    Assert.IsTrue(cursor.Documents.Count() > 0, "No records in collection!");
}

The source code is available here.

Going “Old school” posting ASP.NET to ASP pages

Today I had an interesting problem, how can you get a Form post from ASP.NET to classic ASP?  At first this would seem to be a simple thing, just use Server.Transfer, well as I discovered you can’t do that.

Here is some example code:

default.aspx

<body>
    <form id="form1" runat="server">
        <asp:TextBox ID="send_this" runat="server"></asp:TextBox><asp:Button ID="send"
            runat="server" Text="send" onclick="send_Click" />
    </div>
    </form>
</body>

default.aspx.cs

    protected void send_Click(object sender, EventArgs e)
    {
        Server.Transfer("receive.asp");
    }

receive.asp

<body>
Got: <%=Request.Form("send_this")%>
</body>

Will return you an “Error executing child request for receive.asp” error.  Checking with Microsoft it turned out that this is by design.

Request.Redirect was no good, as it won’t send any information over HTTP and playing around the HTTP streams was fun but again would not pass control over to the other page.

One possible solution

The solution you can use is to capture the information on the way into your ASP.NET code and using JavaScript redirect the post to the other page.  First you will need to add the page body to ASP.NET by adding and id and runat=“server”.

<body id="body1" runat="server">
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="send_this" runat="server"></asp:TextBox><asp:Button ID="send"
            runat="server" Text="send" onclick="send_Click" />
    </div>
    </form>
</body>

Then in the ASP.NET code behind inject some javascript and an action method to your form.

    protected void send_Click(object sender, EventArgs e)
    {
        form1.Action="receive.asp";
        form1.Method = "post";
        body1.Attributes["onload"] = "document.forms[0].submit();";
    }
This will give you the best of both worlds… ability to use all ASP.NET controls on the main page and then post the values to classic ASP.  I can’t wait for the day there won’t be any need to use classic ASP again!

Thursday, January 21, 2010

Approval blogging permission

Had a problem today with permissions on a SharePoint Blog, by default blogs by contributors need to be approved by the Owner before being published.  This is a bit of a pain for Users, especially seeing that it’s only a small number of contributors anyway.  So to remove this open the “Posts” list, and select Settings/List Settings. Click Version Settings and the first option is “Content Approval”.  Set this to “No”.

Friday, January 15, 2010

Modifying a Sharepoint Master page

We had a request to change some of the base layouts of a Sharepoint publishing site today, which turned out to be a lot easier than first expected.  the requirement was to remove the Search feature from the home page.

image

First off I figured I’d need to find some setting for the site but there were none obvious that control this area.  I was just about the modify the code on the server when it occurred to me that this is probably something in the Master Page that can be changed.

Changing a Sharepoint Master Page

First off you need to find out which master page your site is using, do this by going to Site Settings/Master Page.

image

Here you can see that the “default.master” is being served up.

Next we need to get a copy of that page so we can make the changes.  Do this by going to the “Site Settings/Master pages and page layouts” option and download a copy of the master file.

image

Edit this file being sure to keep the placeholders in the correct place as these are needed by Sharepoint.  In this case I wanted to remove the User control that displayed the search box.

image

becomes:

image

Next you upload the new file under a different name, check it in and then approve it.  Once you have completed this task it will be made available in the Site Settings/Master list for selection.

image

select this and click Ok.  Refresh the home page and the search box has now been removed.  The really good thing about this is that now we know how we can change the entire layout of a sharepoint page, basically everything can be modified as long as the content placeholders are left in your Masterpage.

image

Thursday, December 17, 2009

Overlapping dates

Had an interesting problem a few nights ago which at first seemed like a really easy thing, but turned out to be a right pain in the face.  I figured I’d do a blog on it as it might help someone else later on.

A Simple Problem .. not !!

What I wanted to figure out was if two date ranges overlapped.  the logic of this was a lot harder to get my head around than I first expected.  As I was dealing with a range rather than static dates any of the existing DateTime functions were useless, also working with TimeSpans I find difficult.  The solution was to create a good Test case and keep playing around with the logic.

[Test(Description="Test over lapping dates")]
[TestCase("2009-12-17 13:00:00", "2009-12-17 17:00:00", "2009-12-17 13:00:00", "2009-12-17 13:00:00", true)]
[TestCase("2009-12-17 13:00:00", "2009-12-17 13:30:00", "2009-12-17 14:00:00", "2009-12-17 14:30:00", false)]
public void CompareDatesTest(string firstStartDate, string firstEndDate, string secondStartDate, string secondEndDate, bool expectedOverlap)
{
     DateTime first_start_date = DateTime.Parse(firstStartDate);
     DateTime first_end_date = DateTime.Parse(firstEndDate);
     DateTime second_start_date = DateTime.Parse(secondStartDate);
     DateTime second_end_date = DateTime.Parse(secondEndDate);
     //Compare
     Assert.IsTrue(DatesOverlap(first_start_date, first_end_date, second_start_date, second_end_date) == expectedOverlap, "booking overlap validation did not work");
}

the test case above will run two dates through my logic and return True if the first and second date rages overlap, False if they don’t.

My magic function

To work out the problem I had to convert the dates into Ticks.  This converts the date in the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.  Using that conversion I can easily use the numerical Great-than Boolean functions…. so after much playing around with IF statements I came up with:

private bool DatesOverlap(DateTime firstStart, DateTime firstEnd, DateTime secondStart, DateTime secondEnd)
{
     return (firstEnd.Ticks >= secondStart.Ticks) && (secondEnd.Ticks >= firstStart.Ticks);
}

After doing all this I then did a quick Google to find someone had come up with the same solution.  D’oh!.

Friday, December 11, 2009

Reflecting Classes and content

Yesterday someone asked for a way to print out all the contents of a class including the values that were current assigned.  This initially seemed like an easy thing to do, but turned out to be a little more complicated that expected.

The Easy Way

First thing we need to understand about .NET classes is that they are all inherited from a base type called Object.  This base object has a handy little method called ToString(), which will return you a string representation of that object.  You would have used this dozens of times in your code.

int X = 32;
Console.WriteLine("The value of X is:” + X.ToString());

image

This returns “The value of X is:32” which is fine for simple objects like int, float, DateTime but what about our custom classes?.  If you coded up something like the following:

public class SomeObject
{
    public string Firstname { get; set; }
    public string Surname { get; set; }
}

Now you’re test code would look like this:

SomeObject someObject = new SomeObject();
someObject.Firstname = "Tiberius";
someObject.Surname = "Percinus";
Console.WriteLine("The value of someObjectis: " + someObject.ToString());

image

This returns “The value of someObject is: UnitTests.ReflectionExample.SomeObject” which is not really helpful at all.  The normal way around this is to create an override on the ToString() method which returns a more meaningful result.

    public class SomeObject
    {
        public string Firstname { get; set; }
        public string Surname { get; set; }

        /// <summary>
        /// Local implementation of ToString based on class members
        /// </summary>
        public override String ToString()
        {
            StringBuilder sbuffer = new StringBuilder();
            sbuffer.Append("{");
            sbuffer.AppendFormat("Firstname = {0}, ", this.Firstname);
            sbuffer.AppendFormat("Surname = {0}, ", this.Surname);
            sbuffer.Append(" }");
            return sbuffer.ToString();
        }
    }

With this we create a large string with all of the local values returned in a meaningful way.

image 

This returns: “The value of someObject is: {Firstname = Tiberius, Surname = Percinus,  }”.

The Fancy Way

“OK”, I was told, “But this object has only two data items what happens if I’ve got 180?”.  Which is a very valid question.  The best answer to this is to use a technique called “Reflection” which allows you to crack open a class to access its values.

    using System.Reflection;

    public class SomeObject
    {
        public string Firstname { get; set; }
        public string Surname { get; set; }
         //  ……  assume another 180 properties are here ……  //
        public string LastProperty { get; set; }

        /// <summary>
        /// Local implementation of ToString based on reflection
        /// </summary>
        public override String ToString()
        {
            StringBuilder sbuffer = new StringBuilder();
            sbuffer.Append("{");
            PropertyInfo[] properties = this.GetType().GetProperties();
            foreach (PropertyInfo prop in properties)
            {
                sbuffer.AppendFormat("{0} = {1}, ", prop.Name, prop.GetValue(this, null));
            }
            sbuffer.Append(" }");
            return sbuffer.ToString();
        }
    }

Using the foreach loop and the GetType().GetProperties() methods we get an array of all properties in the class.  Then we just have string builder join them all together.

image

This will now return: “The value of someObject is: {Firstname = Tiberius, Surname = Percinus, … and on for all the properties … , LastProperty = ,  }”.

So why not do this all the time? Well the simple reason is that reflection adds a little more load on the processor, so for the majority of cases it’s best to stick to “the easy way”, unless you have a very, very large set of properties.

Tuesday, December 8, 2009

Conditional Pre-Complication is good for what ails you.

Recently found a comments in the code base that stated "Remove on Live!" in the description.  It was perfectly valid code, but unfortunately but there was no way any developer (other than the person who wrote it in the first place) will remove the code before compiling.  The good news is that there is a solution to this problem and that’s "Conditional Pre-Compilation Symbols".  That all sounds very complicated but its really simple.  It means you can mark a section of code, so that it is placed within a specific assembly.

Simple Conditional Pre-Complication

Here is an example of a function that will appear in all environments and assemblies.

//***********************************
// Test code; remove when running on live.
//***********************************
  if (X==Y || Z==A)

{  
      int AnotherX = Convert.ToInt32(X)|
      _log.DebugFormat("AnoterX has been set to {0}", X);
  }

Pleacing this within a Conditional Pre-Compilation Symbols would look like this:

#if(DEBUG)

   //***********************************
   // Test code; remove when running on live.
   //***********************************
   if (X==Y || Z==A
   {  

      int AnotherX = Convert.ToInt32(X)|
      _log.DebugFormat("AnoterX has been set to {0}", X);
    }

#endif

This means that the code still works fine on you're local PC and Miranda, but now that we're using CC.NET to do a "Release" build, this code will not be included in the assembly.

Doing something more funky

You're not limited to just removing code, you can also directly change the code as shown below:

#if(DEBUG)

      _log.DebugFormat("This is Debug Code");

#else

      _log.DebugFormat("This is Release Code");

#endif

You are also not limited to only using the pre-configured "DEBUG" or "RELEASE" variables, you can also set your own.  To do this, open the property page for your project and select the Build tab.  Here you can see a field called "Conditional compilation symbols".  Here you can enter a value like "Design", but you should also note the Configuration currently selected as this is important. 

image

Now in your code you can do this….

  #if(Design)

      _log.DebugFormat("This is only run when Design is entered in the properties");

  #endif

You can of course add as many build configurations as you wish, e.g. “Debug”, “Test”, “Stage”, “Live” etc. and CC.NET will happy ensure that each is built in turn correctly.