Tag Archives: .net

Picking the right .NET Framework Version with Specific Reference

This morning I needed to work on a long-standing ASP.NET web application project. I haven’t had to run it locally for quite a while. I updated my source from TFS, cleaned and built the solution, and started the project in debug mode. After logging in, I went to a page, and was suddenly staring at an unexpected and confusing exception:

The base class includes the field 'ScriptManager1', 
but its type (System.Web.UI.ScriptManager) 
is not compatible with the type of control 
(System.Web.UI.ScriptManager).

I put aside the surprise that a type was not compatible with itself, and checked the source control history. The specific page hadn’t been changed since the last time I’d tried it. I know the project is under active development, including a recent deployment of the latest version at the client site, so I had ever reason to believe the build should work.

Before sending a panicked email to my team, I did a quick Google search. I found a couple links of similar people with this problem in VS2008, but I’m still running VS2005.

I realized, however, that I had installed Framework versions 3.0 and 3.5 since I had last had to work on this project. I went to the project references, and checked that for System.Web.Extensions, and noticed that “Specific Reference” was set to false. I set this to true, rebuilt the project, and started the debugger again.

This time, success! The page displayed as expected.

What problems have you encountered from having multiple .NET Frameworks installed?

Using two Membership Providers for ASP.NET logins

I quite like the Microsoft Membership Framework for handling membership roles, authentication, and security resources in ASP.NET applications. It’s easy to create the initial user login and management framework for a new application, then swap in a more sophisticated Provider as needed.

For my current project, we have a new requirement to allow logins against multiple user stores. The existing application validates against an Active Directory store. But for a subset of users, there is a need to check if they are in a SQL Server database and allow them to login while they wait for their Active Directory setup to complete. This SQL Server also contains a secondary set of roles that will be relevant for any user that is in the SQL Server user store, regardless of whether they were validated via AD or the SQL Server.

The first step I took was to figure out the easiest way to have two separate providers to validate the user. You can configure as many membership providers as you want in the web.config for your application, but you choose a default provider as part of the setup. If you use the standard Login control, it will only check against that default provider.

In order to change that behavior, I overrode the Login.Authenticate event for my Login control. The method looks a little like this:

    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
    {
        bool foundUser = false;
        List<string> roles = new List<string>();
        roles.Add("GeneralUser");
        // this will call the default MembershipProvider
        if (Membership.Provider.ValidateUser(LoginBox.UserName, LoginBox.Password))
        {
            foundUser = true;
            // do any additional lookups for this type of user (Default MembershipProvider) here
        } // otherwise, explicitly call secondary provider
        else if (
            Membership.Providers["SecondarySqlMembershipProvider"].ValidateUser(LoginBox.UserName,
                                                                                LoginBox.Password))
        {
            foundUser = true;
            roles.Add("SecondaryUser");
            // do any additional lookups relevant to this type of user
        }
        if (foundUser)
        {
            Session["UserId"] = LoginBox.UserName;
            Session["Groups"] = roles;
        }
        e.Authenticated = foundUser;
    }

I didn’t need to modify the Authentication Ticket or cookie, so I could rely on the Membership Framework to handle the rest. If I need to add additional information, I can do it in the commented spots to correctly handle the type of user I care about.

Role aware ASP.NET web controls

A common feature I’ve found necessary for web applications is role-based security at the field level. For example, I may have a form that allows editing a user’s information. The requirements may include the rule that only certain types (roles) may edit certain fields.

This can be accomplished in myriad ways. You can create a different form per role, and direct the user to the appropriate form. Or you can put specific logic around each relevant field to show, enable, or hide each field.

Both these routes can lead to a lot of extra coding, and even more maintenance. I’d like to be able to tell each affected field to display itself correctly based on the user’s role.

The Microsoft.NET Framework 2.0 introduced the Membership and Roles framework and the Microsoft Provider Model, which gives us an API-based way to interface with users and roles. If you use a RoleManager (either one of the defaults provided or your own custom implementation), the following code gives an example of how you can extend the existing WebControls to render themselves based on a current user’s roles.

using System.Web.UI;
using System.Web.UI.WebControls;
using System;
using System.ComponentModel;
namespace RoleAwareServerControls
{
    ///
    /// Role Aware Text Box. Will only render as Enabled if user is
    /// in the in the RoleName.
    ///
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:RoleAwareTextBox runat=server RoleName=user></{0}:RoleAwareTextBox>")]
    public class RoleAwareTextBox : System.Web.UI.WebControls.TextBox
    {
        private bool visibleIfUnauthorized;
        ///
        /// if user is not in role, should the field be displayed at all?
        ///
        public bool VisibleIfUnauthorized
        {
            get { return visibleIfUnauthorized; }
            set { visibleIfUnauthorized = value; }
        }
 
        private String roleName;
        ///
        /// if user is in this role, enable this field, else not
        ///
        public String RoleName
        {
            get { return roleName; }
            set { roleName = value; }
        }
 
        ///
        /// determine if TextBox should be Enabled or Visible
        ///
        ///An EventArgs
       /// that contains the event data.
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            // assume normal display if RoleName not set
            if (!String.IsNullOrEmpty(roleName))
            {
                Enabled =
                    (Page.User.Identity.IsAuthenticated && Page.User.IsInRole(roleName));
                Visible = Enabled ? true : visibleIfUnauthorized;
            }
        }
    }
}

To use the new web control, register it with your page (or for the whole application in your web.config) and add it to the page:

<%@ Page Language="C#" MasterPageFile="~/Site.master" 
    AutoEventWireup="true" CodeFile="Default.aspx.cs" 
    Inherits="_Default" Theme="Default" %>
<%@ Register TagPrefix="rasc" Namespace="RoleAwareServerControls" %>
<body>
    <form id="form1" runat="server">
        <rasc:RoleAwareTextBox runat="server" ID="textBox"
            RoleName="administrator" VisibleIfUnauthorized="true" >
            Hi, administrator</rasc:RoleAwareTextBox>
    </form>
</body>