Fredrik Normén's Blog - NSQUARED2
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
NOTE: This list of posts will only list the 15 latest posts, to see the rest, select from the Archives located in the menu to the left. The RSS will only list the 10 lastest posts.
Create your own NavigationBar (tabs) witin ASP.Net 2.0 by using the SiteMapDataSource. Thursday, December 09, 2004

One control that people have requested for ASP.Net 2.0, or rather asked if it exists, is a navigation bar control (tabs). There is no NavigatonBar controls shipped with ASP.Net 2.0, you have to build your own. I have put together a very easy page, where I use the DataLsit control and associate it with the SiteMapDataSoruce to display tabs. You can find the code below. You can take the code and add it to a user control, if you need to reuse it on several pages with you probably want to do, or add it to a MasterPage. Remember that I put together this code within 10 minutes, so it’s not a complete solution, so you need to modify it so suite your needs.

 

Here is an example I put together quickly to show you how you can create your own Tabs by using the DataList control and the SiteMapDataSource:

 

<%@ Page Language="C#" %>

 

<script runat=server>

 

    protected void Page_Load()

    {

        int index = -1;

        Int32.TryParse(Request.QueryString["id"], out index);

 

        Tabs.SelectedIndex = index;

    }

       

</script>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

    <style>

        a

        {

            color: #000000;

            text-decoration: none;

        }

       

        .myTab

        {

            background: #6666ff;

            padding: 4px;

        }

 

        .myTabSelected

        {

            background: #ff00ff;

            padding: 4px;

        }

    </style>

 

</head>

<body>

    <form id="form1" runat="server">

    <div>

       

        <table>

        <asp:DataList RepeatDirection=Horizontal ID="Tabs" runat="server" DataSourceID="SiteMapDataSource1">

            <ItemTemplate>

                 <td width="4" height="20" valign="top" nowrap class="myTab">

                   <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>

                </td>

            </ItemTemplate>

           <SelectedItemTemplate>

                <td width="4" height="20" valign="top" nowrap class="myTabSelected">

                   <a href='<%# Eval("Url") %>'><%# Eval("Title") %></a>

                </td>

           </SelectedItemTemplate>

        </asp:DataList>

        </table>

        <asp:SiteMapDataSource ShowStartingNode=false ID="SiteMapDataSource1" runat="server" />

    </div>

    </form>

</body>

</html>

 

The code above will get the child nodes of the root node from the web.sitemap file, and will add tabs to the page. When a tab is selected, the page will redirect to the url specified within the web.sitemap file for the current node. The tab will be marked as selected by using the “id” query string specified within the web.sitemap file for the url, to know which tab is should select. The following is the web.sitemap file:

 

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

    <siteMapNode url="https://#" title="Home">

            <siteMapNode url="https://#" title="Information"/>

            <siteMapNode url="https://#" title="Customer"/>

    </siteMapNode>

</siteMap>

 

Posted: 9:26 PM GMT+1  Add feedback  Feedback (1)
Defensive programming and Design by Contract on a routine level Thursday, December 09, 2004

“When quality is pursued, productivity follows” – K. Fujino, Vice President of NEC Cooperation’s C&C Software Development Group.

 

People are talking about how to create tools (Software Factories) that will increase productivity. The view of productivity has been important. With good productivity, we could build software rapidly and that will probably save us a lot of money. But will it in the end deliver software with high quality? The productivity could make the quality be left behind, in some organizations, productivity tend to be more important than quality. It’s important to know that quality on a product (or service) is its benefit to satisfy, or preferably exceed the customers’ requirements and expectations. By putting productivity before quality, will in short term goals save money, but will in long term cost more money.

 

A major component of quality in software is reliability. The software will be reliable when it performs its job according to the specification (correctness) and to handle abnormal situations (robustness).

 

If we look at correctness vs robustness from a developer’s perspective, correctness is met when a developer never returns an inaccurate result. It’s better to return no results than returning an inaccurate result. With robustness a developer always tries to do something that allows the software to keep operating, even if a result could be inaccurate sometimes. For safety-critical applications, correctness is more important than robustness. For example, it’s more important that software used in a chemical plant returns no results than wrong results. For a consumer application, it could be more important to flavor robustness than correctness. It’s better to return any result than shutting down a system, for example. It is better if a program closed down instead than showing a blue screen in Windows ;)

 

Reliable software has no bugs (reliability is the absence of bugs), or has it? Can software be completely free from bugs? Defensive programming and Design by Contracts will be a help to create reliable software with good correctness and/or robustness.

 

Defensive Programming

 

Defensive programming is about protecting yourself from being hurt by something dangerous (If bad data is sent to a routine, it will not hurt the routine). By writing code that will protect yourself from bad data, unexpected events, and other programmers mistakes, will in most case reduce bugs and create a high quality software.

 

Good programmers will not let bad data through. It’s important to validate input parameters to not let the garbage in. It’s also important to make sure that if garbage does come in, noting will goes out or an exception will be thrown. The following example is a result from defensive driven programming:

 

public Customer GetCustomerByName(string customerName)

{

   //validate so no garbage is getting through

   if (String.IsNullOrEmpty(customerName))

      throw new ArgumentException("The name of the customer is empty");

 

   //Get the customer from a data source

   try

   {

      //Get customer from data source

      Customer customer = ....

 

      //Make sure the customer is not null before the use

      //of its members in the compare method.            

      if (customer != null && String.Compare(customer.CustomerName, customerName) == 0)

         return customer;

      else

         return null;

   }

   catch

   {

      throw;

   }

}

 

In the code above the input argument is first validated, if the validation failed, an exception is thrown. If the validation passes, the routine will try to get a customer from a data source by using the value from the customerName argument. If the customer was not found, nothing will out (returns null). If the routine fails to get the customer from the data source an exception will be thrown. In the example, correctness is more important than robustness. If robustness was more important, we could return an instance of an empty customer or “introducing Null object“ [Martin Fowler].

 

It’s important to both validate the input data, data returned from a data source and also use error handling to make sure a routine will not return any bad data if it fails. If the try and catch block are used, make sure an exception is passed on (thrown) and not only be catch within the catch block and then ignored, it could make the code more robustness but will violet correctness.

 

When using a defensive driven programming too much, it could create problems. Too much validation codes could make the code less readable and affect performance, so don’t overuse defense driven programming. Defensive programming will make error easier to find, easier to fix, and less damage to production code. The result of using defense driven programming will in return increase the quality of the software.

 

Design by Contract

 

Design by Contract is about is about creating a contract between the client and the supplier. The idea of the Design by Contract theory is to associate a specification with every software elements. This specification will define a contract between client and the supplier. When a supplier writes a contract with the client, it should document the obligations and benefits. When a client makes a call to the supplier, the supplier makes sure that the client follows the contract, this could be done by using precondition within a software routine (Client’s obligations to the code it calls) and postcondition (supplier’s obligations to the code that uses it). The following tabular form shows a contract between a client and its supplier, where an element is inserted into a dictionary:

 

             Obligations                                        Benefits

             (Must ensure precondition)                    (May benefit from postcondition)

Client

    Make sure dictionary is not full               Get the updated dictionary with the given

             and the element is not empty and           element.

             don’t already exists.

 

             (Must ensure postcondition)                  (May assume precondition)

Supplier

             Add the given element to the                Throw an exception if the dictionary is full

             dictionary.                                         or if the element is null.

           

C# doesn’t have support of specifying specifications (contracts). To use Design by Contract with C# we have to simulate it. A language that uses speciation for Design By Contract, is Eiffel. The following is an example in C# where post- and precondition is used (The contract simulated in this example, is the one specified in the tabular form above):

 

public void Add(object element)
{
   //precondition (require)
   if (element==null)
      throw new ArgumentNullException("element");

 

   if (this.IsFull)
      throw new Exception("The dictionary is full");

 

   if (this[element] == element)
      throw new Exception("The element already exists within the dictionary.");


   //do
   this._dictionary.Add(element);

 

   //postcondition (ensure)
   If (!this._dictionary.Contains(element))
      throw new Exception("The element is not added to the dictionary.");

}

 

If a client and a supplier have agreed over a contract where the supplier promises to return a result, the supplier should ensure to fulfill its demand, and the client will know that it will have a result and don’t need to check if it’s true. If the supplier failed to fulfill its demand at the first attempt, it should retry to fulfill its demand (rescue). The following example show an example of the previous code, but where the routines will retry to add an element even if the dictionary is full (Note: this is only pseudocode used by only showing the concept, that is why the code will try to add an element to the dictionary even if each loop will probably result in the same result):

 

public void Add(object element)
{

   //precondition (require)
   if (element==null)
      throw new ArugmentNullException(element);

 

   if (this[element] == element)
      throw new Exception("The element already exists within the dictionary.");

 

 

   bool fail;

 

   //rescue and retry
   for( int i = 0; i<100; i++)
   {
      try
      {
         this._dictionary.Add(element);
         fail = false;
      }
      catch
      {
         fail = true;
      }

      //retry
   }


   if (fail)
      throw new Exception("Can’t add element because the dictionary is full");

 

   //postcondition (ensure)
   if (!this._dictionary.Contains(element))
      throw new Exception("The element is not added to the dictionary.");
}

 

If C# should have support of adding specification to software elements, no validation code should need to be written in the way the example shows in the previous example, instead a contract should have been written. It could look something like this, where  "requires" is the precondition and the "ensures" is the postcondition:

 

public void Add(object element)

   requires element != null

      otherwise ArgumentNullException;

   requires this[element] != element

      otherwise Exception;

   requires !IsFull

      otherwise Exception;

   ensures this[element] == element

      otherwise Exception;

{

this._dictionary.Add(element);

}

 

The Microsoft Research has created and overview of a new language called Spec# (similar to C# but uses contract "Method Contracts"). Information about Spec#.

 

I hope this post has given you some basic understanding about what Defense Programming and Design by Contracts is all about.

Posted: 10:29 AM GMT+1  Add feedback  Feedback (3)
How to use the Profile feature outside an ASP.Net 2.0 application Tuesday, December 07, 2004

The Membership, Roles and Profile feature also work in a non-web application. Many of you already know this and some doesn’t. In this post I will explain how you can use the Profile feature within a non-web application.

 

First of all you need to add a reference to the System.Web.dll. The Profile feature’s classes are located within the System.Web.dll.

 

To use the Profile feature you have to add the profile section to the configuration file of you app, and add the profile provider you want to use. You need to add a provider if you should change the ApplicationName attribute to the name of your application. If you already have a web application, and want to get the profile information stored within the web app, you have to specify the ApplicationName you used for your web app in the configuration file. If you don’t do that, you will not get the data stored within the web app.

 

Note: ApplicationName is used to make it possible to share roles, users and profiles etc between different applications, or to use the same data source for the features but for different applications.

 

The following is an example of how you can add the profile section to an app.config file:

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

   <connectionStrings>

      <add name="AspNetDBConString" connectionString="data source=127.0.0.1;Initial Catalog=aspnetdb" providerName="System.Data.SqlClient" />
   </connectionStrings>

 

   <system.web>

 

      <profile defaultProvider="AspNetSqlProvider">

         <providers>

             <clear/>

                <add

                    connectionStringName="AspNetDBConString"

                    applicationName="/ MyAppName"

                    description=""

                    name="AspNetSqlProvider"

                    type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

         </providers>

 

         <properties>

            <add name="FirstName"/>
            <add name="LastName"/>

         </properties> 
      </profile>

   </system.web>

</configuration>


In the configuration file above, there are two properties specified, FirstName and LastName.

 

Note: If you already have another application and want to get the profile data from that application, you have to specify the same properties you have specified for the other application for you new application, if not there will be a mismatch.


To create a new Profile you can use the ProfileBase class Create method:

 

ProfileBase profile = ProfileBase.Create("myUser", true);

The Create method will create a new profile for the specified user. The ProfileBase class exists in the System.Web.Profile namespace. In Beta 1 the name of the ProfileBase class would be HttpProfileBase:

 

HttpProfileBase profile = HttpProfileBase.Create("John", true);

In ASP.Net 2.0, there is a dynamic compilation feature that autogenerates the typed Profile class. Outside ASP.Net 2.0, the application is not hooked up into this compilation system, so you have no typed access to the Profile class. Instead you have to use the loosely typed syntax instead. This is done by using the indexer of the ProfileBase class.

 

The following code will use the indexer of the ProfileBase class to set the FirstName and LastName property, and save the settings:

 

profile["FirstName"] = "John";

profile["LastName"] = "Doe";

profile.Save();

Note: If you use the Profile feature within a web application, you don’t need to call the Save method to save the profile. It’s automatically handled by the profile features module when the EndRequest event is trigged.

 

The following code will get the profile value from the user “John”:


ProfileBase profile = ProfileBase.Create("John",true);
Console.WriteLine((string)profile["FirstName"]);

Posted: 11:07 AM GMT+1  Add feedback  Feedback (5)
SqlDataSource control and its sorting feature. Monday, December 06, 2004

For some weeks ago I wrote a post about how to use the sorting feature of the ObjectDataSource. There has been some question regarding how the sorting works for the SqlDataSource control, so I decided to write a short post about his.

 

The SqlDataSource will use the Sort property of the DataView of the DataSet returned from the specified SelectCommand.

 

If you use a Stored Procedure and set the SortParamterName property of the SqlDataSource control, you can use your own parameter to make the Sql server do the sorting, this will increase performance.

 

If you want the SqlDataSOurce to return a SqlDataReader instead of a DataSet, the sort feature will be disabled and not work.

 

If you have a doubt if you should use the SqlDataSource or the ObjectDataSource, then the following post on my blog could be useful SqlDataSource, ObjectDataSource and DataComponent in a heads up challenge

Posted: 11:20 AM GMT+1  Add feedback  Feedback (2)
How to name a method. Sunday, December 05, 2004

[UPDATED]

 

For the moment I'm reading the book Code Complete 2:ed written by Steve McConnel, great book by the way.

I was passing through the chapter about naming methods and decided to write down what he suggests based on facts and experience.

 

Naming a method

 

The name of the method should describe what it does, and should explain everything it will do. If you use a bad method name it could be difficult for someone to know when the method should be used and what the method does, for example OutputUser(), Calculation() and ExecuteOperation() etc, don’t tell you what the method does, they could do almost everything.

 

The following is an example uses a bad method name:

 

public void OutputUser(int userId)

{

   User user = UserRepository.GetById(userId);

 

   if (user==null)

      throw new Exception(String.Format("Can't find user with the id '{0}'", userId));

 

   string serializedUser = SerializeUserToXml(user);

   

   PrintUserInformation(serializedUser);

}

 

The method above will get a user from the user’s repository and serialize the user object into XML and send the XML output to a printer. A better name for the method could be PrintSerializedUser(int userId). The new name of the method will explain what the method does. A method name should make the method self explained. With a good name, you can also reduce the documentation of the method, because the name of the method could be the documentation instead. In the book Complete Code, Steve McConnel have another example where he have replaced a method with the name HandleOutput() with FormatAndPrintOutput() to use a name that tells what the method does.

 

I have heard someone said, that "And" and "Or" should not be used in a method name. Mostly a method should only do one operation, not two or more operations, but in the case where a method needs to do more than one operation, the "And" and "Or" could be used, but only if you need them for making the name of the method more understandable.

 

If you create a method, don’t use numbers to separate methods from each other, for example, CreateUser1(), CreateUser2() etc. It will not tell you anything of the differences between those methods. Could you figure out what the following methods will do by only looking at the code?

 

public void InsertUser(User user)

{

   if (user == null)

      throw new ArgumentNullException("user");

 

   if (string.IsNullOrEmpty(user.Password))

      CreateUser1(user);

   else

      CreateUser2(user);

}

 

You can probably figure out, that the different between the two CreateUser methods has something to do if the Password property of the user is empty or not, but you can’t know what the method really do by only looking at the code for the method.

 

It’s not only numbers that will make a method less understandable, abbreviation could also make the code less understandable. Try to avoid abbreviations in names. If you need to use an abbreviation to make the name of the method short, try to only use abbreviation that others understated. The following is an example of a method that uses abbreviation:

 

public void CteNewUsrRptASndItToPrtr()

 

Try to avoid method names like the one above, even if the method name will be long, it’s better than make it not understandable. The above method name could instead be something like the following name:

 

public void CreateNewUserReportAndSendToPrinter()

 

A method name without abbreviation could sometime be very long. But how long should a method name be? It depends; an average name is about 9 to 15 characters. But the important thing is to make the name self explained and it should also fit into the screen, so we don’t need to scroll the code to see the whole name.

 

Try to use pascal casing when you name a method, the first character in each word should be upper cased. If you have a method with a long name and with several of words, the method will hard to read if you don’t use pascal casing, for example, createuserandserializeuserandsendittoprinter() will be difficult to read but if you use  pascal casing it will be easer to read, CreateUserAndSerializeUserAndSentItToPrinter() (I should never used a name like this, I only use it as an example.).

 

When you create method that will return an object, try to have it named for the value it returns. For example if you should get a customer number, you can use a name like GetCustomerNumber(). The GetCustomerNumber() method will tell you that the method will return a customer number. Try to not name a method with the name of the class where the belongs to, for example, User.CreateUser() should instead be Create() because the name of the class will in this case help you to understand what the method  does, and by adding User into the method name it will only repeat the name.

 

If you create two methods that should do the opposite operation, try to use the right opposite names. For example if you have a method that should open a door and one that should close a door, you should not use the names OpenDoor() and Close(), they are not commonly understood. Instead use OpenDoor() and CloseDoor().

 

This is was my guidelines of naming a method, if you have any comment or more things that should be added that I have missed, please add a comment, and share it with us all.

Posted: 7:19 PM GMT+1  Add feedback  Feedback (3)
Add custom attributes to the siteMapNode Wednesday, December 01, 2004

In my previous post I show you how you can use the security trimming to display SiteMap nodes based on roles and permission. This time I will show you how you can add an attributes to the siteManpNode where you can specify a permission that the custom provider in the previous post uses, to check if a user has the right permission to display a node. The following is a web.sitemap that has a permission attribute for the Help node:

 

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

   <siteMapNode url="https://#" title="Home">

      <siteMapNode url="welcome.aspx" title="Welcome"/>

      <siteMapNode url="help.aspx" title="Help" permission="View">

         <siteMapNode url="https://#" title="About"/>

      </siteMapNode>

   </siteMapNode>

</siteMap>

 

To get the value form the permission attribute we can use the indexer of the SiteMapNode class. There is an Attributes property that are protected, but I hope Microsoft will make it public, it’s more obvious to get extra attributes from a Attributes property than the indexer, but that is what I think.

 

The following code is the IsAccessibleToUser method form the customer provider in my previous post, that will get the permission attribute and use it go check if a user has the right permission to a node. If there is no permission attribute added to a node, the node will be displayed:

 

public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)

{

   if (!base.SecurityTrimmingEnabled)

      return true;

 

   if (node["permission"] != null)

      return PermissionManager.HasCurrentUserPermission(node.Url, node["permission"]);

   else

      return true;

}

 

I want to thanks Stefan Schackow from showing me the SiteMapNode indexer.

Posted: 6:31 AM GMT+1  Add feedback  Feedback (1)
Display Menu nodes based on a roles and based on permission. Tuesday, November 30, 2004

In this post I will both describe how to enable security trimming for the SiteMap feature for displaying nodes based on roles, and also how to create a site map provider that will use the Permission Manager for displaying nodes based on permissions.

 

If you use the TreeView, Menu or SiteMapPath control, you can associate them whit a SiteMap data source control. The SiteMap data source controls will get the data for a control, by using a SiteMap provider. The default SiteMap provider is the XmlSiteMapProvider. The XmlSiteMapProvider will get its data from the Web.sitemap file that should by default be located in the web applications root folder. The following code is an example of a Web.sitemap file:

 

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

   <siteMapNode url="https://#" title="Home">

      <siteMapNode url="welcome.aspx" title="Welcome"/>

      <siteMapNode url="help.aspx" title="Help">

         <siteMapNode url="https://#" title="About"/>

      </siteMapNode>

   </siteMapNode>

</siteMap>

 

The SiteMap file above has one root node (Home) which has two child nodes, Welcome and Help and the Help node has one child node, About.

 

The following example will use a Menu control to display the nodes located in the Web.sitemap file for a user:

 

<%@ Page %>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"></asp:Menu>

        <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />

    </div>

    </form>

</body>

</html>

 

By default all nodes will be displayed for the users that visit the page. If you want to hide nodes based on roles, you can turn on security trimming for the SiteMap feature. To make sure that only specified roles will be allowed to see a node, you can add the Roles attribute to a site map node in the Web.sitemap file:

 

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

    <siteMapNode url="https://#" title="Home">

        <siteMapNode url="welcome.aspx" title="Welcome"/>

        <siteMapNode url="help.aspx" title="Help" roles="Customer">

            <siteMapNode url="https://#" title="About"/>

        </siteMapNode>

    </siteMapNode>

</siteMap>

 

The code above will only let users that belong to the Customer role to see the Help node.

 

Before the security trimming will work, you have to enable it. You can for example enable security trimming in the web.config file by setting the securityTrimmingEnabled attribute of the provider you use to true:

 

<siteMap defaultProvider="MySiteMapProvider">

   <providers>

       <clear/>

       <add name="MySiteMapProvider" securityTrimmingEnabled="true" ...></add>

   </providers>

</siteMap>

 

After the security trimming are enable, the Welcome node will be hidden if the current user of the page doesn’t belongs to the role Customer.

 

The SiteMap provider used by the SiteMapDataSource is responsible to check if the user has access to the node or not. The security check is made in the provider’s IsAccessibleToUser method.

 

To use the Permission Manager to check if a user has the permission to view a node, you can create a new SiteMap provider and override the IsAccessibleToUser method. The following code is an example of a custom provider that inherits the XmlSiteMapProvider. The custom provider overrides the IsAccessibleToUser method, and use the Permission Manager to check if a user has permission to view a node:

 

public class MySiteMapProvider : XmlSiteMapProvider

{

    public MySiteMapProvider()

    {

    }

 

    public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)

    {

        if (!base.SecurityTrimmingEnabled)

            return true;

 

        return PermissionManager.HasCurrentUserPermission(node.Url, "View");

    }

}

 

Note: For each node, the Permission Manager’s HasCurrentUserPermission will be executed and based on the provider the Permission Manager is using, performance could be affected negatively.

 

To use the MySiteMapProvider above, you only need to copy the code into the app_code (\Code in Beta 1 and application_code in the October CTP) folder and add the provider to the SiteMap section in the configuration file and configure the Permission Manager:

 

<configSections>

   <section name="permissionManager" type="Nsquared2.Web.Configuration.PermissionManagerSection, Nsquared2.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

</configSections>

           

...

 

<permissionManager>

    <permissions>

        <group>

           <permission name="View" description="View a node"/>

        </group>

    </permissions>

</permissionManager>

 

<system.web>

 

    <siteMap defaultProvider="MySiteMapProvider">

        <providers>

            <clear/>

            <add name="MySiteMapProvider" type="MySiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true"></add>

        </providers>

    </siteMap>

 

    ....

 

</system.web>

 

Before any nodes will be displayed, you have to give a user the permission to view a node. It could be done by using the SetPermissionForUser method of the PermissionManager class:

 

PermissionManager.SetPermissionForUser(“username”, Request.ApplicationPath + "/Welcome.aspx", "View");

 

The code above will give the user the permission to view the Welcome node.

 

Note: You only need to set the permission once, if you do it twice an exception will be thrown from the PermissionManager.

 

Please let me know if you have any question regarding this post.

Posted: 3:25 PM GMT+1  Add feedback  Feedback (5)
A new PM for October CTP is now released. Tuesday, November 30, 2004

I have done some small changes in the code and fixed a few bugs. You only need to replace the Nsquared2.Web.dll with the one from the previous Permission Manager Beta 1 for October CTP. I have missed called the initialization when the DefaultGroup and DefauiltSourceId property of the PermissionManager was called.

 

You can find the fixed version on the Permission Manager's Workspace.

Posted: 2:21 PM GMT+1  Add feedback  Feedback (0)
Create a Hierarchical Data Source for the TreeView and Menu control. Friday, November 26, 2004

In this post, I will show you how you can create your own data source control for the TreeView and Menu control shipped with ASP.Net 2.0.

 

A regular data source control used together with data-bound controls, for example with the GridView or DetailView etc, returns a non hierarchy data structure. Because the data source control do not return a hierarchical data structure, the TreeView and Menu controls that are used to display hierarchical data, can’t use the data source controls. Instead they need to use a hierarchical data source control. A hierarchical data source control has the same purpose as the data source control, but will instead return a hierarchical data structure.

 

To create a hierarchical data source control you need to use two classes, HierarchicalDataSourceControl

and HierarchicalDataSourceView, and two interfaces, IHierarchicalEnumerable and IHierarchyData.

 

The HierarchicalDataSourceControl is the main class that represents the hierarchical data source control. This control has the responsibility to return a HierarchicalDataSourceView. The class that inherits the HierarchicalDataSourceControl needs to override the GetHierarchicalView method, which has the responsibility to return the HierarchicalDataSourceView. The HierarchicalDataSourceView is responsible to collect data from a data source. Another method that you can override is the CreateControlCollection method, is should return an instance of a collection that holds the child controls. The following code is an example of a HierarchicalDataSourceControl:

 

public class FileSystemDataSource : HierarchicalDataSourceControl

{

   private FileSystemDataSourceView _view = null;

 

   public FileSystemDataSource() : base() { }

 

   protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)

   {

      if (null == this._view)

         this._view = new FileSystemDataSourceView(viewPath);

 

      return this._view;

   }

 

   protected override ControlCollection CreateControlCollection()

   {

      return new ControlCollection(this);

   }

}

 

The GetHierarchicalView method above will return a FileSystemDataSourceView class that inherits the HierarchicalDataSourceView. The HierarchicalDataSourceView represents a data view that will collect the hierarchical data from a data source. Classes that inherit the HierarchicalDataSourceView need to override the Select method that should return the hierarchical data structure. The following code is the implementation of a HierarchicalDataSourceView (FileSystemDataSourceView) that the previous FileSystemDataSource class returns from the GetHierarchicalView method:

 

public class FileSystemDataSourceView : HierarchicalDataSourceView

{

   public FileSystemDataSourceView(string viewPath) {}

 

   public override IHierarchicalEnumerable Select()

   {

      HttpRequest currentRequest = HttpContext.Current.Request;

      string rootPath = HttpContext.Current.Request.MapPath(currentRequest.ApplicationPath);

 

      DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);

 

      FileSystemHierarchicalEnumerable fshe = new FileSystemHierarchicalEnumerable();

 

      foreach (FileSystemInfo fsi in rootDirectory.GetFileSystemInfos())

         fshe.Add(new FileSystemHierarchyData(fsi));

 

      return fshe;

   }

}

 

The Select method above will return a hierarchical data structure with information about files and directories located in the web application’s root folder. The FileSystemHierarchicalEnumerable class will return the hierarchical data structure, the FileSystemHierarchicalEnumerable class implements the IHierarchicalEnumerable interface.

 

The IHierarchicalEnumerable represents a hierarchical collection that can be enumerated with an IEnumerator. The classes that implement the IHierarchicalEnumerable interface must implement the GetHierarchyData method, which is a method used to retrieve an IHierarchyData object from an enumerated item, in addition to the GetEnumerator method. The following is an example of the FileSystemHierarchicalEnumerable class that extends an ArrayList and implements the IHierarchicalEnumerable interface. The FileSystemHierarchicalEnumerable is returned from the FileSystemDataSourceView class’s Select method as you can see in the example above.

 

public class FileSystemHierarchicalEnumerable : ArrayList, IHierarchicalEnumerable

{

   public FileSystemHierarchicalEnumerable() : base() {}

 

   public IHierarchyData GetHierarchyData(object enumeratedItem)

   {

      return enumeratedItem as IHierarchyData;

   }

}

 

In the previous example for the FileSystemDataSourceView items of type FileSystemHierarchyData is added to the FileSystemHierarchicalEnumerable class. The FileSystemHierarchyData represents the item that is added to the hierarchy data structure. In the example in this post, the FileSystemHierarchyData holds information about a file or directory and a reference to the Parent and Childs nodes of an item. Classes that implement the IHierarchyData interface need to implement three methods, HasChildren, GetChildren and GetParent. I don’t know if I need to example the HasChildren method. I think you know what is purpose is. The GetChildren will return an IHierarchicalEnumerable that represents all children. The GetParent also returns an IHierarchicalEnumerable with represents the Parent item. If the GetParent method returns null, the current item will be treated as the root item in the hierarchy data structure. The following code is the FileSystemHierarchyData class the represents the item of a structure. This class holds information about a file or a directory:

 

public class FileSystemHierarchyData : IHierarchyData

{

   private FileSystemInfo _fileSystemObject = null;

 

   public FileSystemHierarchyData(FileSystemInfo obj)

   {

      this._fileSystemObject = obj;

   }

 

   public override string ToString()

   {

      return this._fileSystemObject.Name;

   }

 

   public bool HasChildren

   {

      get

      {

         if (typeof(DirectoryInfo) == this._fileSystemObject.GetType())

         {

             DirectoryInfo temp = (DirectoryInfo)fileSystemObject;

             return (temp.GetFileSystemInfos().Length > 0);

         }

         else

             return false;

      }

   }

 

   public string Path

   {

      get { return this._fileSystemObject.ToString(); }

   }

 

   public object Item

   {

      get { return this._fileSystemObject; }

   }

 

   public string Type

   {

      get { return "FileSystemData"; }

   }

 

   public IHierarchicalEnumerable GetChildren()

   {

       FileSystemHierarchicalEnumerable children = new FileSystemHierarchicalEnumerable();

 

       if (typeof(DirectoryInfo) == this._fileSystemObject.GetType())

       {

           DirectoryInfo temp = (DirectoryInfo)this._fileSystemObject;

           foreach (FileSystemInfo fsi in temp.GetFileSystemInfos())

              children.Add(new FileSystemHierarchyData(fsi));

 

            return children;

        }

   }

 

   public IHierarchicalEnumerable GetParent()

   {

      FileSystemHierarchicalEnumerable parentContainer = new FileSystemHierarchicalEnumerable();

 

      if (typeof(DirectoryInfo) == this._fileSystemObject.GetType())

      {

          DirectoryInfo temp = (DirectoryInfo)this._fileSystemObject;

          parentContainer.Add(new FileSystemHierarchyData(temp.Parent));

      }

      else if (typeof(FileInfo) == fileSystemObject.GetType())

      {

          FileInfo temp = (FileInfo)fileSystemObject;

          parentContainer.Add(new FileSystemHierarchyData(temp.Directory));

      }

      return parentContainer;

    }

}

 

You can find the above classes in the MSDN Library shipped with VS 2005. I have done some modification of the original code so it will not take up to much space in this post.

 

The following example is how the above hierarchical data source could be associated to a TreeView control, and will display the folders and directory located in the web applications root folder:

 

<%@ Page Language="C#" %>

<%@ Register Namespace="Nsquared2.Web" TagPrefix="Nsquared2" %>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:TreeView ID="TreeView1" runat="server" DataSourceID="test">

        </asp:TreeView>

       

       <Nsquared2:FileSystemDataSource runat="server" id="test"></Nsquared2:FileSystemDataSource>

   

    </div>

    </form>

</body>

</html>

 

If you copy the code the classes in this post and give them the namespace Nsquared2.Web and put them into the app_code (\Code in Beta 1) folder, you will have a working example where the TreeView control will display the directory and files located in the root folder of the web application.

Posted: 2:57 PM GMT+1  Add feedback  Feedback (1)
Change the style of a column within a GridView control based on its value Wednesday, November 24, 2004

I have seen questions about how to change the background or text color of a column within a GridView control’s row when a value is either null or empty or a value is greater than another value etc. So I decided to blog about how to change the style of a column.

 

The best way of changing the style of a column based on a columns value, is by hook up to the GridView’s RowDataBound event. The RowDataBound event will be executed directly after the row is data bounded. The RowDataBound event uses the GridViewRowEventArgs class as the event argument. With the event’s argument you can get the current row that has been data bound by using the GridViewRowEventArgs’s Row property:

 

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

{

   GridViewRow  row = e.Row;

}

 

The Row property will return a GridViewRow object that inherits the TableRow class.

 

There are different types of rows that could be data bound such as, DataRow, EmptyDataRow, Footer, Header, Pager and Separator. To know which type that is currently data bounded, you can use the GridViewRow’s RowType property. The RowType property is an enum of type DataControlRowType. The following code checks if the type of the Row is a standard row that will be listed in the GridView:

 

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

{

if (e.Row.RowType == DataControlRowType.DataRow)

{

      //Do something!

}

}

 

To get the cells of the row, you can use the Cells property that will return a TableCellCollection object. To get a specific cell, you can use the TableCellCollection indexer. The TableCellColleciton indexer will return a TabelCell object, which will represent a cell in the row:

 

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

{

if (e.Row.RowType == DataControlRowType.DataRow)

{

      TableCell cell = e.Row.Cells[0];

}

}

 

To get the value from a TableCell, you can use the TableCell’s Text property:

 

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

{

if (e.Row.RowType == DataControlRowType.DataRow)

{

      string value = e.Row.Cells[0].Text;

}

}

 

Now when you got the basic understanding of getting the value from a cell within a row, you can easy change the style of a TabelCell based on the cell’s value. The following code will query the “Alphabetical list of products“ table from the Northwind database, and change the background color to red for a column when the fourth cell (That will be the “UnitPrice” column) is greater than 10:

 

<%@ Page Language="C#"%>

<%@ Import Namespace="System.Drawing" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

 

<script runat="server">

 

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)

    {

        if (e.Row.RowType == DataControlRowType.DataRow)

        {

            if (Decimal.Parse(e.Row.Cells[3].Text) > 10)

                e.Row.Cells[3].BackColor = Color.Red;

        }

    }

   

</script>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="False"

            DataKeyNames="ProductID" OnRowDataBound="GridView1_RowDataBound">

            <Columns>

                <asp:BoundField ReadOnly="True" HeaderText="ProductID" InsertVisible="False" DataField="ProductID"

                    SortExpression="ProductID" />

                <asp:BoundField HeaderText="ProductName" DataField="ProductName" SortExpression="ProductName" />

                <asp:BoundField HeaderText="QuantityPerUnit" DataField="QuantityPerUnit" SortExpression="QuantityPerUnit" />

                <asp:BoundField HeaderText="UnitPrice" DataField="UnitPrice" SortExpression="UnitPrice" />

            </Columns>

        </asp:GridView>

        <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [ProductID], [ProductName], [QuantityPerUnit], [UnitPrice] FROM [Alphabetical list of products]"

            ConnectionString="<%$ ConnectionStrings:AppConnectionString1 %>" />

   

    </div>

    </form>

</body>

</html>

Posted: 9:03 AM GMT+1  Add feedback  Feedback (0)
Hide items in a ListBox or DropDownList control. Tuesday, November 23, 2004

In ASP.Net 2.0 you can hide individual items from a ListBox and DropDownList control. To hide an item you use the Enabled property of the ListItem class. The following example uses the constructor to hide the item:

 

ListItem item = new ListItem(text, value, enabled);

 

You can also use the Enabled property to hide an item:

 

item.Enabled = false;

 

If you hide an item, it will still be accessible from the server side code even if it will not be displayed in the list.

 

The following code is an example where a ListBox control is filled with 5 items. The second item is disabled and will not appear in the ListBox. When the Button control in the code is pressed, all the items in the ListBox will be displayed:

 

<%@ Page Language="C#" %>

 

<script runat="server">

   

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!Page.IsPostBack)

        {

            ListItem[] items = new ListItem[]

                                {

                                    new ListItem("Item 1", "Value 1"),

                                    new ListItem("Item 2", "Value 2", false),

                                    new ListItem("Item 3", "Value 3"),

                                    new ListItem("Item 4", "Value 4")

                                };

 

            ListBox1.Items.AddRange(items);

        }

 

    }

    protected void Button1_Click(object sender, EventArgs e)

    {

        foreach (ListItem item in ListBox1.Items)

        {

            Response.Write(item.Text + " enabled=" + item.Enabled + "<br>");

        }

    }   

   

</script>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:ListBox ID="ListBox1" runat="server" />

  <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /></div>

    </form>

</body>

</html>

 

Instead of adding the items dynamically you can of course declare them on the page by adding the ListeItem to the ListBox:

 

<asp:ListBox ID="ListBox1" runat="server">

     <asp:ListItem Text="Item1"></asp:ListItem>

     <asp:ListItem Enabled="false" Text="Item2"></asp:ListItem>

     <asp:ListItem Text="Item3"></asp:ListItem>

     <asp:ListItem Text="Item4"></asp:ListItem>

     <asp:ListItem Text="Item1"></asp:ListItem>

</asp:ListBox>

 

I’m sorry that I didn’t write about something more exiting feature, but some of you have probably not seen this feature yet.

Posted: 10:45 AM GMT+1  Add feedback  Feedback (4)
Information about the Membership feature for .Net 1.x Tuesday, November 23, 2004

.NET 1.x Membership API and Microsoft.ScalableHosting
Posted: 7:19 AM GMT+1  Add feedback  Feedback (0)
New version of the Permission Manager for .Net 2.0 Monday, November 22, 2004

During this weekend I have made a new version of the Permission Manager. There are several changes and the new version will only be available for the Visual Studio 2005 October CTP, it will not work for the Beta 1. Some of the changes are:

 

1)      Permissions are now added to the configuration file. It will make it easier to deploy an application that uses the Permission Manager.

2)      There are new methods for updating and removing permissions from users and roles.

3)      It’s now possible to give a user or role a specific permission without setting the permission on a source (object).

4)      The CreatePermission method is removed, instead there is a Permissions method and a Groups property added to the PermissionProvider. Those members will return the permissions added to the configuration file.

 

The following is a simple demonstration of how you can use the Permission Manager.

 

When you use the Permission Manager you first have to specify the permissions that should be used. This is done by adding the <permissions> element to the <permissionManager> section in the configuration file:

 

<configSections>

  <section name="permissionManager" type="Nsquared2.Web.Configuration.PermissionManagerSection, Nsquared2.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

</configSections>

 

<permissionManager enabled="true">

    <permissions>

        <group>

            <permission name="Read" description=""/>

            <permission name="Write" description=""/>

            <permission name="Modify" description=""/>

        </group>

 

        <group name="News">

            <permission name="Read" description="Allows to read news"/>

            <permission name="Write" description="Allow to create news"/>

        </group>

    </permissions>

</permissionManager>

 

Permissions are grouped into groups by using the <group> element. By using the <group> element, you can specify the permissions that will only be available for a specific kind of object. In the code above there are two groups, one global and a News group. With the global group you can grant a user or role a global permission (permissions that belongs to the user and not to an specific object), for example, user John Doe should have Read permission:

 

PermissionManager.SetPermissionForUser("John Doe", "Read");

 

You don’t need to set this permission to a source. The source will instead be the application. So if you should check if a user has the “Read” permission you can use the HasUserPermission method:

 

if (PermissionManager.HasUserPermission("John Doe", "Read"))

    Response.Write("User has permission to read..");

 

You can’t use the global permissions for a source that belongs to another group. Every source (object) belongs to a specific group. The reason why, is because you should not have the possibility to specify other permissions than the ones allowed to be set for an object. For example if you have a News object, you maybe only want to use a Read and Write permission, nothing else. So if you have given a user or a role the Read permission globally you can’t check if the user has the Read permission for an object that belongs to another group:

 

if (PermissionManager.HasUserPermission("John Doe","News","MyNews","Read"))

   Response.Write("User has permission to read..");

 

The code above will return false. If you have given the user the Read permission for a specific source, you can then check if a user has the permission to read the source:

 

PermissionManager.SetPermissionForUser("John Doe", "News", "MyNews", "Read");

 

if (PermissionManager.HasUserPermission("John Doe","News","MyNews","Read"))

    Response.Write("User has permission to read..");

 

In the code above the “News” is the name if the group that are specified in the configuration file, it’s the group where the “MyNews” source belongs to:

 

<group name="News">

    <permission name="Read" description="Allows to read news"/>

    <permission name="Write" description="Allow to create news"/>

</group>

 

Note: If you try to grant a user or s role permission that does not belong to the “News” group, an exception will be thrown.

 

Every object you can set permissions for must belong to a group and have a unique identifier. Instead of passing the name of the group and a unique identifier to the SetPermissionForUser method etc, you can create an object that you pass as an argument. To create a custom object you have to implement the IAccessObject interface.

 

public interface IAccessObject

{

   string SourceGroup

   {

      get;

      set;

   }

 

   string SourceId

   {

      get;

      set;

   }

}

 

The SourceGroup property returns the name of the group the object belongs to and the SourceId the unique identifier that will unique identify the instance of the object. The following is a News object that uses the IAccessObject interface:

 

public class News : IAccessObject

{

   private string _group = “News”;

   private int _id;

 

   public string SourceGroup

   {

      get { return this._group; }

      set { throw new NotSupportedException(); }

   }

 

   public string SourceId

   {

      get { return this._id.ToString(); }

      set { throw new NotSupportedException() };

   }

 

   public int Id

   {

      get { return this._id; }

      set { this._id = value; }

   }

   ...

}

 

The SourceId in the code above will return a string that will represents the unique id of News object.

 

The following example will give the role “Everyone” permission to modify the News object:

 

News news = new News();

news.ID = 10;

 

PermissionManager.SetPermissionForRole("Everyone", news, "Write");

 

To check if the role “Everyone” has been granted the “Write” permission for the News object you use the HasRolePermission method:

 

if (PermissionManager.HasRolePermission("Everyone", news, "Write"))

   Response.Write("Everyone has the permission to modify the news");

 

Note: You can only set permission for a role if the .Net 2.0 Roles feature is used, if not an exception will be thrown.

 

When you use the HasUserPermission, the method will first check if the roles a user belong to have the specified permission. If one of the roles a user belongs to have the specified permission, the method will return true, but only if the user don’t have the permission denied. The following example have granted the “Everyone” the permission to read the News object, assume that the user “John Doe” belongs to the “Everyone” role, the example will also check if “John Doe” has the permission to read the news object:

 

PermissionManager.SetPermissionForRole("Everyone", news, "Read");

 

//This method will return true

if (PermissionManager.HasUserPermission("John Doe", news, "Read"))

   Response.Write(“John Doe can read the news”);

 

You can also allow or deny permission for a user or role. Denied permission has the highest priority, so even if you have allowed a specific permission for a user, but one of its roles has the same permission set to deny, the user will not have the permission allowed.

 

If you have any questions or if there are methods that you wanted to be added to the Permission manager, please let me know. You can find the latest version of the Permission Manager on the Permission Manager workspace.

Posted: 9:59 AM GMT+1  Add feedback  Feedback (0)
Configuration section handler Wednesday, November 17, 2004

In this post I will write something about the new section handler feature. I have written about the new way of creating section handler before. But this time I will focus on how to create a collection of adding child elements by using the ConfigurationElementCollection class. The code examples in this post will create a section handler that will get the following section automatically, without needing to use XmlDom to get the attributes or elements by our self:

 

<configSections>

        <section name="group" type="Nsquared2.Web.Configuration.GroupSection, Nsquared2.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

</configSections>

 

<group name="Group1">

   <permission name="Read" description=""/>

   <permission name="Write" description=""/>

   <permission name="Modify" description=""/>

</group>

 

The new section handler uses classes where the root element in a section inherits the ConfigurationSection class and each child elements are represented by a classes that inherits the ConfigurationElelement class, and the element’s attributes are created as properties marked with the ConfigurationPropertyAttribute uses to map a property to an attribute. If the element has child controls like the group has in the example above, there is a special class created to add elements like the “permission” elements into a collection. Each collection is created as an own class that inherits the ConfigurationElementCollection class. The following example is the class for the “group” element where the “name” attribute is created as a property and where the “permission” elements are added to the PermissionElementCollection and can be collected from the Permissions property:

 

public class GroupSection : ConfigurationSection

{

 

   [ConfigurationProperty("name", RequiredValue=true)]

   public string Name

   {

       get { return (string)base["name"]; }

       set { base["name"] = value; }

   }

 

   [ConfigurationProperty("permissions", DefaultCollectionProperty=true, RequiredValue=true)]

   public PermissionElementCollection Permissions

   {

       get { return ((PermissionElementCollection)base["permissions"]); }

    }

}

 

As you can see in the code above the Name property are marked with the ConfigurationPropetyAttribute where the “name” of the attribute is passed as an argument to the constructor and the attribute’s RequiredValue is set to true. The RequiredValue is used to specify that the attribute must be specified, if not an exception will be thrown. The Name property will add the mapped attribute’s value to the base class ConfigurationValues collection. The Permission property of the GroupSection class above will return a collection with PermissionElement objects. The DefaultCollectionProperty specify if the property represents the default collection of the “group” element. In this case we only have one collection and it’s the default collection. The “permissions” value passed to the ConfigurationPropertyAttribute’s constructor will not be an attribute or element that should be added to the “group” section in the configuration file. To get a value added to the “group” section, you can use the GetSection method of the ConfigurationSettings class:

 

GroupSection config = ConfigurationSettings.GetSection("group") as GroupSection;

 

When the GetSection method is executed, it will locate the “group” section in the <configSection> element and instantiate the specified type, and use reflection to find the specified ConfigurationProperties in the instantiated class, and automatically get elements and attributes values from the “group” section in the configuration file. The “permission” elements will also be collected and added to the PermissionElementCollection (I will soon show you the implementation of the collection).

 

Note: You don’t need to use a Create method as before when you implemented the IConfigurationSectionHandler, and you don’t need to use XmlDom to get the data from the XmlNode passed as an argument to the Create method.

 

Before I show you the implementation of the PermissionElementCollection, let’s take a look at the classes that will hold the information about the “permission” element and that will be added to the collection when the “group” section is requested from the GetSection method:

 

public class PermissionElement : ConfigurationElement

{

    internal string _ElementName = "permission";

       

       

    public PermissionElement()

    {

    }

 

    protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)

    {

        bool retVal = false;

 

        if (!base.SerializeElement(null, false))

           return false;

 

        if (writer != null)

        {

            writer.WriteStartElement(this._ElementName);

            retVal |= base.SerializeElement(writer, false);

            writer.WriteEndElement();

            return retVal;

        }

            return (retVal | base.SerializeElement(writer, false));

     }

 

     [ConfigurationProperty("name", RequiredValue=true)]

     public string Name

     {

        get { return ((string)base["name"]); }

        set { base["name"] = value; }

     }

 

     [ConfigurationProperty("description")]

     public string Description

     {

        get { return ((string)base["description"]); }

        set { base["description"] = value; }

     }

}

 

The code above has two properties, Name and Description; both are mapped to its own attributes added to the “permission” element. The base class’s SerializeElement method most be overridden if we want to make it possible to add elements to the configuration file programmatically. As I wrote before, the GetSection method of the ConfiguartionSettings class will insatiate the PermissionElement class for each “permission” element added as child elements to the “group” section. Each PermissionElement will be added to the PermissionElementCollection. Let’s take a look at the implementation of the PermissionElementCollection class:

 

public class PermissionElementCollection : ConfigurationElementCollection

{

 

   public PermissionGroupElement this[int index]

   {

      get

      {

         return (PermissionGroupElement)base.BaseGet(index);

      }

      set

      {

         if (base.BaseGet(index) != null)

             base.BaseRemoveAt(index);

 

         this.BaseAdd(index, value);

      }

   }

 

   protected override bool IsElementName(string elementName)

   {

      if ((string.IsNullOrEmpty(elementName)) || (elementName != "group"))

         return false;

 

      return true;

   }

 

   protected override ConfigurationElementCollectionType CollectionType

   {

      get { return ConfigurationElementCollectionType.BasicMapAlternate; }

   }

 

   protected override object GetElementKey(ConfigurationElement element)

   {

      return ((PermissionGroupElement)element)._ElementName;

   }

 

   protected override ConfigurationElement CreateNewElement()

   {

      return new PermissionGroupElement();

   }

}

 

When you create a collection class that inherits the ConfigurationElementCollection, the CollectionType property that decide which type of collection you are going to use, will by default only support <add>, <remove> and the  <clear> element. To support your own elements, you have to override the CollectionType property and make sure to return the collection type BasicMap or BasicMapAlternate:

 

BasicMap

 

“Collections of this type contain elements that apply to the level at which they are specified, and to all child levels. A child level cannot modify the properties specified by a parent element of this type.” – MSDN Lib

 

BasicMapAlternate

 

“Same as BasicMap, except that this type causes the ConfigurationElementCollection object to sort its contents such that inherited elements are listed last.” – MSDN Lib

 

protected override ConfigurationElementCollectionType CollectionType

{

   get { return ConfigurationElementCollectionType.BasicMapAlternate; }

}

 

 

When you use a BasicMap or BasicMapAlrernate collection type, you have to override the IsElementName and make sure to return true if the elemenetName argument of the IsElemntName is the name of your child element:

 

protected override bool IsElementName(string elementName)

{

   if ((string.IsNullOrEmpty(elementName)) || (elementName != "permission"))

      return false;

 

   return true;

}

 

You also have to add an indexer to your collection class. If no indexer is created an exception will be thrown when you use the GetSection method to get the section.

 

public PermissionGroupElement this[int index]

{

   get

   {

       return (PermissionGroupElement)base.BaseGet(index);

   }

   set

   {

       if (base.BaseGet(index) != null)

           base.BaseRemoveAt(index);

 

           this.BaseAdd(index, value);

   }
}

 

The two last methods you most override are the GetElementKey and the CreateNewEelement. The GetElementKey will return the key of the child element and the CreateNewElement will return a new instance of the child element’s class:

 

protected override object GetElementKey(ConfigurationElement element)

{

   return ((PermissionGroupElement)element).Name;

}

 

protected override ConfigurationElement CreateNewElement()

{

   return new PermissionGroupElement();

}

 

I only wrote this class to give your some more information about the new section handler feature. You can find a lot of useful information in the VS 2005 MSDN Library.

 

Posted: 11:13 PM GMT+1  Add feedback  Feedback (0)
ASP.NET 2.0 product design changes between Beta 1 and Beta 2 Tuesday, November 16, 2004

One change that probably most of you are going to like is that the compilation model is more like ASP.Net 1.x, where the .aspx file will now by default remain separated from the code-behind binary when the code is pre-compiled. In beta 1, the pre-compilation compiled even the .aspx pages together with the code-behind.

 

The reserved application_xxxx folder will now use the "app_" prefix. For example:

 

Beta 1              October CTP                Beta 2

 

\Code               \Application_Code         \app_code

 

There will be a new CTP version probably released in November with those changes.

Read more about the ASP.NET 2.0 product design changes between Beta 1 and Beta 2

Posted: 6:30 AM GMT+1  Add feedback  Feedback (2)