Follow @PDSAInc February 2011 - Posts - Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 25+ years in the IT industry

Paul's Favorites

February 2011 - Posts

WPF Login Verification Using Active Directory

Back in October of 2009 I created a WPF login screen (Figure 1) that just showed how to create the layout for a login screen. That one sample is probably the most downloaded sample we have. So in this blog post, I thought I would update that screen and also hook it up to show how to authenticate your user against Active Directory.

Figure 1: Original WPF Login Screen

Figure 1: Original WPF Login Screen

I have updated not only the code behind for this login screen, but also the look and feel as shown in Figure 2.

Figure 2: An Updated WPF Login Screen

Figure 2: An Updated WPF Login Screen

The UI

To create the UI for this login screen you can refer to my October of 2009 blog post to see how to create the borderless window. You can then look at the sample code to see how I created the linear gradient brush for the background. There are just a few differences in this screen compared to the old version. First, I changed the key image and instead of using words for the Cancel and Login buttons, I used some icons. Secondly I added a text box to hold the Domain name that you wish to authenticate against. This text box is automatically filled in if you are connected to a network. In the Window_Loaded event procedure of the winLogin window you can retrieve the user’s domain name from the Environment.UserDomainName property. For example:

txtDomain.Text = Environment.UserDomainName

The ADHelper Class

Instead of coding the call to authenticate the user directly in the login screen I created an ADHelper class. This will make it easier if you want to add additional AD calls in the future. The ADHelper class contains just one method at this time called AuthenticateUser. This method authenticates a user name and password against the specified domain. The login screen will gather the credentials from the user such as their user name and password, and also the domain name to authenticate against. To use this ADHelper class you will need to add a reference to the System.DirectoryServices.dll in .NET.

The AuthenticateUser Method

In order to authenticate a user against your Active Directory you will need to supply a valid LDAP path string to the constructor of the DirectoryEntry class. The LDAP path string will be in the format LDAP://DomainName. You will also pass in the user name and password to the constructor of the DirectoryEntry class as well. With a DirectoryEntry object populated with this LDAP path string, the user name and password you will now pass this object to the constructor of a DirectorySearcher object. You then perform the FindOne method on the DirectorySearcher object. If the DirectorySearcher object returns a SearchResult then the credentials supplied are valid. If the credentials are not valid on the Active Directory then an exception is thrown.

C#
public bool AuthenticateUser(string domainName, string userName,
  string password)
{
  bool ret = false;

  try
  {
    DirectoryEntry de = new DirectoryEntry("LDAP://" + domainName,
                                           userName, password);
    DirectorySearcher dsearch = new DirectorySearcher(de);
    SearchResult results = null;

    results = dsearch.FindOne();

    ret = true;
  }
  catch
  {
    ret = false;
  }

  return ret;
}

Visual Basic

Public Function AuthenticateUser(ByVal domainName As String, _
 ByVal userName As String, ByVal password As String) As Boolean
  Dim ret As Boolean = False

  Try
    Dim de As New DirectoryEntry("LDAP://" & domainName, _
                                 userName, password)
    Dim dsearch As New DirectorySearcher(de)
    Dim results As SearchResult = Nothing

    results = dsearch.FindOne()

    ret = True
  Catch
    ret = False
  End Try

  Return ret
End Function

In the Click event procedure under the Login button you will find the following code that will validate the credentials that the user types into the login window.

C#
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
  ADHelper ad = new ADHelper();

  if(ad.AuthenticateUser(txtDomain.Text,
        txtUserName.Text, txtPassword.Password))
    DialogResult = true;
  else
    MessageBox.Show("Unable to Authenticate Using the
                     Supplied Credentials");
}

Visual Basic
Private Sub btnLogin_Click(ByVal sender As Object, _
 ByVal e As RoutedEventArgs)
  Dim ad As New ADHelper()

  If ad.AuthenticateUser(txtDomain.Text, txtUserName.Text, _
                         txtPassword.Password) Then
    DialogResult = True
  Else
    MessageBox.Show("Unable to Authenticate Using the
                     Supplied Credentials")
  End If
End Sub

Displaying the Login Screen

At some point when your application launches, you will need to display your login screen modally. Below is the code that you would call to display the login form (named winLogin in my sample application). This code is called from the main application form, and thus the owner of the login screen is set to “this”. You then call the ShowDialog method on the login screen to have this form displayed modally. After the user clicks on one of the two buttons you need to check to see what the DialogResult property was set to. The DialogResult property is a nullable type and thus you first need to check to see if the value has been set.

C#

private void DisplayLoginScreen()
{
  winLogin win = new winLogin();

  win.Owner = this;
  win.ShowDialog();
  if (win.DialogResult.HasValue && win.DialogResult.Value)
    MessageBox.Show("User Logged In");
  else
    this.Close();
}

Visual Basic

Private Sub DisplayLoginScreen()
  Dim win As New winLogin()

  win.Owner = Me
  win.ShowDialog()
  If win.DialogResult.HasValue And win.DialogResult.Value Then
    MessageBox.Show("User Logged In")
  Else
    Me.Close()
  End If
End Sub

Summary

Creating a nice looking login screen is fairly simple to do in WPF. Using the Active Directory services from a WPF application should make your desktop programming task easier as you do not need to create your own user authentication system. I hope this article gave you some ideas on how to create a login screen in WPF.

NOTE: You can download the complete sample code for this blog entry at my website: http://www.pdsa.com/downloads. Click on Tips & Tricks, then select 'WPF Login Verification Using Active Directory' from the drop down list.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
We frequently offer a FREE gift for readers of my blog. Visit http://www.pdsa.com/Event/Blog for your FREE gift!

Posted: Feb 28 2011, 03:54 PM by psheriff | with 3 comment(s)
Filed under: ,
'Content' is NOT 'Text' in XAML

One of the key concepts in XAML is that the Content property of a XAML control like a Button or ComboBoxItem does not have to contain just textual data. In fact, Content can be almost any other XAML that you want. To illustrate here is a simple example of how to spruce up your Button controls in Silverlight.

Here is some very simple XAML that consists of two Button controls within a StackPanel on a Silverlight User Control.

<StackPanel>
  <Button Name="btnHome"
          HorizontalAlignment="Left"
          Content="Home" />
  <Button Name="btnLog"
          HorizontalAlignment="Left"
          Content="Logs" />
</StackPanel>

The XAML listed above will produce a Silverlight control within a Browser that looks like Figure 1.

Figure 1 

Figure 1: Normal button controls are quite boring.

With just a little bit of refactoring to move the button attributes into Styles, we can make the buttons look a little better. I am a big believer in Styles, so I typically create a Resources section within my user control where I can factor out the common attribute settings for a particular set of controls. Here is a Resources section that I added to my Silverlight user control.

<UserControl.Resources>
  <Style TargetType="Button"
         x:Key="NormalButton">
    <Setter Property="HorizontalAlignment"
            Value="Left" />
    <Setter Property="MinWidth"
            Value="50" />
    <Setter Property="Margin"
            Value="10" />
  </Style>
</UserControl.Resources>

Now back in the XAML within the Grid control I update the Button controls to use the Style attribute and have each button use the Static Resource called NormalButton.

<StackPanel>
  <Button Name="btnHome"
          Style="{StaticResource NormalButton}"
          Content="Home" />
  <Button Name="btnLog"
          Style="{StaticResource NormalButton}"
          Content="Logs" />
</StackPanel>

With the additional attributes set in the Resources section on the Button, the above XAML will now display the two buttons as shown in Figure 2.

Figure 2

Figure 2: Use Resources to Make Buttons More Consistent

Now let’s re-design these buttons even more. Instead of using words for each button, let’s replace the Content property to use a picture. As they say… a picture is worth a thousand words, so let’s take advantage of that. Modify each of the Button controls and eliminate the Content attribute and instead, insert an <Image> control with the <Button> and the </Button> tags. Add a ToolTip to still display the words you had before in the Content and you will now have better looking buttons, as shown in Figure 3.

 Figure 3

Figure 3: Using pictures instead of words can be an effective method of communication

The XAML to produce Figure 3 is shown in the following listing:

<StackPanel>
  <Button Name="btnHome"
          ToolTipService.ToolTip="Home"
          Style="{StaticResource NormalButton}">
    <Image Style="{StaticResource NormalImage}"
            Source="Images/Home.jpg" />
  </Button>
  <Button Name="btnLog"
          ToolTipService.ToolTip="Logs"
          Style="{StaticResource NormalButton}">
    <Image Style="{StaticResource NormalImage}"
            Source="Images/Log.jpg" />
  </Button>
</StackPanel>

You will also need to add the following XAML to the User Control’s Resources section.

<Style TargetType="Image"
        x:Key="NormalImage">
  <Setter Property="Width"
          Value="50" />
</Style>

Add Multiple Controls to Content

Now, since the Content can be whatever we want, you could also modify the Content of each button to be a StackPanel control. Then you can have an image and text within the button.

<StackPanel>
  <Button Name="btnHome"
          ToolTipService.ToolTip="Home"
          Style="{StaticResource NormalButton}">
    <StackPanel>
      <Image Style="{StaticResource NormalImage}"
              Source="Images/Home.jpg" />
      <TextBlock Text="Home"
                  Style="{StaticResource NormalTextBlock}" />
    </StackPanel>
  </Button>
  <Button Name="btnLog"
          ToolTipService.ToolTip="Logs"
          Style="{StaticResource NormalButton}">
    <StackPanel>
      <Image Style="{StaticResource NormalImage}"
              Source="Images/Log.jpg" />
      <TextBlock Text="Logs"
                  Style="{StaticResource NormalTextBlock}" />
    </StackPanel>
  </Button>
</StackPanel>

You will need to add one more resource for the TextBlock control too.

<Style TargetType="TextBlock"
        x:Key="NormalTextBlock">
  <Setter Property="HorizontalAlignment"
          Value="Center" />
</Style>

All of the above will now produce the following:

Figure 4 

Figure 4: Add multiple controls to the content to make your buttons even more interesting.

Summary

While this is a simple example, you can see how XAML Content has great flexibility. You could add a MediaElement control as the content of a Button and play a video within the Button. Not that you would necessarily do this, but it does work. What is nice about adding different content within the Button control is you still get the Click event and other attributes of a button, but it does necessarily look like a normal button.


Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free video on Silverlight entitled "Silverlight XAML for the Complete Novice - Part 1."

Copy New Files Only in .NET

Recently I had a client that had a need to copy files from one folder to another. However, there was a process that was running that would dump new files into the original folder every minute or so. So, we needed to be able to copy over all the files one time, then also be able to go back a little later and grab just the new files.

After looking into the System.IO namespace, none of the classes within here met my needs exactly. Of course I could build it out of the various File and Directory classes, but then I remembered back to my old DOS days (yes, I am that old!). The XCopy command in DOS (or the command prompt for you pure Windows people) is very powerful. One of the options you can pass to this command is to grab only newer files when copying from one folder to another. So instead of writing a ton of code I decided to simply call the XCopy command using the Process class in .NET.

The command I needed to run at the command prompt looked like this:

XCopy C:\Original\*.* D:\Backup\*.* /q /d /y

What this command does is to copy all files from the Original folder on the C drive to the Backup folder on the D drive. The /q option says to do it quitely without repeating all the file names as it copies them. The /d option says to get any newer files it finds in the Original folder that are not in the Backup folder, or any files that have a newer date/time stamp. The /y option will automatically overwrite any existing files without prompting the user to press the "Y" key to overwrite the file.

To translate this into code that we can call from our .NET programs, you can write the CopyFiles method presented below.

C#

using System.Diagnostics

public void CopyFiles(string source, string destination)
{
  ProcessStartInfo si = new ProcessStartInfo();
  string args = @"{0}\*.* {1}\*.* /q /d /y";

  args = string.Format(args, source, destination);

  si.FileName = "xcopy";
  si.Arguments = args;
  Process.Start(si);
}

VB.NET

Imports System.Diagnostics

Public Sub CopyFiles(source As String, destination As String)
  Dim si As New ProcessStartInfo()
  Dim args As String = "{0}\*.* {1}\*.* /q /d /y"

  args = String.Format(args, source, destination)

  si.FileName = "xcopy"
  si.Arguments = args
  Process.Start(si)
End Sub

The CopyFiles method first creates a ProcessStartInfo object. This object is where you fill in name of the command you wish to run and also the arguments that you wish to pass to the command. I created a string with the arguments then filled in the source and destination folders using the string.Format() method. Finally you call the Start method of the Process class passing in the ProcessStartInfo object. That's all there is to calling any command in the operating system. Very simple, and much less code than it would have taken had I coded it using the various File and Directory classes.


Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free video on Silverlight entitled Silverlight XAML for the Complete Novice - Part 1.

 

Posted: Feb 02 2011, 11:36 PM by psheriff | with 4 comment(s)
Filed under:
More Posts