Biggy: Interface Semantics and The Interface Segregation Principle

Posted on May 19 2014 05:12 AM by jatten in Biggy, C#, Database   ||   Comments (2)

139856309_e91043c010_nOver the past few months I've been working hard on Rob Conery's Biggy project, a high-performance, in-memory query and persistence tool for .NET.

Recently, the architecture of Biggy underwent a major overhaul, implementing an interface-driven structure proposed by K.Scott Allen. The new structure created a much cleaner separation between the core, in-memory list function of Biggy itself and the backing data store.

Image by Dennis Yang  |  Some Rights Reserved

At its core, Biggy provides an in-memory, synchronized abstraction over various types of backing store. The current architecture is such that store implementations are represented by one or more interfaces and injected into the memory list as a constructor argument. Abstracting the backing store behind a set of interfaces isolates the in-memory list implementation from changes to the backing store, and also allows the list to call into the backing store without worrying about store implementation. 

It all works pretty darn well. However, I wonder if we might be approaching things from the wrong perspective in designing our interface structure.

NOTE: For additional background on Biggy, see the following:

Abstracting Backing Stores - Some Background from Biggy

In its current form, the Biggy architecture present a set of interfaces to represent a backing data store:

Interfaces to Represent Backing Stores in Biggy:
public interface IBiggyStore<T>
{
    List<T> Load();
    void Clear();     
    T Add(T item);
    List<T> Add(List<T> items);
}
  
public interface IUpdateableBiggyStore<T> : IBiggyStore<T>
{
    T Update(T item);
    T Remove(T item);
    List<T> Remove(List<T> items);
}
  
public interface IQueryableBiggyStore<T> : IBiggyStore<T>
{
    IQueryable<T> AsQueryable();
}

 

The interfaces above represent the potential capabilities of different backing stores. In general, when we work with databases, file stores, and other persistence mechanisms, we generally seek to perform the basic CRUD functions: Create new records, Read records from the store, Update existing records, and Delete records.

Different Backing Stores Afford Different Levels of Compatibility

However, not all persistence engines afford all of the above capabilities directly. For example, with a file-based JSON store, we can read the records from the file by reading the file data into memory. However, the file store itself is not directly queryable in the same sense that a relational database might be.

Nor can we (technically) Update or Delete a specific record in the middle of the file - the mechanics of the file system are such that, without essentially writing an actual database system (and dealing with some ugly, low-level file system stuff while we're at it). Since the reason for utilizing a file-based store is to keep things simple (and often, keep the data in a human-readable format), this is at cross purposes. We might as well scale up to a relational system at that point.

With a file-based store, we can Read the data from the file, and we can write data to the file, either in bulk, or by appending records to the end of the file. we can also clear the entire file. These functions are effectively represented by the IBiggyStore<T> interface. Lacking are methods to Update records, or to Remove (Delete) records. In order to Update or Remove an existing record, we are essentially stuck flushing the entire modified file back to disk.

Contrast this with a Relational store, which tends to include all of the CRUD functionality: We can query specific records or sets of records, we can INSERT, UPDATE, and DELTE records, etc. These functions are represented by the IBiggyStore<T> interface, an the additional IUpdateableBIggyStore<T> and (Potentially)IQueryableBiggyStore<T> interfaces used in conjunction.

Meaningful Backing Store Abstractions

In proposing the interface-driven architecture, K. Scott Allen indicates he was thinking in terms of the Interface Segregation Principle, as he explains in a discussion on a Github issue from the Biggy repo:

For example, Mongo [DB] is an IQueryable data source, so it might make sense to allow for effecient queries by "advertising" with an IQueryableBiggyStore. The only reason to implement this interface is if the behind the scenes store is IQueryable. A text file of data isn't IQueryable, so I would not implement the interface on a text file store. Same with the updateable interface - it makes sense for data stores that know how to update and persist individual items, which I think . . . would be tricky with a file full of JSON.

In Allen's view, different stores present different potential capabilities with respect to data access and manipulation, and the interfaces implemented should properly reflect (or "advertise") this to the client. This makes total sense, and is a solid example of the interface representing the actual capabilities available for a given store.

Under this scenario we might define a file-based store something like this:

Simplified Example of a File-Based Store Implementation:
public class ExampleFileStore<T> : IBiggyStore<T> {
  
    // ...
    // ... Local methods supporting the core file store functionality
    // ...
  
    List<T> IBiggyStore<T>.Load() {
        // ... Code to read all data from a file
    }
  
    void IBiggyStore<T>.Clear() {
        // ... Code to clear data from a file
    }
  
    T IBiggyStore<T>.Add(T item) {
        // ... Code to append a record to the end of a file
    }
  
    List<T> IBiggyStore<T>.Add(List<T> items) {
        // ... Code to append many records to the end of a file
    }
}

 

And we might similarly define a store against a relational database like so:

A Simplified Relational Store Implementation:
public class ExampleRelationalStore<T> 
    : IBiggyStore<T>, 
    IUpdateableBiggyStore<T>, 
    IQueryableBiggyStore<T> {
    // IBIGGY IMPLEMENTATION:
    List<T> IBiggyStore<T>.Load() {
        // ... Code to read all records from a table
    }
    void IBiggyStore<T>.Clear() {
        // ... Code to clear all records from a table
    }
    T IBiggyStore<T>.Add(T item) {
        // ... Code to INSERT a record into a table
    }
    List<T> IBiggyStore<T>.Add(List<T> items) {
        // ... Code to INSERT many records into a table
    }
    // UPDATEABLE IMPLEMENTATION:
    T IUpdateableBiggyStore<T>.Update(T item) {
        // ... Code to UPDATE a specific record in a table
    }
    T IUpdateableBiggyStore<T>.Remove(T item) {
        // ... Code to DELETE a specific record from a table
    }
    List<T> IUpdateableBiggyStore<T>.Remove(List<T> items) {
        // ... Code to DELETE a set of specific records from a table
    }
    // QUERYABLE IMPLMENTATION:
    IQueryable<T> IQueryableBiggyStore<T>.AsQueryable() {
        // ... Code to return an instance of IQueryable representing table records
    }
}

 

As we can see here, a relational store implementation will generally make use of all the available interface methods with the possible exception of IQueryableBiggyStore<T>. In order to properly return a queryable instance, we would need a provider which returns IQueryable<T> , such as LinqToSql, or we would need to write our own.

Our two example cases present interface-based APIs which accurately reflect the capabilities of each store, and client code can implement the functionality required by implementing the proper combination of interfaces.

A Closer Look at the Interface Segregation Principle

The Interface Segregation Principle (ISP), described as part of Robert "Uncle Bob" Martin's SOLID principles of Object-Oriented Design, states that:

"No client should be forced to depend on methods it does not use"

A potential corollary to ISP which is often cited, but for which I cannot find a direct source, is:

"Interfaces belong to the client, not the implementation"

From the perspective of defining an interface to abstract various data store implementations, the separations implied by IBiggyStore<T> , IUpdateableBiggyStore<T> , and IQueryableBiggyStore<T> make sense. Different clients can consume the featured represented by various store implementations, and the dependencies created between client and interface will indeed be consistent with ISP.

Within Biggy, though, our objective is to represent a data store as an in-memory list structure, and synchronize the data in the in-memory abstraction with that persisted in the actual store. Further, one of our primary goals in separating store implementation from in-memory list implementation is to isolate the memory list implementation from changes to the store implementation.

In other words, once we have built out an application which consumes Biggy as an in-memory data source, we want to be able to swap out (or more commonly, scale up) the backing store without impacting (or at least, minimally impacting) our application code.

Defining the BiggyList API

For the Biggy project, we have defined another interface, IBiggy<T> , which represents the core feature set required in any given BiggyList<T> implementation:

The IBiggy Interface:
public interface IBiggy<T> : IEnumerable<T>
{
    void Clear();
    int Count();
    T Update(T item);
    T Remove(T item);
    List<T> Remove(List<T> items);
    T Add(T item);
    List<T> Add(List<T> items);
    IQueryable<T> AsQueryable();
    bool InMemory { get; set; }
  
    event EventHandler<BiggyEventArgs<T>> ItemRemoved;
    event EventHandler<BiggyEventArgs<T>> ItemAdded;
    event EventHandler<BiggyEventArgs<T>> ItemsAdded;
  
    event EventHandler<BiggyEventArgs<T>> Changed;
    event EventHandler<BiggyEventArgs<T>> Loaded;
    event EventHandler<BiggyEventArgs<T>> Saved;
}

 

As we can see, any BiggyList implementation requires all of the CRUD features we saw defined previously in multiple BiggyStore interfaces. In other words, while not all store implementations will offer all required features, any Biggy list will expect some way to perform all of these actions anyway.

One of the assumptions behind the current interface architecture essentially is the injection of a store into the BiggyList implementation as a constructor argument. A simplified, generic example might look something like this:

Simplified BiggyList Implementation:
public class BiggyListExample<T> : IBiggy<T> {
  
    IBiggyStore<T> _store;
    IUpdateableBiggyStore<T> _updatableStore;
    IQueryableBiggyStore<T> _queryableStore;
  
    List<T> _items;
  
    // . . . Code for various Event Hooks . . . 
  
    // ... Other Implementation Code ...
  
    public BiggyListExample(IBiggyStore<T> store) {
        _store = store;
        _updatableStore = store as IUpdateableBiggyStore<T>;
        _queryableStore = store as IQueryableBiggyStore<T>;
  
        _items = _store.Load();
    }
  
    public void Clear() {
        _store.Clear();
        _items.Clear();
    }
  
    public int Count() {
        return _items.Count();
    }
  
    public T Update(T item) {
        return _updatableStore.Update(item);
    }
  
    public T Remove(T item) {
        _items.Remove(item);
        return _updatableStore.Remove(item);
    }
  
    public List<T> Remove(List<T> items) {
        foreach (var item in items) {
        _items.Remove(item);
        }
        _updatableStore.Remove(items);
        return items;
    }
  
    public T Add(T item) {
        _items.Add(item);
        return _store.Add(item);
    }
  
    public List<T> Add(List<T> items) {
        _items.AddRange(items);
        return _store.Add(items);
    }
  
    public IQueryable<T> AsQueryable() {
        return _queryableStore.AsQueryable();
    }
  
    public IEnumerator<T> GetEnumerator() {
        return _items.GetEnumerator();
    }
  
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return _items.GetEnumerator();
    }
}

 

Given the example above is a very simplified implementation, it would appear that this class could actually represent a core, base-class type implementation. Except that, under our current assumptions about stores and interfaces discussed above, not all stores will offer up all of the features required for the class above to function properly. For example, if we passed in our ExampleFileStore class defined previously, this code will fail, since ExampleFileStore does not implement IUpdateableBiggyStore<T> or IQueryableBiggyStore<T>.

We could (and did, in the current iteration of Biggy) add null checks against the store instances, so that code won't fail if we try to execute an interface method that is not present:

Checking for Null Before Calling Potentially Missing Interface Method:
public T Update(T item) {
    if (_updatableStore != null) {
        return _updatableStore.Update(item);
    }
}

 

This is even more evil, though. Now we think we have updated some data, but nothing happened.

Originally, we had defined a SaveAll() method as part of the IBiggyStore<T> interface. This made some sense when working against a file-based store, in that updating a record essentially requires re-writing the entire file to disk. With a SaveAll() method defined as part of IBiggyStore<T> , the above could be re-written (roughly):

Modified Null Check Example:
public T Update(T item) {
    if (_updatableStore != null) {
        return _updatableStore.Update(item);
    }  else {
        _store.SaveAll(_items);
        return item;
    }
}

 

The code above assumes that, by passing the entire modified list back to the store, the store contents will be over-written reflecting any changes, including updates and deletions. This works well for the file-based store. For other stores where explicit Update and/or Delete methods are available, the first part of the conditional will execute.

The trouble with this is two-fold. First off, one of the core assumptions implied by the Biggy library is that the in-memory list and the backing store are kept in sync in "Real-time" (or it should appear that way to the client, in any case). Including a SaveAll() method as part of the public interface implies that it is possible to make a series of changes before saving, or "flushing" back to the store. In other words, NOT in real time.

Secondly, SaveAll() implies a "Unit of Work" architecture due to widespread use in popular ORMs. The project owner, Rob, has explicitly opted against Unit of Work in favor of a composed transaction model, and we would be prudent to avoid using this term as part of the public store API. The goal is that Biggy will present a more transactional persistence model for writes to the store, and "Save All" implies something else.

We could, of course, create implementations for IBiggyList<T> which take into account the limitations of certain stores, and accomplish through brute force what cannot be provided by the basic interface. But this, to me, limits the effectiveness of our interface architecture.

In a perfect world, it seems we should be able to create a single, basic BiggyList implementation which is unaffected by moving from one store to the next. Special cases, such as stores and lists which are capable of using IQueryable, could then be created using specialized interfaces. But we should be able to assume core CRUD functionality, and compatibility within Biggy for all the various stores.

Re-thinking the Interface Structure from a Different Perspective

It seems like we have some decisions to make here. On the one hand, defining the store interfaces according to the available functionality makes 100% sense, and is probably in keeping with "proper" Object-Oriented Design principles. After all, if it is not technically possible (for example) to UPDATE a specific item in the store without re-writing the entire list back to disk, then should we be advertising that capability with and Update(item) method?

This would make sense if we were defining our stores as a straight-forward data-access library. However, we are explicitly defining store interfaces to provide compatibility with the Biggy library. Since "the interface belongs to the client, not the implementation" perhaps we should consider meeting the needs of the client first.

The over-arching premise of Biggy as a library is to provide an in-memory abstraction over a data store, along with all of the things we might expect to do with such a store. When we access data from any source, we expect some version of the basic CRUD functionality to be available.

Different stores may present other capabilities beyond the basic CRUD (the IQueryable returned by Mongo and/or LinqToSql is an example), but the basic ability to Create, Read, Update, and Delete records is a core function we expect to do from the context of a Biggy in-memory list. In cases where a certain store does not directly support one or more of the basic CRUD features, we might instead opt to implement the brute-force approach at the store implementation level. In other words, in order to be consumable by Biggy, and store must be compliant with the minimum feature set required by IBiggy<T> .

I propose combining the former IBiggyStore<T> and IUpdateableBiggyStore<T> :

Proposed Store Interface Organization:
public interface IBiggyStore<T> {
    List<T> Load();
    void Clear();
    T Add(T item);
    List<T> Add(List<T> items);
    T Update(T item);
    T Remove(T item);
    List<T> Remove(List<T> items);
}
  
    
public interface IQueryableBiggyStore<T> : IBiggyStore<T> {
    IQueryable<T> AsQueryable();
}

 

We can leave the IQueryableBiggyStore<T> interface as a distinct and separate item, since:

A. Most store options do not directly return an IQueryable anyway, and;

B. The premise of Biggy is that we are working with data directly in memory, and not querying directly against the backing store. IQueryable<T> is explicitly contrary to this notion, in that you are creating queries which will execute in a deferred manner against the backing store

C. Including AsQueryable<T> as part of the basic IBiggy<T> interface implies that it will always be possible to work with the store via an IQueryable instance, when in fact this is not necessarily possible (at least in any practical sense). This here might be considered a violation of the Interface Segregation Principle, in theory if not in fact.

While we can take a brute-force approach to implement (for example) an Update() method with a file-based store by writing the entire file contents to disk (including any updated data) then reading the updated file back from disk into memory, we can't, in a practical sense, write an effective IQueryable<T> provider against a file-based store that isn't doing exactly what the file-based store already does - read file contents into an in-memory list.

This doesn't mean an IQueryableBiggyStore is not useful, nor that using IQueryable from a BiggyList is not a desirable option. Simply, that to do so may be a case where one should "opt-in" through use of a specialized store, interface, and, potentially, a specialized implementation of IBiggy<T>.

In cases where the IQueryable option is desired, it almost makes sense to create a specialized IBiggy<T> implementation for this purpose, since the usage may differ significantly from the standard implementation.

In keeping with the above, we might then find the following Biggy List interfaces:

Modified IBiggy<T> with Separate IQueryableBiggy Interface
public interface IBiggy<T> : IEnumerable<T>
{
    void Clear();
    int Count();
    T Update(T item);
    T Remove(T item);
    List<T> Remove(List<T> items);
    T Add(T item);
    List<T> Add(List<T> items);
    bool InMemory { get; set; }
  
    event EventHandler<BiggyEventArgs<T>> ItemRemoved;
    event EventHandler<BiggyEventArgs<T>> ItemAdded;
    event EventHandler<BiggyEventArgs<T>> ItemsAdded;
  
    event EventHandler<BiggyEventArgs<T>> Changed;
    event EventHandler<BiggyEventArgs<T>> Loaded;
    event EventHandler<BiggyEventArgs<T>> Saved;
}
  
  
public interface IQueryableBiggy<T> : IBiggy<T> {
    IQueryable<T> AsQueryable();
}

 

Summing Up

If we were creating our stores and attendant interfaces in the context of designing a straight-forward data-access/querying library, for direct consumption by client code, the original interface structure would likely be the right choice. The interface semantics would correctly describe the functionality each store implementation is capable of providing.

In Biggy, we have created and additional abstraction layer, the in-memory list representation of a store, and we might better define our basic store interface in terms of what a minimal BiggyList implementation will require. Then, we can build out store implementations to meet the needs of the client – in this case, the BiggyList.

I would be fascinated to here contrary views on this in the comments, or you can email me at the address in the “About the Author” section.

Additional Resources and Items of Interest

 

Posted on May 19 2014 05:12 AM by jatten     

Comments (2)

ASP.NET Identity 2.0: Setting Up Account Validation and Two-Factor Authorization

Posted on April 20 2014 04:56 AM by jatten in C#, ASP.NET MVC, CodeProject, ASP.Net   ||   Comments (4)

4097092685_cd75ff7679_zWith the release of the Identity 2.0 framework in March of 2014, the Identity team has added a significant set of new features to the previously simple, but somewhat minimal ASP.NET Identity system. Some of the most visible, and in-demand features introduced with the new release are account validation and two-factor authorization.

The Identity team has created a terrific sample project/template which can effectively serve as the starting point for just about any ASP.NET MVC project you wish to build out with Identity 2.0 features. In this post, we will look at implementing email account validation as part of the account creation process, and two-factor authorization.

Image by Lucas | Some Rights Reserved

Previously, we took a very high-level tour of some of the new features available in Identity 2.0, and how key areas differ from the previous version 1.0 release. In this article, we'll take a close look at implementing Email Account Validation, and Two-Factor Authentication.

Getting Started: Create the Sample Project Using Nuget

To get started and follow along, create an empty ASP.NET project in Visual Studio (not an MVC project, use the Empty project template when creating a new project). Then, open the Package Manager Console and type:

Install the Sample Project from Nuget:
PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

Once Nuget has done its thing, you should see a familiar ASP.NET MVC project structure in the Solution Explorer:

ASP.NET Identity 2.0 Sample Project in Solution Explorer:installed-project-in-solution-explorer

 

This structure should look mostly familiar if you have worked with a standard ASP.NET MVC project before. There are, however, a few new items in there, if you look closely. For our purposes in this article, we are primarily concerned with the IdentityConfig.cs file, located in the App_Start folder.

If we open the IdentityConfig.cs file and scroll through, we find two services classes defined, EmailService and SmsService:

The Email Service and SMS Service Classes:
public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your email service here to send an email.
        return Task.FromResult(0);
    }
}
  
public class SmsService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your sms service here to send a text message.
        return Task.FromResult(0);
    }
}

 

Notice the both EmailService and SmsService implement the common interface, IIdentityMessageService. We can use IIdentityMessageService to create any number of Mail, SMS, or other messaging implementations. We'll se how this works momentarily.

Set Up A Default Admin Account

Before you go too much further, we need to set up a default Admin account that will be deployed when the site runs. The example project is set up so that the database is initialized when the project is run, and/or anytime the Code-First model schema changes. We need a default Admin user so that once the site runs, you can log in and do admin-type things, and you can't do THAT until you have a registered admin account.

As with the previous version of Identity, the default user account created during on-line registration has no admin privileges. Unlike the previous version, the first user created when the site is run is NOT an admin user. We need to seed the database during initialization.

Take a look at ApplicationDbInitializer class, also defined in IdentityConfig.cs:

The Application Db Initializer Class:
public class ApplicationDbInitializer 
    : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
    protected override void Seed(ApplicationDbContext context) {
        InitializeIdentityForEF(context);
        base.Seed(context);
    }
  
    //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
    public static void InitializeIdentityForEF(ApplicationDbContext db) 
    {
        var userManager = 
            HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
  
        var roleManager = 
            HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
  
        const string name = "admin@admin.com";
        const string password = "Admin@123456";
        const string roleName = "Admin";
  
        //Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
        if (role == null) {
            role = new IdentityRole(roleName);
            var roleresult = roleManager.Create(role);
        }
  
        var user = userManager.FindByName(name);
        if (user == null) {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
  
        // Add user admin to Role Admin if not already added
        var rolesForUser = userManager.GetRoles(user.Id);
        if (!rolesForUser.Contains(role.Name)) {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

The lines highlighted in yellow define the default admin user that will be created when the application is run for the first time. Before we proceed, change these to suit your own needs, and ideally, include a live, working email address.

Account Validation: How it works

You are no doubt familiar with email-based account validation. You create an account at some website, and a confirmation email is sent to your email address with a link you need to follow in order to confirm your email address and validate your account.

If we look at the AccountController in the example project, we find the Register method:

The Register Method on Account Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
            var callbackUrl = Url.Action(
                "ConfirmEmail", 
                "Account", 
                new { userId = user.Id, code = code }, 
                protocol: Request.Url.Scheme);
  
            await UserManager.SendEmailAsync(
                user.Id, 
                "Confirm your account", 
                "Please confirm your account by clicking this link: <a href=\"" 
                + callbackUrl + "\">link</a>");
  
            ViewBag.Link = callbackUrl;
            return View("DisplayEmail");
        }
        AddErrors(result);
    }
  
    // If we got this far, something failed, redisplay form
    return View(model);
}

 

Looking close at the above, we see a call to UserManager.SendEmailAsync where we pass in some arguments. Within AccountController, UserManager is a property which returns an instance of type ApplicationUserManager. If we take a look in the IdentityConfig.cs file in the App_Start folder, we find the definition for ApplicationUserManager. On this class, the static Create() method initializes and returns a new instance of ApplicationUserManager, and this is where our messaging services are configured:

The Create() Method Defined on the ApplicationUserManager Class:
public static ApplicationUserManager Create(
    IdentityFactoryOptions<ApplicationUserManager> options, 
    IOwinContext context)
{
    var manager = new ApplicationUserManager(
        new UserStore<ApplicationUser>(
            context.Get<ApplicationDbContext>()));
  
    // Configure validation logic for usernames
    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };
  
    // Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator
    {
        RequiredLength = 6, 
        RequireNonLetterOrDigit = true,
        RequireDigit = true,
        RequireLowercase = true,
        RequireUppercase = true,
    };
  
    // Configure user lockout defaults
    manager.UserLockoutEnabledByDefault = true;
    manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
    manager.MaxFailedAccessAttemptsBeforeLockout = 5;
  
    // Register two factor authentication providers. This application 
    // uses Phone and Emails as a step of receiving a code for verifying the user
    // You can write your own provider and plug in here.
    manager.RegisterTwoFactorProvider(
        "PhoneCode", 
        new PhoneNumberTokenProvider<ApplicationUser>
    {
        MessageFormat = "Your security code is: {0}"
    });
  
    manager.RegisterTwoFactorProvider(
        "EmailCode", 
        new EmailTokenProvider<ApplicationUser>
    {
        Subject = "SecurityCode",
        BodyFormat = "Your security code is {0}"
    });
  
    manager.EmailService = new EmailService();
    manager.SmsService = new SmsService();
    var dataProtectionProvider = options.DataProtectionProvider;
  
    if (dataProtectionProvider != null)
    {
        manager.UserTokenProvider = 
            new DataProtectorTokenProvider<ApplicationUser>(
                dataProtectionProvider.Create("ASP.NET Identity"));
    }
    return manager;
}

 

The lines highlighted in yellow show where we set the Email and SMS services on the ApplicationUserManager instance. Just above the highlighted lines, we see how we register two-factor providers for Email and SMS messages.

From the above, we can see that the Register() method of AccountController calls the SendEmailAsync method of ApplicationUserManager, which has been configured with an Email and SMS service at the time it is created.

Email validation of new user accounts, two-factor authentication via email, and two-factor authentication via SMS Text all depend upon working implementations for the EmailService and SmsService classes.

Implementing the Email Service Using Your Own Mail Account

Setting up the email service for our application is a relatively simple task. You can use your own email account, or a mail service such as Sendgrid to create and send account validation or two-factor sign-in email. For example, if I wanted to use an Outlook.com email account to send confirmation email, I might configure my Email Service like so:

The Mail Service Configured to Use an Outlook.com Host:
public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Credentials:
        var credentialUserName = "yourAccount@outlook.com";
        var sentFrom = "yourAccount@outlook.com";
        var pwd = "yourApssword";
  
        // Configure the client:
        System.Net.Mail.SmtpClient client = 
            new System.Net.Mail.SmtpClient("smtp-mail.outlook.com");
  
        client.Port = 587;
        client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
        client.UseDefaultCredentials = false;
  
        // Creatte the credentials:
        System.Net.NetworkCredential credentials = 
            new System.Net.NetworkCredential(credentialUserName, pwd);
  
        client.EnableSsl = true;
        client.Credentials = credentials;
  
        // Create the message:
        var mail = 
            new System.Net.Mail.MailMessage(sentFrom, message.Destination);
  
        mail.Subject = message.Subject;
        mail.Body = message.Body;
  
        // Send:
        return client.SendMailAsync(mail);
    }
}

 

The precise details for your SMTP host may differ, but you  should be able to find documentation. As a general rule, though, the above is a good starting point.

Implementing the Email Service Using Sendgrid

There are numerous email services available, but Sendgrid is a popular choice in the .NET community. Sendgrid offers API support for multiple languages as well as an HTTP-based Web API. Additionally, Sendgrid offers direct integration with Windows Azure.

If you have a standard Sendgrid account (you can set up a free developer account at the Sendgrid site), setting up the Email Service is only slightly different than in the previous example. First off, your network credentials will simply use your Sendgrid user name and password. Note that in this case, your user name is different than the email address you are sending from. in fact, you can use any address as your sent from address.

The EmailService Configured to Use Sendgrid:
public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Credentials:
        var sendGridUserName = "yourSendGridUserName";
        var sentFrom = "whateverEmailAdressYouWant";
        var sendGridPassword = "YourSendGridPassword";
  
        // Configure the client:
        var client = 
            new System.Net.Mail.SmtpClient("smtp.sendgrid.net", Convert.ToInt32(587));
  
        client.Port = 587;
        client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
        client.UseDefaultCredentials = false;
  
        // Creatte the credentials:
        System.Net.NetworkCredential credentials = 
            new System.Net.NetworkCredential(credentialUserName, pwd);
  
        client.EnableSsl = true;
        client.Credentials = credentials;
  
        // Create the message:
        var mail = 
            new System.Net.Mail.MailMessage(sentFrom, message.Destination);
  
        mail.Subject = message.Subject;
        mail.Body = message.Body;
  
        // Send:
        return client.SendMailAsync(mail);
    }
}

 

In the above, we see all we really had to change were our credentials, and the SMTP host string.

With that done, we can give our email service a quick trial run.

Testing Account Confirmation Using the Email Service

First, let's run our application, and attempt to register a new user. User a working email address to which you have access. If all goes well you will be redirected to a view resembling the following:

Redirect to Confirmation Sent View:

redirect-to-confirmation-view

As you can see, there is some language there indicating that you can click the link in the view to confirm account creation for the purpose of the demo. However, an actual confirmation email should have been sent to the address you specified when creating the account, and following the confirmation link will, in fact, confirm the account and allow you to log in.

Once we have our site working properly, we will obviously want to do away with the demo link, and also change the text on this view. We'll look at that shortly.

Implementing the SMS Service

To use two-factor authentication with SMS/Text, you will need an SMS host provider, such as Twilio. Like Sendgrid, Twilio is quite popular in the .NET community, and offers a comprehensive C# API. You can sign up for a free account at the Twilio Site.

When you create a Twilio account, you will be issued an SMS phone number, an account SID, and an Auth Token. You can find your Twilio SMS phone number by logging into your account, and navigating to the Numbers tab:

Locate Twilio SMS Number:

twilio-sms-number

Likewise, you can find your SID and Auth Token on the Dashboard Tab:

Locate Twilio SID and Auth Token:

twilio-sid-and-auth-token

In the above, see the little padlock icon next to the Auth Token? If you click that, your token will be visible, and can be copied for pasting into your code.

Once you have created an account, in order to use Twilio from within your application, you will need to get the Twilio Nuget package:

Add the Twilio Nuget Package Using Package Manager Console:
PM> Install-Package Twilio

 

That done, we can add Twilio to the using statements at the top of our IdentityConfig.cs file, and then implement the SMS service as follows:

The SMS Service Using Twilio:
public class SmsService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        string AccountSid = "YourTwilioAccountSID";
        string AuthToken = "YourTwilioAuthToken";
        string twilioPhoneNumber = "YourTwilioPhoneNumber";
  
        var twilio = new TwilioRestClient(AccountSid, AuthToken);
  
        twilio.SendSmsMessage(twilioPhoneNumber, message.Destination, message.Body); 
  
        // Twilio does not return an async Task, so we need this:
        return Task.FromResult(0);
    }
}

 

Now that we have both an email service and an SMS service configured, we can see if our two-factor authentication works as expected.

Testing Two-Factor Authentication

The example project is set up so that two-factor authentication is an "opt-in" feature per user. To see if everything is working properly, log in using either your default admin account, or the account you created previously when testing out the email validation feature. Once logged in, navigate to the user account area by clicking on the user name displayed top right in the browser view. You should see something like this:

The Manage User Account View:

enable-two-factor-auth

In the above window, you will want to enable two-factor authentication, and add your phone number. When you go to add your phone number, you will be sent an SMS message to confirm. If we have done everything correctly so far, this should only take a few seconds (sometimes it can be more than a few seconds, but in general, if 30 or more seconds goes by, something is probably wrong . . .).

Once two-factor auth is enabled, you can log out, and try logging in again. You will be offered a choice, via a drop-down menu, where you can choose to receive your two-factor code via email or SMS:

Select Two-Factor Authentication Method:

two-factor-choose-medium

Once you make your selection above, the two-factor code will be sent to your selected provider, and you can complete the login process.

Remove the Demo Shortcuts

As mentioned previously, the example project comes with some shortcuts built-in so that, for development and testing purposes, it is not necessary to actually send or retreive the two-factor code (or follow the account validation link from an actual email) from an email or SMS account.

Once we are ready to deploy, we will want to remove these shortcuts from the corresponding views, and also the code which passes the links/codes to the ViewBag. For example, if we take another look at the Register() method on AccountController, we can see the following code in the middle of the method:

if (result.Succeeded)
{
    var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
    var callbackUrl = 
        Url.Action("ConfirmEmail", "Account", 
            new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
  
    await UserManager.SendEmailAsync(user.Id, "Confirm your account", 
        "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
  
    // This should not be deployed in production:
    ViewBag.Link = callbackUrl;
    return View("DisplayEmail");
}
AddErrors(result);

 

The highlighted lines should be commented out or deleted in production.

Likewise, the View that is returned by the Register() method, DisplayEmail.cshtml, will need some adjustment as well:

The DisplayEmail View:
@{
    ViewBag.Title = "DEMO purpose Email Link";
}
<h2>@ViewBag.Title.</h2>
<p class="text-info">
    Please check your email and confirm your email address.
</p>
<p class="text-danger">
    For DEMO only: You can click this link to confirm the email: <a href="@ViewBag.Link">link</a>
    Please change this code to register an email service in IdentityConfig to send an email.
</p>

 

In a similar manner, the controller method VerifyCode() also pushes the two-factor code out into the view for ease of use during development, but we absolutely don't want this behavior in production:

The Verify Code Method on AccountController:
[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string provider, string returnUrl)
{
    // Require that the user has already logged in via username/password or external login
    if (!await SignInHelper.HasBeenVerified())
    {
        return View("Error");
    }
  
    var user = 
        await UserManager.FindByIdAsync(await SignInHelper.GetVerifiedUserIdAsync());
  
    if (user != null)
    {
        ViewBag.Status = 
            "For DEMO purposes the current " 
            + provider 
            + " code is: " 
            + await UserManager.GenerateTwoFactorTokenAsync(user.Id, provider);
    }
    return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl });
}

 

Also, as with the Register() method, we want to make suitable adjustments to the VerifyCode.cshtml View:

The VerifyCode.cshtml View:
@model IdentitySample.Models.VerifyCodeViewModel
@{
    ViewBag.Title = "Enter Verification Code";
}
  
<h2>@ViewBag.Title.</h2>
  
@using (Html.BeginForm("VerifyCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary("", new { @class = "text-danger" })
    @Html.Hidden("provider", @Model.Provider)
    <h4>@ViewBag.Status</h4>
    <hr />
    <div class="form-group">
        @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Code, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <div class="checkbox">
                @Html.CheckBoxFor(m => m.RememberBrowser)
                @Html.LabelFor(m => m.RememberBrowser)
            </div>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Submit" />
        </div>
    </div>
}

 

Again, the highlighted line could prove troublesome, and should be removed.

Keep Mail and SMS Account Settings Secure

The examples in this article have account user names and passwords, Auth tokes, and such hard-coded into the methods in which they are used. It is unlikely we would want to deploy this way, and equally unlikely we would even want to push our code into source control with these things exposed in such a manner (ESPECIALLY to Github!!).

Far better to put any private settings in a secure location. See Keep Private Settings Out of Source Control for more information.

The Tip of the Iceberg

ASP.NET Identity 2.0 has introduced a number of exciting new features previously not available as "out-of-the-box" features available to ASP.NET developers. Email account validation and two-factor authentication are but two of the most visible, and easily implemented (at least, within the framework of the example project provided by the Identity team!).

New features such as these have added greatly to the security arsenal available to the average developer, but have also added complexity to development of sites which utilize Identity 2.0. The Identity 2.0 team has provided some powerful security tools, but it may be easier to introduce new and harder to find security holes if we are not careful.

Additional Resources and Items of Interest

The Following Focus on Identity 1.0:

 

 

Posted on April 20 2014 04:56 AM by jatten     

Comments (4)

ASP.NET MVC and Identity 2.0: Understanding the Basics

Posted on April 20 2014 04:55 AM by jatten in ASP.NET MVC, C#, ASP.Net, CodeProject   ||   Comments (11)

Kryha-crypto-machineOn March 20, 2014, the ASP.NET team released the RTM version 2.0 of the new Identity framework. The new release brings with it some long-awaited new features, and marks a substantial expansion of the security and authorization capabilities available to ASP.NET applications of all types.

The ASP.NET Identity framework was originally introduced in 2013 as the follow-on to the ASP.NET Membership system, a staple of MVC applications for several years, but which was beginning to show its age. Originally, ASP.NET Identity presented a useful, if somewhat minimal API for managing security and authorization in the context of a public-facing web application built using ASP.NET. The Identity framework introduced modern features such as social network log-in integration, and easily extensible user model definitions.

Image by Ryan Somma  |  Some Rights Reserved

The new RTM release introduces the following features, among others:

  • Extended User Account Definition, including Email and contact information
  • Two-Factor Authentication via email or SMS messaging, functionally similar to that used by Google, Microsoft, and others
  • Account Confirmation via email
  • Administrative management of Users and Roles
  • Account Lock-Out in response to invalid log-in attempts
  • Security Token Provider to regenerate a user's security token in response to changes in security settings.
  • Improved support for Social log-ins
  • Easy Integration of Claims-Based Authorization

Identity 2.0 represents a substantial revision from the original version introduced last year. With the numerous new features, comes some added complexity. If, like myself, you had just recently found your way through the first iteration of the Identity framework, be ready. While you won't be starting over from scratch with version 2.0, there is a lot to learn.

In this article, we're going to take a look around, get familiar with the major components of the system, and in general familiarize ourselves with the new features, and where they fit in the overall scheme of things. We won't go into too much detail yet. Think of this as a familiarization tour.

If you are looking for more detailed how-to's, I will be adding posts over the next few weeks examining specific implementation concerns here:

While we will be looking at a decent amount of code, it's not necessary yet to understand the details of what it all does - just get familiar with the general concepts, where the major components are located, and how things are structured.

Identity 2.0 Introduces Breaking Changes

Identity 2.0 does not slide smoothly into place for applications written using version 1. The additional capabilities appear to have required significant changes to the architecture, and the manner in which the Identity API is consumed from within the application. Upgrading an existing ASP.NET application from Identity 1.0 to the 2.0 version will require some new code, and is beyond the scope of this article. Be aware, though, that moving from Identity 1.0 to the 2.0 version is not a simple "plug-it-in-and-go" affair.

Getting Started - Get the Examples from Nuget

As of this writing, there is not a directly available ASP.NET MVC project template using Identity 2.0. In order to take Identity for a spin, you need to pull the example project libraries into an empty ASP.NET MVC project. First, Create a new ASP.NET project, and select the Empty Project template from the template options dialog:

Select the Empty ASP.NET Project Template:

select-empty-asp-net-project-template

Once you have create the new Empty project, you can get the Identity 2.0 sample project from Nuget by typing the following into the Package Manager Console:

Install the Sample Project from Nuget:
PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

Once Nuget has done its thing, you should see a folder structure in the Solutions Explorer that looks quite like a standard MVC project. Nuget has basically added everything needed to compose a complete ASP.NET MVC project, including Models, Views, Controllers, and various components required for this basic application to run.

While at first glance the project components look fairly similar, a closer look will reveal some significant changes, and some added complexity.

Identity 2.0 Configuration - Not So Simple Anymore

In my mind, one of the strengths of the original Identity framework was also its primary weakness (strange how THAT works in software, isn't it?). The simplicity of the Identity version 1.0 made it extraordinarily easy to use, and relatively intuitive to figure out. On the other hand, the utter simplicity also meant that the feature set available "out-of-the-box" was limited, and to some, insufficient.

Just to get an idea, we'll take a quick look at some of the configuration that runs when our application starts, and compare it to the comparable code in an application which used Identity Version 1.0.

In both flavors of project, we find a class file named Startup.cs at the root level of the project. In this file a class named Startup is defined, and makes a single call to the method ConfigureAuth(). What we DON'T see anywhere in this file is an actual method named ConfigureAuth(). This is because the rest of the code for the Startup class is defined in a partial class tucked away in the App_Start folder. The code file is named Startup.Auth.cs, but if we open that, we find a standard partial class definition, which contains the ConfigureAuth() method. In a project using the original version 1.0 of the Identity Framework, the standard code for ConfigureAuth() looks like this:

Standard ConfigureAuth() Method Using Identity 1.0:
public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // Enable the application to use a cookie to 
        // store information for the signed in user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
        // Use a cookie to temporarily store information about a 
        // user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
  
        // Uncomment the following lines to enable logging 
        // in with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");
  
        //app.UseTwitterAuthentication(
        //   consumerKey: "",
        //   consumerSecret: "");
  
        //app.UseFacebookAuthentication(
        //   appId: "",
        //   appSecret: "");
  
        //app.UseGoogleAuthentication();
    }
}

 

In the above, we see some boilerplate code for configuring cookies, and some commented out code which can be uncommented, and then called to enable third-party logins from various social media providers.

In contrast, when we look at the ConfigureAuth() method in our project using Identity 2.0, we see a bit more code has been added:

ConfigureAuth() Method from Project Using Identity 2.0:
public partial class Startup {
  
    public void ConfigureAuth(IAppBuilder app) {
  
        // Configure the db context, user manager and role 
        // manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
    
        // Enable the application to use a cookie to store information for the 
        // signed in user and to use a cookie to temporarily store information 
        // about a user logging in with a third party login provider 
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider {
  
                // Enables the application to validate the security stamp when the user 
                // logs in. This is a security feature which is used when you 
                // change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator
                    .OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) 
                    => user.GenerateUserIdentityAsync(manager))
            }
        });
  
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
  
        // Enables the application to temporarily store user information when 
        // they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(
            DefaultAuthenticationTypes.TwoFactorCookie, 
            TimeSpan.FromMinutes(5));
  
        // Enables the application to remember the second login verification factor such 
        // as phone or email. Once you check this option, your second step of 
        // verification during the login process will be remembered on the device where 
        // you logged in from. This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(
            DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
  
        // Uncomment the following lines to enable logging in 
        // with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");
  
        //app.UseTwitterAuthentication(
        //   consumerKey: "",
        //   consumerSecret: "");
  
        //app.UseFacebookAuthentication(
        //   appId: "",
        //   appSecret: "");
  
        //app.UseGoogleAuthentication();
    }
}

 

Above, the first thing we notice are several calls to app.CreatePerOwinContext, wherein we register callbacks to be invoked to create instances of the type specified by the type arguments. Type instances created are then available using the context.Get() method.

What this tells us is that, at least for the purpose of the example project supplied by the Identity 2.0 team, Owin is now part of our application, and Identity 2.0 relies upon it to deliver the goods. I am not clear on whether Owin is REQUIRED in general for identity 2.0 to work, but for the purpose of our example project, it is.

We can also see some other new calls in the ConfigureAuth method body setting up Two-Factor Authentication, and some additional cookie authentication configuration code not present in the previous version. 

For our purposes here, we can assume that most of this stuff has been configured optimally for our basic use, and short of adding social media logins (which we're not going to look at in this article), we can leave this code alone. But bear in mind that this is where a lot of the Identity behavior in your application is set at runtime, based on the configuration components and helpers defined in another file in the App_Start folder, IdentityConfig.cs.

Before we go seeing what's up in IdentityConfig.cs, though, it will help us understand what's going on there is we first take a look at the ApplicationUser class, defined for us in the Models folder.

The New ApplicationUser Class in Identity 2.0

If you have built out an application using the previous version of Identity framework, you may have run into the situation where you found the core IdentityUser class rather limiting. Previously, Identity used a very simple IdentityUser implementation which represented a very minimal user profile:

The Original IdentityUser Class From Identity Version 1.0:
public class IdentityUser : IUser
{
    public IdentityUser();
    public IdentityUser(string userName);
  
    public virtual string Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual ICollection<IdentityUserRole> Roles { get; }
  
    public virtual ICollection<IdentityUserClaim> Claims { get; }
    public virtual ICollection<IdentityUserLogin> Logins { get; }
    public virtual string PasswordHash { get; set; }
    public virtual string SecurityStamp { get; set; }
}

 

Of the properties available in the above, only the first three, Id, UserName, and Roles were of much use from the business perspective of our application. The other items are mainly used by the security logic, which, while important, does not help us maintain useful information about users.

In a previous article, we examined how to extend Identity Accounts and implement Role-Based Authentication under Identity 1.0 to add more useful data, such as a user email address and/or other information which might be needed by our application.

With the advent of Identity 2.0, the need to create such work-arounds is diminished somewhat. While it is still possible to extend the Identity 2.0 ApplicationUser class in a similar manner, the Identity team has taken care of some of the more common use-cases for us.

What we find is that the example project already contains a subclass ApplicationUser, which is derived from a more complex default IdentityUser implementation.

We find the definition for ApplicationUser in the Models folder, in a file named IdentityModels.cs. We can see that the class definition itself is as simple as can be:

The ApplicationUser Class in Identity 2.0:
public class ApplicationUser : IdentityUser {
    
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager) {
        // Note the authenticationType must match the one 
        // defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = 
            await manager.CreateIdentityAsync(this, 
                DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

 

We see here that ApplicationUser is, as stated previously, a sub-class of IdentityUser. However, if we find the definition for IdentityUser (using VS Go to definition context menu item) we see that IdentityUser, as defined under the Identity 2.0 framework, is itself a sub-class of IdentityUser<TKey, TLogin, TRole, TClaim> . When we look at the definition of THAT, we find a significantly different animal from the version 1.0 implementation:

IdentityUser Implementation from Identity 2.0:
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
    where TLogin : Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<TKey>
    where TRole : Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole<TKey>
    where TClaim : Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim<TKey>
{
    public IdentityUser();
    // Used to record failures for the purposes of lockout
    public virtual int AccessFailedCount { get; set; }
    // Navigation property for user claims
    public virtual ICollection<TClaim> Claims { get; }
    // Email
    public virtual string Email { get; set; }
    // True if the email is confirmed, default is false
    public virtual bool EmailConfirmed { get; set; }
    // User ID (Primary Key)
    public virtual TKey Id { get; set; }
    // Is lockout enabled for this user
    public virtual bool LockoutEnabled { get; set; }
    // DateTime in UTC when lockout ends, any 
    // time in the past is considered not locked out.
    public virtual DateTime? LockoutEndDateUtc { get; set; }
    // Navigation property for user logins
    public virtual ICollection<TLogin> Logins { get; }
    // The salted/hashed form of the user password
    public virtual string PasswordHash { get; set; }
    // PhoneNumber for the user
    public virtual string PhoneNumber { get; set; }
    // True if the phone number is confirmed, default is false
    public virtual bool PhoneNumberConfirmed { get; set; }
    // Navigation property for user roles
    public virtual ICollection<TRole> Roles { get; }
    // A random value that should change whenever a users 
    // credentials have changed (password changed, login removed)
    public virtual string SecurityStamp { get; set; }
    // Is two factor enabled for the user
    public virtual bool TwoFactorEnabled { get; set; }
    // User name
    public virtual string UserName { get; set; }
}

 

Note in the above, a whole lot of those properties are again related to authorization and security, and not to our business needs for user data. However, the Email and PhoneNumber fields definitely go a long way towards minimizing the need for additional customization of the ApplicationUser class.

But, what's with the weird generic type arguments in the class declaration?

The new version of IdentityUser implements generic type arguments to allow for additional flexibility. As an example, recall that in Identity Version 1.0, the Id property was a string. Here, the generic type argument TKey allows us to specify the type of the Id field. We can see in the above, the Id property declaration returns the type specified by TKey:

The Id Property Declaration:
public virtual TKey Id { get; set; }

 

Also of particular note, the Roles property, defined as follows:

The Roles Property:
public virtual ICollection<TRole> Roles { get; }

 

We can see the the Type TRole is left open at compile time, and in fact is specified in the generic declaration of the IdentityUser class. If we look at the type constraints in that declaration, we see the TRole is constrained to the type IdentityUserRole<TKey> which is not terribly different from the version 1.0 implementation. What IS different, and which represents a breaking change, is the definition of IdentityUserRole itself.

Previously, in version 1.0 of the Identity Framework, IdentityUserRole was defined as follows:

The IdentityUserRole Class from Identity 1.0:
public class IdentityUserRole 
{
      public IdentityUserRole();
      public virtual IdentityRole Role { get; set; }
      public virtual string RoleId { get; set; }
      public virtual IdentityUser User { get; set; }
      public virtual string UserId { get; set; }
}

 

Compare with the Identity 2.0 Implementation:

The IdentityUserRole Class from Identity 2.0:
public class IdentityUserRole<TKey> 
{
    public IdentityUserRole();
    public virtual TKey RoleId { get; set; }
    public virtual TKey UserId { get; set; }
}

 

See what happened there? The former contained references to an IdentityRole object, and an IdentityUser object. The version 2.0 implementation contains only Id values. If you had done any customization under the previous version, such as we discussed in Implementing Group-Based Permissions, this will break things.

We will take a closer look at the new flexibility created with the new, extended IdentityUser class in a subsequent post. For now, realize that while the basic user class definition has become more complex, it has also become significantly more flexible.

Since ApplicationUser sub-classes IdentityUser, all of the above properties are available to ApplicationUser, which is the basic implementation used in the example application.

Now that we have taken a quick look at the new ApplicationUser implementation, the configuration components and helpers we are about to look at will make more sense.

Identity 2.0 Configuration Components and Helpers

While the ConfigAuth() method of the Startup class is where the runtime configuration for Identity happens during startup, we actually use the components defined in the IdentityConfig.cs file to configure how most of the Identity 2.0 features behave in our application.

If we examine the content of the IdentityConfig.cs file, we find that there are a number of individual classes defined therein. We could split each one out into its own code file, but for now, we will just examine each class independently, despite the fact that they all share the same file location in our project. Not that all of these classes are enclosed in the ApplicationName.Models namespace.

Application User Manager and Application Role Manager

The first things we run into in the IdentityConfig.cs file are two helper classes, ApplicationUserManager and ApplicationRoleManager. Be ready - large blobs of code with generic types ahead!

The Identity 2.0 Application User Manager Class:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }
  
    public static ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(
            new UserStore<ApplicationUser>(
                context.Get<ApplicationDbContext>()));
  
        // Configure validation logic for usernames
        manager.UserValidator = 
            new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
  
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6, 
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
  
        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;
  
        // Register two factor authentication providers. This application uses 
        // Phone and Emails as a step of receiving a code for verifying 
        // the user You can write your own provider and plug in here.
        manager.RegisterTwoFactorProvider("PhoneCode", 
            new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is: {0}"
        });
  
        manager.RegisterTwoFactorProvider("EmailCode", 
            new EmailTokenProvider<ApplicationUser>
        {
            Subject = "SecurityCode",
            BodyFormat = "Your security code is {0}"
        });
  
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = 
                new DataProtectorTokenProvider<ApplicationUser>(
                    dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
  
  
    public virtual async Task<IdentityResult> AddUserToRolesAsync(
        string userId, IList<string> roles)
    {
        var userRoleStore = (IUserRoleStore<ApplicationUser, string>)Store;
  
        var user = await FindByIdAsync(userId).ConfigureAwait(false);
        if (user == null)
        {
            throw new InvalidOperationException("Invalid user Id");
        }
  
        var userRoles = await userRoleStore
            .GetRolesAsync(user)
            .ConfigureAwait(false);
  
        // Add user to each role using UserRoleStore
        foreach (var role in roles.Where(role => !userRoles.Contains(role)))
        {
            await userRoleStore.AddToRoleAsync(user, role).ConfigureAwait(false);
        }
        // Call update once when all roles are added
        return await UpdateAsync(user).ConfigureAwait(false);
    }
  
  
    public virtual async Task<IdentityResult> RemoveUserFromRolesAsync(
        string userId, IList<string> roles)
    {
        var userRoleStore = (IUserRoleStore<ApplicationUser, string>) Store;
  
        var user = await FindByIdAsync(userId).ConfigureAwait(false);
        if (user == null)
        {
            throw new InvalidOperationException("Invalid user Id");
        }
  
        var userRoles = await userRoleStore
            .GetRolesAsync(user)
            .ConfigureAwait(false);
  
        // Remove user to each role using UserRoleStore
        foreach (var role in roles.Where(userRoles.Contains))
        {
            await userRoleStore
                .RemoveFromRoleAsync(user, role)
                .ConfigureAwait(false);
        }
        // Call update once when all roles are removed
        return await UpdateAsync(user).ConfigureAwait(false);
    }
}

 

For what appears to be a large chunk of code, ApplicationUserManager actually only provides a handful of very important functions - Adding new Users, Adding Users to Roles, and Removing Users from Roles. However, ApplicationUserManager is derived from the UserManager<ApplicationUser> class, so all the functionality provided by UserManager is also available to ApplicationUserManager. Other than that, there is a static Create() method defined which returns an instance of ApplicationUserManager itself. It is in this method that much of your user configuration settings and default are set up.

Of particular note in the Create() method is the call to context.Get<ApplicationDBContext>(). Remember earlier, when we looked at the ConfigAuth() method with those calls to CreatePerOwinContext and we passed in a callback method? The call to context.Get<ApplicationDbContext>() executes that call back, in this case, the static method ApplicationDbContext.Create() . We'll see more of this shortly.

If you look closely, you can see that user authorization, authentication, and management settings and defaults are set up in the Create() method, before returning a new ApplicationUserManager instance to the caller. Also, this is where two-factor auth services are set up. We can see that most of the settings are fairly self-explanatory. However, the two services bear a closer look. We'll come back to that in a moment. First, a quick look at  the ApplicationRoleManager class:

The Application Role Manager Class:
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
    public ApplicationRoleManager(IRoleStore<IdentityRole,string> roleStore)
        : base(roleStore)
    {
    }
  
    
    public static ApplicationRoleManager Create(
        IdentityFactoryOptions<ApplicationRoleManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationRoleManager(
            new RoleStore<IdentityRole>(
                context.Get<ApplicationDbContext>()));
  
        return manager;
    }
}

 

As with ApplicationUserManager, we can see that ApplicationRoleManager is derived from RoleManager<IdentityRole> and thus brings with it all of the functionality offered by that class as well. Once again, we see a static Create() method returning an instance of the class itself.

Email Service and SMS Service for Account Validation and Two-Factor Auth

Also in the IdentityConfig.cs file are two service classes, EmailService and SmsService. Out of the box, these two classes are basically empty wrappers, providing an abstraction within which you can implement Email and/or SMS services required for two-factor authentication and account validation.

The ASP.NET Identity Email Service Class:
public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your email service here to send an email.
        return Task.FromResult(0);
    }
}

 

The ASP.NET Identity SmsService Class:
public class SmsService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your sms service here to send a text message.
        return Task.FromResult(0);
    }
}

 

Note that both of these classes implement a common interface, IIdentityMessageService. Also recall in the ApplicationUserManager.Create() method, the following lines:

Setting Up the Email Service and the SMS Service in the ApplicationUserManager Create Method:
// Register two factor authentication providers. This application uses 
// Phone and Emails as a step of receiving a code for verifying 
// the user You can write your own provider and plug in here.
manager.RegisterTwoFactorProvider("PhoneCode", 
    new PhoneNumberTokenProvider<ApplicationUser>
{
    MessageFormat = "Your security code is: {0}"
});
  
manager.RegisterTwoFactorProvider("EmailCode", 
    new EmailTokenProvider<ApplicationUser>
{
    Subject = "SecurityCode",
    BodyFormat = "Your security code is {0}"
});
  
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();

 

We can see that during the course of the Create() method new instances of both EmailService and SmsService are initialized, and referenced by corresponding properties on the new ApplicationUserManager instance.

Sign-In Helper - The Basic Identity 2.0 Sign-In API

In creating the Identity Sample project, the Identity team has added a handy helper class, also found in the IdentityConfig.cs file, which wraps commonly needed calls for sign-in and authentication into an efficient and easy to use API. We can see how these methods are consumed by examining the AccountController in the Controllers folder. First, though, let's take a look at the SignInHelper class itself.

As with the previous examples, we're not going to go into much detail here, other than familiarizing ourselves with the basic structure of the class, the methods available, and get a rough idea how we might use the methods in SignInHelper from within our application.

The Sign-In Helper Class:
public class SignInHelper
{
    public SignInHelper(
        ApplicationUserManager userManager, 
        IAuthenticationManager authManager)
    {
        UserManager = userManager;
        AuthenticationManager = authManager;
    }
  
  
    public ApplicationUserManager UserManager { get; private set; }
    public IAuthenticationManager AuthenticationManager { get; private set; }
  
  
    public async Task SignInAsync(
        ApplicationUser user, 
        bool isPersistent, 
        bool rememberBrowser)
    {
        // Clear any partial cookies from external or two factor partial sign ins
        AuthenticationManager.SignOut(
            DefaultAuthenticationTypes.ExternalCookie, 
            DefaultAuthenticationTypes.TwoFactorCookie);
        var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
        if (rememberBrowser)
        {
            var rememberBrowserIdentity = 
                AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(user.Id);
            AuthenticationManager.SignIn(
                new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity, 
                rememberBrowserIdentity);
        }
        else
        {
            AuthenticationManager.SignIn(
                new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity);
        }
    }
   
  
    public async Task<bool> SendTwoFactorCode(string provider)
    {
        var userId = await GetVerifiedUserIdAsync();
        if (userId == null)
        {
            return false;
        }
    
        var token = await UserManager.GenerateTwoFactorTokenAsync(userId, provider);
  
        // See IdentityConfig.cs to plug in Email/SMS services to actually send the code
        await UserManager.NotifyTwoFactorTokenAsync(userId, provider, token);
        return true;
    }
    
  
    public async Task<string> GetVerifiedUserIdAsync()
    {
        var result = await AuthenticationManager.AuthenticateAsync(
            DefaultAuthenticationTypes.TwoFactorCookie);
  
        if (result != null && result.Identity != null 
            && !String.IsNullOrEmpty(result.Identity.GetUserId()))
        {
            return result.Identity.GetUserId();
        }
        return null;
    }
  
  
    public async Task<bool> HasBeenVerified()
    {
        return await GetVerifiedUserIdAsync() != null;
    }
  
  
    public async Task<SignInStatus> TwoFactorSignIn(
        string provider, 
        string code, 
        bool isPersistent, 
        bool rememberBrowser)
    {
        var userId = await GetVerifiedUserIdAsync();
        if (userId == null)
        {
            return SignInStatus.Failure;
        }
  
        var user = await UserManager.FindByIdAsync(userId);
        if (user == null)
        {
            return SignInStatus.Failure;
        }
  
        if (await UserManager.IsLockedOutAsync(user.Id))
        {
            return SignInStatus.LockedOut;
        }
  
        if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, provider, code))
        {
            // When token is verified correctly, clear the access failed 
            // count used for lockout
            await UserManager.ResetAccessFailedCountAsync(user.Id);
            await SignInAsync(user, isPersistent, rememberBrowser);
            return SignInStatus.Success;
        }
  
        // If the token is incorrect, record the failure which 
        // also may cause the user to be locked out
        await UserManager.AccessFailedAsync(user.Id);
        return SignInStatus.Failure;
    }
  
  
    public async Task<SignInStatus> ExternalSignIn(
        ExternalLoginInfo loginInfo, 
        bool isPersistent)
    {
        var user = await UserManager.FindAsync(loginInfo.Login);
        if (user == null)
        {
            return SignInStatus.Failure;
        }
  
        if (await UserManager.IsLockedOutAsync(user.Id))
        {
            return SignInStatus.LockedOut;
        }
  
        return await SignInOrTwoFactor(user, isPersistent);
    }
  
  
    private async Task<SignInStatus> SignInOrTwoFactor(
        ApplicationUser user, 
        bool isPersistent)
    {
        if (await UserManager.GetTwoFactorEnabledAsync(user.Id) &&
            !await AuthenticationManager.TwoFactorBrowserRememberedAsync(user.Id))
        {
            var identity = new ClaimsIdentity(DefaultAuthenticationTypes.TwoFactorCookie);
            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
            AuthenticationManager.SignIn(identity);
            return SignInStatus.RequiresTwoFactorAuthentication;
        }
        await SignInAsync(user, isPersistent, false);
        return SignInStatus.Success;
    }
  
  
    public async Task<SignInStatus> PasswordSignIn(
        string userName, 
        string password, 
        bool isPersistent, 
        bool shouldLockout)
    {
        var user = await UserManager.FindByNameAsync(userName);
        if (user == null)
        {
            return SignInStatus.Failure;
        }
  
        if (await UserManager.IsLockedOutAsync(user.Id))
        {
            return SignInStatus.LockedOut;
        }
  
        if (await UserManager.CheckPasswordAsync(user, password))
        {
            return await SignInOrTwoFactor(user, isPersistent);
        }
  
        if (shouldLockout)
        {
            // If lockout is requested, increment access failed 
            // count which might lock out the user
            await UserManager.AccessFailedAsync(user.Id);
            if (await UserManager.IsLockedOutAsync(user.Id))
            {
                return SignInStatus.LockedOut;
            }
        }
        return SignInStatus.Failure;
    }
}

 

That's a lot of code to wade through, and like I said, we're not going to look too closely right now. We are mainly here to find our way around, get oriented. We can see that the methods in this class all appear to be related to sign-in and authorization responsibilities.

The methods available in the SignInHelper class all represent some of the new features introduces in Identity 2.0. We see a familiar SignInAsync() method, of course, but then we see a host of new methods related to two-factor authorization and external log-in. Further, there appears to be a lot more going on here in order to sign in than previously.

We can look at the Login method on AccountController in the example project for an example of how authentication is handled in Identity 2.0:

The Login Method on Account Controller Using Identity 2.0:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    
    // This doen't count login failures towards lockout only two factor authentication
    // To enable password failures to trigger lockout, change to shouldLockout: true
    var result = await SignInHelper.PasswordSignIn(
        model.Email, 
        model.Password, 
        model.RememberMe, 
        shouldLockout: false);
    
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresTwoFactorAuthentication:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}

 

Signing in: Compare to Identity 1.0

If we take a quick look at how the log-in task was handled in an MVC project using Identity 1.0, we can go straight to the AccountController.Login method, and we find the following bit of code:

The Login Method on Account Controller Using Identity 1.0:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindAsync(model.UserName, model.Password);
        if (user != null)
        {
            await SignInAsync(user, model.RememberMe);
            return RedirectToLocal(returnUrl);
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
  
    // If we got this far, something failed, redisplay form
    return View(model);
}

 

Within the method above, we call into a UserManager class, similar to the code we saw for the SignInHelper. We also call the SignInAsync method, also defined directly in AccountController:

The SignInAsync Method on Account Controller Using Identity 1.0:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(
        DefaultAuthenticationTypes.ExternalCookie);
 
    var identity = await UserManager.CreateIdentityAsync(
        user, DefaultAuthenticationTypes.ApplicationCookie);
 
    AuthenticationManager.SignIn(
        new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

 

Obviously, with the added features related to security, authentication, and authorization comes additional complexity, even at the basic log-in level.

The Heart of it All - ApplicationDbContext

If you have spent any time at all working with ASP.NET MVC in general, and Identity in particular, you are likely familiar with the ApplicationDbContext. This is the default Entity Framework implementation class by which your application accesses and stores Identity-related data.

In the example project, the team has set this up a little differently than in the standard ASP.NET project using Identity 1.0. First, if we take a look in the IdentityModels.cs file, we find the ApplicationDbContext class defined thusly:

The ApplicationDbContext Class from Identity 2.0 Example Project:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> {
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false) {
    }
  
    static ApplicationDbContext() {
        // Set the database intializer which is run once during application start
        // This seeds the database with admin user credentials and admin role
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
  
    public static ApplicationDbContext Create() {
        return new ApplicationDbContext();
    }
}

 

The code above sets up two static methods, Create() , and another, ApplicationDbContext(), which sets a database initializer. This latter method is called during startup, and performs whatever database initialization is established in the ApplicationDbInitializer class.

If we go back to the IdentityConfig.cs file, we find the ApplicationDbInitializer defined like so:

The ApplicationDbInitializer Class from the IdentityConfig.cs File:
public class ApplicationDbInitializer 
    : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
  
    protected override void Seed(ApplicationDbContext context) 
    {
        InitializeIdentityForEF(context);
        base.Seed(context);
    }
  
  
    public static void InitializeIdentityForEF(ApplicationDbContext db) 
    {
        var userManager = HttpContext
            .Current.GetOwinContext()
            .GetUserManager<ApplicationUserManager>();
  
        var roleManager = HttpContext.Current
            .GetOwinContext()
            .Get<ApplicationRoleManager>();
  
        const string name = "admin@admin.com";
        const string password = "Admin@123456";
        const string roleName = "Admin";
  
        //Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
        if (role == null) 
        {
            role = new IdentityRole(roleName);
            var roleresult = roleManager.Create(role);
        }
  
        var user = userManager.FindByName(name);
        if (user == null) 
        {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
  
        // Add user admin to Role Admin if not already added
        var rolesForUser = userManager.GetRoles(user.Id);
        if (!rolesForUser.Contains(role.Name)) 
        {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

As it is currently configured, this initializer will drop and re-create the database is the model schema (as defined by our code-first model objects) has changed. Otherwise, it will continue using the existing database.

If we want to drop and re-create the database every time our application is run we could change the base class from which it inherits to DropCreateDatabaseAlways<ApplicationDbContext>. We might want to do this during development if we wanted to start with an empty (or nearly so) data set every time for testing, for example.

Also, take note of the InitializeIdentityForEF() method. This method performs a function similar to that of the Seed() method when we use EF Migrations, allowing us to initialize the database with some data. In this case, the example project is set up with a pre-defined admin user, password, and role.

Ok John, That's All Great. Now What?

In this article we have looked broadly at where some of the new features and configuration items live in an ASP.NET MVC project using the Identity 2.0 framework. There is a lot more to it, and we will look at specifics in several upcoming posts.

For now, explore and run the example project, and get more familiar with how things work.

Additional Resources and Items of Interest

The Following Focus on Using the Identity 1.0 Framework:

 

 

Posted on April 20 2014 04:55 AM by jatten     

Comments (11)

About the author

My name is John Atten, and my "handle" on many of my online accounts is xivSolutions. I am Fascinated by all things technology and software development. I work mostly with C#, JavaScript/Node, and databases of many flavors. Actively learning always. I dig web development. I am always looking for new information, and value your feedback (especially where I got something wrong!). You can email me at:

jatten at typecastexception dot com

Web Hosting by