When analogies break down…

USB 3.0 (running at a mind-numbing 5.0 Gbps) is just around the corner, and it got me thinking about the similarities of version numbers vs. features to the .NET Framework.  Let’s have a look so far:

Version USB .NET Framework
v1.0 First release, 1.5 Mbps First release, slow and buggy
v1.1 Full speed, 12 Mbps Many improvements, but no major leaps in technology
v2.0 High speed, 480 Mbps Significantly improved performance and development speed, reduces LoC required by (up to) 80%
v3.0 SuperSpeed 5.0 Gbps WPF, WCF, WF, etc.

OK, so .NET 3.0 was just a few layers on top of v2.0, while USB 3.0 is an order of magnitude faster. The real question is however, what will USB v3.5sp1 bring us?

Advertisements

The IEqualityComparer in action

I recently had the situation where I had a class similar to the following:

public class Item
{
    public Guid ItemID { get; set; }
    public string ItemName { get; set; }
    public IList Categories { get; set; }
}

public class Category
{
    public Guid CategoryID { get; set; }
    public string CategoryName { get; set; }
}

Data for the application was pulled out of a Linq to SQL class, working off a SQL database.  (I don’t want to get into a discussion on the semantics of my design choice – perhaps Items should be members of Categories instead of the other way around.  Just enjoy the show for now…)

What I wanted to do was to filter a Linq query from the database (containing IQueryable<Item>) for items that contained Categories with a given CategoryID.  No problems!   Just run up a Linq to SQL query to get the Category instance matching that CategoryID as follows:

var myCategory = (from c in datacontext.dbCategories
                  where c.ID == myCategoryID
                  select new Category
                  {
                      CategoryID = c.ID,
                      CategoryName = c.Name
                  }).Single();

Note that the filter as shown below won’t work on an IQueryable<Item> (due to the Contains() clause), so we’ll evaluate the incoming IQueryable<Item> as it comes in, and (for convenience) convert it back to IQueryable on the way out.  We’ll implement the method as an extension method, because we can.

public IQueryable FilterByCategory(this IQueryable qry, Category cat)
{
    return (from i in qry.ToList()        // Evaluate the qry
            where i.Categories.Contains(cat)
            select i).AsQueryable();
}

Now, this is all fine, as far as it goes.   Except for one small thing.

It didn’t work.

My result set was empty.  Always.

So what’s going on?  Basically, here’s the thing.  Have a look at the following code fragments:

int x = 7;
int y = 7;
Debug.Assert(x == y);    // Assert is true

class MyObject
{
    public int Value;

    public MyObject(int val)
    {
        Value = val;
    }
}
MyObject a = new MyObject(7);
MyObject b = new MyObject(7);
Debug.Assert(a == b);    // Assert fails!

It may seem obvious, but the reason the second Assert fails is that, despite having the same internal value, a and b are not the same! And this is the problem with my filter query above.   Despite the Category instance I received from the SQL query having the same internal values as (perhaps) a Category in the Categories property of an Item, they are not the same object and so the comparison will fail.
What we need is some way of telling .NET that two instances of an object are the same, even if they are different objects, and this is where the IEqualityComparer comes in.  We can create the following class:

class CategoryComparer : IEqualityComparer
{
    #region IEqualityComparer Members

    public bool IsEqual(Category x, Category y)
    {
        return x.CategoryID == y.CategoryID;
    }

    public int GetHashCode(Category obj)
    {
        return obj.CategoryID.GetHashCode();
    }

    #endregion
}

We have created a class that says that two instances of Category are equal when their CategoryID values match, and have based their Hash Code on the CategoryID value rather than the instance itself.  All we need to do now is to plug it in to the query, as follows:

public IQueryable FilterByCategory(this IQueryable qry, Category cat)
{
    return (from i in qry.ToList()        // Evaluate the qry
            where i.Categories.Contains(cat, new CategoryComparer())
            select i).AsQueryable();
}

Voila!  .NET is a wonderful environment, but there are always a few gotchas lying around for the unsuspecting.  Work through probelms methodically, and you’ll find there’s always a way.

Premature Optimization

Aren’t the people at Microsoft nice?  Apparently they made Internet Explorer 8 just right for NineMSN.

optimised

optimised2

(Maybe a more truthful approach would be to say that the NineMSN site is optimized for IE8?  But why let the facts get in the way of a good story?)

Extending the Microsoft ASP.NET Membership Provider

Microsoft did a wonderful thing when they gave us the ASP.NET Membership Provider.  With a single command line call to aspnet_regsql.exe, we can have a fully implemented membership system providing persistence of usernames, one-way encrypted passwords, question / answer combinations, account lockout, roles, personalization, and all sorts of other useful (and not-quite-so-useful) features.

However, there is also a bit missing.  Most websites will also want to store a bit more information about their users, such as first / last names, maybe their address, birthdate, favorite color, etc, etc.  For Microsoft to have supplied fields for all of this would have made things quite unwieldy, to say the least, but fortunately there is an easy way to extend the provider.

DISCLAIMER: Before I begin, let me say that this is not the only way to extend the provider, nor is it necessarily the best.  It is quite simple, however, and therein lies it’s appeal…

Database Tables

Once you have decided which fields you wish to add to the membership provider, create a table that includes these fields along with an ID field (you can call it what you want, but ID or UserID are obvious choices) of type uniqueidentifier.

The value in the ID field will be used to link to the ASP.NET Membership Provider tables (the UserId field in aspnet_Users).  You can create a relationship between these fields if you want, but I don’t worry about it as it saves messing with the auto-generated tables.  The table structure I am using for this example is as shown below:

databasetables

MyUser class

Create a class for your membership provider, called something like MyUser.  It’s structure should be something like the following:

public class MyUser
{
    public Guid ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    public MembershipUser User
    {
        get { return Membership.GetUser(ID); }
    }

    public static bool IsLoggedIn
    {
        get
        {
            MembershipUser u = null;
            try
            {
                u = Membership.GetUser();
            }
            catch
            {
            }

            return (u != null);
        }
    }

    public static bool IsAdmin
    {
        // Assumes a role called "Admin"
        get { return (IsLoggedIn && Roles.IsUserInRole("Admin")); }
    }

    public bool IsUserAdmin
    {
        get { return (Roles.IsUserInRole(User.UserName, "Admin")); }
    }

    private static UsersService _service;

    private static UsersService Service
    {
        get
        {
            if (_service == null)
                _service = new UsersService();

            return _service;
        }
    }

    public static MyUser GetUser(Guid userId)
    {
        return Service.GetUser(userId);
    }

    public static MyUser GetCurrentUser()
    {
        try
        {
            return Service.GetUser((Guid)Membership.GetUser().ProviderUserKey);
        }
        catch
        {
            return null;
        }
    }

    public static MyUser AddNewUser(string username, string password, string email, string firstName, string lastName, out MembershipCreateStatus createStatus)
    {
        MembershipUser u = Membership.CreateUser(username, password, email, null, null, false, out createStatus);
        if (u != null)
        {
            MyUser user = Service.AddUser((Guid)u.ProviderUserKey, firstName, lastName);
            return user;
        }
        else
            return null;
    }

    public static MyUser ConfirmUser(Guid id)
    {
        var user = Service.GetUser(id);

        if (user != null)
        {
            if (user.User.IsApproved)
                user = null;
            else
            {
                var mu = user.User;
                mu.IsApproved = true;
                Membership.UpdateUser(mu);
            }
        }
        return user;
    }
}

Okay, there’s quite a bit there, so let’s have a look at the various parts.

Lines 3-5 provide the extended field set we want, including the Guid field (which maps to the SQL uniqueidentifier) to link to the ASP.NET Membership Provider.  Lines 7-10 just provide a quick way to get a user’s full name, while lines 12-15 provides a simple way to get to the ASP.NET Membership User.

Following this are a few static and instance methods for getting the status of a user:  Lines 17-32 is a static call to see if anyone is currently logged in;  Lines 34-38 can be used to see if the currently logged in user is a member of the Admin role (you can use several of these methods for different roles), while lines 40-43 is an instance method to see if a particular user is a member of the Admin role.

Line 45 introduces a reference to a UsersService class.  We’ll be using this service class to provide access to our database repository, and I’ll provide full details below.  This is a static field, and lines 47-56 essentially provide a single property accessor to this field (sort of a Singleton, even though it’s all static).  Following this are several methods for CRUD (Create Read Update Delete – okay, there’s no Delete here, but you get the idea..).  The only surprise here is the ConfirmUser method.  I like users to confirm their email address by clicking a link in an email sent to them, so create their user as Unapproved.  When they click on a link in an email (which contains their UserID as a parameter), the ConfirmUser method is called with that ID, which updates their status.

Now, about that UsersService…

The UsersService class

The UsersService relies on a repository class, so let’s get that first.  I’m using Linq to SQL, so create a new LINQ to SQL class, and let’s call it LinqUsers.dbml.  Drag the User table (from the top of this post) onto the designer and check your namespaces if required.  I have named my data context ‘DB’ to make things easy.  Now, here’s the UsersRepository code…

public class UsersRepository
{
    public IQueryable<MyUser> GetUsers()
    {
        DB db = new DB();
        return from u in db.Users
               orderby u.LastName
               select new MyUser
               {
                   ID = u.ID,
                   FirstName = u.FirstName,
                   LastName = u.LastName
               };
    }

    public MyUser AddUser(Guid id, string firstName, string lastName)
    {
        MyUser result = null;

        using (DB db = new DB())
        {
            User user = new User();
            user.ID = id;
            user.FirstName = firstName;
            user.LastName = lastName;

            db.Users.InsertOnSubmit(user);
            db.SubmitChanges();

            result = GetUsers().ByID(id);
        }

        return result;
    }

    public bool RemoveUser(Guid id)
    {
        bool result = false;

        using (DB db = new DB())
        {
            var del = from u in db.Users
                      where u.ID == id
                      select u;

            db.Users.DeleteAllOnSubmit(del);
            db.SubmitChanges();

            result = true;
        }

        return result;
    }
}

The only thing this needs is the ByID() filter, as follows:

public static class UserFilters
{
    public static MyUser ByID(this IEnumerable<MyUser> qry, Guid id)
    {
        return (from u in qry
                where p.ID == id
                select p).SingleOrDefault();
    }
}

Now, the UsersService class can be defined as follows:

public class UsersService
{
    UsersRepository _repository = new UsersRepository();

    public IList<MyUser> GetUsers()
    {
        return _repository.GetUsers().ToList();
    }

    public MyUser GetUser(Guid id)
    {
        return _repository.GetUsers().ByID(id);
    }

    public MyUser AddUser(Guid id, string firstName, string lastName)
    {
        return _repository.AddUser(id, firstName, lastName);
    }

    public bool RemoveUser(Guid id)
    {
        MyUser user = _repository.GetUsers().ByID(id);
        if (user == null)
            return false;

        MembershipUser mu = user.User;
        _repository.RemoveUser(id);
        return Membership.DeleteUser(mu.UserName, true);
    }
}

This should all be fairly self explanatory.  The reference to the UsersRepository could be taken through a constructor, and the UsersRepository should really implement an IUsersRepository interface, so that IOC and Dependency Injection can be used to enable unit testing, but if you need it, you’ll know how to do it (yes, I do it on my own code, so don’t beat me…).

So that’s it, really.  While there is a fair whack of code in there, it’s all fairly simple stuff.  Linq to SQL makes the database work easy, and the database and MyUser class are easily extendable to provide for the management of more fields and roles.  Feel free to leave comments if this has helped, or to offer suggestions for how this could be improved.

SimpleSlideShow update…

Ran into a problem with SimpleSlideShow recently where a flash drive contained files with a .jpg extension, but that were not JPEG files. While I don’t know exactly where they came from, the best solution was to add some code to SimpleSlideShow that would check the validity of alleged JPEG images before importing them. The result is at https://simpleslideshow.svn.codeplex.com/svn, version 1.1.

Yes, but why is his hair green??

Overheard in a local shopping centre:

    FRIEND: Oh, so you’ve had your baby?

    MUM: Yes.

    FRIEND: And what did you have?

    MUM: A boy.

    FRIEND: Another boy?  Oh, you could start your own soccer field!

Err, yeah.

InsertScript for ASP.NET MVC

I recently had a situation where a custom control I was using in a page required jQuery.  Since I like the idea of keeping such controls self-contained, I added the usual <script type="text/javascript" src="jquery-1.2.6.min.js"></script> tag.

No problem – until I then loaded a page that included this control AND also had its own requirement for jQuery.  It seems that jQuery doesn’t like begin included twice, so I had a choice.  I could:

  • Include jQuery once in the header (or wherever) of each page (i.e. in the Master Page), hence breaking the self-containment of my control, or;
  • Write a helper method to keep track of which script files had been included in each page and hence allow a script file to only be included once per request.

It should come as no surprise (as otherwise there would be no point in this post) that I went for the second option.

The HttpContext object has an Items collection, and since the HttpContext has a lifetime of one request, we can use this Items collection to keep track of our included files.  Just add the following static method to a static class (Don’t you just love Extension Methods!):

public static string InsertScript(this HtmlHelper helper, string jsFile)
{
    const string RESID = "__resources";

    List<string> _resources = (List<string>)helper.ViewContext.HttpContext.Items[RESID];
    if (_resources == null)
    {
        _resources = new List<string>();
        helper.ViewContext.HttpContext.Items[RESID] = _resources;
    }

    string url = ScriptUrl(jsFile);
    if (!_resources.Contains(url.ToLower()))
    {
        _resources.Add(url.ToLower());
        return "<script type=\"text/javascript\" src=\"" + url + "\"></script>";
    }
    else
        return "";
}

Notice the call to ScriptUrl(jsFile) – this is just a static helper method to map javascript file names to the Scripts folder in my web app. It’s up to you whether you use such a method.

It’s now just a matter of calling this from your .aspx pages, replacing the usual
<script type="text/javascript" src="myjavascriptfile.js"></script>
with
<%= Html.InsertScript("myjavascriptfile.js") %>