January 2006 - Posts

If you are looking for an OR mapper LLBLGen is certainly worth a look. I have used it on projects and it certainly saved me a lot of work. And now there is a book out about how to use LLBLGen Pro making it even easier to get started.

Check out this blog entry by Frans.

Recommended!

Maurice de Beijer
www.TheProblemSolver.nl
If you where planning to come to and visit Tech-Ed in Amsterdam this year you might want to revise your plans. Why you might wonder? Well Microsoft has decided to reschedule and reformat Tech-Ed. Instead of July in Amsterdam it will be held in Barcelona, Spain in the beginning of November and it will be focused more on software development

Maurice de Beijer
www.TheProblemSolver.nl


All I had to do was go to Morocco for a week and Rocky comes up with a great post that just completely mirrors my feeling.

Users don’t care a damn bit about technology!

Maurice de Beijer
www.TheProblemSolver.nl

If things are a little quite next week it is because I am off to Morocco for the week [:D] I will have some pictures to share when I get back so stay tuned for more.

Maurice de Beijer
www.TheProblemSolver.nl

Microsoft has announced that there will be a SP3 for Windows XP during 2007 and a SP2 for Windows 2003 server in the second half of this year. See http://www.microsoft.com/windows/lifecycle/servicepacks.mspx for more details.

While still quite a long way away it is certainly good news. Just make sore you report all bugs you run into so they can get on a fix list. Of course you need to send in any crash reports as well as they are looked at and can be instrumental in prioritizing and fixing bugs.

Maurice de Beijer
www.TheProblemSolver.nl


Working with ASP.NET and doing anything with threads or thread related info? In that case you might want to read Rocky's post about ASP.NET thread switching. He has some nice info to share about some of the possible traps you might fall into.
 
Maurice de Beijer

One cool, and not quite new, feature of Visual Studio 2005 is data binding to your own business objects. Just create a new business object class, add a property, add it to the Data Sources window as an object data source and drag it onto your form. Simple as that and you are good to go.

However as usual there is a gotcha :-(
It throw an exception in a property get or get during the data binding the exception is eaten by the DataBindings object. There are two ways around this, either pass False as the formattingEnabled parameters or add an event handler to the BindingComplete event and check for the Exception property being set.

The first option seems the easiest but isn’t :-( Even if you set the Format type to no formatting in the Formatting and Advanced Binding dialog the formattingEnabled will still be true.

That leaves the second option. To handle the BindingComplete event you need to ass an event handler to all Binding objects on the form. Not difficult once you have a reference to all controls. The following code does just that.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each control As Control In GetAllControls(Me)
            For Each binding As Binding In control.DataBindings
                AddHandler binding.BindingComplete, AddressOf BindingCompleteHandler
            Next
        Next

    End Sub

    Private Sub BindingCompleteHandler(ByVal sender As Object, ByVal e As BindingCompleteEventArgs)
        If e.Exception IsNot Nothing Then
            Throw New Exception("Unhandled exception during databinding actions.", e.Exception)
        End If
    End Sub


    Private Function GetAllControls(ByVal container As Control) As List(Of Control)
        Dim result As New List(Of Control)
        Dim pos As Integer = 0
        result.Add(container)
        Do While pos < result.Count
            For Each control As Control In result(pos).Controls
                result.Add(control)
            Next
            pos += 1
        Loop
        Return result
    End Function
End Class

Public Class SomeData

    Private _lastName As String = "Maurice de Beijer"
    Public Property LastName() As String
        Get
            Throw New Exception("Get: " + _lastName)
            Return _lastName

        End Get
        Set(ByVal value As String)
            _lastName = value
        End Set
    End Property
End Class


Maurice de Beijer
www.TheProblemSolver.nl


The My.Settings feature in Visual Basic 2005 is a great way to store form settings like the forms location so the user gets the form at the same place as he/she closed it last time. Adding it is real simple. Just go to ApplicationSettings in the property sheet, expand it, open the combo after location, choose new and type a name like “FormLocation”. Simple as that and you are done [:)]

 However there are some problems [:(]

 The property name must be unique, Give two separate forms the same name and both will be shown at exactly the same position. Makes it kind of hard to view the info on both [:(]

 Adding the ApplicationSettings to a base form class means that all derived forms use the same property name.

 However there is an easy way around it. By using the My.Settins.SettingsKey you can group related entries together. Adding the following code to you base form class will ensure that all form classes keep their own distinct location:

Public Class BaseForm
    Private _setting As New My.MySettings() 

    Private Sub BaseForm_FormClosed( _
        ByVal sender As Object, _
        ByVal e As System.Windows.Forms.FormClosedEventArgs) _
        Handles Me.FormClosed

         _setting.Save()
    End Sub 

    Private Sub BaseForm_Load( _
        ByVal sender As System.Object, _
        ByVal e As System.EventArgs) _
        Handles MyBase.Load

        _setting.SettingsKey = Me.GetType().FullName
        DataBindings.Add(New Binding("Location", _
            _setting, _
            "FormLocation", _
            True, _
            DataSourceUpdateMode.OnPropertyChanged))
    End Sub
End
Class

 
Maurice de Beijer
www.TheProblemSolver.nl

 

In my last three blog entries I showed how to use the ASP.Net membership provider in a Windows application. I finished with the problem of storing the current user name and the fact that there is a second overload to the IsUserInRole() function that only takes a role name. Well it turns out that this function checks for the current user and uses either the HttpContext.Current.User or the Threading.Thread.CurrentPrincipal depending on the fact if the application is hosted. As the Threading.Thread.CurrentPrincipal is the normal way access is provided to the current user and role information in a windows application this seems like the natural thing to do.

 

The System.Web.Security.RolePrincipal class implements the required IPrincipal interface so this is the class we need to use. To create the required object we need an IIDentity object to provide the user identity information. This can be provided using the System.Security.Principal.GenericIdentity class that implements the IIdentity interface.

 

Add the following code to the top of the Module1.vb:

Imports System.Security.Principal

 

Now we can set the principal and check for specific roles using the following code:

        Dim user As MembershipUser = Membership.GetUser("Maurice")
        Dim identity As New GenericIdentity(user.UserName)
        Dim principal As New RolePrincipal(identity)
        Threading.Thread.CurrentPrincipal = principal

        If Roles.IsUserInRole("Developer") Then
            Console.WriteLine("Is a developer.")
        Else
            Console.WriteLine("Doesn't write code.")
        End If

 

An alternative way of checking the user and role is:

        Console.Write(Threading.Thread.CurrentPrincipal.Identity.Name)
        If Threading.Thread.CurrentPrincipal.IsInRole("Developer") Then
            Console.WriteLine(" is a developer.")
        Else
            Console.WriteLine(" doesn't write code.")
        End If

 

So the complete console application now looks like:

Imports System.Security.Principal
Imports
System.Web.Security

Module Module1
    Sub Main()
        ' Creating a new user
        Dim status As MembershipCreateStatus
        Membership.CreateUser( _
            "Maurice", _
            "Password_1", _
            "maurice@TheProblemSolver.nl", _
            "Password question", _
            "Password answer", _
            True, _
            status)
        ' Check the status for errors
        Console.WriteLine(status.ToString())

        ' Validate a username/password
        If Membership.ValidateUser("Maurice", "Password_1") Then
            Console.WriteLine("User validated.")
        Else
            Console.WriteLine("User invalid!")
        End If
 

        ' Create a new Developer role.
        ' Add the <roleManager enabled="true" /> to the app.config for this to work
        If Not Roles.RoleExists("Developer") Then
            Roles.CreateRole("Developer")
        End If

        ' Add a new role to a known user.
        If Not Roles.IsUserInRole("Maurice", "Developer") Then
            Roles.AddUserToRole("Maurice", "Developer")
        End If

        ' Create a second user with only username/password
        ' Add the <membership><providers> element to the app.config first
        Dim user As MembershipUser
        user = Membership.GetUser("User2")
        If user Is Nothing Then
            user = Membership.CreateUser("User2", "p")
            Console.WriteLine(user.UserName)
        End If


        ' Check is a specified user is in a specific role
        If Roles.IsUserInRole("Maurice", "Developer") Then
            Console.WriteLine("Is a developer.")
        Else
            Console.WriteLine("Doesn't write code.")
        End If 

        ' Set the current application principal information to a known user
        Dim identity As GenericIdentity
        Dim principal As RolePrincipal
        user = Membership.GetUser("Maurice")
        identity = New GenericIdentity(user.UserName)
        principal = New RolePrincipal(identity)
        Threading.Thread.CurrentPrincipal = principal

        ' Check if the current principal is in a specific role
        If Roles.IsUserInRole("Developer") Then
            Console.WriteLine("Is a developer.")
        Else
            Console.WriteLine("Doesn't write code.")
        End If


        ' Set the current application principal information to another known user
        user = Membership.GetUser("User2")
        identity = New GenericIdentity(user.UserName)
        principal = New RolePrincipal(identity)
        Threading.Thread.CurrentPrincipal = principal

        ' Use the principal to check for role information
        Console.Write(Threading.Thread.CurrentPrincipal.Identity.Name)
        If Threading.Thread.CurrentPrincipal.IsInRole("Developer") Then
            Console.WriteLine(" is a developer.")
        Else
            Console.WriteLine(" doesn't write code.")
        End If

        Console.ReadLine()
    End Sub
End
Module

 

 
<?
xml version="1.0" encoding="utf-8" ?>
<
configuration>
  <
system.web>
    <
roleManager enabled="true" />
    <
membership
      <
providers>
        <
remove name="AspNetSqlMembershipProvider"/>
        <
add name="AspNetSqlMembershipProvider"
            
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            
connectionStringName="LocalSqlServer"
            
enablePasswordRetrieval="false"
            
enablePasswordReset="true"
            
requiresQuestionAndAnswer="false"
            
applicationName="/"
            
requiresUniqueEmail="false"
            
passwordFormat="Hashed"
            
maxInvalidPasswordAttempts="5"
            
minRequiredPasswordLength="1"
            
minRequiredNonalphanumericCharacters="0"
            
passwordAttemptWindow="10"
            
passwordStrengthRegularExpression="" />
      </
providers>
    </
membership>
  </
system.web>
</
configuration>
 

Maurice de Beijer
www.TheProblemSolver.nl

In my last two blog entries I showed how to use the ASP.Net membership provider in a Windows application. Now that we can add a validate users we might want to start using roles as well. To work with security roles we need to use the class System.Web.Security.Roles. This class works pretty much in the same way as the Membership provider. To add a new role we use the CreateRole() function and to associate a user with this role we use the AddUserToRole() function. So adding the Developer role to my previously created user account can be done with the following code:

        Roles.CreateRole("Developer")
        Roles.AddUserToRole("Maurice", "Developer")

 

However if you try this you will receive an error: “The Role Manager feature has not been enabled.”. To enable roles we need to add one more thing to the app.config. Add following line to the <system.web> section:

<roleManager enabled="true" />

Once this is done you are ready to add roles and associate users with there roles.

Use the following code to check if a user has a specific role:

        If Roles.IsUserInRole("Maurice", "Developer") Then
            Console.WriteLine("Is a developer.")
        Else
            Console.WriteLine("Doesn't write code.")
        End If
 

Of course this leaves us with a place to store the current user name so we know which user is logged in when we need to check for a specific role. The IsUserInRole() function has an additional overload that takes only a single parameter, the role name. Next time more about how to use this overload.


Maurice de Beijer
www.TheProblemSolver.nl


In my last blog entry I showed how to use the ASP.Net membership provider in a Windows application. In the sample I used the Membership.CreateUser() function to create a new user. However I had to supply quite a bit of information, like password question and answer, that I would not use in a typical windows application. Fortunately the Membership.CreateUser() also has an overload with just the username and password combination.

        Dim user As MembershipUser
        user = Membership.CreateUser("User2", "Password")
        Console.WriteLine(user.UserName)

 
However trying to use this overload results in the error: “The password-answer supplied is invalid.”. Additionally there might be some other properties you might like to change, like the requirement for at least one non alphanumeric character in the password. Even though these settings are exposed as properties they are read-only so setting them like:
Membership.MinRequiredNonAlphanumericCharacters = 0

Will not work. To change them we need to use the app.config so lets add one to the application. Add the following to the bottom of the <configuration> section:

<system.web>
    <
membership>
      <
providers>
        <
remove name="AspNetSqlMembershipProvider"/>
        <
add name="AspNetSqlMembershipProvider"
            
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            
connectionStringName="LocalSqlServer"
            
enablePasswordRetrieval="false"
            
enablePasswordReset="true"
            
requiresQuestionAndAnswer="false"
            
applicationName="/"
            
requiresUniqueEmail="false"
            
passwordFormat="Hashed"
            
maxInvalidPasswordAttempts="5"
            
minRequiredPasswordLength="1"
            
minRequiredNonalphanumericCharacters="0"
            
passwordAttemptWindow="10"
            
passwordStrengthRegularExpression="" />
      </
providers>
    </
membership>
  </
system.web>

This removes the default membership provider as defined in the machine.config and adds the same one but this time with more relaxed password format and questions settings.

Now run the application again and this time we are allowed to add a user with just a username and password combination. Because of the relaxed password requirements even a password of just 1 single letter is accepted.

Stay posted for more.
 

Maurice de Beijer

www.TheProblemSolver.nl

One of the new features in ASP.Net 2.0 is the membership and role provider system. This is nicely designed system that allows the developer to handle the storage of user information pretty much any way he likes, all he has to do is create the appropriate providers and configure his application to use these. While this is very powerful there is something else I was much more interested in and that is the fact that user and role management can be added to an application without having to do any of the implementation work. Now this is very convenient if you don’t already have a user database to work with and something I would like to be able to use in my Windows forms applications as well as in my web application.

Fortunately this is possible without much work at all! So let’s create a very small console application with user management.

First create a new Visual Basic console application in Visual Studio 2005. No problem if you prefer C#, all you need to do is translate the remaining syntax to C#.

Add a reference to the System.Web namespace.

Add a line with  “Imports System.Web.Security” to the top of the Module1.vb.

Now add the following code to the Sub Main()

        ' Validate a username/password
        If Membership.ValidateUser("Maurice", "Password_1") Then
            Console.WriteLine("User validated.")
        Else
            Console.WriteLine("User invalid!")
        End If

        Console.ReadLine()

 
Go ahead and run the application.
Not surprisingly the application reports that the user is invalid, after all how it can’t know which users are valid.


Now add the following code to the top of the Sub Main()

        ' Creating a new user
        Dim status As MembershipCreateStatus
        Membership.CreateUser( _
            "Maurice", _
            "Password_1", _
            "maurice@TheProblemSolver.nl", _
            "Password question", _
            "Password answer", _
            True, _
            status)
        Console.WriteLine(status.ToString())

 

Go ahead and run the application again.

If you have never used the membership provider in a Web application you might me surprised to see this just works, the user is created and is validated. Run the application again and the creation will return a DuplicateUserName error but the ValidateUser() still works. How is this possible as we haven’t done anything to configure the membership provider or told it which database to use? Well the secret is that the membership provider checks for, and creates if needed, a new directory under the application directory named App_Data with a SQL Express database ASPNETDB with the required structure. This database is then used to store the user information.


Maurice de Beijer

www.TheProblemSolver.nl