Handling Null Values (Part Two)

August 11th, 2008

During my studies whilst over in Baku for work, I came onto the topic of Generics in .Net. I wont bore you with all the details of Generics here, but one of the interesting features of it, is that if you assign a generic variable a value of nothing when the generic is something like a date, or an integer, you get a default value for that type.

This got me thinking about whether I could compress the whole class from my previous Blog into just a single generic Function. I believe I can! See the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    Public Class HandleNullValues
 
        Private Sub New()
            'Does nothing. Set to private to prevent instantiation of the class.
        End Sub
 
        Public Shared Function CheckNull(Of T)(ByVal obj As Object) As T
            If IsDBNull(obj) Then
                Dim ret As T = Nothing
 
                Return ret
            Else
                Return CType(obj, T)
            End If
        End Function
 
        Public Function DefaultValue(Of T)() As T
            Dim ret As T = Nothing
            Return ret
        End Function
    End Class

As you can see, this class consists of just two methods (ignoring the ‘new’ method). The core of the class is the CheckNull Function. This will compare the object and return the objects value if there is one. If it is null, it returns nothing (for objects) or the default value of the type (for things like dates/integers/boolean/etc).

There is a proviso to this function, however. The usage is not necessarily the most clear cut. You need to use the syntax below:

Dim myVal as Integer
Dim obj as new object
 
myVal = CheckNull(of Integer)(obj)

As you can see, you need to specify the generic type in brackets after the Function name, but before the parameters list.

The second Function, DefaultValue, takes no parameters (although you still need to specify the generic type as above). This Function will return the default value of the given type. I’ve only really provided it so that you can see what will be returned if the object is null. Remember that, this may or may not be the same as a valid object value (ie, if the object holds an integer value of 0, then this is the same as a null object)

Time Journalling with Timesnapper

July 2nd, 2008

At work, all my time is billable back to the business. As a result, I need to keep track on exactly what I’m doing at any given time. This can be an absolute nightmare, and I find myself resorting to checking my sent items.

 One of the guys at work, though, uses a snazzy little application called Timesnapper, to log his daily activities.

Although there is a professional (paid for) version of the application, the free version seems to have the important basic features.

When you download the free file, you need to place the zipped exe and manifest into a directory of your choice (C:\Timesnapper, for instance), and copy a shortcut for it into the startup folder on your machine. Once you have done that, you are good to go! Fire up the application, and set the various options. The most important of this is the timescale: The lower the period, the more images you will end up with - and the more disk space used as a result.

The options menu allows you to control the filetype of the snapshots, and the resolution, as well as wether the application captures only the active window, a particular monitor, or all monitors.

 

Once set up, this application will sit in your taskbar, and take a screenshot of your machine every x seconds (as specified by you). You can then play back the entire day )or day period) like a movie, by opening the application and selecting ‘Play’

This has additional benefits beyond just time management, of course. It also allows you to keep a record of your changes. So long as your period is low enough (mine is 30 seconds), you should be able to see what you were typing at a particular moment in time. So if you delete a wad of commands/text (something I coincidentally did whilst writing this blog), and are unable to recover the text, you can replay this step by step and see what was written.

Check it out sometime.

Monitor Files

July 1st, 2008

Have you ever wanted to monitor a directory for new files? Or monitor a file for changes? This can be particularly useful for inter-company system communications: Company A uploads a txt file every day, containing all the data from their system for that day. You want to update your system with their information, but want to automate the system (nothing more annoying that you or a user having to do it by hand).

With older versions (ie VB3, or even VBScript), you would have to poll the file every x minutes, and sleep the application between polls.

.Net makes this fairly straightforward, with the use of the FileSystemWatcher object (Under System.IO).  As best I can tell, the FileSystemWatcher subscribes to events in the Windows Operating System, so that when a file is changed, Windows notifies the application of the change, which in turn raises the associated event within the application.

For a start, this allows your application to remain responsive to user input, as it doesnt freeze whilst it waits for the files to change.

The FSW is controlled by a number of methods, including:

  • .Path - Specifies the path to monitor, this can be a standard filepath (eg C:\) or a UNC Path (eg \\server1\share
  • .IncludeSubdirectories - Specifies if the FSW should monitor subdirectories of .Path (this is recursive - so not just one level down)
  • .Filter - Specifies files to monitor. If you want to check all files ending in .txt, this should be “*.txt”. If you want all files, use “*.*”. A special note on this, “*.*” only works for files that have an extension. If you want all files regardless, use String.Empty. If you want a specific file (such as test.txt) you can specify it there too, using “text.txt”
  • .NotifyFilter - This specifies the type of events we want to watch for, you can combine multiple versions using the bitwise Or method (ie NotifyFilters.LastAccess Or NotifyFilters.LastWrite)
  • .EnableRaisingEvents - specifies if the FSW should be able to raise events for changes - use this to turn the monitoring on and off
  • .WaitForChanged - This is a synchronous method that will pause the application until the specified type of change is detected. This can be handy if you know that the change will take place shortly, and want the application to hold until its done.

There are other methods, but the above are sufficient to get the watcher running.

Remember, you need to create Methods that handle the events when they are raised. They can be done either at design time (by using the handles keyword after the sub parameters list), or dynamically in code, using the addhandler method. The events that can be raised are:

  • Changed - when a file/directory in the scope is changed
  • Created - when a file/directory in the scope is created
  • Deleted - when a file/directory in the scope is deleted
  • Disposed - when a FSW component is disposed via its .Dispose Method
  • Error - when  the FSW’s internal buffer overflows
  • Renamed - when a file/directory in the scope is renamed

A caveat to this, I’ve noticed that (certainly when you use all the notifyfilter values) renaming a file raises a rename and a Changed event.

The Buffer is a non-paged section of memory the application uses to store changes. By default its about 8KB, but can be altered. However, remember that this obviously takes memory from the system while its running. If too many change notifications arrive too quickly, the buffer will overflow, so you should take care to restrict the files being monitored using the methods above.

For more details, and a good example of the code in action, check out the MSDN documentation on the FSW class, here

Handling Null Values

June 23rd, 2008

When returning data from databases, its quite common to get null values within your data. Handling the data, to prevent errors with the nulls, can end up being quite an involved process, and often looks like this:

If Not IsDBNull(ds.Tables(0).Rows(0).Item("Email")) Then
    pEmail = ds.Tables(0).Rows(0).Item("Email")
Else
    pEmail = String.Empty
End If

Of course, doing that reduces readability of the code, and increases the odds that you are going to incorrectly write the code.

Instead, I’ve started using a standard class in any application. This class consists of a series of functions checking objects for null, and converting them to a specified type.

The code for this class is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Public Class HandleNull
 
Private Sub New()
'Does nothing. These functions are static, so prevent instantiation of the class
End Sub
 
Public Shared Function CheckString _
(ByVal Value As Object) As String
If IsDBNull(Value) Then
Return String.Empty
Else
Return CType(Value, String)
End If
End Function
 
Public Shared Function CheckBoolean _
(ByVal value As Object) As Boolean
If IsDBNull(value) Then
Return False
Else
Return CType(value, Boolean)
End If
End Function
 
Public Shared Function CheckInteger _
(ByVal value As Object) As Integer
If IsDBNull(value) Then
Return 0
Else
Return CType(value, Integer)
End If
End Function
 
Public Shared Function CheckDouble _
(ByVal value As Object) As Double
If IsDBNull(value) Then
Return 0
Else
Return CType(value, Double)
End If
End Function
 
Public Shared Function CheckDate _
(ByVal value As Object) As Date
If IsDBNull(value) Then
Return New Date(1901, 1, 1)
Else
Return CType(value, Date)
End If
End Function
 
Public Shared Function Checksingle _
(ByVal value As Object) As Single
If IsDBNull(value) Then
Return 0
Else
Return CType(value, Single)
End If
End Function
 
End Class

To call this code, all you need to do now is:

pEmail = HandleNull.CheckString _
(ds.Tables(0).Rows(0).Item("Email"))

A Note on this though, when calling these functions, you want to pass the object in, rather than the value of the object. ie, use:

myRS("Email")

as opposed to

myRS("Email").value

or anything similar.

Active Directory Webservice

June 20th, 2008

I’ve been writing an asp.net webservice, to serve the Active Directory integration functions for our applications.

AD is something fairly close to my heart. My promotion out of service desk took my into Account Administration, which dealt with the creation/modification of user accounts, and controlling group memberships, etc. It was there that I started out in programming, writing vbscripts to query and amend data in AD. I was actually torn between pursuing a career in AD management/Network admin, and programming.

In this day and age, in an environment which makes use of AD (such as ours). I’m a big fan of integrating new applications into Active Directory. Users dont want to be bothered with remembering passwords for every application they use, and it can increase overhead on the developers/administrators of a system every time the user forgets their password. Instead, why not hook it up with AD, so that any login to the database is done using their AD username? Ideally, once a user logs into the system with their AD username, any and all applications should use that information to check their own systems and make sure that they are permitted access.

Of course, this opens a potential security risk, in that once someone gets logged into a machine as that user, they have access to all the systems that the user has access to. But to be honest, its a tradeoff. Users get the ease of use for all their systems, and only have a single password to remember. In return, they should observe increased security practices for their access to the system. Starting with locking a machine when they walk away from it, and including not writing their password down - if you only have a single password to remember at a time, I’m sure you can commit it to memory!

Initially, the service is aimed at producing user details from a given upn or samaccountname, or searching for users against specified criteria. I’m modifying it to allow returning the groups a listed user is a member of, and intend to include functions to query the system from other angles (ie, not by a specific user). In time, I should have a service that will work in any domain you care to place it (with some initial setup provisos).

Once I make some progress, I’ll post the files up, and let you see what I’ve done. In the meantime, If anyone needs any help for querying AD (either in vbscript or VB.Net) let me know. Chances are I’ve done something similar in my time, or can work out what needs to be done.


AJAXed with AWP