Wednesday, July 07, 2004

I realize that's a pretty boring title, but let me explain:

I have a few websites that I've created over the past several years that I use quite frequently.  These include:

  • A bug tracking system that I developed a few years ago that I'm in the process of overhauling
  • A custom media server that streams audio content based off of custom, user-defined playlists from my personal collection of WMA and miscellaneous files
  • A special family gallery of photographs

Needless to say I am not the only user of these sites.  Various friends, associates, and family members frequent the sites (despite their work-in-progress nature).  However, there is a catch:  anonymous access is not allowed.  If a user wants to view the contents of a site, he must log in.  With the myriad of individuals out there that access these sites it would be impractical, not to mention extremely labor-intensive and would expose my network to security risks to provide a Windows logon for each user...that would be insanity.

For these and other reasons I opted for a Forms-over-SSL-based authentication mechanism to gain access to these sites.  The forms authentication backends ultimately to a SQL Server database that maintains the users and their encrypted credentials.  Ok, nothing magic here.  Simple, routine computing.  But this is where the fun begins.

A user may have access to one, two, or all of the sites.  I don't want to store multiple credentials for the same user (potentially with all the same values), one for each site.  Heaven forbid that we create a user credentials database for each site!  I wanted a single repository for all credentials.  Ok, still nothing magic - everyone has to solve these kinds of problems.  Despite these relatively mundane and trivial tasks, the whole reason I bring this up is because I think my solution is pretty cool.  Note: I haven't yet tested this solution for scalability nor have I profiled it.  I'm not expecting a boatload of traffic, so this suits my personal needs fine, but I would test this for any real-world application...don't just take my word for it that it's good.

On the backend I have a SQL Server 2000 database that maintains a master list of websites and logins and mappings between the two among some other stuff.  Stored procedures exist that allow for the management of these tables as well as the validating that a user has permissions to a particular site.

Over this database exists a set of web services that make calls to the stored procedures.  These web services (by their very nature) are accessible to the web sites but instead of accessing them directly, the web sites rely on a set of helper classes that abstract the web service interfaces.  For security reasons, the web services are hidden completely behind a firewall with no outside access.  Additionally, the only user with access to the database procedures (and only the procedures) is the user associated with the web service virtual directory in IIS.

An example of the web service call that validates the user is the following:

[WebMethod(Description="Checks to determine if the login id and password are associated with a particular website.")]
public bool IsValidLogin(string loginID, string password, string webSite) {
   string pwdHash = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");

   using ( SqlCommand cm = new SqlCommand("dsProc_ssoIsValidLogin", getConnection()) ) {
      cm.CommandType = CommandType.StoredProcedure;
      cm.Parameters.Add("@LoginID", SqlDbType.NVarChar, 25).Value = loginID;
      cm.Parameters.Add("@Password", SqlDbType.NVarChar, 40).Value = pwdHash;
      cm.Parameters.Add("@Website", SqlDbType.NVarChar, 30).Value = webSite;
      return (int)cm.ExecuteScalar() > 0;
   }
}

As can be ascertained, each website to which the users can gain access has a name.  The userid/password combination is matched up to the website name.  In the case of a match, a value of True is returned.

I mentioned a second ago that there is a set of helper classes that provide the interfaces to the Web Services.  Now with Visual Studio .NET I could have just as easily created a web reference and called it good.  However, I don't know if you may have had the same experiences that I've had, but I tend to open the References.cs file (which is automatically generated when the web reference is created) and edit it.  Mainly the edits involve the line that reads

this.Url = "http://localhost/.....";

because this url differs between development and production.  I usually edit it to read the value from a configuration file (Web.config).  It's a pain to have to edit that file only to have to reedit it when the web reference is refreshed - it's easy to forget to do it, that's for sure.  Not that my web services change their contracts often but you know.

That's one of the reasons I decided to create the set of helper classes, but the main driving reason was that I wanted a consistent, simplified, and shared object that didn't behave like a web service.  I didn't want to have to create an instance of the soap client to call a method and then dispose of it.  I wanted this class to be sharable across all of the web sites that needed the same functionality.

The solution I came up with was to create a class called SignOnValidator that has a single static method called IsValidLogin that takes the user's login id and password as parameters.  This method then resolves the name of the website by reflecting on the calling assembly to find a custom attribute called SignOnWebSiteNameAttribute instead of relying on a parameter passed in.  Then it creates an instance of an internal class that manages the call to the web service proper, returning the result.  I might need to do some optimization to the code, but here it is (unoptimized):

using System;
using System.Configuration;
using System.Reflection;
using System.Web.Services;
using System.Web.Services.Protocols;

[assembly:AssemblyVersion("1.0.0.0")]
[assembly:AssemblyCopyright("Copyright © 2004, Devstone Software")]

namespace Devstone.Web.WebAuth {

   public sealed class SignOnValidator {

      private SignOnValidator() { /* no public constructor */ }

      public static bool IsValidLogin(string loginID, string password) {
         string siteName;

         // get the instance of the attribute in the calling assembly
         Assembly caller = Assembly.GetCallingAssembly();
         if ( caller.IsDefined(typeof(SignOnWebSiteNameAttribute), false) ) {
            // retrieve the SignOnName for the calling application
            SignOnWebSiteNameAttribute attrib = caller.GetCustomAttributes(typeof(SignOnWebSiteNameAttribute), false)[0] as SignOnWebSiteNameAttribute;
            siteName = attrib.SiteName;
         }
         else {
            throw new ArgumentException("Unable to authenticate the user.  Please make sure that the calling assembly has the SignOnWebSiteNameAttribute specified.");
         }

         using ( SignOnWebService svc = new SignOnWebService() ) {
            return svc.IsValidLogin(loginID, password, siteName);
         }
      }

   } // SignOnValidator class


   [WebServiceBinding(Name="SignOnValidatorSoap", Namespace="
http://signon.devstone.com/")]
   internal sealed class SignOnWebService : SoapHttpClientProtocol {
      internal SignOnWebService() {
         string url = ConfigurationSettings.AppSettings["LogonServiceUrl"];
         if ( null == url )
            throw new ArgumentException("Unable to resolve the URL for the logon service.  Please make sure your application's configuration settings are correct.");
         else
            this.Url = url;
      }

      [SoapDocumentMethod("
http://signon.devstone.com/IsValidLogin",
       RequestNamespace="
http://signon.devstone.com/",
       ResponseNamespace="
http://signon.devstone.com/",
       Use=System.Web.Services.Description.SoapBindingUse.Literal,
       ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
      public bool IsValidLogin(string loginID, string password, string webSite) {
         object[] results = this.Invoke("IsValidLogin", new object[] { loginID, password, webSite});
         return ((bool)(results[0]));
      }

   } // SignOnWebService class

// Devstone.Web.WebAuth namespace

Then of course there's the question of the SignOnWebSiteNameAttribute.  Each website that utilizes this sign on mechanism will have to define this attribute, but in my book this simplifies management of the site names.

[assembly: SignOnWebSiteName("mysitename")]

Done.  Everything else will be taken care of because the helper class will automatically resolve the proper site name on invocation.  Oh, and if you're wanting the code for the attribute class, here it is:

using System;

namespace Devstone.Web.WebAuth {

  
[AttributeUsage(AttributeTargets.Assembly)]
   public sealed class SignOnWebSiteNameAttribute : Attribute {
      private string _siteName = null;

      public SignOnWebSiteNameAttribute(string siteName) {
         _siteName = siteName;
      }

      public string SiteName {
         get { return _siteName; }
      }
   } // SignOnWebSiteNameAttribute class

// Devstone.Web.WebAuth namespace

I really like this solution despite the fact that I have to maintain changes made in the web service manually in the SignOnValidator class.  Apart from everything else, I found a good example for using a custom Attribute!  I really think this will simplify the management of website users while providing a very simple programming model for validating users.  Not to mention the benefit that a user has a single login id, name, password, and email across all sites - I hate trying to remember 50 million user IDs and passwords

Wednesday, July 07, 2004 3:34:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Monday, July 05, 2004

I don't think that I'm unique in this experience (I've spoken with others that have the same experience), but have you ever solved some of your most difficult problems in your sleep?  It happens repetitively to me.  Time after time, especially after slaving away and not getting anywhere on an issue (primarily code issues) I solve the problem in the middle of the night while I'm sleeping.  I hate it when I wake up, fully aware that the problem was solved, but am unable to recall the solution - it's infuriating!

Case in point: I am working with a friend from California on an ASP.NET product and am banging my head against some pretty intense issues.  Just the other night I was (while sleeping) running into the issue yet again, but solved it rapidly.  When I awoke shortly thereafter I knew the problem had been solved but couldn't remember.  But this morning while working on it came to solve the problem and had a deja vú moments and the dream came back to me.

Maybe that's why I like to sleep as much as I do.  Or perhaps it's my body telling me that it's time to solve problems and it wants to shut down.  I guess I should listen to it more often rather than kill myself working into the wee hours of the morning.

Monday, July 05, 2004 7:56:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, July 04, 2004

On this day, the United States of America's Independence Day, I am overcome with gratitude for those that sacrificed so much for the country in which I live.  What a wonderful, blessed country!  It is because of their willingness to place their beliefs and even their very lives on the line that I live in such a beautiful place.  I commit to do what I can to live up to their legacy.

Sunday, July 04, 2004 2:25:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, July 02, 2004

In a recent post Eric Gunnerson points out some important concepts involving .NET assemblies and how they should be packaged to yield the best performance.  Basically, the fewer the better.  Each assembly that your application must load increases it's load time.  That said, one should not simply package all of his classes into a single, massive dll.  That would have a very negative and far-reaching impact.  Way back when I got into .NET development (back when it was it Beta 2) I wanted to understand what assemblies were all about.  A very important conclusion that I came to, and EricGu doesn't fail to bring it up, is that of versioning and security.  All code in the assembly versions at the same rate.  More importantly, however, are the security implications.  All code within an assembly has the same identity (and therefore the same level of trust).  If your assembly has to perform various types of actions (such as file IO, registry access, P/Invoke, all code will ultimately have the ability to perform all of those tasks - which may not be what you're wanting).

Aside from the performance and security implications, there may be very good reasons to partition your assemblies into smaller units of code.  Some components might need to be registered into the GAC, while others might need to reside remotely.  The concept of application layers and tiers comes to mind.  While application tiering is a logical design construct, it can have physical implications.  To enforce business requirements, you might not want the UI (user interface) tier to call directly into the DA (data access) tier (there are exceptions to this cut and dry rule).  Were all your classes in a single dll, there would really not be anything stopping them from doing so.  Of course, even then all the developer has to do is set a reference to your DAL (and with the proper know-how and permissions) go to town.

Developing an assembly as a single gargantuan project may not be the right thing to do.  Sometimes your developers are not geographically together or it simply makes more sense to create and test smaller projects.  Well, if you use the Visual Studio .NET environment for compilation, a project = an assembly.  There's not really a way around that.  Barry Gervin beat me to the punch on writing about this, but it's pretty easy to compile from the command prompt.  What you must do is compile your project files to a NetModule.  Then using the AL (Assembly Linker) utility, link the NetModules together into a single assembly.  (Note, this also makes it quite possible to combine, say VB.NET and C# in the same assembly).

Friday, July 02, 2004 3:33:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, June 28, 2004

As a courtesy to developers out there, I'd like to remind all who write and develop Windows applications to take the time to position your windows (forms) properly on the screen.  Not all users have their taskbar on the bottom on the screen.  I am constantly annoyed by applications that assume that 0,0 is the upper left corner of the screen and that it's a safe place to position your windows - especially because I like my task bar along the left side and toolbars across the top.  This configuration is, to me, extremely productive especially with a widescreen monitor.

The list of applications that don't position themselves correctly is too long to mention, but some tools that I quite frequently use (almost daily) are ILDASM and Virtual PC.  ILDASM has the annoying nuance in that it always starts in the upperleft corner of the screen (0,0) so the entire titlebar always appears (or rather doesn't appear) completely obscured beneath the taskbar/toolbars - thank goodness for the ALT key and system menus.  Virtual PC never quite stays in the same place, creeping towards 0,0 each time you open it.

It's not hard to get it right.  If your application requires manual placement of the form you simply need to call Screen.GetWorkingArea([form variable]) to get the screen on which (the majority of) your form is positioned.  Then you can do a little magic otherwise known as basic math and you have it.

The following example identifies how to do this:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace WorkingAreaTest {
   public sealed class EntryPoint {

      [STAThread()]
      public static void Main() {
         Form f = new Form();
         f.StartPosition = FormStartPosition.Manual;
         Rectangle rct = Screen.PrimaryScreen.WorkingArea;
         // you could also call Screen.GetWorkingArea(f)
   
         // to center the form on the screen
         // by bitshifting to divide by 2, we get two benefits:
         // 1) improved performance (negligible here)
         // 2) we don't need to cast the result to an int

         f.Location = new Point(
            (rct.Left + (rct.Width >> 1) - (f.Width >> 1)),
            (rct.Top + (rct.Height >> 1) - (f.Height >> 1)));

         // to position the form on the upperleft corner of the screen
         f.Location = new Point(rct.Left, rct.Top);

         // show the form and get the application running
         Application.Run(f);
      }
   }
}

If you're programming a traditional Windows applications (non-.NET), you can use the SystemParametersInfo() function passing in SPI_GETWORKAREA.

RECT rct;
BOOL ret = SystemParametersInfo(SPI_GETWORKAREA, 0, &rct, 0);

Well, there you go, not much too it at all...and your users will thank you for it, or maybe they'll use your program and never notice you did thim this courtesy - and that's the best praise one could receive.  Believe me, they'll notice if you don't.

Monday, June 28, 2004 3:50:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Sunday, June 27, 2004

This is pretty common and straightforward (and quite elementary), but can be a gotcha if you're new to software development so I figured it'd be worth blogging about.

When you're assembling your applications you'll be invariably presented with the quandary of whether you should use a struct or a class to represent your data.  This choice isn't often cut and dry.  While in many respects they are semantically similar, there are some distinctions that should be known.

First and foremost, perhaps, is how they are allocated in memory.  Structs, by nature, are ValueType objects and are loaded onto the application's stack.  Class instances, on the other hand reference types and are heap-allocated.  A nicety of stack-allocated objects is that they are automatically taken care of when a procedure finishes (unless you move the object to the heap).  They are more deterministic in that respect.  Memory, however, is finite, and the stack is much smaller than the heap so you're limited to how many objects you can load onto it.  Stack allocations are faster than heap allocations as well, though the .NET runtime has some advanced memory assignment and allocation algorithms that make heap allocations nearly (almost imperceptively) as fast as stack allocations.  Okay, enough about that.

There are some other marked differences between the two:

Constructors:  In a struct you can define constructors, but the constructors be parameterized; you cannot create a parameterless constructor as you can with a class.

Fields:  Within a struct you can define fields, but initialization of the field's value in the declaration is not acceptable.  An exception to this is that static fields can be initialized.

As a parameter:  Another important distinction between the two is their behavior when passed as a parameter to a method.  When you pass a struct, it is passed by value (that is, it's copied) whereas a class instance is passed by reference (the reference is copied - not the object).  This has some far-reaching implications.  Suppose you have the following scenario, ignoring the fact that a similar struct may already exist in the .NET framework (it's just for illustration purposes):

struct Coords {
   public int x;
   public int y;

   public Coords(int xCoord, int yCoord) {
      x = xCoord;
      y = yCoord;
   }
}

public static void Main() {
   Coords pt = new Coords(10, 10);
   movePt(pt, 5, 3);
   // what is the value of pt.x and pt.y here?
}

private static movePt(Coords pt, int xOffset, int yOffset) {
   pt.x += xOffset;
   pt.y += yOffset;
}

When you call movePt() pt is copied so the method is affecting a different pt than the one passed in (though the values are the same).  Now, this may be exactly the functionality you want, but then again it might not.  Sure you can solve your problem by making the parameter a ref parameter, but that's another story, and it might impose some discipline upon the caller.

Interfaces:  Ok, now this is potentially a bit more confusing for the novice, but here goes.  Structs, just like classes, can implement interfaces.  This adds a twist to the ValueType / reference type relationship.  When you cast a struct to its interface, the struct is boxed; it is copied up to the managed heap.  Changes made to it through the interface affect the boxed copy.  The struct is never unboxed back to the struct (unless you explicitly unbox it).  Let's see this in action (Okay, okay, I know the names are stupid, but hey, it's all off the cuff):

interface IIncrementer {
   void AddValue(int value);
}

struct IntWrapper : IIncrementer {
   private int _value;

   public IntWrapper(int value) {
      _value = value;
   }

   void IIncrementer.AddValue(int value) {
      _value += value;
   }

   public int Value {
      get { return _value; }
   }
}

public sealed class EntryPoint {
   public static void Main() {
      IntWrapper iw = new IntWrapper(5);   // the initial value is 5
      ((IIncrementer)iw).AddValue(3);      // the value of iw is still 5!  the
                                           // change to the value happened on the
                                           // heap copy and was immediately
                                           // discarded!

      // box and unbox example:
      IIncrementer iiw = (IIncrementer)iw; // box it and obtain a reference
      iiw.AddValue(4);                     // increment the boxed copy
      iw = (IntWrapper)iiw;                // unbox it, replacing the stack copy.
                                           // the value is now 9!
   }
}

Personally, I find the class model (vs the struct model) much more intuitive and welcoming, but structs definitely have their place - I use them all the time.  When it comes down to it, though, I think that one of the interesting characteristics of structs is that they have meaning or state in their default, unitialized form.  That is, the default state of a struct must have some intuitiveness upon creation (you can't control it's default constructor, nor can you deny someone from creating an instance without parameters).  You don't want someone creating an instance of your struct and calling a method or referencing a field/property and having it throw.  This is where classes and their constructors come in really handy.

Pretty much everything mentioned above focuses on structs that have ValueType members.  The playing field changes a little if you a struct that has reference types (such as Strings or other objects) internally as those are heap allocated objects maintained within a ValueType - now your struct isn't quite as deterministic.

Enjoy!

Sunday, June 27, 2004 6:33:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [7]  |  Trackback
 Thursday, June 24, 2004

Well, a lot of things have been going on in my life lately, but not much to blog about.  I've been swamped at work and at home, but I hope to be back at the blogging machine from now on.

Over the last several weeks, I have decided to make some changes in my life and career that will have longlasting and (hopefully) beneficial effect on my family.  Yesterday was my last day with my previous employer and I've moved on to be an independent consultant.  This change means that I will be able to spend more time with my family (which is always a bonus) as well as work from home.  I will also be able to spend more time devoted to things that I have been slacking on over the years.

Leaving a steady job and income to the wild unknown is not something that I take lightly.  It was in many respects a very difficult decision to make and I left behind a lot of what I worked for over the years - though it could be said that all that I worked for over the years has led me to this.

Here's to new beginnings and a prosperous future!

Thursday, June 24, 2004 4:38:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, June 18, 2004

As developers we're constantly faced with the need to crank out good quality code.  This isn't often the easiest task, especially with the mounting need to stay at the forefront of technology.  Visual Studio, while a powerhouse development environment, can only offer so much.  Here is a great list of tools that should be a part of every developer's toolkit.  These tools will aid in the generation of good, quality code and keep the productivity high.  Additionally, Scott Hanselman has his Ultimate Developer and Power Users Tools List, a recommended set of tools that all developers must know how to use.

Of these tools, I have loads of firsthand experience with NDoc (love it!) and FxCop (currently version 1.3) and the Regulator.  I've played with several others.

Some other tools that I really find useful and enjoy are:

Aaron Skonnard's XML Tools

The VS.NET Command Prompt (invaluable - I moved this shortcut to my Start Menu for quick access)

ISO Recorder - invaluable tool for creating images of your CDs

Notepad 2 - A very capable replacement for the boring, ordinary Notepad...try it out! it's awesome!

UltraMagnifier - Excellent tool for giving presentations

What tools do you use?

Friday, June 18, 2004 4:06:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback