December 30, 2009

Getting the Cisco AnyConnect VPN adapter working with Kaspersky Anti-Virus

I hadn't used my VPN connection to the office in a while and for the past week I've been having problems connecting. I haven't had time to sort it out until this morning and as I had problems nailing down why I wasn't able to connect I thought I'd share the solution in case anyone else has the same issue and set up.

I've been connecting to the office using the Cisco AnyConnect VPN Client and after entering my username and password and clicking connect my system administrator tells me that the authentication at the server end was successful. But still I get the message when I try and connect:

"The VPN client is unable to establish a connection."

No reason is provided and delving through the log file didn't indicate anything sinister either.

By complete dumb luck, I remembered that I'd installed Kaspersky Anti-Virus about a month ago - maybe a bit longer. I disabled virus scanning and attempted to connect again and the connection was successful.

Surfing without protection enabled isn't something I particularly want to do, so I needed to figure out how to go about fixing this. It turns out the solution is simple - disable port scanning on port 443, that is all.

  1. Fire up the Kaspersky GUI.
  2. Select the Online activity option.
  3. In the online activity window that follows, select the Web Anti-Virus option.
  4. In the web anti-virus page select Network from the options down the left hand side.
  5. The network settings options will now be displayed on the right side of the window.
  6. In the Monitored ports section, select Monitor selected ports only and click the Select... button.
  7. The Network ports window will now be displayed.
  8. In the top part of the window, scroll down until you find HTTP SSL (https://) in the list - port 443.
  9. Uncheck this port and click OK to confirm the setting change and close the network window.
  10. Click the OK button to close the web anti-virus window.
  11. Click the Close to close the online security window.
  12. Click the red X in the top right corner of the Kaspersky Anti-Virus window to close the GUI

You should now find that your Cisco AnyConnect VPN adapter works again now even when Kaspersky Anti-Virus and Online Scanning is enabled.

December 19, 2009

Women in technology

Yesterday the legendary author, mentor and teacher Kathy Sierra (@KathySierra) made a comment on Twitter about women in technology, and I will quote, and I hope Kathy won't take issue with this:

"Tired of being a Woman In Tech. I'm a programmer. I'm female. Does it have to be SO political/significant? Sometimes a coder's just a coder."

I have a few thoughts on the subject, and writing them all down on Twitter in any sort of coherent fashion with everyone else's interjections is a pain in the neck, so I will do it here instead.

While I understand the sentiment, it can be a drag to have so much responsibility on your shoulders all the time - especially when you're a figurehead, and such a visible one at that...

Firstly, I think that women in technology are valuable, extremely so. Does it have to be political? Well, I guess it doesn't and wouldn't be if they weren't such a huge and often willing minority. I will clarify what I mean by willing - women (in general) opt not to play in this industry. Why that is comes down to many reasons that I'm not fully familiar with and don't wish to debate in this post. The point that I wish to press though is that the women in technology are important.

There have been various psychological studies done over the years that have all but proven that women and men think differently - and some go as far as to suggest that for all intensive purposes, we may as well be different species. How true that is I'm not sure, but it's not important. The purpose of this point is that if we're only getting the guys' point of view, doesn't that leave our industry's effectiveness in the world very one sided? The fact is, I'm a guy, I think like a guy and work like a guy, I look at the world from a guy's point of view. Of course, when I design software I try and design it logically - so gender shouldn't make any difference.

What's logical is logical, doesn't matter whether you're male or female, right? Well that was what I thought until I got married - now it's very obvious to me that what seems logical to me isn't always (in fact frequently isn't) logical to my wife... nor was it logical to my previous wife, or any of my girlfriends before them. I used to write it off as they just didn't think logically and in the context of computer software, they just didn't get it - we spoke a different language and would never understand each other.

The more time goes on, the more I'm forced to look at myself and think that maybe it's not the women in my life that don't get it - maybe it's me. Asking any of the guys I work with, they all agree that my idea is the most logical approach. But asking the women, they all agree to the contrary, the most logical approach to me often just doesn't seem to make sense to them, even when I explain it. So without having women's input and perspective in the design process, the result is skewed very much in the favour of the way guys think. Maybe this is "why guys are technologically inclined and women aren't" [just repeating the anecdote, it's not mine]. It's not because women don't get technology - it's that they don't understand the technology that was produced. It doesn't make sense because they've [women] had very little input into the design process.

Anyone can have a good idea, anyone, any time, any where. Male or female. So in a world where we have approximate balance between the sexes, how effective is our software if input into its design and user experience is almost entirely driven by guys?

Female input into software design is extremely valuable and if you are one of the few females in software development, I would call on you to be role models to other girls and women that the industry needs you. For every bigot, sexist or moronic asshole in this industry that look at women in technology as inferior, or objects to be leered over, there are many who value their opinions, input and ideas. There are guys out there that fit the stereotypic geek that lives for Star Trek conventions, girls too - to each their own, but if this or other stereotypes are what's making you lean away from a career in technology, please reconsider.

So Kathy, while I understand the sentiment of your comment that you just want to be you and that being a coder shouldn't be political just because you're female - you are an ambassador that can bring balance to an industry where there is currently little, if any - in fact, all women in this industry are, more so if they have any level of visibility.

Maybe I should extend the reach of this post as far as to say - it's not just women that are important, but diversity in general is important. If you are in any visible, social or any other kind of minority in the industry and you have any kind of visibility, you are an important ambassador too. Diversity in points of view, experience and approach is good for the industry and will benefit us far more than ignoring it or worse actively participating in behaviour that inhibits it.

Of course, this is just my opinion, and I hope, nay encourage my readers to post their comments in response.

Thank you for taking the time to read my blog, I appreciate that your time is valuable and you have other important things to do. So the fact that you've chosen to spend it reading my views is appreciated - whether you agree or not.

December 17, 2009

Why effective programmers *can* be paid 10 times what ineffective programmers make

This blog post is because I can't fit my comment in 140 characters and it's a rebuttal to StackOverflow podcast #77 - specifically in regard to why productive programmers can't be paid 10 times as much as unproductive ones.

The argument goes that you cannot effectively measure programmer productivity because lines of code doesn't equal productivity, number of bugs per lines of code doesn't measure productivity because what if you only write 1 line of code and there are no bugs in it etc etc, I've heard all the arguments why this cannot be done and I'm still in disbelief that people as influential as Joel Spolsky and Jeff Attwood couldn't put their intelligence together and come up with some metric that justly rewards superstar programmers the same way that superstar sales people are rewarded.

Everything about a successful business is based on metrics, and it's these metrics with programmers that seem to be impossible not to be gamed. Who cares about whether or not the system is gamed? As a business person, I don't give two hoots about whether or not you're gaming the system. I couldn't care less. What I do care about is how you're affecting my bottom line. That comes down to one of two questions - "Are you making me money?" or "Are you saving me money?". And specifically in relation to those questions - "How much?". Pay not only your rock star programmers, but all your programmers based on that!

When it comes to business, every outgoing should have the question attached "How does this benefit my bottom line?". Forget whether or not your programmer is a rock star computer scientist that spends months writing a flawless project that does next to nothing but is completely bug free vs. the idiot you hired for peanuts that did it all in 2 days but it fell flat on its face as soon as it was released to the wild because it only worked in perfect conditions. Forget measuring lines of code vs. number of bugs per line. Ask the same question about the programmer's salary as you would for any other member of staff: "How have you helped my bottom line?".

If the code they wrote has worked well enough to save the company money, reward the programmer for that. If the code they wrote earned your company millions of dollars, reward them for that. If the code they wrote that has a net cost your company, pay them their minimum salary or hourly rate, fine them or get rid of them.

Of course, this seems very black and white, and there is certainly some grey area, just like any other metric - what if your rock star programmer has cost your company money in the short term because the software needed to be completely restructured, (s)he has put up a convincing argument why it should be restructured, and their argument has been verified as technically sound by an unbiased third party - well, they don't necessarily earn their commission or bonus this month and only get their salary. However, next month the company reaps huge rewards for their work and the bottom line is affected positively in a huge way. When the code is released and the bottom line earnings are calculated, pay them a bonus for their efforts.

Now, I'd like to add a disclaimer that this doesn't necessarily guarantee that the best and most efficient code (from a technical standpoint) will be produced, but it does mean that what needs to get done will get done in the most efficient manner from a time perspective - everyone wants their bonus, poor quality code that has bugs that cause customers to stop using the software affects the bottom line negatively and as such no bonus. Bugs that nobody cares about would take lesser priority over those that people care about. In the real world, this is how rock star programmers (and all programmers in fact) can effectively (and in line with business objectives) be paid on the same scale as sales people.

When your team starts looking at the long term benefits of writing code that saves/makes the company money, they will start to see that it's in their best interest to write the best code, from a maintenance standpoint, from a performance standpoint and from a usability standpoint, and they will be enticed to do this by significant financial reward.

December 16, 2009

Why technology makes me insane...

Okay, this blog post, rather than being informative, although I hope it provides some useful information is a cry for help regarding my attempt to build a home theatre system that does the following:

  • Has a single centralized machine that will be used for receiving the cable input from my Bell TV (ExpressVu) satellite dish (or Cable if I choose to switch to Rogers/Shaw at some later point), including all my premium subscription channels.
  • Streams the live TV input it receives from said cable input to extender boxes around the house so we can watch live TV (in HD as per my subscription) without having set top boxes as well as media extender boxes attached to each TV.
  • Will PVR shows from said cable input for later playback by any of the extender boxes on my network.
  • Streams my family's last.fm selection through the extender boxes and does all the other usual stuff that media centers do.

That all seems like a perfectly reasonable scenario to me. However, I'm coming unstuck. The only way that it seems possible to do this is using a ridiculous concoction of technologies like so:

One HTPC used for your media center - running Windows 7 or Windows Home Server or some operating system that can handle one of the Media Center variants out there: BeyondTV, SageTV, MediaPortal, Windows Media Center or any number of the other lesser known media center applications.

One set top box for every concurrent channel that you want to watch and/or record. Hence if you want to have 3 TVs in your house and you want to be able to watch them all independently of each other and you want to be able to record 2 concurrent shows without interfering with what is being watched on those TVs then you need 5 set top boxes.

One Hauppage HD-PVR box (at $299 a pop) for each concurrent channel you want to be able to record - hence if you want to record two shows at the same time, you need two of these device. It connects to your HTPC via USB to store the shows and you can use your Media Center to control the device which in turn controls the set top box it's connected to to make sure it's on the right channel to record your show. The video file is then stored on your HTPC in H.264 format ready for your media center to play back at your leisure.

Here's where I come unstuck - how do I watch live TV? It seems like I can't. In order to watch live TV through the media center, I'm limited to OTA or ATSC/ClearQAM. OTA is over the air - this means across the radio waves which requires an antenna capable of good enough quality to receive the digital HD signal from over the air waves which isn't an ordeal but it means I'm restricted to a very limited subset of HD channels - and doesn't include most of my subscription channels which is what I pay for and am willing to continue paying for (for the record). ClearQAM is the signal that is broadcast digitally via Satellite (or ATSC via Digital cable) in an unencrypted format - like OTA this is a very limited subset of the crap channels that is the reason you pay your subscription for the good channels in the first place - so this is out too.

<RANT>Why the **** isn't there a technology out there that allows me to set up my home entertainment system the way I want it instead of the way the TV provider wants me to have it?!?! I thought that in a time we call the age of technology we would be able to set simple things up like this without having to jump through a series of bull**** hoops to get it done. I would like to be able to just hook my satellite dish DIRECTLY to my computer and have my media center handle the rest. Instead, I've gotta pay for as many set top boxes as I need TVs and recording devices, recording devices and tuners that don't allow me to watch most of my subscription channels! This is a crock. It doesn't take very much imagination to realise that someone would want to do this - do I really have to rip the set top boxes to pieces and figure out a way to wire them to the available slots in my PC and write drivers that can integrate them into Media Center to make this happen? In order to watch live TV, I have to have a set top box hooked up to each TV I want to watch live TV on, and then I have to have a separate set top box hooked up to each TV to watch media center. WHY ON GOD'S GREEN EARTH DOES THAT MAKE SENSE TO ANYONE?!</RANT>

Can someone please (1000 times please) tell me there's a way to do this that I haven't stumbled across yet where I can have:

  • One device (media center extender and no separate set top box) hooked to each TV
  • One media center server that acts as a streaming device for:
    • Streaming Live TV to the extenders (including all my subscription channels).
    • Hosts the PVRs and streams recorded programs to the extenders.
    • Integrates with internet radio and FM radio and streams that to the extenders.
    • Hooks up to some kind of DVD jukebox that I can load up with DVDs and stream them to the extenders. (Optional)

I don't care how many set top boxes I need, nor am I interested in losing my subscription channels. I'm not looking to stop paying my Satellite TV bill or stop paying for my subscription channels. All I'm trying to do is this:

  • Integrate all my home entertainment into a network where all the TVs in the house have the same interface and don't have a stack of boxes of various descriptions next to them.
  • Allow me to playback recorded TV on any TV in the house, rather than being limited to the one the PVR is connected to.
  • Have all required set top boxes hooked up to the media center server so that every TV only has ONE interface to control everything - that of the media center extender.

This shouldn't be so hard...

December 1, 2009

How can I customize my user model in my ASP.NET MVC web site? Part 4

Extending the RoleProvider

Related Posts

In my previous blog post, I described the method for integrating a custom user model into the .NET Framework’s implementation of the MembershipModel. In this blog post I’ll discuss using a custom RoleProvider. The role provider handles whether or not your user has access to certain resources within your site. This is different than the MembershipProvider in that the MembershipProvider is used primarly to allow the user to log into your site.

This works in a very similar manner to the MembershipProvider we discussed previously. We hook it up in the web.config in exactly the same way.

I’ve created a class called MySiteRoleProvider which derives from the RoleProvider abstract base class.

using System;
using System.Web.Security;
public class MySiteRoleProvider : RoleProvider
{
}

…and I’ve hooked it into my application in the section of the web.config.

<roleManager enabled="true" defaultProvider="MySiteRoleProvider">
 <providers>
  <clear />
  <add  name="MySiteRoleProvider"
     type="UserModel.MySiteRoleProvider" 
    connectionString="MySiteDatabase" />
 </providers>
</roleManager>

I’ve got considerably less properties specified in my custom role provider than I do in my membership provider – in fact the only one of any relevance that I’ve kept from the AspNetSqlRoleProvider is connectionString. Once again, the MVC framework will do the heavy lifting and automatically use MySiteRoleProvider as the role provider for this site. We don’t need to do any more heavy lifting to get things working.

I’ll start off with the Initialize() method again to hook my configuration up to my provider… I'll condense my code somewhat to keep it brief. If you don't understand how to implement the Initialize method, please review my previous post

private string _connectionString;
private ConnectionStringSettings _connectionStringSettings;

public override void Initialize(string name, NameValueCollection config)
{
 base.Initialize(name, config);

 _connectionString = (string)config["connectionString"];
 _connectionStringSettings = 
 ConfigurationManager.ConnectionStrings[_connectionString];
}

As you’ll notice, it’s quite a bit simpler than the initialize for the membership provider, but it does the same thing. It’s just parsing the configuration and configuring our private members.

Next I’ll move on to the GetUsersInRole and IsUserInRole methods:

public override string[] GetUsersInRole(string roleName)
{
    using (IDbConnection con = InitConnection())
    using (IDbCommand cmd = con.CreateCommand("dbo.GetUsersInRole", CommandType.StoredProcedure))
    {
        cmd.AddParameters(
            cmd.CreateParameter("@RoleName", DbType.String, roleName),
            cmd.CreateParameter("@ReturnValue", DbType.Int32, ParameterDirection.ReturnValue));

        using (IDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
        {
            List roles = new List();
            while (rdr.Read())
            {
                roles.Add(rdr.GetString(0));
            }
            return roles.ToArray();
        }
    }
}

public override bool IsUserInRole(string username, string roleName)
{
 return Array.Exists(GetRolesForUser(username), role =>
 {
  role.Equals(roleName));
 }
}

As you can see, these two methods are the crux of the RoleProvider from your website’s perspective. The GetUsersInRole method grabs a list of all the users that are part of the role specified by the roleName parameter using the stored proc, which could easily hook up to a custom table in your database rather than the provided AspNet model. The IsUserInRole method looks for the existence of the username in the resulting array produced by the GetUsersInRole method. In the next post I’ll discuss the ProfileProvider which is the key to including user profile information like a custom display name, reputation and a host of other bits of useful and interesting data about your users.

How can I customize my user model in my ASP.NET MVC web site? Part 3

Extending the MembershipProvider

Related Posts

So now that we’ve got our model set up and we’ve figured out which components need to be extended, where do we start?

The easiest place to start is your MembershipProvider – because this is the component that logs your user into your website. So let’s create our derived class and hook it into our ASP.NET MVC application:

public class MySiteMembershipProvider : MembershipProvider
{
}

Of course, we must implement all the abstract methods that are defined in the MembershipProvider base class, but I will come back to that momentarily. In order to tell our site that we need to use this membership provider we hook it up in the web.config:

So open your web.config and scroll down until you find the membership node of the system.web section. By default you will find a provider defined called AspNetSqlMembershipProvider… we can scrap that one because it doesn’t do what we want. We need to replace this with our derived type and give it a more befitting name – so, this is what I’ve got in my web.config:

<membership defaultProvider="MySiteMembershipProvider">
 <providers>
  <clear/>
  <add  applicationName="MySite"
    name="MySiteMembershipProvider" 
    type="SecurityPrototype.Models.CustomMembershipProvider"
    enablePasswordRetrieval="true" 
    enablePasswordReset="true" 
    requiresUniqueEmail="true" 
    passwordFormat="clear" />
 </providers>
</membership>

Some of the fields might not make sense right now, but that’s okay, they’ll make more sense later on.

So now that we’ve got our custom provider hooked up to our web.config. Thankfully the MVC Framework does the heavy lifting to defer calls your class; so that’s all you need as far as hookup goes. The Account Controller’s Logon method will now automagically find your derived class and use that for validating the user credentials.

So now that MVC is all hooked up to our custom MembershipProvider we’ve got to hook our custom MembershipProvider up to our data store.

I won’t fill out every method in this blog post, I will pick some key ones to give you the idea of what’s going on and I will provide a link to the cs file if you need to look at the whole thing.

Perhaps one of the most important methods in our MembershipProvider is the Initialize() method which does all the interpretation of the web.config and parses the values out into the properties/fields within our class:

using System;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Security.Authentication;
using System.Web.Security;
using UserModel.Helpers;

public class MySiteMembershipProvider : MembershipProvider
{
 private string _connectionStringName;
 private ConnectionStringSettings _connectionStringSettings;
 private int _minNonAlphaNumeric = 0;
 private int _minPasswordLength = 0;
 private string _passwordStrengthRegularExpression;
 
 public override void Initialize(string name, NameValueCollection config)
 {
  if (string.IsNullOrEmpty(name))
   name = "MySiteMembershipProvider";
   
  if (config == null)
   throw new ArgumentNullException("config");
  
  //Set property defaults for optional configuration parameters
  string minPwdLenStr = config["minPasswordLength"];
  if (!string.IsNullOrEmpty(minReqPwdLenStr) && int.TryParse(minReqPwdLenStr, out _minRequiredPasswordLength))
  {
   config.Remove("minRequiredPasswordLength");
   config.Add("minRequiredPasswordLength", _minRequiredPasswordLength);
  }
 
  string minNonAlphaStr = config["minNonAlphaNumericCharacters"];
  if (!string.IsNullOrEmpty(minAlphaStr)) && int.TryParse(minNonAlphaStr, out _minNonAlphaNumeric))
  {
   config.Remove("minRequiredNonAlphaNumericCharacters");
   config.Add("minRequiredNonAlphaNumericCharacters", _minRequiredNonAlphaNumeric);
  }

  //Initialize the base provider after you've set the config defaults.
       base.Initialize(name, config);
  
  //Parse required values.
        _passwordStrengthRegularExpression = config["passwordExpression"];
  if (string.IsNullOrEmpty(_passwordStrengthRegularExpression))
   throw new ProviderException("Missing property \"passwordExpression\"");
   
  config.Remove("passwordExpression");
   
  _connectionStringName = config["connectionStringName"];
  if (string.IsNullOrEmpty(_connectionStringName))
   throw new ProviderException("Missing property connectionStringName");
   
  config.Remove("connectionStringName");
    
  _connectionStringSettings = ConfigurationManager.ConnectionStrings[_connectionString];
  if (_connectionStringSettings = null)
   throw new ProviderException(string.Format("Missing connection string {0}", _connectionString));

  if (config.Count > 0)
   throw new ProviderException(string.Format("Invalid property {0} found.", config.GetKey[0]);
 }
}

Sweet, so we’ve got our custom MembershipProvider created and hooked up to the web.config and we’ve got it reading the values provided by the web.config so that it can configure itself. Now what?

Let’s hook up the validate method which is what validates that our user is indeed a member of our site:

public override bool ValidateUser(string username, string password)
{
 using (IDbConnection con = InitConnection())
 using (IDbCommand cmd = con.CreateCommand("dbo.ValidateUser", CommandType.StoredProcedure))
 {
  cmd.AddParameters(
   cmd.CreateParameter("@Username", DbType.String, username),
   cmd.CreateParameter("@Password", DbType.String, password),
   cmd.CreateParameter("@Validated", DbType.Boolean, ParameterDirection.Output),
   cmd.CreateParameter("@ReturnValue", DbType.Int32, ParameterDirection.ReturnValue));
  
  cmd.ExecuteNonQuery();

  DbParameter param = (DbParameter)cmd.Parameters["@Validated"];
  return param.ValueOrZero() == 1;
 }
}

As you can see, the validate user method just hooks right into my database and runs the ValidateUser stored procedure. The stored procedure returns either a 0 – the user credentials are not valid, or 1 – the user credentials are valid. The method returns the corresponding boolean response.

Then I’ll implement the next most important method – GetUser(). This method returns an instance of MembershipUser which is likely a subset of the data held in your user’s profile in your database. For instance, in this prototype – my user’s profile is a single record in a single table in the database. Unlike the one provided by the AspNetSqlMembershipProvider which keeps the user’s credentials separate from their profile. In fact, in a multi-application system, this would make sense because a single user may want multiple profiles – one attached to each of the applications. For the purpose of our application though, there is only a single application and hence a single profile. Consequently there is only one table containing our user data.

public override MembershipUser GetUser(string username, bool userIsOnline)
{
 using (IDbConnection con = InitConnection())
 using (IDbCommand cmd = con.CreateCommand("dbo.GetUserByName", CommandType.StoredProcedure)
 {
  cmd.AddParameters(
   cmd.CreateParameter("@Username", DbType.String, username),
   cmd.CreateParameter("@UpdateLastActivity", DbType.Boolean, userIsOnline),
   cmd.CreateParameter("@ReturnValue", DbType.Int32, ParameterDirection.ReturnValue));

  using (IDataReader rdr = cmd.ExecuteReader(CommandBehavior.SingleResult))
  {
   DbParameter ret = ((DbParameter)cmd.Parameters["@ReturnValue"];

   if (!rdr.Read())
    return null;

   int userId = rdr.GetInt32(0);
   string userName = rdr.GetString(1);
   string email = rdr.GetString(2);
   string question = rdr.GetString(3);
   bool isApproved = rdr.GetBoolean(4);
   bool isLockedOut = rdr.GetBoolean(5);
   DateTime createDate = rdr.GetDateTime(6).ToLocalTime();
   DateTime lastLoginDate = rdr.GetDateTime(7).ToLocalTime();
   DateTime lastActivityDate = rdr.GetDateTime(8).ToLocalTime();
   DateTime lastPasswordChange = rdr.GetDateTime(9).ToLocalTime();
   DateTime lastLockout = DateTime.MinValue; //Lockout not used

   return new MembershipUser(
    Name,
    userName, 
    userId, 
    email, 
    question,
    null, 
    isApproved, 
    isLockedOut, 
    createDate, 
    lastLoginDate, 
    lastActivityDate,
    lastPasswordChange,
    lastLockout);
  }
 }
}

So as you can see from the previous examples, the MembershipProvider is actually hooking up directly to our database. You could equally easily hook this into your business layer or your DAL if that is more appropriate. The point I’m attempting to demonstrate is that the MembershipProvider is your site’s link between the HttpContext .User and your underlying application model. For instance, if I were to use a data layer in between the provider and my database, then I would use something more akin to this:

using System;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Security.Authentication;
using System.Web.Security;
using UserModel.Helpers;

public class MySiteMembershipProvider : MembershipProvider
{
 public override MembershipUser GetUser(string username, bool userIsOnline)
 {
  ArgumentHelper.CheckParam("username", ref username, true, true, true);

    //My underlying business object is a custom class called MySiteUser
    //it contains the complete user profile, but we only need the bits
    //that pertain to the MembershipUser, so we’ll grab the profile and
    //create a new MembershipUser instance from it.
  MySiteUser user = DataAccess.GetUser(username);
  if (userIsOnline)
  {
   user.LastActivity = DateTime.Now;
   DataAccess.SaveUser(user);
  }

  return new MembershipUser(
  this.Name,
  user.UserName,
  user.UserId,
  user.Email,
  user.Question,
  null,
  user.IsApproved,
  user.IsLockedOut,
  user.CreateDate,
  user.LastLoginDate,
  user.LastActivityDate,
  user.LastPasswordChange,
  user.LastLockout);
 }
}

The rest of the provider follows the same concept. There are a couple of methods that require an instance of MembershipUserCollection returned. This is handled in exactly the same way by iterating through your model adding MembershipUser instances to the collection and returning the collection.

In the next blog post I will move on to discuss the RoleProvider which is used to provide restriction on which resources a user account has or hasn’t got access to.

How can I customize my user model in my ASP.NET MVC web site? Part 2

What do I extend/replace?

Related Posts

Carrying on from my previous blog post I need to figure out which bits of the framework I need to customize or extend in order to connect to the database schema we created. It turns out there are a number of components and this isn’t exactly the laziest route forward - nor perhaps the most intuitive – especially given that I’m new to ASP.NET MVC, in fact, this is my first project using this pattern – well, I guess this prototype is my second, but you get the idea.

I will first discuss which components need to be modified/extended so that you have an understanding of the scope of what needs to be done and how to go about that. I will then go on to discuss how, so just in case you read this post and wonder when I’m going to get to the how… it’s coming, your patience will pay off ;)

So these are the components that need extending:

  • System.Web.Mvc.AuthorizeAttribute
  • System.Web.Security.MembershipProvider
  • System.Web.Security.RoleProvider
  • System.Web.Profile.ProfileProvider
  • System.Web.Profile.ProfileBase

System.Web.Mvc.AuthorizeAttribute

This is the class that will be used to verify that the user has authorization to access a resource – either a controller or an action. I will explain how this is achieved further on.

System.Web.Security.MembershipProvider

Think of this like a repository manager for our membership base [base as in a community sense not a base-class sense]. This isn’t designed to be used for managing user profiles, but rather it manages the user account credentials, including provision for the ability for a user to reset their password using a security question and answer – although we don’t use that feature in this prototype. It also allows you to search your membership base for things like number of users currently online, inactive user accounts, locked accounts etc [our prototype doesn’t lock accounts out, so we’ve ditched all the fields that pertain to that]. You will need to create a class that derives from MembershipProvider to hook into your own data repository [database, flatfile, whatever you’re using to hold your user information].

System.Web.Security.RoleProvider

The RoleProvider is similar to the MembershipProvider. It is the repository manager for managing roles and role assignment within your application. Once again, you’ll need to create a class that derives from RoleProvider to hook into your own data repository.

System.Web.Profile.ProfileProvider

By now you’ve probably spotted a pattern with the providers – the ProfileProvider is no different. This provider is similar to the MembershipProvider, except that it is used to manage the user’s profile information – this is personalization information about this user as opposed to their credentials. In this prototype they’re all stored in the same table – but if you’ve looked at the aspnet_regsql generated database you will notice that the user’s credential information and their personal profiles are stored in separate tables. Just like the MembershipProvider and RoleProvider you will need to create a class that derives from ProfileProvider that hooks into your own data repository.

The Provider classes all provide the data abstraction layer between your application and your physical data store.

System.Web.Profile.ProfileBase

This is the class that we extend to hold our custom user information relevant to your web application. For instance, in my application things like FirstName, LastName, DisplayName, Reputation, Location and a few other fields. It should be said that strictly speaking you don’t need to extend this class. You can access each of your defined properties using the GetPropertyValue and SetPropertyValue methods to access the data in each of your fields. You only need to extend this class if you’d prefer to access your values in a type safe manner.

Why use these objects instead of completely running your own user API? I asked myself the same question. The best reason I can think of is this: There are plenty of utilities written out there that manage user bases that sit on top of the prebuilt API – this means that they can be modified very simply to sit on top of these objects rather than having to completely write your own management system from scratch.

How can I customize my user model in my ASP.NET MVC web site? Part 1

Introduction

Related Posts

Well it's about time I wrote another blog post so I thought I'd cover some material that's caused me a lot of headaches and frustrations this week: Trying to integrate ASP.NET's web security and profile models into an MVC application that I'm jointly developing with @JohnMacIntyre.

Because of the amount of material, I will spread it over a number of posts to attempt to keep things succinct and easy to read. I trawled through many blogs in order to try and gleen useful information, but in the end most of it was futile and I ended up getting most of my understanding from Timothy VanFosson via StackOverflow.com (Thanks Tim, I appreciate it) and right from the .NET Framework courtesy of Red Gate's .NET Reflector - Thank you Red Gate :)

I have made some assumptions about you, the reader and I apologize now if any of them are wrong.

  1. You already have Visual Studio 2008 installed and are running .NET Framework 3.5.
  2. You have ASP.NET MVC 1.0 downloaded and installed.
  3. You’ve created a new ASP.NET MVC Project.
  4. You already understand the concepts of the MVC model – I won’t be discussing them as that’s beyond the scope of this post/tutorial.
  5. You’ve already looked at the out of the box database generated by aspnet_regsql and decided that’s not going to work for your site and like me you’re frustrated at the lack of serious documentation about how to use the existing .NET Membership/Role/Profile Framework on top of your own model.
  6. You already understand the Provider Pattern - It will make life easier if you have read and at least understand the provider model to a rudimentary level. If you haven’t, then the following documents are good reading that will help you understand it [the PDF is probably the most comprehensive, but it’s 136 pages]
    1. ASP.NET 2.0 Provider Model: Introduction to the Provider Model
    2. The ASP.NET 2.0 Provider Model [PDF]
    3. The .NET 2.0 Framework Provider Pattern

It would seem from many blog posts out there that most people seem to be using the aspnet_regsql wizard and using out-of-the-box functionality provided by Microsoft. This process appears to be fairly well done to death, so I won’t continue to beat a dead horse. Instead, I will be taking a different approach – one that allows us to take complete control of our database schema and throw out the schema and procedures that the default model uses.

This caused me no end of frustration because we'd already designed our database model and I'm not happy to rip it out and start again just because that is the way all the material I can find tells me I should do it. So I will provide a step by step tutorial of the understanding I've gleened along the way and hopefully where I've misunderstood others may provide further insight and/or correction.

So let’s mock up a database schema that we’ll be working to. This is just a quick knock together for demonstration purposes, so no best practice bashing please. And while this schema is probably a lot different than the schema you wish to use for your system the techniques I will discuss should be easily transferrable.

Create Table Roles(
 RoleId Int Identity(1, 1) Not Null
 RoleName NVarChar(64),
 Constraint PK_Roles Primary Key Clustered(
  RoleId Asc
 )
)
Create NonClustered Index IX_Roles_RoleName On Roles(
 RoleName Asc
)

Create Table Users(
 UserId Int Identity(1,1) Not Null,
 FirstName NVarChar(32), 
 LastName NVarChar(32) Not Null,
 UserName NVarChar(104) Not Null,
 DisplayName NVarChar(32),
 EmailAddress NVarChar(254) Not Null,
 Password NVarChar(256) Not Null,
 Question NVarChar(64) Not Null,
 Answer NVarChar(64) Not Null,
 CreateDate DateTime Not Null,
 LastLoginDate DateTime,
 LastActivityDate DateTime Not Null,
 LastUpdateDate DateTime Not Null,
 Location NVarChar(64),
 Biography NText,
 Constraint PK_Users Primary Key Clustered(
  UserId
 )
)
Create NonClustered Index IX_Users_UserName On Users(
 UserName Asc
)

UserRoles(
 UserId Int Not Null Constraint FK_UserRoles_UserId Foreign Key
 RoleId Int Not Null Constraint FK_UserRoles_RoleId Foreign Key
 Constraint PK_UserRoles Primary Key Clustered(
  UserId,
  RoleId
 )
)
Create NonClustered Index IX_UserRoles_UserId On UserRoles(
 UserId Asc
)
Create NonClustered Index IX_UserRoles_RoleId On UserRoles(
 RoleId Asc
)

Okay, that should suffice for the purpose of a prototype. I considered role inheritance schema (i.e. roles that inherit other roles), but considered them unnecessary for the scope of these posts. Maybe in a future post I will revisit that, but for now, we’ll stick with this model. In further posts on this topic, I will be referring to this schema, so print it out and pin it up next to your monitor ;)