About the author

J Sawyer is a developer based in Houston, TX and loves to write code, especially ASP.NET and other web-related stuff. He is currently working on implementing Team Foundation Server at a large energy company in Houston and is loving that too.

He also loves to ride his Yamaha FZ1. And sometimes his Ninja 650.

But he doesn't code and ride at the same time. That would be bad.

.NET Dojo: ASP.NET MVC

July 22, 2008 7:37 PM

First, what's this .Net Dojo stuff? Well, here it is ... it is a new series of events (I'm hoping monthly) that we will be having monthly to help developers hone and sharpen their .Net Kung Fu. It will be a combination of lecture and hands-on labs ... lecture to explain the concepts (of course) and hands-on to let you get your fingers dirty playing with the technology. Since it is hands-on, you will need to bring a laptop to do the labs and (possibly) install some additional prerequisites before the session (these will be listed, of course). They will be held at the Houston Microsoft office from 1:00 PM to 5:00 PM and cover a wide range of .Net topics. I'm also hoping to be able to get some of the technical leaders here in Houston to deliver some of the sessions ... so that you'll be learning from the best around.

Ben Scheirman of Sogeti has volunteered to deliver the very first .Net Dojo on the ASP.NET MVC Framework. (Didn't I tell you that I wanted to get the best around?) Here are the details:

Overview: ASP.NET MVC is one of the key new features that will be included in .NET Framework 3.5 Service Pack1. It provides a framework that enables you to easily implement the model-view-controller (MVC) design pattern in your web applications, helping you build loosely-coupled, pluggable components for application design, logic and display. While not a replacement for traditional ASP.NET WebForms, ASP.NET MVC does provide a compelling alternative for developing web applications and better facilitates test driven development (TDD) in web applications. This workshop will dig into what ASP.NET MVC is, what it does, and how it is different from WebForms.

What you will learn: Through a combination of lecture and hands-on labs, attendees will learn how to create ASP.NET MVC applications using Visual Studio 2008 and how to work with the key components of an ASP.NET MVC application. Additionally, they will learn how to test their MVC components and applications using TDD principles.

Prerequisites: To fully participate in this workshop, attendees will need the following:

  • An open mind
  • A working knowledge of ASP.NET, C#, HTML and CSS.
  • A laptop with:
    • Visual Studio 2008 Professional or higher (Trial is OK)
    • ASP.NET MVC Preview 4 (available as a separate download.
    • A CD-ROM drive to load additional components and lab files.

Sign up here ... but hurry ... space is limited!

Hope to see you there ...

Tags: , ,

.NET Stuff | Events | Web (and ASP.NET) Stuff

C# SIG Presentation

July 22, 2008 11:59 AM

I have uploaded (finally) the presentation that I delivered to the C# SIG last Wednesday, July 16 to my SkyDrive. You can download it here.

I did make some little modifications to it though ... and they address one of the outstanding questions of the evening ... how does ASP.NET Role-based security work with ASP.NET Dynamic Data? Well, it's pretty simple and straightforward, actually.

Some background first. ASP.NET Dynamic Data uses SP1's UrlRoutingModule to map requests to the correct table ... with the name of the table appearing as a directory on the web site. So, when editing the "Products" table, the URL will be http://mydatasite/Products/[NameOfView]. Adding authentication and authorization for the entire site is a no-brainer; just add the authorization element into the web.config with the proper entries and you're done. Doing it for individual tables is just about as easy; in this case, you just need to add a location element to your web.config and configure the settings for the location. For example:

<location path="products">
  <system.web>
    <authorization>
      <allow roles="Products"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>

In this case, we have defined a role called "Products" that can edit (and view, of course) the products table, but no one else can. This will behave exactly as would a "real" folder in any ASP.NET web site using role-based authorization with the built-in RoleManager (regardless of where the roles are actually coming from!).

As I said, I added this to the demos that I uploaded. All access to the site is authenticated; no anonymous users are allowed. There are 2 roles - Products, which can edit the Products table and HR, which can edit the Employees table - and 3 users. All users have the same password (Pass@word1). Here's the breakdown:

User ID Role
User1 HR
User2 Products
User3 <No Role>

 

You can, of course, get a bit more complicated than this, but you'd have to do some additional customization of the different pages to do that.



Tags: , ,

Community | User Groups | Web (and ASP.NET) Stuff

Cool way to do ASP.NET Caching with Linq

July 11, 2008 8:18 PM

OK, well, I think it's cool (and since the mind is its own place ...). I've been a big fan of ASP.net's cache API since I found out it way back in the 1.0 beta. It certainly solves something that was problematic in ASP "Classic" in a clean, elegant and darn easy to use way. Unfortunately, not a lot of folks seem to know about it. So I'll start with a little overview of ASP.net caching.

As the name implies, it's a cache that sits server side. All of the relevant, .Net-supplied classes are in the System.Web.Caching namespace and the class representing the cache itself is System.Web.Caching.Cache. You can access it from the current HttpContext (which you'll see). The management of the cache is handled completely by ASP.net ... you just have to add objects to it and then read from it. When you add to the cache, you can set options like dependencies, expiration, priority and a delegate to call when the item is removed from the cache. Dependencies are interesting ... they will automatically invalidate (and remove) the cache item based on notification from the dependency. ASP.net 1.x had only 1 cache dependency class (System.Web.Caching.CacheDependency) that allowed you to have a dependency on a file, another cache item, and array of them or another CacheDependency. Framework 2.0 introduced System.Web.Caching.SqlCacheDependency for database dependencies and System.Web.Caching.AggregateCacheDependency for multiple, related dependencies. With the AggregateCacheDependency, if one of the dependencies changes, it item is invalidated and tossed from the cache. Framework 2.0 also (finally) "unsealed" the CacheDependency class, so you could create your own cache dependencies. With expiration, you can have an absolute expiration (specific time) or a sliding expiration (TimeSpan after last access). Priority plays into the clean-up algorithm; the Cache will remove items that haven't expired if the cache taking up too much memory/resources. Items with a lower priority are evicted first. Do yourself a favor and make sure that you keep your cache items reasonable. Your AppDomain will thank you for it.

ASP.net also provides page and partial-page caching mechanisms. That, however, is out of our scope here. For the adventurous among that don't know what that is ...

So ... the cache ... mmmmm ... yummy ... gooooood. It's golly-gee-gosh-darn useful for items that you need on the site, but don't change often. Those pesky drop-down lookup lists that come from the database are begging to be cached. It takes a load off the database and is a good way to help scalability - at the cost of server memory, of course. (There ain't no free lunch.) Still, I'm a big fan of appropriate caching.

So ... what's the technique I mentioned that this post is title after? Well, it's actually quite simple. It allows you to have 1 single common method to add and retrieve items from the cache ... any Linq item, in fact. You don't need to know anything about the cache ... just the type that you want and the DataContext that it comes from. And yes, it's one method to rule them all, suing generics (generics are kewl!) and the Black Voodoo Majick goo. From there, you can either call it directly from a page or (my preferred method) write a one-line method that acts as a wrapper. The returned objects are detached from the DataContext before they are handed back (so the DataContext doesn't need to be kept open all) and returned as a generic list object. The cache items are keyed by the type name of the DataContext and the object/table so that it's actually possible to have the same LinqToSql object come from two different DataContexts and cache both of them. While you can load up the cache on application start up, I don't like doing that ... it really is a killer for the app start time. I like to lazy load on demand. (And I don't wanna hear any comments about the lazy.)

Here's the C# code:

/// <summary>
/// Handles retrieving and populating Linq objects in the ASP.NET cache
/// </summary>
/// <typeparam name="LinqContext">The DataContext that the object will be retrieved from.</typeparam>
/// <typeparam name="LinqObject">The object that will be returned to be cached as a collection.</typeparam>
/// <returns>Generic list with the objects</returns>
public static List<LinqObject> GetCacheItem<LinqContext, LinqObject>()
    where LinqObject : class
    where LinqContext : System.Data.Linq.DataContext, new()
{
    //Build the cache item name. Tied to context and the object.
    string cacheItemName = typeof(LinqObject).ToString() + "_" + typeof(LinqContext).ToString();
    //Check to see if they are in the cache. 
    List<LinqObject> cacheItems = HttpContext.Current.Cache[cacheItemName] as List<LinqObject>;
    if (cacheItems == null)
    {
        //It's not in the cache -or- is the wrong type. 
        //Create a new list.
        cacheItems = new List<LinqObject>();
        //Create the contect in a using{} block to ensure cleanup. 
        using (LinqContext dc = new LinqContext())
        {
            try
            {
                //Get the table with the object from the data context.
                System.Data.Linq.Table<LinqObject> table = dc.GetTable<LinqObject>();
                //Add to the generic list. Detaches from the data context. 
                cacheItems.AddRange(table);
                //Add to the cache. No absolute expirate and a 60 minute sliding expiration
                HttpContext.Current.Cache.Add(cacheItemName, cacheItems, null,
                    System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60),
                    System.Web.Caching.CacheItemPriority.Normal, null);
            }
            catch (Exception ex)
            {
                //Something bad happened.
                throw new ApplicationException("Could not retrieve the request cache object", ex);
            }
        }
    }
    //return ... 
    return cacheItems;
}

And in VB (see, I am multi-lingual!) ...

''' <summary>
''' Handles retrieving and populating Linq objects in the ASP.NET cache
''' </summary>
''' <typeparam name="LinqContext">The DataContext that the object will be retrieved from.</typeparam>
''' <typeparam name="LinqObject">The object that will be returned to be cached as a collection.</typeparam>
''' <returns>Generic list with the objects</returns>
Public Shared Function GetCacheItem(Of LinqContext As {DataContext, New}, LinqObject As Class)() As List(Of LinqObject)
    Dim cacheItems As List(Of LinqObject)

    'Build the cache item name. Tied to context and the object.
    Dim cacheItemName As String = GetType(LinqObject).ToString() + "_" + GetType(LinqContext).ToString()
    'Check to see if they are in the cache. 
    Dim cacheObject As Object = HttpContext.Current.Cache(cacheItemName)

    'Check to make sure it's the correct type.
    If cacheObject.GetType() Is GetType(List(Of LinqObject)) Then
        cacheItems = CType(HttpContext.Current.Cache(cacheItemName), List(Of LinqObject))
    End If

    If cacheItems Is Nothing Then
        'It's not in the cache -or- is the wrong type. 
        'Create a new list.
        cacheItems = New List(Of LinqObject)()
        'Create the contect in a using   block to ensure cleanup. 
        Using dc As LinqContext = New LinqContext()
            Try
                'Get the table with the object from the data context.
                Dim table As Linq.Table(Of LinqObject) = dc.GetTable(Of LinqObject)()
                'Add to the generic list. Detaches from the data context. 
                cacheItems.AddRange(table)
                'Add to the cache. No absolute expirate and a 60 minute sliding expiration
                HttpContext.Current.Cache.Add(cacheItemName, cacheItems, Nothing, _
                    Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60), _
                   CacheItemPriority.Normal, Nothing)
            Catch ex As Exception
                'Something bad happened.
                Throw New ApplicationException("Could not retrieve the request cache object", ex)
            End Try
        End Using
    End If

    'return ... 
    Return cacheItems
End Function

 

The comments, I think, pretty much say it all. It is a static method (and the class is a static class) because it's not using any private fields (variables). This does help performance a little bit and, really, there is no reason to instantiate a class if it's not using any state. Also, note the generic constraints - these are actually necessary and make sure that we aren't handed something funky that won't work. These constraints are checked and enforced by the compiler.

Using this to retrieve cache items is now quite trivial. The next example shows a wrapper function for an item from the AdventureWorks database. I made it a property but it could just as easily be a method. We won't get into choosing one over the other; that gets religious.

public static List<StateProvince> StateProvinceList
{
    get
    {
        return GetCacheItem<AdvWorksDataContext, StateProvince>(); 
    }
}

And VB ...

Public ReadOnly Property StateProvinceList() As List(Of StateProvince)
    Get
        Return GetCacheItem(Of AdvWorksDataContext, StateProvince)()
    End Get
End Property

Isn't that simple? Now, if you only have one DataContext type, you can safely code that type into the code instead of taking it as a generic. However, looking at this, you have to admit ... you can use this in any ASP.net project where you are using Linq to handle the cache. I think it's gonna go into my personal shared library of tricks.

As I think you can tell, I'm feeling a little snarky. It's Friday afternoon so I have an excuse. BTW ... bonus points to whoever can send me an email naming the lit reference (and finish it!) in this entry. Umm, no it isn't Lord of the Rings.



Tags: , , ,

.NET Stuff | Linq | Web (and ASP.NET) Stuff

New Account Email Validation (Part II)

June 25, 2008 8:39 PM

In my previous post, I discussed the things to keep in mind with new account validation. Well, as promised, I've done a sample of one way to do this.

Certainly step 1 to to do as much as possible without writing any code, following the KISS principle. Since I am using the CreateUserWizard Control, I set the DisableCreatedUser property to true and LoginCreatedUser to false. Easy enough. But that's not the whole story. We need to generate the actual validation key. There are a lot of ways that one can do this. Personally, I wanted, as much as possible, to not have any dependency on storing the validation code in the database anywhere. This, of course, ensures that, should our database be penetrated, the validation codes cannot be determined. With that, then, the validation code should come from data that is supplied by the user and then generated in a deterministic way on the server. Non-deterministic, of course, won't work too well.

I started down (and really, almost completed) a path that took the UserName and Email, concatenated them, generating the bytes (using System.Security.Cryptography.Rfs2898DeriveBytes) to create a 32-byte salt from this. I again concatenated the UserName and email, then hashing it with SHA1. This certainly satisfied my conditions ... the values for this would come from the user and so the validation code didn't need to be stored. And it was certainly convoluted enough that a validation code would be highly difficult to guess, even by brute force. In the email to the user, I also included a helpful link that passed the validation code in the query string. Still, this code was some 28 characters in length. Truly, not an ideal scenario. And definitely complex. It was certainly fun to get the regular expression to validate this correct ... more because I'm just not all that good at regular expressions then anything else. If you are interested, the expression is ^\w{27}=$, just in case you were wondering.

Thinking about this, I really didn't like the complexity. It seems that I fell into that trap that often ensnares developers: loving the idea of a complex solution. Yes, it's true ... sometime developers are absolutely drawn to create things complex solutions to what should be a simple problem because they can. I guess is a sort of intellectual ego coming out ... we seem to like to show off how smart we are. And all developers can be smitten by it. Developing software can be complex enough on its own ... there really is no good reason to add to that complexity when you don't need to. There are 3 key reasons that come to mind for this. 1) The code is harder to maintain. Digging through the convolutions of overly complicated code can make the brain hurt. I've done it and didn't like it at all. 2) The more complex the code, the more likely you are to have bugs or issues. There's more room for error and the fact that it's complicated and convoluted make it easier to introduce these errors and then miss them later. It also makes thorough testing harder, so many bugs may not be caught until it's too late.

So, I wound up re-writing the validation code generation. How did I do it? It's actually very simple. First, I convert the user name, email address and create date into byte arrays. I then loop over all of the values, adding them together. Finally, I subtract the sum of the lengths of the user name, password and creation date and subtract from the previous value. This then becomes the validation code. Typically, it's a 4 digit number. This method has several things going for it. First, it sticks to the KISS principle. It is simple. There are very few lines of code in the procedure and these lines are pretty simple to follow. There are other values that can be used ... for example, the MembershipUser's ProviderKey ... when you are using the Sql Membership provider, this is a GUID. But not depending on it gives you less dependence on this. Second, it is generated from a combination of values supplied by the user and values that are kept in the database. There is nothing that indicates what is being used in the code generation ... it's just a field that happened to be there. This value is not as random as the previous, I know. It's a relatively small number and a bad guy could likely get it pretty quickly with a brute-force attack if they knew it was all numbers. To mitigate against this, one could keep track of attempted validations with the MembershipUser using the comments property, locking the account when there are too many attempts within a certain time period. No, I did not do this. Considering what I was going to use the for (yes, I am actually going to use it), the potential damage was pretty low and I felt that it was an acceptable risk. Overall, it's a pretty simple way to come up with a relatively good validation code. And it's also very user-friendly. Here's the code:

public static string CreateValidationCode(System.Web.Security.MembershipUser user)
{
    byte[] userNameBytes = System.Text.Encoding.UTF32.GetBytes(user.UserName);
    byte[] emailBytes = System.Text.Encoding.UTF32.GetBytes(user.Email);
    byte[] createDateBytes = System.Text.Encoding.UTF32.GetBytes(user.CreationDate.ToString());

    int validationcode = 0;
    foreach (byte value in userNameBytes)   { validationcode += value; }
    foreach (byte value in emailBytes)      { validationcode += value; }
    foreach (byte value in createDateBytes) { validationcode += value; }

    validationcode -= (user.UserName.Length + user.Email.Length + user.CreationDate.ToString().Length);
    return validationcode.ToString(); 

}

Architecturally, all of the code related to this is in a single class called MailValidation. Everything related to the validation codes is done in that class, so moving from the overly-complex method to my simpler method was easy as pie. All I had to do was change the internal implementation. Now that I think of it, there's no reason why it can't be done using a provider model so that different implementations are plug-able.

Once the user is created, we generate the validation code. It is never stored on the server, but is sent to the user in an email. This email comes from the MailDefinition specified with the CreateUserWizard ... this little property points to a file that the wizard will automatically send to the new user. It will put the user name and password in there (with the proper formatting), but you'll need to trap the SendingMail event to modify it before it gets sent in order to put the URL and validation code in the email.

//This event fires when the control sends an email to the new user. 
protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)
{
    //Get the MembershipUser that we just created.
    MembershipUser newUser = Membership.GetUser(CreateUserWizard1.UserName);
    //Create the validation code
    string validationCode = MailValidation.CreateValidationCode(newUser);

    //And build the url for the validation page. 
    UriBuilder builder = new UriBuilder("http",
        Request.Url.DnsSafeHost,
        Request.Url.Port, Page.ResolveUrl("ValidateLogin.aspx"), "C=" + validationCode); 
    //Add the values to the mail message. 
    e.Message.Body = e.Message.Body.Replace("<%validationurl%>", builder.Uri.ToString());
    e.Message.Body = e.Message.Body.Replace("<%validationcode%>", validationCode);
    
}

One thing that I want to point out here ... I'm using the UriBuilder class to create the link back tot he validation page. Why don't I just take the full URL of the page and replace "CreateAccount.aspx" with the new page? Well, I would be concerned about canonicalization issue. I'm not saying that there would be any, but it's better to be safe. The UriBuilder will give us a good, clean url. The port is added in there so that it works even if it's running under the VS development web server, which puts the site on random ports. I do see a lot of developers using things like String.Replace() and parsing to get urls in these kinds of scenarios. I really wish they wouldn't.

Things do get a little more complicated, however, when actually validating the code. There is a separate form, of course, that does this. Basically, it collects the data from the user, regenerated the validation key and then compares them. It also checks the user's password by calling Membership.ValidateUser. If either of these fails, the user is not validated. Seems simple, right? Well, there is a monkey wrench in here. If the MembershipUser's IsValidated property is false, ValidateUser will always fail. So we can't fully validate the user until they are validated. But ... we need the password to validate their user account. See the problem? If I just check the validation code and the password is incorrect, you shouldn't be able to validate. What I had to wind up doing was this: once the validation code was validated, I had to then set IsApproved to true. Then I'd called ValidateUser. If this failed, I'd then set it back.

protected void Validate_Click(object sender, EventArgs e)
{
    //Get the membership user. 
    MembershipUser user = Membership.GetUser(UserName.Text);

    bool validatedUser = false;
    if (user != null)
    {
        if (MailValidation.CheckValidationCode(user, ValidationCode.Text))
        {
            //Have to set the user to approved to validate the password
            user.IsApproved = true;
            Membership.UpdateUser(user);
            if (Membership.ValidateUser(UserName.Text, Password.Text))
            {
                validatedUser = true;
            }
        }
    }
    //Set the validity for the user.
    SetUserValidity(user, validatedUser);
}

You do see, of course, where I had to Approve the user and then check. Not ideal, not what I wanted, but there was really no other way to to it. There are a couple of things, however, that I want to point out. Note that I do the actual, final work at the very end of the function. Nowhere am I called that SetUserValidity method until the end after I've explored all of code branches necessary. Again, I've seen developers embed this stuff directly in the If blocks. Ewww. And that makes it a lot harder if someone needs to alter the process later. Note that I also initialize the validatedUser variable to false. Assume the failure. Only when I know it's gone through all of the tests and is good do I set that validatedUser flag to true. It both helps keep the code simpler and ensure that if something was missed, it would fail.

Well, that's it for now. You can download the code at http://code.msdn.microsoft.com/jdotnet.



Tags: , ,

.NET Stuff | Security | Web (and ASP.NET) Stuff

New Account Email Validation (Part I)

June 18, 2008 9:31 AM

We’ve all seen it … when you sign up for a new account, your account isn’t active until you validate it from an email sent to the registered email address. This allows sites with public registration to ensure a couple of things. First, that the email provided by the user actually does exist (and they didn’t have a typo). Second, it also validates that the person signing up has access to that email address. Now, let’s be clear, it doesn’t necessarily ensure that the user signing up is the legitimate owner of the email address … there isn’t much more that we can do to actually validate that as we don’t control the email system that they use … but, in a realistic world, that’s the best we can do.

Now, there was a little exchange recently on the ASP.NET forums that I had with someone asking how to do this very thing with ASP.NET’s membership system. Of course, this is perfectly possible to do. Now, I do believe in the KISS (that’s Keep It Simple Stupid) principle, so I look at this from a perspective of using as much built-in functionality as possible to accomplish it. So, for example, I’d really prefer not to have any additional database dependencies such as new tables, etc., to support this new functionality (that isn’t there out-of-the-box) as possible.

First things first … when the new account is created, the account (represented by the MembershipUser class) should have the IsApproved property set to false. This will prevent any logins until such time as the flag is changed. There are two ways to do this, depending on how you the user signs up. If you are using the built-in CreateUserWizard, you can set the DisableCreatedUser property to true.You can also do it if you are calling the API directly from a custom WebForm (or other method). This is accomplished by calling the CreateUser method on the Membership class. There are two overloads that will allow you to do this; both of them take a boolean IsApproved argument. Again, if this is false, the user won’t be allowed to log in until they are approved.

Of course, in extranet-type scenarios with some user self-service, this can be used to validate that the newly registered extranet user is valid via a manual review process. And in those types of cases, because of the very nature of extranets, you would want it to be a manual review process to thoroughly vet the users. Note that you’ll also want to do this if you happen to be a judge and you may have some nasty personal stuff that some people may find offensive think leads to a conflict of interest in a case that you are trying.

But that’s not what we are doing here. We want this to be open and completely self-service, but to still validate that the email is valid and the user has access to it, ensuring that we can communicate with them (or spam them, depending on your viewpoint).

We’ve already discussed the whole e-mail-account-security thing … nothing that we can do about that, so we’ll just move on. But how can we further ensure that we have a (relatively) secure method for doing this, even with the whole e-mail security issue?

First, we need to make sure that whatever validation code we use is not easy for a bad guy to guess … this does defeat the purpose. How far you go with this will certainly depend a great deal on what the risk is from this failure … for example, if this is a site where you have dog pictures, it’s not that big of a deal. If, however, it’s an ecommerce site, you need to be a bit more cautious.

Second, we also need to make sure that the validation code wasn’t intercepted en route. Keep in mind – and a number of devs seem to forget this – SMTP is not a secure protocol. Neither is POP3. They never were; they just weren’t designed for it. (This highlights one of the things that I tell developers a lot … There is no majik security pixii dust … you cannot bolt “security” on at the end of the project; it absolutely must be built in from the initial design and architecture phase.) Everything in SMTP is transmitted in the clear, as is POP3. In fact, if you’re feeling ambitious, you can pop open a telnet client and use it for SMTP and POP3. It’s not the most productive but it is enlightening.

These are the two things that come to mind that are unique to this scenario. There are additional things that you need to account for … Sql Injection, XSS and the rest of the usual suspects.

Now that I’ve said all of that, I will also tell you that I’m working on a sample that shows some techniques for doing this. When I’m done, I will post it here along with a discussion of what was done and what alternative options are that you can do based on your needs, requirements and risk analysis. So … keep tuned right here for more fun and .Net goodness!



Tags: , ,

.NET Stuff | Security | Web (and ASP.NET) Stuff