Hilton Giesenow's Jumbled Mind

the madness that is...

News

This is my little spot in cyberspace where you will find a collection of random (but mostly software-related) thoughts and ideas that are frightening in their shining brilliance (or something like that ;->).
 
Please enjoy your stay and feel free to Contact Me.
 
Microsoft MVP

.Net Links

BlogRoll

Misc. Links

Syndication

January 2008 - Posts

Auto-Implemented Properties & Object Initializers

Auto-Implemented Properties

I'm working on a C# 3.0 project at the moment and getting to use all the new toys and features and they really are quite fun so far. Working with them has given me a chance to think about them more and I've been giving some thought to Auto-Implemented Properties (or just "auto-properties" as they're sometimes affectionately called). The syntax, in case you haven't seem them, is basically:

public int MyProperty { get; set; }

Under the covers, the C# compiler will actually generate a private field for you, which is pretty cool. You can create read-only properties very easily using this feature too, like so:

public int MyProperty { get; private set; }

Write-only properties are not supported, but attributes are (despite what some of the documentation says - I think it may have not been supported in early beta releases but that this changed. Atif Aziz added a comment to this affect on the MSDN page for auto-properties, and I've been using them quite successfully in WCF with the DataMember attribute). Scott Guthrie of course discusses the feature further on a post on his blog.

However, what I've been giving some thought to is - what is the difference between an auto-property, such as:

public int MyProperty { get; set; }

and just a public field, such as:

public int MyProperty;

Effectively, from the class developer's perspective, they're much the same thing. The first might actually be quicker to type because of the 'prop' code snippet, but essentially they're providing the same thing. Trey Nash gets into it a bit here, and he comments that it affects the encapsulation, which is true, but I think the main point of using an auto-property is that, once a client is bound to your property, they won't be affected if you decide to change it to using a backing private field, for instance to add an event call, set another property (perhaps a 'dirty' flag), or similar. Client code that uses your property would, in these instances, not need a recompile, whereas they would if a public field became a property.

Object Initializers

One of the other new features I've been playing with is Object Initializers, which basically let you set any properties on an object when you initialize it, but without needing explicit constructors. This only works for non-read-only properties (makes sense ;->), and works as follows. For the following class:

    public class Customer
    {

        public string FirstName { get; set; }

        public string LastName { get; set; }
    }

You could write code to use this class and set the properties without needing a specific constructor, as follows:

Customer customer = new Customer { FirstName = "Hilton", LastName = "Giesenow" };

And you can set or not set any of the non-readonly properties in this way. However, what might not be obvious is that you can still create specific explicit constructors and combine the two. You might want to initialize a base class or do some other work which may make a constructor worthwhile. Alternatively, let's say you want to set one of the (auto-)properties to be readonly (as we learnt about a few paragraphs ago), as follows:

    public class Customer
    {
        public Customer(string newLastName)
        {
            this.LastName = LastName;
        }

        public string FirstName { get; set; }

        public string LastName { get; private set; }
    }

Now the only way to set the LastName property is to use the new constructor, as follows:

Customer customer = new Customer("Giesenow") { FirstName = "Hilton" };

Where this gets tricky is that, in this example you can now no longer use the original call with no constructor, because no default constructor now exists for the class. To be able to just set the FirstName property, add a regular old default constructor, as follows:

    public class Customer
    {
        public Customer()
        {

        }
        public Customer(string newLastName)
        {
            this.LastName = LastName;
        }

        public string FirstName { get; set; }

        public string LastName { get; private set; }
    }
and you can once again do the following:

Customer customer = new Customer { FirstName = "Hilton" };

Enjoy :-)

Injecting a Page Base Class in ASP.Net

One of the slightly lesser-known features in ASP.Net is the use of ControlAdapters. These are classes that inherit from the base ControlAdapter class, and they allow you at runtime to override certain implementation details for another control. For instance, you could inject the ability to automatically have all textboxes on your site render with red text, but without changing any of the existing testbox code directly in the site. They were originally intended to be used to allow you to easily add targeting in your site for mobile browsers, which is why their implementation calls for the use of a .browser file, and they have been used by Microsoft recently to override the default rendering of the ASP.Net menu control to use CSS instead of tables for its layout (see the ASP.NET 2.0 CSS Friendly Control Adapters kit at www.asp.net and an Architecture Overview of Adapters) (see more on the CSS vs tables approach in this great How Do I video from Chris Pels, it's one of the videos in the series I blogged about recently).

Associated with ControlAdapters are PageAdapters, which function much the same way, the difference being that these apply to the ASP.Net System.Web.UI.Page class rather than to controls specifically. One of the most discussed uses of this is the ability to more easily convert ViewState to being stored in Session, and this is the sample I covered recently in my Hidden Gems in ASP.Net 2.0 talk at Tech Ed (see here for the slides). However, this class also allows you to control not just the rendering but also to interact with the page lifecycle as well. This feature can be used in a variety of ways, one of these is the implementation of a standard security model.

As an aside, the following approach is for use where portions of a page, for example specific functionality or specific controls, need to be targeted to specific users (using, for instance, User.IsInRole()). Where an entire group of pages needs to be accessible only to a specific group or role, rather make use of the location element in the web.config (here's a nice tutorial on the using the location section).

In the past, I have made use of a base class that inherits from System.Web.UI.Page and from which I convert all of the other pages in the system to inherit from. This is a very common approach and it allows you to put certain standard features into all pages in your system. This can be used to enforce page-specific security by use of an abstract (MustInherit in VB), or at least a virtual (Overridable in VB) method, as the following sample shows:

    public class BasePage : System.Web.UI.Page
{

protected override void OnInit(EventArgs e)
{
base.OnInit(e);

this.CheckSecurity();
}

// This could be abstract, but that would force its implementation
//
in the derived class, which might not be desired for all pages.
protected virtual void CheckSecurity()
{
}

}

This would then be implemented in the derived class as follows:

    public partial class _Default : BasePage     {

        protected override void CheckSecurity()
        {
            if (!User.IsInRole(RoleSecurity.ROLE_SUPERUSER) ||
                SomeOtherDatabaseLookup())
                this.superUsersOnlyButton.Enabled = false;
            else
                this.superUsersOnlyButton.Enabled = true;
        }

    }

Note: I keep my role names in a public constant to avoid anyone's finger trouble on the project and to allow me to easily change them in one place, too:

    public class RoleSecurity
{
public const string ROLE_NORMALUSER = "Normal User";
public const string ROLE_SUPERUSER = "Super User";
}

Where this idea falls down is that it will only work if the developer remembers to change the generated page code to inherit from the new base class when she creates the page. This should ideally be done for all pages in the system to keep them consistent, even if the specific security method is not required for that page, but this does mean that every file needs to be touched just because a few need some additional functionality. A better way would be if we could implement the security only on the pages that need it, and have the infrastructure detect and make use of this automatically. Using PageAdapters allows us to implement this approach.

First off, create an interface that the pages requiring security can implement. This interface requires only a single method that pages will implement to enforce their security:

    interface ISecurable
{

void CheckSecurity();

}

The implementation in an actual page would then appear as follows:

    public partial class _Default : System.Web.UI.Page, ISecurable
{

public void CheckSecurity()
{
if (!User.IsInRole(RoleSecurity.ROLE_SUPERUSER) ||
SomeOtherDatabaseLookup())
this.superUsersOnlyButton.Enabled = false;
else
this.superUsersOnlyButton.Enabled = true;

}

}

The call to make use of this security method would then appear not in a base class, but in a class derived from PageAdapter, as follows:

    public class MyPageAdapter : System.Web.UI.Adapters.PageAdapter
{

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.CheckDerivedSecurity();
}

private void CheckDerivedSecurity()
{
ISecurable myPage = (Page as ISecurable);
if (myPage != null) myPage.CheckSecurity();
}

}

Wiring the two together requires a .browser file (make sure you put it in the App_Browsers special folder) as follows:

<browsers>
<
browser refID="Default">
<
controlAdapters>
<
adapter controlType="System.Web.UI.Page" adapterType="[MyNameSpace].BasePage" />
</
controlAdapters>
</
browser>
</
browsers>

Remember to replace [MyNameSpace] in the above file with any namespace you have used for the BasePage class.

This approach more cleanly separates out your security model from the other pages in the system, and it can be used to implement other features as well, without affecting the developers not working on those features. It does still allow you to implement a base class for your pages though, if you decide you need it later for something else, and you could even consolidate the code out of the PageAdapter very easily.