Hugoware

The product of a web developer with a little too much caffeine

Archive for February 2010

Enumeration Extensions 2.0

with 8 comments

A while back I had posted some code about making it easier to work with enumerated types — Especially with the Flags attribute. An experienced programmer won’t have a hard time understanding all the voodoo magic behind the the bitwise operators but for the rest of us then something a little easier to read is always welcome.

The problem with the previous code is that it was created to work with the project I was currently working on so I didn’t put a lot of effort into making it work with multiple types. That said, below is the official version 2.0 of the EnumerationExtensions class.

using System;

namespace Extensions {

    /// <summary>
    /// Extension methods to make working with Enum values easier
    /// </summary>
    public static class EnumerationExtensions {

        #region Extension Methods

        /// <summary>
        /// Includes an enumerated type and returns the new value
        /// </summary>
        public static T Include<T>(this Enum value, T append) {
            Type type = value.GetType();

            //determine the values
            object result = value;
            _Value parsed = new _Value(append, type);
            if (parsed.Signed is long) {
                result = Convert.ToInt64(value) | (long)parsed.Signed;
            }
            else if (parsed.Unsigned is ulong) {
                result = Convert.ToUInt64(value) | (ulong)parsed.Unsigned;
            }

            //return the final value
            return (T)Enum.Parse(type, result.ToString());
        }

        /// <summary>
        /// Removes an enumerated type and returns the new value
        /// </summary>
        public static T Remove<T>(this Enum value, T remove) {
            Type type = value.GetType();

            //determine the values
            object result = value;
            _Value parsed = new _Value(remove, type);
            if (parsed.Signed is long) {
                result = Convert.ToInt64(value) & ~(long)parsed.Signed;
            }
            else if (parsed.Unsigned is ulong) {
                result = Convert.ToUInt64(value) & ~(ulong)parsed.Unsigned;
            }

            //return the final value
            return (T)Enum.Parse(type, result.ToString());
        }

        /// <summary>
        /// Checks if an enumerated type contains a value
        /// </summary>
        public static bool Has<T>(this Enum value, T check) {
            Type type = value.GetType();

            //determine the values
            object result = value;
            _Value parsed = new _Value(check, type);
            if (parsed.Signed is long) {
                return (Convert.ToInt64(value)& (long)parsed.Signed) == (long)parsed.Signed;
            }
            else if (parsed.Unsigned is ulong) {
                return (Convert.ToUInt64(value) & (ulong)parsed.Unsigned) == (ulong)parsed.Unsigned;
            }
            else {
                return false;
            }
        }

        /// <summary>
        /// Checks if an enumerated type is missing a value
        /// </summary>
        public static bool Missing<T>(this Enum obj, T value) {
            return !EnumerationExtensions.Has<T>(obj, value);
        }

        #endregion

        #region Helper Classes

        //class to simplfy narrowing values between 
        //a ulong and long since either value should
        //cover any lesser value
        private class _Value {

            //cached comparisons for tye to use
            private static Type _UInt64 = typeof(ulong);
            private static Type _UInt32 = typeof(long);

            public long? Signed;
            public ulong? Unsigned;

            public _Value(object value, Type type) {

                //make sure it is even an enum to work with
                if (!type.IsEnum) {
                    throw new ArgumentException("Value provided is not an enumerated type!");
                }

                //then check for the enumerated value
                Type compare = Enum.GetUnderlyingType(type);

                //if this is an unsigned long then the only
                //value that can hold it would be a ulong
                if (compare.Equals(_Value._UInt32) || compare.Equals(_Value._UInt64)) {
                    this.Unsigned = Convert.ToUInt64(value);
                }
                //otherwise, a long should cover anything else
                else {
                    this.Signed = Convert.ToInt64(value);
                }

            }

        }

        #endregion

    }

}

This code results in a much easier to read syntax and is mildly better at avoiding type casting issues. Instead of defaulting to int as the other version did, this version attempts to decide between Int64 or UInt64 since either could meet the requirements for any of their lesser counterparts.

Now we can use syntax similar like you see below…

//create the typical object
RegexOptions options = RegexOptions.None;

//Assign a value
options = options.Include(RegexOptions.IgnoreCase); //IgnoreCase

//Or assign multiple values
options = options.Include(RegexOptions.Multiline | RegexOptions.Singleline); //IgnoreCase, Multiline, Singleline

//Remove values from the list
options = options.Remove(RegexOptions.IgnoreCase); //Multiline, Singleline

//Check if a value even exists
bool multiline = options.Has(RegexOptions.Multiline); //true
bool ignoreCase = options.Missing(RegexOptions.IgnoreCase); //true

Anyways, a whole lot easier to read in my opinion. Enjoy!

Advertisements

Written by hugoware

February 23, 2010 at 10:26 pm

CSMongo Driver – Part 1

with 8 comments

My new project CSMongo, a Mongo driver for .NET, is now online! Check it out!

Lately, I’ve been spending a lot of my time writing a driver for Mongo in C#. The primary goal was to make it comfortable to work with dynamic objects in a static language — which is a project I’ve worked on before in the past.

I still have a lot of code to write but I’m getting close to a working version that I can get out the door. This post discusses how my Mongo driver works currently works.

Dynamic In Static-Land

The next version of .NET introduces the dynamic keyword but until then I needed to build a class that worked with C# and was dynamic enough to work with Mongo. The main hurdle is that a ‘dynamic’ isn’t just a dictionary of key/value pairs. Instead, an object can be nested several level deep.

Additionally, data types between static languages and dynamic languages are also handled differently. Think about numbers for a second. In C# you have single, double, float, decimal, etc. – But Javascript? Yeah, you have Number — A heck of a lot easier to deal with but can cause problems when trying to pull a value back out of your object.

Below are some samples how you can create Mongo document with this driver.


//Creating And Assigning Vaues
//===============================
MongoDocument document = new MongoDocument(new {
	name = "Hugo",
	age = 29,
	admin = true
	});
	
//make changes and assign new values using +=
document += new {
	age = 30,
	settings = new {
		color = "red",
		width = 700
	},
	permissions = new string[] {
		"read", "write", "delete"
	}
};

//make changes using the path to a field
document["name"] = "Hugoware";
document["settings.color"] = "blue";

//or create new objects entirely
document["settings.urls.favorite"] = "http://hugoware.net";

//remove fields using -= and a string or string array
document -= "name";
document -= "settings.color";

//or remove multiple items
document -= new string[] { "age", "permissions" };

//also use typical methods to perform same changes
document.Set("name", new {
	first = "Hugo",
	last = "Bonacci"
});

document.Remove("settings", "name", "age");


//Merging multiple documents
//===============================

MongoDocument first = new MongoDocument();
MongoDocument second = new MongoDocument(new {
	name = "Hugo"
});

//merge either of the two ways listed
first += second; /* or */ first.Merge(second);
string name = first["name"]; // "Hugo"

This class allows for a lot of flexability to write to an object and make changes to it without needing to know about the object.

Going back to data types, each object has a value handler that manages working with the type and performing conversions. You are also able to provide a default value in case the property requested doesn’t exist or can’t be converted.

Here are a few more examples of accessing values types.

//Accessing Typical Values
//===============================

//create an empty object and access not real values
MongoDocument document = new MongoDocument();

//accessing by default property returns an object
//NOTE: Using Get() is better for accessing values
int a = (int)document["not.real"]; // *crash* null
int? b = document["not.real"] as int?; // null

//accessing by Get<T>() returns default(T)
int c = document.Get<int>("not.real"); // 0

//or define a fallback value
int d = document.Get<int>("not.real", 55); // 55

//next examples are assigned '54.342' which defaults to 'double'
document.Set("value", 54.342");

//access by default property
double e = (double)document["value"]; // 54.342

//or use the Get method that allows a cast request type
double f = document.Get<double>("value"); // 54.342
int g = document.Get<int>("value"); // 54
bool h = document.Get<bool>("value"); // true
string i = document.Get<string>("value"); // "54.342"

//Accessing Uncommon Values
//===============================

doc["count"] = long.MaxValue;
int a = (int)doc["count"]; // *crash*
int b = doc.Get<int>("count"); // 0
long c = doc.Get<int>("count"); // 0
long d = doc.Get<long>("count"); // 9223372036854775807

doc["count"] = uint.MaxValue;
uint e = doc.Get<uint>("count"); // 4294967295
long f = doc.Get<long>("count"); // 4294967295
decimal h = doc.Get<decimal>("count"); // 4294967295
int g = doc.Get<int>("count", int.MaxValue); // 0 (no default!)

As you can see there are a lot of different ways data types like this could play out. Failed conversions tend to be easier to detect than incorrect conversions. I suspect this will improve over time.

If you don’t like the way conversions are handled for a certain type, or if you have a custom class you want special rules created for, can define your own custom DataTypes that handle the formatting, parsing and saving to the database.

Database Queries

If you’ve grown accustomed to SQL queries then you’re going to be in a world of hurt with Mongo. They make sense after a bit of time but not like the somewhat human-readable format of a standard SQL query.

In this driver I’ve attempted to to make a LINQ-ish style query builder. This builder is used in a variety of places depending on the purpose (such as selection as opposed to updating).

Here are some query examples.

MongoDatabase database = new MongoDatabase("100.0.0.1", "website");

//simple chained query
database.From("users")
    .Less("age", 50)
    .EqualTo("group", "admins")
    .Select();

//anonymous types for parameters
database.From("users")
    .In("permissions", "write", "delete")
    .Select(new {
        take = 30
    });

//updating without a record using a
//query selector and update arguments
database.From("users")
    .Match("name", "^(a|b|c)", RegexOptions.IgnoreCase)
    .Update(new {
        enabled = false,
        status = "Disabled by Admin"
    });

Mongo queries appear to be missing several pretty important features that might make it a little more difficult for you to find records. I figured out how to use jLinq directly within Mongo so I’m going to see if version two might include a little jLinq supportHow cool would that be?

I’m hoping I’ll have the first version of my driver released sometime this week so check back for more news on the progress!

Written by hugoware

February 21, 2010 at 10:31 pm

jLinq in MongoDB (Oh snap!!)

with 9 comments

My new project CSMongo, a Mongo driver for .NET, is now online! Check it out!

Yeah, you read that right – jLinq in MongoDB!

Lately I’ve been working on a Mongo database driver and I got to thinking — Since I can use Javascript with MongoDB then I wonder if I could use jLinq to write queries? As it turns out the answer is yes!

… and if you don’t know what jLinq is… – jLinq is a javascript query language, similar to the LINQ project created by Microsoft, for JSON data which was designed to run within web pages using Javascript

Getting Started

I’m not really sure how you can get a Javascript library to load directly into MongoDB but for now I was simply copying and pasting the existing jLinq packed library into the command line and allowing it to evaluate the script — and that is it! You can use jLinq right away!

You should be aware though that you can’t just evaluate results directly. You actually need to call the toArray() function on each of them to see the results. So for example, your query would look something like…

jLinq.from(db.users.find().toArray()).startsWith("name", "h").select();

You don’t need to actually do anything with the results since they are automatically displayed on the screen for you.

So far everything works. I could do standard queries, use the OR operator, reorder records, join different databases, perform comparisons against sub-properties — really everything I’ve tried has worked just the way I’d expect it to!

Granted, database and collection names are going to be different, here are some interesting queries you can try with your database.

//Selects records where the name starts with a, b or c (case-insensitive)
jLinq.from(db.users.find().toArray())
    .startsWith("name", "a")
    .or("b")
    .or("c")
    .select();

//selects users older than 50 and are administrators then orders them by their names
jLinq.from(db.users.find().toArray())
    .greater("age", 50)
    .is("admin")
    .orderBy("name")
    .select();

//performs a join against another database to get locations
//and then queries the location to find users that live in 'texas'
//and then selects only the name of the person and location
jLinq.from(db.users.find().toArray())
    .join(db.locations.find().toArray(), "location", "locationId", "id")
    .equals("location.name", "texas")
    .select(function(rec) {
        return {
            person: rec.name,
            location: rec.location.name
        };
    });

More On jLinq

Unfortunately, it isn’t possible to go over all of the cool stuff you can do with jLinq – but here are some screencasts and blog posts that you can read that might help you get started.

jLinq Project Page
Screencast 1 – Getting Started
Screencast 2 – Extending jLinq (Custom commands)
Screencast 3 – Modifying Live Data In A Query (Joins, Assignment)
Screencast 4 – jLinq 2.2.1 (Updates)

Anyways, for now I’m not sure how to integrate jLinq into Mongo queries but keep an eye for future blog posts as I find out more.

Written by hugoware

February 14, 2010 at 11:45 pm

Using MongoDB With Visual Studio

with 6 comments

My new project CSMongo, a Mongo driver for .NET, is now online! Check it out!

I recently found out about MongoDB and decided to check it out and so far I’ve been really impressed. The most interesting thing about MongoDB that it doesn’t work like a normal database — there aren’t really any schemas for any of the “tables”. In fact, you can make changes to the structure of any record at any time without affecting the rest of the “table”.

Getting Started

Here are a few steps I used to get MongoDB running and testable from my Visual Studio. To keep my main computer clean I used a virtual instance of Ubuntu to host the “database server”.

This part might take a little bit of time but start by downloading VirtualBox and Ubuntu 9.10 (You don’t need to download Mongo just yet). Once everything is downloaded install and configure Ubuntu but don’t start it up right away (you need to configure some stuff).

You’re going to want to make sure that your PC can connect to the virtual instance on the standard MongoDB port (unless you change it of course). If not, open a command prompt (on the host system) and then run the following commands (from the VirtualBox directory).

VBoxManage setextradata UbuntuDev "VBoxInternal/Devices/pcnet/0/LUN#0/Config/MongoDB/HostPort" 27017
VBoxManage setextradata UbuntuDev "VBoxInternal/Devices/pcnet/0/LUN#0/Config/MongoDB/GuestPort" 27017
VBoxManage setextradata UbuntuDev "VBoxInternal/Devices/pcnet/0/LUN#0/Config/MongoDB/Protocol" TCP

This example uses the same name (UbuntuDev) that I used for the screenshot example above. Make sure you use the correct name when setting yours up.

It is also worth mentioning that I had to use a Bridged Connection for my Network connection so I’d get an IP address from my wireless. But, if you aren’t on a wireless network… say, like your in-laws house for several hours… you can use Host Only Adapter so you can keep working… just sayin’…

Inside Ubuntu

Once you’ve successfully setup your Ubuntu system go on and download the MongoDB binaries. I don’t know the correct location to install these files so I placed them inside /etc/mongodb.

If you’ve never used Linux before then warm up your typing fingers and open a terminal window (Applications > Accessories > Terminal). Start typing in the following commands…

sudo bash
mkdir /data
mkdir /data/db
mkdir /etc/mongodb
chmod a=rwx /etc/mongodb

Note: This is certainly not the recommended security setup for this folder but for our testing purposes it is sufficient.

At this point we can revert back to our lazy Windows ways and drag the contents of the .tgz file into the /etc/mongodb directory. Once we have the contents copied over switch back to the terminal window and then type…

sudo /etc/mongodb/bin/mongod

And you should see something like the screenshot below…

Once you see this message you should be ready to test from Visual Studio but you can always test it from Ubuntu by opening a new Terminal window and typing…

sudo /etc/mongodb/bin/mongo

Which allows you to enter commands and make changes to the database similar to the online demo on their website.

Connecting Via Visual Studio

I haven’t found much for C# code to connect to Mongo but there is currently a project hosted on GitHub that allows you to perform queries and edit documents. It is a mess of code – but it *does* at least work… mostly… (nothing personal guys) 😉 Here is a simple example of how to use the code…

//connect to the source (IP address of virtual)
Mongo mongo = new Mongo("100.0.0.1");
mongo.Connect();

//get the database and 'table'
Database website = mongo.getDB("website");
IMongoCollection users = website.GetCollection("users");

//make a new document of information
Document user = new Document();
user["name"] = "Hugoware";
user["age"] = 29;
user["isAdmin"] = false;

//then save the document
users.Insert(user);

If you still have your Terminal window up then you might have noticed messages listed in response to your update. If you still have the MongoDB command line up you can view your changes by entering in a few commands. For example, to see the database I just created in the sample above I would enter…

use website
db.users.find()

And I would get a response similar to this…

What Is Next?

Personally, I think MongoDB is going to end up being huge. The main problem I see for C# developers is that MongoDB really favors Dynamic Languages which isn’t really a strong suit of the language.

Right now I’m working on my own driver to talk to Mongo that heavily relies on my AnonymousType code (anybody remember that old stuff?). It is still early on in the project so if you’re interested in helping feel free to contact me.

Written by hugoware

February 9, 2010 at 11:04 am

Testing ASP.NET Sites for iPhone

with one comment

Writing a iPhone version of a website it can be a slight pain. After writing some code you have to upload it to a public location so you can browse to it with your phone. Even though you can browse the site you are still somewhat limited in your debugging options once your site is on a remote server.

You might have read before how impressed I am with the Mono project. You can fire up a Mac, import and existing .NET project and more than likely it is going to run just fine.

So here is the cool thing – You have a pretty good .NET IDE (MonoDevelop) on the Mac and you also have a built-in iPhone simulator. Browse to the local test server and…

Cool!

I’m not sure all the options available for debugging in MonoDevelop (or mostly for the ASP.NET side) but since you are running the test server then you have more options available to you than if it ran on another website (for example writing debugging messages)

Naturally, this will work for regular ASP.NET sites as well as MVC. In fact, anything that runs a local server for testing should be able to do this without a problem.

Anyways, certainly not the greatest thing ever but something fun to mess around with and another example of just how useful Mono can be.

Written by hugoware

February 4, 2010 at 10:58 pm