Visual Basic.Net Related Posts by ThinqLinq

Rx for Windows Phone article now available

A couple of years ago I gave a presentation at the last MIX for doing asynchronous programming using Reactive Extensions (Rx) on the Windows Phone. The video of the presentation is still available for watching. Around the same time, I was approached by Code Magazine to write a similar article, which I was happy to oblige. It took a while but I was happy to see the article finally published in the Sep/Oct 2013 edition of Code Magazine.

In the article I demonstrate how to use Rx to build a dice rolling game (like Yhatzee) for the Windows Phone 7 or 8 and communicating with a service tier for rolling the dice (hiding the fact that you may be loading the results). While the particular solution was targeted to Windows Phone, the concepts are valid across the wide variety of platforms that Rx supports. Give the article a read and let me know what you thinq.

Posted on - Comment
Categories: C# - Rx - VB - WP7 -

Beware of Async Sub or Void

At my VS Live last week, I gave a survey of Asynchronous programming from .Net 1 through .Net 4.5. As part of the presentation, I showed off this simple example of doing Async starting with a synchronous example. Here’s the beginning example:

Sub Main() DoWorkAsync() Debug.WriteLine("All Done")

Console.ReadLine() End Sub Sub DoWorkAsync() PrintIt() Debug.WriteLine("Done Async") End Sub Public Sub PrintIt() Dim text = "Hello World" Task.Delay(2000) Debug.WriteLine(text) End Sub

Before continuing on, try to figure out what you would see in the output window. For those impatient, here’s the output:

Hello World
Done Async
All Done

However, if you try this code, you will notice that the output is all produced prior to the expected 2 second delay (from the Task.Delay). Why is the delay ignored, because the TPL schedules the delay operation on a different thread than the main UI one and then lets the rest of the code operate on the main thread. We can force the delay to pause by changing the PrintIt method as follows:

    Public Sub PrintIt()
        Dim text = "Hello World"
        Task.Delay(2000).Wait()
        Debug.WriteLine(text)
    End Sub

Now, we do delay for the 2 seconds as expected, but we loose any asynchronous behavior that we expected. As a result, we should use the new Async/Await keywords to make our PrintIt method async:

    Public Async Sub PrintIt()
        Dim text = "Hello World"
        Await Task.Delay(2000)
        Debug.WriteLine(text)
    End Sub

Now, if we check our output, we’ll see the following results:

Done Async
All Done
(2 second pause)
Hello World

Notice here that the Done Async and All Done messages appear before Hello World.  Why? Because when the line with the Await is encountered, control is passed back to the calling method (DoWorkAsync) and schedules the continuation of the await operation on the thread context of the Task.Delay operation. This is just one of the problems with the “Async Sub” or in C#, “async void” patterns. They are acceptable for fire and forget operations, but can cause issues if you want to rely on structured exception handling, resource disposal, and a number of other useful constructs, you shouldn’t use Async Sub. For more information, see Lucian Wischik’s Async Patterns article or any of a number of excellent articles by Stephen Toub.

So, how do we call the PrintIt operation asynchronously and ensure that it completes prior to continuing the “Done Async”  operation? We need to change the signature of the PrintIt method to return a Task rather than returning nothing (void). We then need to move the await up the stack to also Await PrintIt and mark DoWorkAsync as Asynchronous.

    Sub Main()
        DoWorkAsync()
        Debug.WriteLine("All Done")
        Console.ReadLine()
    End Sub

    Async Sub DoWorkAsync()
        Await PrintIt()
        Debug.WriteLine("Done Async")
    End Sub

    Public Async Function PrintIt() As Task
        Dim text = "Hello World"
        Await Task.Delay(2000)
        Debug.WriteLine(text)
    End Function

Now when we run our program, we see the following output:

All Done
Hello World
Done Async

Notice here that the “All Done” message appears before the 2 second delay, but Hello World and Done Async come out in the expected order showing how the DoWorkAsync operation was indeed run asynchronously from the rest of the app. If you want to see the internals of how the compiler interprets the Async and Await keywords, see my earlier post on using ILSpy with Async.

Also, if you are interested in using Async with Asp.Net or WCF, make sure to check out the Async session from Asp.Net Conf 2012 which details some of the potential issues you should consider there.

Posted on - Comment
Categories: VB Dev Center - VB -

JSON Literals for VB

One of the stand-out features of VB.Net since VB9 has been the inclusion of XML Literals. Followers of this blog should be well familiar with the concept because I first wrote about XML Literals way back in 2006. With them, we can imbed XML directly into our code as follows:

Dim value = <root>
                <child attrib="foo">bar</child>
            <root>

While XML Literals make the task of working with XML more of a joy than a necessary evil, they do add a certain level of complexity to the language. Any language feature then needs to be maintained moving forward. When I asked Anders about adding them to C#, he pointed to the ongoing maintenance issue along with the supposition that although XML was becoming a de-facto data persistence syntax, would adopting the literals into the language then set a precedence that they would need to support other persistence mechanisms when XML was replaced with some other syntax.

With the rise of REST and decline of SOAP, we have indeed seen the popularity of XML wane in favor of the more compact json syntax. The popularity is increased due to the fact that most JavaScript clients make parsing json into objects trivial. As a result, I have had conversations at conferences joking about the need for json literals in the language as well. At a recent conference an idea came to me which could actually make them (almost) a reality.

At its heart, json is simply a string representation of the JavaScript object structures. These object structures behave much like the .Net dynamic PropertyBag object. As a result, all we really need is a way to embed a long, multi-line string into our VB code and then parse it into a dynamic PropertyBag in order to consume it. Unfortunately, VB doesn’t support multi-line strings. However, it does support multi-line XML. All we need to do is wrap the multi line string inside of an XML element literal:

        Dim jsonLiteral = <js>[
            {author:'Jim Wooley', bookName:'LINQ in Action'},
            {author:'Frank Herbert', bookName:'Dune'},
            {author:'Joe Albahari', bookName:'LINQ Pocket Reference'},
            {author:'Joseph Rattz', bookName:'Pro LINQ'},
            {author:'Charlie Calvert', bookName:'Essential LINQ'}
        ]</js>

With that, we just need to decode the jsonLiteral.Value into a dynamic object. A quick search of Stack Overflow finds a number of handy options for this task. For the sake of this example, I’m just going to use the System.Web.Helpers.Json library that’s part of MVC. We’ll create an extension method to take an XElement and convert it into a dynamic object using the Json.Decode method:

<Extension>
Public Module JsonExtensions
    <Extension>
    Public Function JsonDecode(input As XElement) As Object
        Return Json.Decode(input.Value)
    End Function
End Module

With this in place, we can now operate on the literal just as if it was any other dynamic object type. Here’s the full code for this example.

Option Strict Off

Imports System.Runtime.CompilerServices
Imports System.Web.Helpers

Public Class Test1

    Public Sub TestJsonLiteral()
        Dim jsonLiteral = <js>[
            {author:'Jim Wooley', bookName:'LINQ in Action'},
            {author:'Frank Herbert', bookName:'Dune'},
            {author:'Joe Albahari', bookName:'LINQ Pocket Reference'},
            {author:'Joseph Rattz', bookName:'Pro LINQ'},
            {author:'Charlie Calvert', bookName:'Essential LINQ'}
        ]</js>

        For Each book In jsonLiteral.JsonDecode()
            Console.WriteLine(book.author)
        Next
    End Sub
End Class

<Extension>
Public Module JsonExtensions
    <Extension>
    Public Function JsonDecode(input As XElement) As Object
        Return Json.Decode(input.Value)
    End Function
End Module

I’m sure that there are features that this technique doesn’t cover (including LINQ because Object isn’t directly convertible to IEnumerable). I’m also not sure if this really has any practical benefit. It just is interesting to consider.

Posted on - Comment
Categories: VB - VB Dev Center - Linq to XML -

Dynamic Programming in a Statically Typed World

Tomorrow night, I’m giving my presentation discussing not only how, but when to consider using the dynamic features of C# 4 and VB (forever). If you attend the presentation, you can download the samples and slides from my download page. Part of the key in this presentation is  discussing the Why as compared to the simpler How of Dynamic. Here are some of my top reasons to use the dynamic features:

Testability

When trying to use unit testing, the compiler often limits the ability to follow-through on the test first methodology because you have to write at least a bare implementation before your tests and solution can compile. If you declare your objects as dynamic in your tests, you can write all of your tests without having to write the implementation. Naturally, the tests will fail at this point, but with test driven development, your tests should fail until you have written your implementation.

One of the main things to understand if you are using dynamic types is that you no longer have your compiler acting as a unit-test, checking your code to make sure that the methods and types that you are trying to consume actually exist. Instead, you need to take extra care to fully unit test your code to ensure that it truly works the way you intend. Frankly, I don’t care what testing framework you use or how much code coverage you have, just do it!

COM Iterop

One of the traditional advantages VB has had over the C based languages is the late binding ability to work naturally with COM interfaces like those exposed in Office. Using dynamic in C# 4, gives the curly-bracket world to work with office with less ceremony. VB still has an edge in that it can retain intellisense support because of the late binding rather than “object with dynamic semantics” typing that C# utilizes.

Flexible data structures

There are times when building frameworks where you might not know the structure of your data at compile time. I’ve written before about how to use the dynamic features for parsing CSV files. The same technique can be used to parse XML files as well. If you’ve used DataSets in the past, this is another such framework which currently uses strings as parameters to access tables and fields as objects. With Microsoft.Data in the WebMatrix libraries, Microsoft introduced a dynamic implementation over datasets as well, simplifying the programming model there as well. David Fowler wrote a series of blog posts introducing Microsoft.Data last year.

Scripting and DLR

Often, applications need the ability to allow for end user customization without the need to re-compile the application. With the DLR integration, you can add these script extension points in your application so that users can write code in Python, Ruby or any other DLR supported language. As long as you add the hooks in your application, you can take advantage of the user’s scripted changes.

In addition, the web contains a plethora of python and ruby code components that you can include in your .Net application by interacting with them via the DLR. Taking advantage of mature and well tested modules is often better than trying to re-invent the wheel yourself. Don’t fall into the trap of the “Not invented here” syndrome.

Increased separation of concerns

By using dynamic connections between your types, you can have components interact without needing to share version compatible interfaces and contracts. As long as your modules follow established conventions, it can work nicely without relying on the ceremony required otherwise. I demonstrated a while back how to connect MVC 1 views with anonymous types using VB’s late binding. More recent versions of MVC use dynamic features by default to bind to views with C# as well.

Along similar lines, Robert McCarter demonstrated using DynamicObject in the ViewModel of a MVVM pattern to eliminate the need to delegate all of the property Set/Get pairs between the View and the Model.

Summary

I’m sure this is just the tip of the iceberg of areas to use dynamic features. Can you thinq of others? The nice thing about VB and C# is that you can scope the use of dynamic features to just those parts of the application that benefit from them. This way you get the best of both worlds: the performance, tooling, and compiler support of static languages and simplicity, no compilation, implicitly typed objects and methods of dynamic languages.

Ultimately, when I have to choose between the two, I return to the mantra from Erik Meijer, et. al.

Use “Static typing where possible, dynamic typing when needed.

Posted on - Comment
Categories: VB - Dynamic - C# -

Reactive Framework Subscribing to Observables

It’s been a while since I started the Reactive Framework series. In case you missed the earlier posts, here’s the links to what we’ve done so far:

At this point, we’ve created our observer and set up the the logic that handles our OnNext values. What we haven’t done yet is wired our LINQ based processing pipeline to the event source. To do this, we need to Subscribe the handler to the Observables. By default, we need to create a new class that implements IObserver. To keep this simple, let’s just output the values to the console for now:


Class ConsoleObserver(Of T)
    Implements IObserver(Of T)


    Public Sub OnCompleted() Implements System.IObserver(Of T).OnCompleted

    End Sub

    Public Sub OnError(ByVal [error] As System.Exception) Implements System.IObserver(Of T).OnError

    End Sub

    Public Sub OnNext(ByVal value As T) Implements System.IObserver(Of T).OnNext
        Console.WriteLine(value.ToString)
    End Sub
End Class

The IObserver interface has three methods: the method that is fired when the source is done (OnCompleted), the method that occurs when an exception occurs (OnError) and the method that is used when each new value is received (OnNext). In the case of this simple example, we only implement the OnNext method and output the value to the Console Window.

With this in place, we can tie this all together creating and starting our sensor, filtering and projecting from the values (using LINQ) and displaying the values (through the new ConsoleObserver):


Dim Sensor As New ObservableSensor
Sensor.Start()

Dim lowvalueSensors = From s In Sensor
                      Where s.SensorValue < 3
                      Select s.SensorValue

lowvalueSensors.Subscribe(New ConsoleObserver(Of Double))

Thankfully, consuming our Observable chain doesn’t require creating a new class. Observable.Subscribe offers an additional overload which, instead of taking an IObservable, we can use an Action Lambda. As a result, we can restate our example above as follows:


Dim Sensor As New ObservableSensor
Sensor.Start()

Dim lowvalueSensors = From s In Sensor
                      Where s.SensorValue < 3
                      Select s.SensorValue

lowvalueSensors.Subscribe(Sub(value) Console.WriteLine(value))

While this consuming code is slightly longer, the total net effect is significantly more maintainable code since we don’t need to declare a separate class to just output our results.

We now could have a fully functioning set of examples. Unfortunately or example at this point is extremely unresponsive because we are completely CPU bound constantly running all of the process on the current thread. Up next time, moving our logic to the background thread.

Posted on - Comment
Categories: Rx - VB - VB Dev Center -

Reactive Framework Getting your LINQ on

Last time in our exploration of the Reactive Framework, we built a random Observable event generator. Now that we have our data source, we can start working with it. In the past, we would have hooked up event handlers to the event delegate and imperatively interacted with the values passed in the sender and EventArgs. Of course, when we Thinq LINQ, we try to find simpler, more declarative models to represent our intent.

To start, we need to instantiate and start our event generator:


Private Sensor as New ObservableSensor
Sensor.StartSensor()

Now that we are generating Observables, we can process them using LINQ query comprehensions. For example, if we wanted to filter out only the sensors who's type is "4", we could use this LINQ:


Dim TypeSensors = From s In Sensor
                  Where s.SensorType = "4"
                  Select s

If we wanted to filter out only those sensor readings that are low (less than 3), and only return the sensor's value, we could include the filter (Where) and projection (Select). The following results in an IObservable(Of Double) rather than IObservable(Of SensorInfo) that we started with.


Dim lowValueSensors = From s In Sensor
                      Where s.SensorValue < 3
                      Select s.SensorValue

Of course, if you prefer the Lambda syntax over query comprehensions, you can use those interchangeably with rX just as you would with LINQ. The following query waits for the first case where the sensor value is high (over 17) and fires OnNext returning a boolean once the value is hit.


Dim AnySensor = Sensor.Any(Function(s) s.SensorValue > 17)

All's well in LINQ land with rX, right? Well kind of. Doing these simple projections and filters are straight forward. However, if we start trying to use sorting, grouping, and aggregations, we start running into additional challenges. With these query types, we can't start returning results until the entire set of events is known. Since we're working with a potentially infinite stream of events, we will need to figure out how to partition the results and work with those segments. That will be a task for a future post.

Posted on - Comment
Categories: Rx - VB Dev Center - VB -

Reactive Framework Building an IObservable Event Generator

In my last post, I mentioned a number of cases where you may want to use the Reactive Framework. For some upcoming presentations, I wanted to focus on a couple of these scenarios, particularly on how you can use the Reactive Framework (rX) to work with events from device sensors. You can often find these kind of sensors in a number of industries, including Robotics, automated manufacturing systems, Medical monitors, Telecom usage, and Live financial feeds. In order to demonstrate using rX in this environment, I needed to build a module that simulated generating a bunch of sample random events. Below is the module that I created. We’ll use this module in some of the future discussions of Reactive Framework.

We’re going to start with a small class that will contain the state of the individual sensor events. We’ll call this our SensorInfo class. It will hold values for the date and time that the event occurred, an indicator on the sensor’s type and the value that the sensor returns. We'll also override the ToString method to allow us to output the values easily.


Public Class SensorInfo
    Public Property TimeStamp As DateTime
    Public Property SensorType As String
    Public Property SensorValue As Double

    Public Overrides Function ToString() As String
        Return String.Format("Time: {0}  , Type: {1}  Value: {2}", TimeStamp, SensorType, SensorValue)
    End Function
End Class

Now that we have our instance class, we can create a class that will generate these sensor items randomly. (This class is not thread safe, nor is it truly random so don't use it in production applications. It is merely designed for demonstration purposes.)


Public Class ObservableSensor

    Private _running As Boolean

    Public Sub StartSensor()
        If Not _running Then
            _running = True
            Dim randomizer = New Random(Date.Now.Millisecond)
            While _running
                Dim randVal = randomizer.NextDouble
                Dim info As New SensorInfo With {.SensorType = CInt(randVal * 4).ToString(),
                                                 .SensorValue = randVal * 20,
                                                 .TimeStamp = Now}
                End If
                Threading.Thread.Sleep(CInt(randomizer.NextDouble * 500))
            End While
        End If
    End Sub

    Public Sub StopSensor()
        _running = False
    End Sub

End Class

In this class, we maintain an internal variable (_running) which tracks whether the sensor is running or not. We also have a method that Starts the sensor and stops it. While the sensor is running, we essentially generate a number of SensorInfo instances with randomized values and then pause for a random period of time before creating another value. At this point, the values that are returned don’t have much meaning. We could easily change this to return stock quotes, manufacturing defects or other sensor responses by manipulating the values this randomizer generates.

Now that we can generate random SensorInfos, we need to actually do something with them. In the past, we could just raise an event for consumers to handle after we generate each sensor’s value. Since we want to leverage the power of the new IObservable/IObserver interfaces and the Reactive Framework, I’ll make this class implement IObservable(Of T) so that we can register a number of IObserver clients and notify them each time we generate a new sensor.

The IObservable(Of T) interface requires of a single method: Subscribe. This takes a single parameter which is the IObserver client that wants to listen to our sensor data. It returns a class that implements IDisposable (so that we can make sure each of our observers know when we’re done sending them data). Since the return object here is actually the ObservableSensor itself, we need to implement both IObservable and IDisposable. Here's our revised ObservableSensor class.


Public Class ObservableSensor
    Implements IObservable(Of SensorInfo)
    Implements IDisposable

    Private _observers As New List(Of IObserver(Of SensorInfo))
    Private _running As Boolean

    Public Function Subscribe(ByVal observer As System.IObserver(Of SensorInfo)) 
                              As System.IDisposable 
                              Implements System.IObservable(Of SensorInfo).Subscribe
        _observers.Add(observer)
        Return Me
    End Function

    Public Sub StartSensor()
        If Not _running Then
            _running = True
            Dim randomizer = New Random(Date.Now.Millisecond)
            While _running
                Dim randVal = randomizer.NextDouble
                If _observers.Any Then
                    Dim info As New SensorInfo With {.SensorType = CInt(randVal * 4).ToString,
                                                     .SensorValue = randVal * 20,
                                                     .TimeStamp = Now}

                    _observers.ForEach(Sub(o) o.OnNext(info))
                End If
                Threading.Thread.Sleep(CInt(randomizer.NextDouble * 500))
            End While
        End If
    End Sub

    Public Sub StopSensor()
        _running = False
    End Sub


#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                If _observers IsNot Nothing Then
                    _observers.ForEach(Sub(o) o.OnCompleted())
                    _observers.Clear()
                End If
                ' TODO: dispose managed state (managed objects).
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

In this new version, we now have a new _observers object that maintains a list of the observers (clients). This allows us to notify multiple sensor handlers and work with them how they deem appropriate. The subscribe method simply takes the supplied observer and sticks it in the collection.

When we start the sensor, we now check to see if there are any observers (using the LINQ .Any method). If we do, we’ll generate the random sensor data. We then notify all of the listeners using the list .ForEach method passing the lambda expression instructing the observer to invoke it’s OnNext handler (part of the IObserver(Of T) implementation. This is the method which corresponds to IEnumerable’s MoveNext. It is this method which will trigger our reactive framework’s event pipeline to begin processing our sensor notifications.

When we’re done, we need to clean up our resouces. In the Disposing event, we make sure that we call the OnCompleted method on each (ForEach) of the observers in our _observers collection. We also clear the observer collection to remove the reference pointers between the client and our sensor generator.

There you have it, a generic random event generator that we can consume with the Reactive Framework (or similar technologies like StreamInsight). Next time, we’ll start to consume these events.

As always, let me know what you Thinq and if there are any modifications I should consider.

Posted on - Comment
Categories: Rx - VB - VB Dev Center - Visual Studio -

Visual Studio 2010 Keyboard Binding Poster

When I work with new teams, I often get asked how I did x using the keyboard instead of reaching for the mouse. I find if I can keep my hands on the keyboard, I can often be much more productive. So, how do you learn to take advantage of the keyboard shortcuts, I recommend downloading one of the Key binding posters like the ones that were just released for Visual Studio 2010. The posters are available for VB.Net, C#, F#, and C++.

Once you have then downloaded, pick a  a different key binding each day and dedicate yourself to using that one throughout the day. You’ll find some bindings work better for you than others. Each person has their favorite way of working, so try them all and see which are your favorites. So, what are you waiting for? Download them and get coding!

Posted on - Comment
Categories: Visual Studio - C# - VB -

Replace Foreach with LINQ

One of the best ways to start Thinqing in LINQ is to find places where you can replace iterative loops with LINQ queries. This won’t necessarily make your applications any faster at the moment, but by taking advantage of the declarative syntax, it will allow you to change your underlying implementation (ie. parallelize it with PLINQ) easier in the future. Recently, I came across some code that mimicked creating a control array as we used to have in VB6 by iterating over a list of fields and adding controls to a form adding the index to the end of the field name. As the fields are being added,we hook up event listeners along the way. Here’s the old code:


Dim Fields() As String = {"a", "one", "and", "a", "two"}

Dim index As Integer

For Each item As String In Fields
    Dim box As New TextBox
    With box
        .Name = item + index.ToString
        .Top = index * 30
        .Height = 24
        AddHandler .TextChanged, AddressOf OnValueChanged
    End With
    Controls.Add(box)
    index += 1
Next
To break this down, we're creating an index so that we won't have any repeats. We then iterate over our list of fields and create (Project) new textboxes for each of the items in our list. Once we create that value, we then add the handler. Finally we add this item to another list. If we think about this in a set based manner rather than iterative, we can start getting a grasp of what LINQ really has to offer. Let's rewrite this in LINQ starting with our source:

Dim Fields() As String = {"a", "one", "and", "a", "two"}
Dim b1 = From item In Fields
         Select New TextBox With
         {
             .Name = item,
             .Top = 30,
             .Height = 24
         }

Controls.AddRange(boxes)

In this example, we take our starting list. Project (Select) new objects from these values and then pass this list directly into the Controls collection using AddRange. No more For Each.

This is a start, but there's an issue. We need to be able to add the index to this set based operation. One of the little secrets in the LINQ operators is that there are overloads which expose the index. In VB, you can't access these using the LINQ query comprehensions. You have to use the extension methods and Lambda Functions directly as follows:


Dim Fields() As String = {"a", "one", "and", "a", "two"}
Dim boxes = Fields _
            .Select(Function(item, index) _
                New TextBox With {
                    .Name = item + index.ToString(),
                    .Top = index * 30,
                    .Height = 24})

Controls.AddRange(boxes.OfType(Of Control).ToArray)

We're almost there. We just need to add our handlers for each of our new text boxes. While we could call ForEach over an array, it would cause us to iterate over our field list twice (creating two sets of text boxes). We need a way to only iterate over it once. Here, we need to create a new method and using C# iterators. It will take an IEnumerable and return an IEnumerable. By using Yield, it will not cause the enumeration to happen multiple times, but rather to add a new step as each value is being pulled through the enumeration pipeline.


public static class Extensions
    {
       public static IEnumerable<T> WhileEnumerating<T>(this IEnumerable<T> source, Action<T> action)
       {
           foreach (T item in source)
           {
               action(item);
               yield return item;
           }
       }
    }

Now, we can inject methods into the pipeline as follows:


Dim boxes = Fields _
            .Select(Function(item, index) _
                New TextBox With {
                    .Name = item + index.ToString(),
                    .Top = index * 30,
                    .Height = 24}) _
            .WhileEnumerating(Sub(item) AddHandler item.TextChanged, AddressOf OnValueChanged)

Controls.AddRange(boxes.OfType(Of Control).ToArray)

If we wanted to inject more functions, we would just add more .WhileEnumerating methods. Make sure however that each of these methods do not have side effects on other methods of the set. There you have it. Go search for those For Each (foreach) loops in your code and see how you can clean them up with LINQ to Objects.

Posted on - Comment
Categories: C# - LINQ - VB - Visual Studio -

LINQ to CSV using DynamicObject and TextFieldParser

In the first post of this series, we parsed our CSV file by simply splitting each line on a comma. While this works for simple files, it becomes problematic when consuming CSV files where individual fields also contains commas. Consider the following sample input:

CustomerID,COMPANYNAME,Contact Name,CONTACT_TITLE
ALFKI,Alfreds Futterkiste,Maria Anders,"Sales Representative"
ANATR,Ana Trujillo Emparedados y helados,Ana Trujillo,"Owner, Operator"
ANTON,Antonio Moreno Taqueria,Antonio Moreno,"Owner"

Typically when a field in a CSV file includes a comma, the field is quote escaped to designate that the comma is part of the field and not a delimiter. In the previous versions of this parser, we didn’t handle these cases. As a result the following unit test would fail given this sample data:


    <TestMethod()>
    Public Sub TestCommaEscaping()
        Dim data = New DynamicCsvEnumerator("C:\temp\Customers.csv")
        Dim query = From c In data
                    Where c.ContactTitle.Contains(",")
                    Select c.ContactTitle

        Assert.AreEqual(1, query.Count)
        Assert.AreEqual("Owner, Operator", query.First)
    End Sub

We could add code to handle the various escaping scenarios here. However, as Jonathan pointed out in his comment to my first post there are already methods that can do CSV parsing in the .Net framework. One of the most flexible ones is the TextFieldParser in the Microsoft.VisualBasic.FileIO namespace. If you code in C# instead of VB, you can simply add a reference to this namespace and access the power from your language of choice.

Retrofiting our existing implementation to use the TextFieldParser is fairly simple. We begin by changing the _FileStream object to being a TextFieldParser rather than a FileStream. We keep this as a class level field in order to stream through our data as we iterate over the rows.

In the GetEnumerator we then instantiate our TextFieldParser and set the delimiter information. Once that is configured, we get the array of header field names by calling the ReadFields method.


    Public Function GetEnumerator() As IEnumerator(Of Object) _
        Implements IEnumerable(Of Object).GetEnumerator

        _FileStream = New Microsoft.VisualBasic.FileIO.TextFieldParser(_filename)
        _FileStream.Delimiters = {","}
        _FileStream.HasFieldsEnclosedInQuotes = True
        _FileStream.TextFieldType = FileIO.FieldType.Delimited

        Dim fields = _FileStream.ReadFields
        _FieldNames = New Dictionary(Of String, Integer)
        For i = 0 To fields.Length - 1
            _FieldNames.Add(GetSafeFieldName(fields(i)), i)
        Next
        _CurrentRow = New DynamicCsv(_FileStream.ReadFields, _FieldNames)

        Return Me
    End Function

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        Dim line = _FileStream.ReadFields
        If line IsNot Nothing AndAlso line.Length > 0 Then
            _CurrentRow = New DynamicCsv(line, _FieldNames)
            Return True
        Else
            Return False
        End If
    End Function

While we are at it, we also change our MoveNext method to call ReadFields to get the parsed string array of the parsed values in the next line. If this is the last line, the array is empty and we return false in the MoveNext to stop the enumeration. We had to make one other change here because in the old version, we passed the full unparsed line in the constructor of the DynamicCsv type and did the parsing there. Since our TextFieldParser will handle that for use, we’ll add an overloaded constructor to our DynamicCsv DynamicObject accepting the pre parsed string array:


Public Class DynamicCsv
    Inherits DynamicObject

    Private _fieldIndex As Dictionary(Of String, Integer)
    Private _RowValues() As String

    Friend Sub New(ByVal values As String(),
                   ByVal fieldIndex As Dictionary(Of String, Integer))
        _RowValues = values
        _fieldIndex = fieldIndex
    End Sub

With these changes, now we can run our starting unit test including the comma in the Contact Title of the second record and it now passes.

If you like this solution, feel free to download the completed Dynamic CSV Enumerator library and kick the tires a bit. There is no warrantee expressed or implied, but please let me know if you find it helpful and any changes you would recommend.

Posted on - Comment
Categories: Dynamic - LINQ - VB - VB Dev Center - Visual Studio -

LINQ to CSV using DynamicObject

When we wrote LINQ in Action we included a sample of how to simply query against a CSV file using the following LINQ query:


From line In File.ReadAllLines(“books.csv”) 
Where Not Line.StartsWith(“#”) 
Let parts = line.Split(“,”c) 
Select Isbn = parts(0), Title = parts(1), Publisher = parts(3)

While this code does make dealing with CSV easier, it would be nicer if we could refer to our columns as if they were properties where the property name came from the header row in the CSV file, perhaps using syntax like the following:


From line In MyCsvFile
Select line.Isbn, line.Title, line.Publisher

With strongly typed (compile time) structures, it is challenging to do this when dealing with variable data structures like CSV files. One of the big enhancements that is coming with .Net 4.0 is the inclusion of Dynamic language features, including the new DynamicObject data type. In the past, working with dynamic runtime structures, we were limited to using reflection tricks to access properties that didn't actually exist. The addition of dynamic language constructs offers better ways of dispatching the call request over dynamic types. Let's see what we need to do to expose a CSV row using the new dynamic features in Visual Studio 2010.

First, let's create an object that will represent each row that we are reading. This class will inherit from the new System.Dynamic.DynamicObject base class. This will set up the base functionality to handle the dynamic dispatching for us. All we need to do is add implementation to tell the object how to fetch values based on a supplied field name. We'll implement this by taking a string representing the current row. We'll split that based on the separator (a comma). We also supply a dictionary containing the field names and their index. Given these two pieces of information, we can override the TryGetMember and TrySetMember to Get and Set the property based on the field name:


Imports System.Dynamic

Public Class DynamicCsv
    Inherits DynamicObject

    Private _fieldIndex As Dictionary(Of String, Integer)
    Private _RowValues() As String

    Friend Sub New(ByVal currentRow As String,
                   ByVal fieldIndex As Dictionary(Of String, Integer))
        _RowValues = currentRow.Split(","c)
        _fieldIndex = fieldIndex
    End Sub

    Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
                                           ByRef result As Object) As Boolean
        If _fieldIndex.ContainsKey(binder.Name) Then
            result = _RowValues(_fieldIndex(binder.Name))
            Return True
        End If
        Return False
    End Function

    Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder,
                                           ByVal value As Object) As Boolean
        If _fieldIndex.ContainsKey(binder.Name) Then
            _RowValues(_fieldIndex(binder.Name)) = value.ToString
            Return True
        End If
        Return False
    End Function
End Class

With this in place, now we just need to add a class to handle iterating over the individual rows in our CSV file. As we pointed out in our book, using File.ReadAllLines can be a significant performance bottleneck for large files. Instead we will implement a custom Enumerator. In our customer enumerable, we initialize the process with the GetEnumerator method. This method opens the stream based on the supplied filename. It also sets up our dictionary of field names based on the values in the first row. Because we keep the stream open through the lifetime of this class, we implement IDisposable to clean up the stream.

As we iterate over the results calling MoveNext, we will read each subsequent row and create a DynamicCsv instance object. We return this row as an Object (Dynamic in C#) so that we will be able to consume it as a dynamic type in .Net 4.0. Here's the implementation:


Imports System.Collections

Public Class DynamicCsvEnumerator
    Implements IEnumerator(Of Object)
    Implements IEnumerable(Of Object)

    Private _FileStream As IO.TextReader
    Private _FieldNames As Dictionary(Of String, Integer)
    Private _CurrentRow As DynamicCsv
    Private _filename As String

    Public Sub New(ByVal fileName As String)
        _filename = fileName
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of Object) _
        Implements IEnumerable(Of Object).GetEnumerator

        _FileStream = New IO.StreamReader(_filename)
        Dim headerRow = _FileStream.ReadLine
        Dim fields = headerRow.Split(","c)
        _FieldNames = New Dictionary(Of String, Integer)
        For i = 0 To fields.Length - 1
            _FieldNames.Add(GetSafeFieldName(fields(i)), i)
        Next
       
        Return Me
    End Function

    Function GetSafeFieldName(ByVal input As String) As String
        Return input.Replace(" ", "_")
    End Function

    Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function

    Public ReadOnly Property Current As Object Implements IEnumerator(Of Object).Current
        Get
            Return _CurrentRow
        End Get
    End Property

    Public ReadOnly Property Current1 As Object Implements IEnumerator.Current
        Get
            Return Current
        End Get
    End Property

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        Dim line = _FileStream.ReadLine
        If line IsNot Nothing AndAlso line.Length > 0 Then
            _CurrentRow = New DynamicCsv(line, _FieldNames)
            Return True
        Else
            Return False
        End If
    End Function

    Public Sub Reset() Implements IEnumerator.Reset
        _FileStream.Close()
        GetEnumerator()
    End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                _FileStream.Dispose()
            End If
            _CurrentRow = Nothing
        End If
        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

Now that we have our custom enumerable, we can consume it using standard dot notation by turning Option Strict Off in Visual Basic or referencing it as a Dynamic type in C#:

VB:



Public Sub OpenCsv()
    Dim data = New DynamicCsvEnumerator("C:\temp\Customers.csv")
    For Each item In data
        TestContext.WriteLine(item.CompanyName & ": " & item.Contact_Name)
    Next

End Sub

C#:


[TestMethod]
public void OpenCsvSharp()
{
    var data = new DynamicCsvEnumerator(@"C:\temp\customers.csv");
    foreach (dynamic item in data)
    {
        TestContext.WriteLine(item.CompanyName + ": " + item.Contact_Name);
    }
}

In addition, since we are exposing this as an IEnumerable, we can use all of the same LINQ operators over our custom class:

VB:


Dim query = From c In data
            Where c.City = "London"
            Order By c.CompanyName
            Select c.Contact_Name, c.CompanyName

For Each item In query
    TestContext.WriteLine(item.CompanyName & ": " & item.Contact_Name)
Next

C#:


[TestMethod]
public void LinqCsvSharp()
{
    var data = new DynamicCsvEnumerator(@"C:\temp\customers.csv");
    var query = from dynamic c in data 
                where c.City == "London"
                orderby c.CompanyName
                select new { c.Contact_Name, c.CompanyName };

    foreach (var item in query)
    {
        TestContext.WriteLine(item.CompanyName + ": " + item.Contact_Name);
    }
}

Note: This sample makes a couple assumptions about the underlying data and implementation. First, we take an extra step to translate header strings that contain spaces to replace the space with an underscore. While including spaces is legal in the csv header, it isn't legal in VB to say: " MyObject.Some Property With Spaces". Thus we'll manage this by requiring the code to access this property as follows: "MyObject.Some_Property_With_Spaces".

Second, this implementation doesn't handle strings that contain commas. Typically fields in CSV files that contain commas are wrapped by quotes (subsequently quotes are likewise escaped by double quotes). This implementation does not account for either situation. I purposely did not incorporate those details in order to focus on the use of DynamicObject in this sample. I welcome enhancement suggestions to make this more robust.

Posted on - Comment
Categories: LINQ - VB Dev Center - VB - C# - Dynamic -

Setting DataContext Connection String in Data Tier

LINQ to SQL offers a quick mechanism to build a data tier in a n-Tier application. There’s a challenge when using the DBML designer in a Class Library. The designer stores the connection string in the Settings file. Although it appears that you can change it in the config file, any changes you make there will be ignored because they are actually retained in the generated Settings file.

While you could go into the DataContext’s .Designer file and change the location of the connection string, any changes you make there will be overwritten if you make changes to the DBML file. So what are you to do?

Remember, one of the nice features added to VB 9 and C# 3 was partial properties. With the DataContext, the code generators add a OnCreated method that is called as part of the context’s constructors. As a result, we can implement the partial method in a separate partial DataContext class that is not changed when the DBML is regenerated. Here’s a sample to do that for the context on this site (LinqBlogDataContext):


Imports System.Configuration

Public Class LinqBlogDataContext
  Private Sub OnCreated()
    MyBase.Connection.ConnectionString = _
      ConfigurationManager.ConnectionStrings("LinqBlogConnectionString") _
         .ConnectionString
    End Sub
End Class

When you do this, you can change the connection string in the app.config or web.config and it will be picked up in the business tier correctly. Realize that the design surface will still use the value in the settings in& the Class Library project instead of the config file.

Posted on - Comment
Categories: LINQ - VB Dev Center - VB -

Using Cast Or OfType Methods

When working with generic lists, often you want to work with a more specific type than the list natively exposes. Consider the following where Lions, Tigers and Bears derive from Circus Animal:


  Dim items As New List(Of Object)
  items.Add(New Lion)
  items.Add(New Tiger)
  items.Add(New Bear)
  
  Dim res1 = items.Cast(Of CircusAnimal)() 
  Dim res2 = items.OfType(Of CircusAnimal)()

In this case, both res1 and res2 will return an enumerable of CircusAnimal objects rather than just returning Object types. However what would happen if you added something that wasn’t a CircusAnimal (an operation perfectly legal for the items list since it will take any Object:


  Dim items As New List(Of Object)
  items.Add(New Lion)
  items.Add(New Tiger)
  items.Add(New Bear)
  items.Add(“Elephant”)

  Dim res1 = items.Cast(Of CircusAnimal)() 
  Dim res2 = items.OfType(Of CircusAnimal)()

In this case, evaluating res1 would give an InvalidCastException when evaluating the newly added Elephant (string). The OfType method would return only the Lion, Tiger, and Bear objects casting them to CircusAnimal and skips the “Elephant”. What’s going on here? Under the covers, Cast performs a DirectCast operation as we iterate over each result. OfType performs an extra operation to see if the source object is of the correct type before trying to cast it. If the type doesn’t match, we skip that value. If code helps to visualize the difference, here’s an approximation of what’s happening under the covers (don’t bother to use Reflector here as it doesn’t know how to simplify the yield operation):


public static IEnumerable<T> Cast<T>(this IEnumerable source) {
  foreach (object obj in source)
    yield return (T)obj;

public static IEnumerable<T> OfType<T>(this IEnumerable source) {
  foreach (object obj in source) {
    if (obj is T) 
      yield return (T)obj;
   }
}

Note that the main difference here is the added check to see if the source object can be converted to the target type before trying to cast it. So which should you use and when? If you know that the objects you are working with are all the correct target type, you can use Cast. For example if you wanted to work with the CheckedListItem values in a CheckedListBox’s SelectedItems collection (which returns Object), you can be sure that all values returned are CheckedListItem instances.


Dim Query = From item in Me.Options.Items.Cast(Of LIstItem) _
            Where item.Selected _
            Select item.Value

If you want to work with diverse object types and only return a subset, OfType is a better option. For example, to disable all buttons on a form (but not the other controls), we could do something like this:


For Each button In Me.Controls.OfType(Of Button)
   button.Enabled = False
Next

If you want to be safe, you can always use OfType. Realize that it will be slightly slower and may ignore errors that you may want to actually know about otherwise.

Posted on - Comment
Categories: VB - C# - LINQ -

Watch language differences when parsing Expression Trees

I’ve run into a number of cases where people have built LINQ providers and only tested them with C# clients. In one case, I was sitting next to the person who wrote the provider when we discovered that using a VB client didn’t work with their provider because they failed to test it.

I’ve even seen it in the sample Entity Framework provider  available on the MSDN Code Gallery when parsing the .Include() method. Hopefully, you will be able to access my VB translation of the EF sample provider once it finishes going through the legal hoops.

So, why are these providers failing when run against a different language? Much of LINQ is based around language syntactic sugar. The various compiler teams added different optimizations when translating your LINQ code into real framework code. (Update: the VB Team explained the difference in a blog post from 2 years ago.) Let’s take a look at a simple case which tripped up at least two providers I tested recently. The query in question is perhaps the most common query when looking at LINQ samples:


From c In Customers _
Where c.City = "London" _
Select c

This seems to be a very straight forward example. Let’s take a look at what the compiler translates is query into.

C#:


Customers.Where (c => (c.City == "London"))

VB:


Customers.Where (Function(c) => (Operators.CompareString (c.City, "London", False) == 0))
         .Select ((Function(c) => c)

Notice here that the C# code does a literal translation into an equality operator. However, the VB team uses what turns out to be a slightly faster CompareString operator implementation. This doesn’t seem like too much of an issue until you consider the differences that this causes in the Expression tree that you need to parse in your provider. Using the Expression Tree Visualizer, you can see how much of a difference these two expressions cause under the covers. In this case, the C# version is on the left and VB is on the right.

image

Notice that both versions start with the same constant expression and the right expression constant of the Binary Expression is the same in both cases. However, the remainder of the expression is different between the two source examples.

The moral of the story: If creating a framework or API which will be consumed by multiple languages, make sure to include tests in each of those languages.

Posted on - Comment
Categories: C# - VB - LINQ -

Generating Interfaces for LINQ to SQL Entities

At DevLink I had the pleasure of presenting a session on LINQ to SQL Tricks and Tips. The slides and demos for LINQ to SQL Tricks and Tips are available on my download page if you are interested. Following the session, an attendee voiced the desire for LINQ to SQL to create interfaces while it creates the class definitions in order to make it easier to mock the entities in unit testing scenarios.

As part of the presentation, I showed Damien Guard’s L2ST4 code generation template. The great thing about these templates is that they are fully customizable.  If you’ve been following this blog, you may remember my post showing adding property Get logging to LINQ to SQL with T4. In this post, I’m going to show you how to add the ability to generate and implement interfaces for the table’s columns. I’m only going to show implementing the table’s columns and not the associations. Additionally, you will need to modify this if you use inheritance in your LINQ to SQL models. I’m using the VB Template in this example, but the C# changes are very similar. Hopefully, you will see how easy it is to make these kinds of changes and can add these extensions yourself if necessary.

Ok, so let’s get started. First off, we will set up a flag in the options so that we can toggle creating the interfaces in our code generation. At the top of the file, change the declaration of the options anonymous type adding the CreateInterfaces = true as follows:

var options = new {
	DbmlFileName = Host.TemplateFile.Replace(".tt",".dbml"), // Which DBML file to operate on (same filename as template)
	SerializeDataContractSP1 = false, // Emit SP1 DataContract serializer attributes
	FilePerEntity = false, // Put each class into a separate file
	StoredProcedureConcurrency = false, // Table updates via an SP require @@rowcount to be returned to enable concurrency	
	EntityFilePath = Path.GetDirectoryName(Host.TemplateFile), // Where to put the files	
	CreateInterfaces = true // Add interfaces for each table type
};

Next, we define the interfaces. To make things easier, we’ll just declare the interface for each table just before we define the table itself. This will keep the interfaces in the same namespace and the same file as the tables (if you use the FilePerEntity option). The biggest trick is to figure out where to insert this code.  Search for the following text in the existing template: “if (data.Serialization && class1.IsSerializable) {“. Change the template between the Namespace declaration and the serialization settings as follows:

Namespace <#=data.EntityNamespace#>	

<#		}
#>		

<#
if (options.CreateInterfaces) { #>
	'Interface
	<#=code.Format(class1.TypeAttributes)#>Interface I<#=class1.Name#>
	<#			foreach(Column column in class1.Columns) {#>
	<# if (column.IsReadOnly) {#>ReadOnly <#}#>Property <#=column.Member#> As <#=code.Format(column.Type)#>
	<# } 
	#>
	End Interface
<# } 
#>
<#		if (data.Serialization && class1.IsSerializable) {

Here we create an interface named IClass where Class is the actual name of the class we are going to generate.  Once we have the interface created, we iterate over each of the columns defining the properties that correspond to the table’s columns.

Next, we need to alter the Class definition to have it implement our new interface. Scrolling down about 15 lines, find the line where we declare that the class implements the INotifyPropertyChanging and INotifyPropetyChanged interfaces. Change this line to read as follows:

	Implements INotifyPropertyChanging, INotifyPropertyChanged<#
if (options.CreateInterfaces) {#>, I<#=class1.Name#><#}#>

If we were using C#, our job would be done. However, VB requires that interfaces be implemented explicitly.  Since we are generating this code, making this last change is relatively easy as well. Scroll down to the definition of the property getter and setter (in my copy, this is line 334). Change the property definition to read as follows:

#>		<#=code.Format(column.MemberAttributes)#><# if (column.IsReadOnly) {#>ReadOnly <#}#>Property <#=column.Member#> As <#=code.Format(column.Type)#><# 
			if (options.CreateInterfaces) {#> Implements I<#=class1.Name#>.<#=column.Member#><#}#>

			Get

Ok. We’re done. All we need to do is save our changes to the TT file and it will regenerate the classes from our DBML assuming you have already set your project up to use the TT files rather than the default LINQ to SQL generator.

Posted on - Comment
Categories: VB - LINQ - VB Dev Center -

MVC Sitemap Navigation with XML Literals

As I continue re-writing this site to use MVC, I find more substructures that I can refactor easily. In the original implementation for the menu, I used the asp:Menu control. As I was working to theme the site, I had problems getting it to work acceptably with CSS styles. I also didn't like the reliance on tables.

In an effort to improve on it, I found the method of using unordered lists with list items for the menus (<ul> <li>). I then moved to a modified version of the UL SiteMap menu discussed by Byant Likes.

In moving to MVC, I was looking for a better option and found one on the MVC tutorial site. This builds the menu with a StringBuilder. I had a couple problems with this implementation however:

  • By using a StringBuilder, you don't get compiler assistance in validating the markup.
  • The implementation doesn't handle security trimming.
  • It only handles a single level of menu items.
  • For Each loops seem to be an anti-pattern for me with my LINQ experience.

To fix these issues, I figured we could re-write this relatively easily using XML Literals and VB with a recursive call to handle the potential n-levels of SiteMenuItems possible in the SiteMap XML specification. Even without adding any of the additional functionality, we can drastically simplify the implementation in the MVC Tutorial by re-writing it in XML Literals in VB:


Dim xMenu1 = <div class="menu">
                <ul id="menu">
                   <%= From node In SiteMap.RootNode.ChildNodes _
                                    .OfType(Of SiteMapNode)() _
                       Select <li class=<%= if(SiteMap.CurrentNode Is node, _
                                               "active", _
                                               "inactive") %>>
                                 <a href=<%= % node.Url>>
                                    <%= helper.Encode(node.Title) %></a>
                     </li> %>
                 </ul>
              </div>
Return xMenu1.ToString()

There are a couple things to point out here. First, the SiteMap.RootNode.ChildNode property returns a list of Object rather than SiteMapNode items. We can fix that by purposely limiting the results and strongly typing it at the same type using the .OfType(Of T) extension method.

Second, We eliminate the for each loop by projecting the new li items in the select clause. In this, we use the ternary If to determine if the node in the iteration is the same as the one selected. If it is, we apply the "active" style. The rest is relatively straight forward.

At this point, we have fixed issues 1 and 4 from my objection list above. Next, let's deal with the n=levels of menu items. To do this, we will replace the LINQ query with a recursive function call. The Menu helper extension now looks like the following:


Imports System.Runtime.CompilerServices

Namespace Helpers
    Public Module MenuHelper
        <Extension()> _
        Public Function Menu(ByVal helper As HtmlHelper) As String
            Dim xMenu = <div class="menu">
                            <ul id="menu">
                                <%= AddNodes(SiteMap.RootNode, helper) %>
                            </ul>
                        </div>
    
            Return xMenu.ToString()
        End Function
    End Module
End Namespace

Now we have an extremely clean and concise XML building of the basic structure. The hard work comes in the AddNodes method.


Private Function AddNodes(ByVal currentNode As SiteMapNode, ByVal helper As HtmlHelper) _
                 As IEnumerable(Of XElement)

   Return From node In currentNode.ChildNodes.OfType(Of SiteMapNode)() _
          Select <li class=<%= If(SiteMap.CurrentNode Is node, "active", "inactive") %>>
                     <a href=<%= node.Url %>><%= helper.Encode(node.Title) %></a>
                     <%= If(node.ChildNodes.Count > 0, _
                          <ul class="child">
                              <%= AddNodes(node, helper) %>
                          </ul>, Nothing) %>
                  </li>
End Function

Essentially this function moves the LINQ projection we did in the original re-write into a separate method. This method takes a SiteMapNode and returns rendered lists of XElements. In addition to generating the HTML for the current node's children, we also check to see if the respective child in turn has  are any child nodes and if so, we create a new unordered list and recursively call back into AddNodes to render those children as well. By using a recursive function, we can handle any level of children nodes that the SiteMap throws at us.

In order to add security trimming, we simply need to add a where clause. The SiteMap contains a non-generic IList that happens to contain strings. To use LINQ on this, we use the .Cast method to turn it into a generic IEnumerable(Of String). With that in place, we can use the .Any extension method to find if any of the roles specified in the SiteMap source meet the criteria where the HttpContext's current user is in at least one of those roles. We'll also check to see if there are no roles specified for that node (which means that it is not trimmed and all users can access the node). Here is the revised body of the AddNodes method:


Return From node In currentNode.ChildNodes.OfType(Of SiteMapNode)() _
       Where node.Roles.Count = 0 OrElse _
             node.Roles.Cast(Of String).Any(Function(role) _
                                            HttpContext.Current.User.IsInRole(role)) _
       Select <li class=<%= If(SiteMap.CurrentNode Is node, "active", "inactive") %>>
                  <a href=<%= node.Url %>><%= helper.Encode(node.Title) %></a>
                  <%= If(node.ChildNodes.Count > 0, _
                      <ul class="child">
                          <%= AddNodes(node, helper) %>
                      </ul>, Nothing) %>
              </li>

That's it. The only thing left is to manage the css styles to handle the fly-outs. You should be able to find plenty of sites that demonstrate how to set that up. If you can thinq of any enhancements to this, let me know.

Posted on - Comment
Categories: MVC - VB Dev Center - VB -

Binding Anonymous Types in MVC Views

While translating this site over to MVC, I ran into a challenge when converting the RSS feed implementation. Currently I'm using XML Literals to generate the RSS and I could certainly continue to use that track from the Controller similar to the Sitemap implementation on Mikesdotnetting. However, putting the XML generation in the controller directly conflicts with the separation of concerns that MVC embraces. If I were only displaying one RSS feed, I might be willing to break this here. However, I'm rendering a number of different RSS feeds here: Posts, Posts by Category, and Files.

Since it would be good to have a reusable view, I decided to create a single view which various controllers can use. I was dynamically generating the XML in the past so my queries would now need to project into a type that the view can consume. Here we have several alternatives:

  1. Create a strongly typed object structure which is strictly used to shape our results for the shared Rss view.
  2. Project into a list of System.ServiceModel.SyndicationItem and then bind to that.
  3. Project into an anonymous type and figure out a way to bind to that projection in our view.

I initially thought I would go down the second route similar to the implementation discussed on the DeveloperZen post. However, I wanted to support some of the RSS extensions including comments and enclosures that aren't directly supported in that implementation.

At first I was unsure how to bind an anonymous projection in a View, so I eliminated option 3 and implemented option 1 similar to the strongly typed implementation discussed on Mikesdotnetting blog. To do this, I needed to build the following set of strongly typed structures:


Public Structure RssElement
    Public Title As String
    Public Link As String
    Public PubDate As DateTime
    Public PermaLink As String
    Public TrackBackUrl As String
    Public CommentRss As String
    Public CommentUrl As String
    Public CommentCount As Integer
    Public Description As String
    Public Categories() As Category
    Public Enclosures() As Enclosure
End Structure

Public Structure Category
    Public Url As String
    Public Title As String
End Structure

Public Structure Enclosure
    Public Url As String
    Public Length As Integer
    Public Type As String
End Structure

If I were using VB 10, this would have been done with auto-implemented properties. However I went with structures at this point because I didn't want to type that much for something that was going to be view only anyway.

With this structure in place, I could go ahead and implement the controller and view. The controller simply projected into this new object structure in the Select clause of a LINQ query. The view then was able to consume this as we could strongly type the view as a ModelView(Of IEnumerable(Of RssElement)). Here's the view that I created:

<%@ Page Language="VB" ContentType="application/rss+xml"
Inherits="System.Web.Mvc.ViewPage(Of IEnumerable(Of RssElement))" %> <rss version='2.0' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:slash='http://purl.org/rss/1.0/modules/slash/' xmlns:wfw='http://wellformedweb.org/CommentAPI/' xmlns:trackback='http://madskills.com/public/xml/rss/module/trackback'> <channel> <title>Thinq Linq</title> <link><%=Url.Action("Post") %></link> <description>LINQ and related topics.</description> <dc:language>en-US</dc:language> <generator>LINQ</generator> <% For Each item In Model%> <item> <title><%=item.Title%></title> <link><%=item.Link%></link> <pubDate><%=item.PubDate%></pubDate> <guid isPermaLink="false"><%= item.PermaLink %></guid> <dc:creator>jwooley</dc:creator> <slash:comments><%=item.CommentCount%></slash:comments> <trackback:ping><%=item.TrackBackUrl%></trackback:ping> <comments><%=item.CommentUrl%></comments> <wfw:commentRss><%=item.CommentRss%></wfw:commentRss> <wfw:comment><%=item.CommentUrl%></wfw:comment> <description><%=Html.Encode(item.Description)%></description> <% if Not item.Categories is Nothing then %> <%For Each c In item.Categories%> <category domain="<%= c.Url %>"><%=c.Title%></category> <% Next %> <% End If%> <%If Not item.Enclosures is Nothing then %> <% For Each e In item.Enclosures%> <enclosure url='<%=e.Url %>' length='<%=e.length %>' type='<%=e.type %>' /> <% Next%> <% end if %> </item> <% Next%> </channel> </rss>

In comparing this code with the XML Literal implementation, they are amazingly similar. With MVC, I may be able to live without XML Literals in the views as we simply replace a LINQ projection with a For Each loop. Notice here I check to see if the Categories and Enclosures objects exist before I enumerate over each of those arrays. This is because the Post feed doesn't include enclosures and the File feed doesn't need Categories. This flexibility allows us to create a reusable view for all of our needs.

But, I'm not quite happy with this implementation. I would prefer not to have to declare the additional structure layer just to pass the view something to consume. In this case, it feels like we are having the Controller consume the data Model and create a ModelView (RssElement) to be consumed by the View. We don't really need a new pattern (M-C-MV-V), do we? Instead, I would like to be a bit more "Dynamic" in my implementation so that I didn't need this class and could simply project into an anonymous type and eliminate the RssElement structures entirely.

After a bit of reflection, I realized that this is a case where VB is uniquely positioned crossing the bridge between strong typing and dynamic languages. Normally, I do not recommend using the Option Strict Off option, but this is one case where it does come in useful. To begin, we'll remove those pesky structures. Next, we'll change the controllers to project into anonymous types. Here's the revised code for the Post Rss Controller:


    Function ShowPosts() As ActionResult
        Dim posts = From p In (From post In Context.PostItems _
                    Order By post.PublicationDate Descending _
                    Take 20).AsEnumerable _
                    Select New With { _
                        .Description = p.Description, _
                        .Link = Url.Action("Title/" & p.TitleUrlRewrite & ".aspx", "Post"), _
                        .PubDate = p.PublicationDate.ToString("r"), _
                        .Title = p.Title, _
                        .TrackBackUrl = Url.Action("Trackback/" & p.Id, "Seo"), _
                        .PermaLink = "42f563c8-34ea-4d01-bfe1-2047c2222a74:" & p.Id, _
                        .Categories = (From c In p.CategoryPosts _
                                    Select New With { _
                                         .Title = c.Category.Title, _
                                         .Url = Url.Action("Category/" & c.CategoryID, _
                                                           "Post")}).ToArray, _
                        .Commentrss = Url.Action("Comment/" & p.Id, "Rss"), _
                        .CommentUrl = Url.Action("Title/" & p.TitleUrlRewrite, "Post"), _
                        .CommentCount = p.Comments.Count, _
                        .Enclosures = Nothing}

        Return View("ShowFeed", posts.ToList)
    End Function

Notice here, that we have to be very careful with our property naming and can't leave off anything. This is why we have to initialize our .Enclosures property to Nothing because we can't initialize it to an empty collection. Since our view checks to see if the object is null before binding it, we are fine here.

Now back to the view. How do we tell the view what type of data the Model contains if we can't name it? Here's where option strict off comes in handy. However, in a View page, we can't simply state Option Strict Off at the top of our code. Instead, we need to set the CompilerOptions to set optionstrict- as follows:

<%@ Page Language="VB" ContentType="application/rss+xml" 
CompilerOptions="/optionstrict-" Inherits="System.Web.Mvc.ViewPage" %>

In this case, we are not only setting the CompilerOptions, but removing the generic type definition in the Inherits clause. The rest of the view remains intact. Now, we can consume our anonymous type (because we aren't typing the view) and let the Option Strict setting dynamically resolve our method and type names. Notice here, if we were using C# 4.0, we wouldn't be able to use the Dynamic option and state that the page inherits ViewPage<Dynamic> because we can't project into a Dynamic type in our LINQ query.

Now that we have modified our view, we can reuse it. First move it to the Shared folder so that the view will be accessible regardless of which controller tries to consume it. Next, we create other controllers making sure that all of the properties are projected correctly in our LINQ query.


    Function Rss() As ActionResult
        Return View("ShowFeed", _
            From f In GetFiles() _
            Select New With { _
                .Description = f.Description, _
                .Link = "http://www.ThinqLinq.com/" & f.URL, _
                .PubDate = f.LastWriteTime.ToString("r"), _
                .PermaLink = "42f563c8-34ea-4d01-bfe1-2047c2222a74:" & f.Name, _
                .TrackBackUrl = "", _
                .CommentRss = "", _
                .CommentUrl = "", _
                .CommentCount = 0, _
                .Categories = Nothing, _
                .Title = f.Name, _
                .Enclosures = New Object() {New With { _
                                            .Length = f.Length, _
                                            .Type = "application/x-zip-compressed", _
                                            .Url = "http://www.ThinqLinq.com/" & f.URL}}})
    End Function

 

Be aware. Here we are playing with the dangerous part of dynamic languages. We no longer get the compiler to ensure that our type includes all of the necessary properties. If we forget a property or mis-type the property name, we will only know about it when a run-time exception is thrown. Of course, since this is MVC, we can use unit tests to check our type. With dynamic programming, think of the compiler as just another unit test. You need to write the rest of them by hand.

While I like the flexibility that the new dynamic option provides, I miss the comfort that comes from strong typing. Also, I haven't checked the performance differences between these implementations and suspect that the previous strongly typed option may out perform this one. With optimizations in VB 10 around Option Strict Off, I suspect that the performance differences may shrink, but would need to test this as well.

I'll also admit to being relatively new to MVC and welcome better alternatives from those who have been using it longer. What do you Thinq?

Posted on - Comment
Categories: VB Dev Center - VB - LINQ -

VB Syntax Highlighting with JQuery and Chili

At CodeStock, I attended Rod Paddock's intro to JQuery session since I hadn't played with JQuery yet. As often happens when I go to conferences, being in the different environment starts to get the mind thinking in different ways. Sometimes the benefit of the conference isn't necessarily something stated directly, but rather a thought when the mind wanders. One such thought occurred during Rod's presentation where I thought that it might be interesting to "query" sets of text over a larger document and apply formatting to selected words (similar to how Visual Studio colors keywords and other code elements).

A quick search on syntax highlighting found that I was not alone thinking that JQuery might be a good option for syntax highlighting. Chili is a JQuery based code highlighter that already supports a number of languages. It is relatively easy to incorporate into the site. First, you need to add a script reference to JQuery by adding the following:

<script type="text/javascript" src=http://jquery.com/src/jquery-latest.pack.js" />

Next, we add a link to the chili script code:

<script type="text/javascript" src="jquery/chili/jquery.chili-2.2.js" />

Third, we designate the path that contains the various language specific implementation details in a script block:

<script id="setup" type="text/javascript"> 
    ChiliBook.recipeFolder = "jquery/chili/";
</script>

Now, when we want to add highlighting to our code, we include it inside a <code> tag that is assigned to the class name of the language we want to colorize. Unlike the popular SyntaxHighlighter, Chili doesn't require you to specify the location of each language individually. It loads it dynamically based on matching up the file name with the class name.

To see how I added colorization to the source on the above code, see how the actual code is wrapped by a <code class="js"> … </code> tag. In this case, there is a js.js file in the recipeFolder that Chili uses to highlight this code. In addition, I'm wrapping the code tag inside a pre tag to eliminate otherwise unnecessary markup (like &nbsp; and <br />). This makes copying and pasting the code easier.

<pre><code class="js">


  <script id="setup" type="text/javascript">
     ChiliBook.recipeFolder = "jquery/chili/";
  </script>
</code></pre>

There's a problem with directly integrating Chili into this site however. Chili does not include a native VB syntax highlighter. However, adding new code definitions is as simple as adding a new .js file containing a collection of JSON objects defining what terms are to be colorized and how the styles should be applied. For the current VB implementation, I've added the following colorizations:

  • Comments are green
  • String literals are red
  • Processing instructions (like #Region and #If) are silver
  • Keywords and LINQ keywords are #4040c2
  • XML Literal expression hole symbols (<%= and %>) are a bit different as they use a yellow background with dark gray foreground, but we can easily set this through the style tag.

To do this, we set up a JSON structure to contain the various Regular Expression match patterns and the corresponding styles:

{
      _name: "vb"
    , _case: true
    , _main: {
          com    : { 
              _match: /'.*/ 
            , _style: "color: green;"
        }
        , string : { 
              _match: /(?:\'[^\'\\\n]*(?:\\.[^\'\\\n]*)*\')|(?:\"[^\"\\\n]*(?:\\.[^\"\\\n]*)*\")/ 
            , _style: "color: red;"
        }
        , preproc: { 
              _match: /^\s*#.*/ 
            , _style: "color: silver;"
        }
        , keyword: { 
              _match: /\b(?:AddHandler|AddressOf|AndAlso|Alias|And|Ansi|As|Assembly|Auto|
Boolean|ByRef|Byte|ByVal|Call|Case|Catch|
CBool|CByte|CChar|CDate|CDec|CDbl|Char|CInt|Class|CLng|CObj|
Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|
Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|Enum|Erase|Error|Event|Exit|
False|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|
If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|
Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|
Namespace|New|Next|Not|Nothing|NotInheritable|NotOverridable|
Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|
ParamArray|Preserve|Private|Property|Protected|Public|
RaiseEvent|ReadOnly|ReDim|REM|RemoveHandler|Resume|Return|
Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|
Sub|SyncLock|Then|Throw|To|True|Try|TypeOf|Unicode|Until|Variant|
When|While|With|WithEvents|WriteOnly|Xor)\b/ 
            , _style: "color: #4040c2;"
        }
        , linqkeyword: { 
              _match: /\b(?:From|Select|Where|Order By|Descending|Distinct
|Skip|Take|Aggregate|Sum|Count|Group|Join|Into|Equals)\b/ 
            , _style: "color: #4040c2;"
        }
        , xmlexpressionhole: {
              _match: /\<%=|\%>/
            , _style: "background: #fffebf; color: #555555;"
        }
    }
}

If you want, you can download this file at http://www.thinqlinq.com/jquery/chili/vbasic.js. Now, to use the new definition, simply add the file to the path you defined as the chiliBook.RecipeFolder above. Then add code to your page like the following:


<pre><code class="vbasic">
Private Function FormatCategories(ByVal post As PostItem) As String If post.CategoryPosts.Count > 0 Then 'Categories found. Return them Dim response = _ From catPost In post.CategoryPosts _ Select val = _ <span> <a href=<%= "default.aspx?CategoryId=" & _ catPost.Category.CategoryId %>> <%= catPost.Category.Description.Trim %></a> </span>.ToString() Return String.Join(", ", response.ToArray) Else Return "" End If End Function
</code></pre>

There are a couple issues with this implementation: First, the highlighting only works if you view the page on the site. If you are viewing this through an aggregator, you won't see the syntax highlighting. Personally, I find this to be an acceptable tradeoff to the alternative--injecting the styles inline with the code as is done with the CopySourceAsHtml project or the Windows Live Writer VSPaste plug-in. Although the code is correctly highlighted when viewed from an aggregator, it is horrendous when consumed by a reader for the blind with screen reader systems.

The second issue with this implementation is that it doesn't take context into account. As a result, if you have an object with the same name as one of the keywords, it will be highlighted  incorrectly. This will become more of an issue in VS 2010 when we (finally) get type colorization in VB. To do type colorization, we need access to the object symbols which are unavailable outside of the compiler's environment.

The third issue is that this version doesn't correctly colorize the XML Literals. While I'm sure it is possible, I'm not enough of a Regular Expression expert to figure out all of the options required to enable syntax highlighting for the XML Literals. If someone wants to add that, I would love to try out your suggestions.

Posted on - Comment
Categories: VB - JQuery - VB Dev Center -

Iterators OR Excuse me waiter theres a goto in my C sharp

At Codestock '09, I gave my LINQ Internals talk and had a number of people express shock when I showed the underlying implementation of their beloved iterators when looking at the code through Reflector. Let's look first at the C# that we wrote. This is similar to the implementation of LINQ to Object's Where method as shown in the sequence.cs file that's part of the C# Samples.


public static IEnumerable Where(this QueryableString source, Func predicate)
{
   foreach (char curChar in source)
        if (predicate(curChar))
            yield return curChar;
}

C# Iterators aren't really first class citizens, but syntactic sugar around the actual implementation. The meat of the implementation occurs in a generated class that implements the actual MoveNext method as we foreach over the results. The results are much less pretty:


private bool MoveNext()
{
    bool CS$1$0000;
    try
    {
        switch (this.1__state)
        {
            case 0:
                break;

            case 2:
                goto Label_0087;

            default:
                goto Label_00A5;
        }
        this.1__state = -1;
        this.7__wrap2 = this.4__this.GetEnumerator();
        this.1__state = 1;
        while (this.7__wrap2.MoveNext())
        {
            this.<curString>5__1 = this.7__wrap2.Current;
            if (!this.predicate(this.<curString>5__1))
            {
                continue;
            }
            this.2__current = this.<curString>5__1;
            this.1__state = 2;
            return true;
        Label_0087:
            this.1__state = 1;
        }
        this.m__Finally4();
    Label_00A5:
        CS$1$0000 = false;
    }
    fault
    {
        this.System.IDisposable.Dispose();
    }
    return CS$1$0000;
}

As you can see, the iterator sets up a switch (Select Case) statement that checks to see where we are in the loop (using a state variable). Essentially this is a state machine. The first time through we set up the environment. As we iterate over the results, we call the predicate that was passed in. If the predicate evaluates as true, we exit out of the method returning true.

The next time we return to the MoveNext, we use goto Label_0087 to re-enter the loop and continue the iteration. It's at this point that the jaws dropped in my presentation. Yes, Virginia, there are "Goto's" in C#. Spaghetti code isn't limited to VB. It's this point in my presentation where I quipped that the reason why iterators aren't in VB yet is because we want to do them "Right". While this is partly a joke, there is a level of seriousness in the comment. If you want to dig deeper on iterators, I recommend the following for your reading pleasure (note, these are NOT for the faint of heart):

After reading these, I'm sure you will have a better understanding of why it is taking so long to get iterators in VB. In the mean time, you might also find Bill McCarthy's recent article on using Iterators in VB Now to be interesting.

Posted on - Comment
Categories: VB - C# - LINQ -

Fetching XML from SQL Server using LINQ to SQL

With SQL Server, you can use the For Xml clause (read more in BOL). The quickest option is to add For XML Auto at the end of a SQL statement. You can do this with dynamic SQL or inside a stored proc. If you use a stored proc, the DBML tool doesn't recognize this as XML (and return it as an XElement as it does for XML Data type columns).

Regardless of whether you are using stored procs or dynamic SQL, the server returns the result as an array of strings broken up into 4000 character chunks. It is your responsibility to piece this back together. You can concatenate the strings and parse the XML, however there is no true root node in this return set, only a series of XML elements.

Since you are not going to be able to rely on the generated method stub for the procedure, you may want to consider using ExecuteQuery directly and handle the string parsing. If you define this in a partial class for your context, it will appear to calling code as if it came directly from the database pre formatted.  For example, here is some code that returns the customers from Northwind as an XElement:

Public Function CustomerAsXml() As XElement
    Dim returnVal = Me.ExecuteQuery(Of String)("Select * from Customers For XML Auto")
    Dim fullString = String.Concat((From x In returnVal Select x).ToArray)
    Dim xml = XElement.Parse("<root>" & fullString & "</root>")
    Return Xml
End Function

You could substitute the name of your stored proc with parameters in the place of this dynamic SQL and it should work equally well.

Dim returnVal = Me.ExecuteQuery(Of String)("CustomersXml", New Object() {})
 
Posted on - Comment
Categories: LINQ - VB - VB Dev Center - Linq to XML -

Add Extension Methods in LinqPad

As we already announced, the samples for chapters 1-8 of our LINQ in Action book are available through LINQPad. This includes the LINQ to Objects and LINQ to SQL. I've been working on the LINQ to XML chapters (9-11) and hope that we will add them to the download soon. In the process, I've needed to learn a bit about how LINQPad works under the covers in order to add specialized classes.

By default, LINQPad offers three options: Expressions, Statements and Programs. With the Expressions, you can include a single statement and have the result output. Typically here you would include a LINQ query as follows:

From cust in Customers _
Where cust.Country = "USA" _
Order By cust.CompanyName _
Select cust.CompanyName, cust.ContactName

Notice here that we don't include the Context as we typically would inside Visual Studio. That's the first clue as to what's happening under the covers. Keep this in mind as we'll come back to this in a bit.

If you need more than just a single statement, for example when demonstrating deferred execution, you can use the Statements option to include multiple statements that would otherwise appear inside a single method:

Dim books = dataContext.GetTable(Of Book)()
Dim query = From book In books _
            Skip 2 _
            Take 2 _
            Select book.Title, book.Pricequery.Dump()

If you need to refer to external methods or add other classes, choose the Program option. This will add a Sub Main method and allow you to add additional methods. Here's the sample we used for the compiled query option:


Sub Main
  ExpensiveBooks(Me, 30).Dump()
End Sub

''' 
''' Precompiled version of the Expensive Books query
''' 
Public Shared ExpensiveBooks As Func(Of TypedDataContext, Decimal, _
                                     IQueryable(Of Book)) = _
  CompiledQuery.Compile(Function(context As TypedDataContext, minimumPrice As Decimal) _
  From book In context.Books() _
  Where (book.Price >= minimumPrice) _
  Select book)

Notice here, when we pass the context in the Sub Main, that we are referring to "Me" (in C#, "this"). So what is this "Me" class that we are referring to and how were we able to refer to the Customers in the first query without including the Context? In a nutshell, LINQPad wraps your code inside of a class that is generated when you run the snippet. This class inherits from DataContext and includes the typical generated code for the objects in the database similar to the definitions generated by SqlMetal. (There are subtle differences which can cause some unexpected results, particularly when looking at the concurrency SQL on generated update statements.) Thus when using the Program option, your code is inserted into a class using the following Pseudo-code:


Public Class TypedDataContext
  Inherits DataContext
  'Generated constructors, tables, functions, views, etc
  'LINQPad user entered code
  Sub Main
    'Your functionality goes here
  End Sub
  'Other LINQPad user entered code
End Class

In the area of the other LINQPad user entered code, you are not limited to methods, fields, etc., but can also include full class/module/type definitions. Since we can include full classes, we should be able to add extension method definitions. We can't add extension methods to the generated TypedDataContext class because it doesn't fit the required signature for extension method classes (Module in VB or Shared Class in C#). Thus we need a separate class.

To create an extension method that uppercases each word, it would be nice if we could do the following:

Sub Main
  Console.WriteLine("this is a test".ToTitleCase())
End Sub

' Define other methods and classes here
Public Module Extensions
  <System.Runtime.CompilerServices.Extension()> _
  Public Function ToTitleCase(ByVal input As String) As String
    Return New System.Globalization.CultureInfo("en-US") _
                 .TextInfo.ToTitleCase(input)
  End Function
End Module

At first glance, this would seem to work. However remember that this extension module is actually nested inside of the TypedDataContext class. Here's a snapshot of the class relationships:


Public Class TypedDataContext
  Inherits DataContext
  ' SQL Metal generated classes
  ' LINQPad user entered code
  Sub Main
  End Sub
  Public Module Extensions
  End Module
End Class

If we try to run this, we get the message indicating that the extension method can't be found. By definition, nested classes can't contain extension methods. They have to be root level classes. The trick here is to trick our code to close off the generated TypedDataContext and then inject the start of a new dummy class definition at the end which will be closed off when we insert our code into the code generated by LINQPad as follows:


Sub Main
  Console.WriteLine("this is a test".ToTitleCase())
End Sub
' Close off the TypedDataContext Class
End Class

Public Module Extensions
  <System.Runtime.CompilerServices.Extension()> _
  Public Function ToTitleCase(ByVal input As String) As String
    Return New System.Globalization.CultureInfo("en-US") _
                 .TextInfo.ToTitleCase(input)
  End Function
End Module

' Create a new dummy class which will be closed by LINQPad
Class Foo

Notice here, we don't explicitly close the Foo class, but rather let LINQPad add that End Class for us. (For those of you familiar with SQL Injection, this is a technique that is typically used there as well).

Realizing the relationship between your code and the TypedDataContext that LINQPad generates allows you to use LINQPad in a host of interesting ways. Try playing with it, and while you're at it, check out the LINQ in Action samples.

Posted on - Comment
Categories: LINQ - VB - LinqPad -

LINQ In Action Samples available in LINQPad

I've been asked for some time what I think about the LINQPad tool. For those of you unfamiliar with it, LINQPad is a small but powerful tool that allows you to test your LINQ queries along with other VB and C# code. With this tool, you insert your code snippets in the code window and run it directly. If you point it to a database connection, LINQPad will build the .DBML behind the scenes and let you access the generated classes just as you would inside visual studio. When you execute the code, you can see the results in a grid layout along with the corresponding Lambda expressions and generated SQL statements.

LINQPad is a nice tool from the author of C# 3.0 in a Nutshell, Joe Albahari. I've frequently told programmers interested in LINQ to try LINQPad to get up to speed and use it instead of SQL Management Studio for a week. After a week, see how difficult it is to go back to TSQL.

Joe recently added the ability to integrate with other sample sources and offered the opportunity to Fabrice, Steve, and myself to have the samples from LINQ in Action available in LINQPad. Although we have all of our book samples available already, adding them to LINQPad offered the advantage of making it easier for you to try the queries and change them to learn better. You can then save your queries and re-run them later.

So, how do you use these samples? First Download the LINQPad executable and run it. When you open it, you will see a Samples tab that has a link to "download more samples."

LinqPad1

Clicking on this link will bring you to a dialog listing the additional samples available. Currently, there is only one additional sample, so it should be easy to find the samples from LINQ in Action.

image

Once you download the samples, you will see the LINQ in Action samples appear in the samples list broken up by chapter including both the VB and C# versions of each sample. You can then run each sample independently as shown below:

image

We have currently included chapters 1-8 which covers LINQ to Objects and LINQ to SQL. We plan to integrate the LINQ to XML and other chapters as we have the time. I hope you take the opportunity to try out this free product and our new samples.  Let us know if you find them helpful.

Posted on - Comment
Categories: VB - LINQ - C# -

GhostDoc with full VB support

I have used the GhostDoc tool before and found it to be helpful in adding comment stubs to methods. Using it is really easy. Just select the method you want to annotate and press the hot-key (CTRL-SHIFT-D by default). For example, when we were showing how to implement pingbacks we added a method that parsed the post and sent the pingbacks accordingly. To refresh your memory, the method's signature was as follows

Public Shared Sub ParsePostAndSendPostbacks(ByVal source As PostItem)
End Sub

Although we tried to make this code self-commenting. It never hurts to have fuller commenting, particularly if you are interested in creating code documentation with a tool like Sandcastle. With Ghost Doc, we simply select the method we want to annotate and press the hotkey. GhostDoc parses our method name and stubs out our HTML comments as follows:

''' <summary>
''' Parses the post and send postbacks.
''' </summary>
''' <param name="source">The source.</param>
Public Shared Sub ParsePostAndSendPostbacks(ByVal source As PostItem)
End Sub

Notice that it tries to take our method and make the comments more readable, including changing "Parse" to "Parses". Naturally, you shouldn't just use the stubs blindly and should add more comments to make your code more maintainable, but something's better than nothing.

The great thing about the latest release and SubMain taking over the code base is that they've finally taken away the "Experimental" status of the VB support. They even have support built in for VS 2005, 2008, and 2010.

Way to go Sub Main! Also, thanks for keeping GhostDoc free.

Posted on - Comment
Categories: VB -

LinqDataSource and CUD operations with Inheritance

When I added the Pingbacks and Trackbacks, I changed the implementation of the Comments to use an inheritance model (TPH) where Comments, Trackbacks, and Pingbacks all inherit from the abstract CommentBase class. To refresh your memory, here's the appropriate part of the DBML designer surface:

Comment inheritance model

While this works fine with minimal changes when viewing data, it can cause problems if you are using the LinqDataSource for editing values. When trying to update or delete a record, you may encounter a message similar to the following:

Cannot create an abstract class.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: Cannot create an abstract class.

So what's happening here? When the page is posted back, the LinqDataSource tries to re-create the object based on the incoming values so that it can reattach it to the context to perform the update. In the case of our polymorphic CommentBases collection, the data source doesn't know how to recreate the necessary object and thus throws the exception.

Normally when trying to override CRUD behaviors with the LinqDataSource, you would use the Deleting, Inserting, Updating, and Selecting methods. However in this case, the datasource has already tried to hydrate the object in order to pass it into the method handler as part of the event args. Thus handling it here is too late.

As an alternative, we can intercept the request earlier in the process. In the case of the ListView control, we can intercept this in the ItemDeleting, ItemUpdating and ItemInserting event handlers. The key here is that when we're done intercepting the request on this level that we need to keep the LinqDataSource from receiving the request by setting the Cancel property of the EventArgs and cleaning up ourselves.

When deleting a record, this is a simple process. First, we grab the key of the record being updated from the e.Keys collection. We then use that to search for the comments that have that ID passing the results to DeleteAllOnSubmit. Once the change is saved, we block future notifications setting the cancel. Here's a sample implementation:

Protected Sub ListView1_ItemDeleting(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.ListViewDeleteEventArgs) _
Handles ListView1.ItemDeleting If e.Keys.Count > 0 Then Using dc As New LinqBlog.BO.LinqBlogDataContext dc.CommentBases.DeleteAllOnSubmit(From c In dc.CommentBases _ Where c.CommentId = CInt(e.Keys(0))) dc.SubmitChanges() 'Suppress the default behavior of the binding source 'The binding source doesn't know how to instantiate the 'original value type on post-back due to the MustInherit inheritance ListView1.EditIndex = -1 e.Cancel = True End Using End If End Sub

Updating follows a similar process. In this case, we get the object we are editing based on the value in the Keys and then replay the changes based on the arg's NewValues collection.

Protected Sub ListView1_ItemUpdating(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.ListViewUpdateEventArgs) _
Handles ListView1.ItemUpdating If e.Keys.Count > 0 Then Using dc As New LinqBlog.BO.LinqBlogDataContext Dim id As Integer = CInt(e.Keys(0)) Dim item = dc.CommentBases.Where(Function(c) c.CommentId = id).FirstOrDefault If Not item Is Nothing Then 'Set the values For i = 0 To e.NewValues.Count - 1 CallByName(item, e.NewValues.Keys(i), CallType.Set, e.NewValues(i)) Next dc.SubmitChanges() 'Suppress the default behavior of the binding source 'The binding source doesn't know how to instantiate the 'original value type on post-back due to the MustInherit inheritance ListView1.EditIndex = -1 e.Cancel = True End If End Using End If End Sub

Since we're not implementing inserting from the grid for comments, we don't need to code that piece. I'll leave it to you, the reader to try that one. Realize that you will need to determine the CommentType prior to creating the appropriate instance object before setting the values on insert. Otherwise, the process is basically the same.

One other thing to keep in mind is handling concurrency. Because we are refetching the object as part of the CUD operation, we are effectively throwing away the true original values. Of course we can take care of that if we use a database issued timestamp (rowversion) for concurrency.

Posted on - Comment
Categories: VB Dev Center - VB - LINQ -

Implementing Pingbacks

Recently, I discussed Sending and Receiving TrackBacks on this blog. The TrackBack API is not the only mechanism which blog engines use to communicate between each other about the links that are included in individual posts. Wikipedia lists three methods to keep track of which articles are cross linked: Refback, Trackback, and Pingback. Of these, perhaps the trickiest to implement is the Pingback because it uses the xml-rpc style of communication rather than SOAP or REST that most .Net programmers are familiar with.

Thankfully, Cook Computing has released an open source implementation for xml-rpc which makes programming for it similar to programming .Net services by relying on attributes to specify the methods and contracts that a class consumes. The source and documentation can be found at http://www.xml-rpc.net/. Once we add a reference to the CookComputing.XmlRpcV2.dll, we can begin coding our Pingback implementation.

Unlike WCF, we don't need to perform a lot of configuration steps. We simply add a Generic Handler (.ashx) file and point it to the class that will perform the implementation. In this case, our handler will be called PingbackService.ashx and consists of the following:

<%@ WebHandler Language="VB" Class="LinqBlog.BO.Services.PingbackService" %>

As they say in the Staples advertisement, "That was easy!" Next, we implement the PingbackService class in our business tier. Similar to the Trackback, we'll separate this process into the sending operation and the receiving operation.

Sending Pingbacks

The steps to send a pingback are similar to those for a Trackback:

  • Find the links in our post.
  • Check the post's to see if the hosting server supports the Pingback API
  • Send the pingback to the hosting server's URI

The first step is identical to the TrackBack, so refer to the ParseAndSendTrackbacks method from my previous post for that code. Before we can send the ping, we need to check the server for our link to see if it supports Pingbacks. The Pingback Specification allows for two options for server discovery: based on the presence of a X-Pingback HTTP header looking like:

X-Pingback: http://www.ThinqLinq.com/Api/PingbackService.ashx

Or a <link> tag in the web page as follows:

<link rel="pingback" href="http://www.ThinqLinq.com/Api/PingbackService.ashx" />

Thus we need to check for the presence of either of these auto discovery mechanisms in our check to find the URI for the pingback server. Here's a sample implementation which takes a post's url and returns the url of the server's service (or an empty string if the server doesn't support Pingbacks).

Private Function GetPingbackServer(ByVal destination As String) As String
    Dim destUri As Uri = Nothing
    If Not Uri.TryCreate(destination, UriKind.Absolute, destUri) Then
        'Make sure we have a valid uri and that it isn't from this site (relative uri)
        Return ""
    End If

    Dim server As String = ""
    Dim req = DirectCast(WebRequest.Create(destination), HttpWebRequest)
    req.Referer = "http://www.thinqLinq.com"
    Using resp = DirectCast(req.GetResponse, HttpWebResponse)
        'Check headers for x-Pingback
        server = resp.Headers.Get("x-Pingback")
        If server <> "" Then Return server

        'Check for link element
        If resp.Headers.AllKeys.Contains("Content-Type") AndAlso _
            resp.Headers("Content-Type").StartsWith("text/html") Then

            Dim client As New WebClient()
            client.UseDefaultCredentials = True
            Dim page = client.DownloadString(destination)
            Dim regexString = _
String.Format("<link rel={0}pingback{0} href={0}[a-z0-9:\.\/_\?\-\%]*{0}", _
ControlChars.Quote) Dim match = Text.RegularExpressions.Regex.Match(page, regexString, _
RegexOptions.IgnoreCase).Value If Not String.IsNullOrEmpty(match) Then Dim startIndex As Integer = match.IndexOf("href=") + 6 Dim ret = match.Substring(startIndex, match.Length - startIndex - 1) Return ret End If End If End Using Return "" End Function

In this case, checking the headers is easy. Finding the <link> link tag takes a combination of Regular Expressions and string parsing since the <link> tag can either be HTML or XHTML compliant (and thus we can't use XML parsing on it. Now that we know the address of our post, the address that we're linking to and the address of the linking site's pingback server, we can issue the request to the server using Xmlrpc.Net. Here's the code:

Public Function SendPing(ByVal source As String, ByVal destination As String) As String

    Dim server = GetPingbackServer(destination)
    If Not server = "" Then
        Dim proxy As IPingbackPing = _
DirectCast(XmlRpcProxyGen.Create(GetType(IPingbackPing)), _
IPingbackPing) proxy.Url = server Return proxy.Ping(source, destination) End If Return "" End Function

Typically with the XMLRPC.Net, we specify the server's address in a static attribute on the service type. However, in our case the URL isn't known at compile time. As a result, we use the XmlRpcProxyGen.Create method to create a proxy for the RPC service at runtime. The Create method takes a type as an interface. We define the type with the required attributes as follows:

<XmlRpcUrl("http://ThinqLinq.com/SetAtRuntime.aspx")> _
 Public Interface IPingbackPing
    Inherits IXmlRpcProxy

    <XmlRpcMethod("pingback.ping")> _
    Function Ping(ByVal source As String, ByVal destination As String) As String

End Interface

Notice that the interface does specify a XmlRpcUrl. This is just a place holder which we replace in the SendPing method by setting the proxy.Url to the actual server's address. The act of calling the Ping method is trivial thanks to the generated proxy.

Receiving a Pingback

Switching gears to the server side now, receiving a ping is actually easy to do with the xml-rpc.net implementation. On our class, we inherit from the CookComputing.XmlRpc.XmlRpcService. This takes care of the core handler code and wiring up our method with the RPC call. To associate our method with the RPC method name, we add the CookComputing.XmlRpc.XmlRpcMethod specifying a method name of "pingback.ping" as required by the Pingback specification. This method takes two string parameters: source url and destination url; and returns a message indicating the outcome of the request.

      <XmlRpcMethod("pingback.ping")> _
      Public Function Ping(ByVal source As String, ByVal destination As String) As String
          Using dc As New LinqBlogDataContext
              'Get the post's ID based on the destination url from 
              'the custom URL Rewriting scheme.
              Dim postId As Integer = GetPostId(destination, dc)
              If postId > 0 Then
                  'Make sure we haven't already added this pingback
                  If (From c In dc.CommentBases _
                      Where c.CreatorLink = source And _
                          c.PostId = postId).Count = 0 Then

                      dc.CommentBases.InsertOnSubmit( _
                          New Pingback With {.CreatorLink = source, _
                                             .Description = "Pingback from " & source, _
                                             .EnteredDate = Now, _
                                             .PostId = postId, _
                                             .Creator = "Pingback", _
                                             .CreatorEmail = ""})
                      dc.SubmitChanges()

                      Return "pingback registered successfully"
                  Else
                      Return "pingback already registered"
                  End If
              Else
                  Return "pingback not registered, no post found"
              End If
          End Using
End Function

 

In this case, we need to make sure that a) the destination location does include a reference to a post (through the id in the querystring or via URL Rewriting). If we have a valid ID, we then check to see if there is already a linkback associated with this post and the given source address. We don't want to register duplicate linkbacks. This is particularly important since we are implementing both Postbacks and Trackbacks and the calling site could send both requests. We only want to register one. Assuming we have a new Pingback for this post, we will create a new Pingback object (which inherits from CommentBase) and set the necessary values. With LINQ to SQL, applying the change is the standard SubmitChanges call on the context. We finish by letting the client know what happened in our call. This is mostly a courtesy as the specification doesn't require a specific response outside of exception codes.

Feel free to pingback (or trackback) to this post to let me know if this series of posts has been helpful to you.

Posted on - Comment
Categories: VB Dev Center - VB - LINQ - SEO -

ADO.NET Entity Framework Documentation Samples in VB

Last week, I announced that my translations of the Entity Framework samples were available in VB. Today the ADO.Net team announced that next set have been posted. These are part of the ADO.Net Entity Framework Documentation Samples. These are the projects that are used in the EF quick start and walkthroughs that come with the .Net documentation. They are a set of mini applications demonstrating using EF within the context of an application.

The Course Manager sample was previously translated, but the HR Skills, Adventureworks data binding and research and collaboration tool were just updated today. Unlike the other samples, these don't have separate downloads for each sample, but rather have both C# and VB versions included with each download. Here's the description of each of these projects as taken from the MSDN site:

  • CourseManager.zip
    The CourseManager Windows forms application created by completing the Entity Framework quickstart.
  • HRSkillsCombined.zip
    This is a Visual Studio 2008 solution that contains both a Windows forms project and an ASP.NET project. Both samples demonstrate data binding to entity objects. The ASP.NET sample uses the EntityDataSource control for data binding.
  • AdWksSalesWinDataBind.zip
    The AdventureWorks Data Binding sample demonstrates data binding that uses the Entity Framework. This application displays and modifies SalesOrderDetail entities associated with SalesOrderHeader entities.
  • ResearchCollaborationAssistant.zip
    The Annotation and Research Collaboration Tool aids research and collaboration by creating reference annotations and contact entities that can be searched for both relevant Web pages and people associated with topics or search texts.

I hope you find these samples helpful. I'm not sure that I would recommend using the manual databinding that the team used when creating these samples as there are quite a few cases where they could have relied on native databinding rather than manually adding items to text boxes. These translations were fairly literal translations on purpose.

If you're just wanting to learn the query syntax and see the capabilities of EF, the Entity Framework Query Samples are a better source of information.

Thanks to both the VB Team and Data Team for recognizing the need for these samples in VB.

Posted on - Comment
Categories: Entity Framework - VB Dev Center - VB - ADO.Net Data Services -

Sending TrackBacks

Yesterday, I showed how we can receive trackbacks from other sites using the TrackBack API. Today, we'll look at the other side of this picture: sending TrackBacks to other sites based on links in the post. Sending a TrackBack entails several steps:

  1. Parsing the post to find links to other sites.
  2. Checking the target site to see if it supports TrackBacks.
  3. Formatting and sending the TrackBack to the target's service.
  4. Checking for error responses.

Thus with every post I create now, I include a method to parse the post and send the trackbacks as necessary. Parsing the post is a relatively painless process. In it, I query the raw HTML of the post finding anything that looks like href="….". Although I typically use LINQ for querying, in this case the best tool for the job is a regular expression. I admit that I'm not the best at regular expressions, so if anyone has a better alternative, let me know. Here's the method that starts the parsing process:


Public Shared Sub ParseAndSendTrackbacks(ByVal post As PostItem)
    'find references that support trackbacks
    Dim pattern As String = String.Format("href={0}[a-z0-9:\.\/_\?\-\%]*{0}", _
                                          ControlChars.Quote)
    Dim matches = Regex.Matches(post.Description, pattern, RegexOptions.IgnoreCase)
    For Each Link In matches.OfType(Of RegularExpressions.Match)()
        Try
            Dim startIndex = Link.Value.IndexOf(ControlChars.Quote) + 1
            Dim urlPart As String = Link.Value.Substring(startIndex, _
                                        Link.Value.Length - startIndex - 1)
            Dim svc As New TrackbackService
            svc.SendTrackback("http://www.ThinqLinq.com/Default/" & _
                              post.TitleUrlRewrite & ".aspx", post, urlPart)
        Catch ex As Exception
            Trace.Write(ex.ToString)
        End Try
    Next
End Sub

As you can see, this consists mostly of the Regex match and some string parsing to get down to the url that we are referring to. We then send that url into a method which will send the trackback.


Public Sub SendTrackback(ByVal postUrl As String, ByVal post As PostItem, ByVal externalUrl As String)

    Dim server = GetTrackbackServer(externalUrl)
    If server <> "" Then
        'Send the trackback to the sever
    End If
End Sub

Here, the first step is to see if the post that we are referencing in our post supports the trackback API. The trackback API has an auto-discovery mechanism whereby the page needs to include an embedded RDF which specifies the URI that a client should ping when it wants to issue a trackback. On this site, the trackback server URI for my Receiving Trackbacks post is:

<!--
    <rdf:RDF xmlns:rdf=http://www.w3.org/1999/02/22-rdf-syntax-ns#
      xmlns:dc=http://purl.org/dc/elements/1.1/
      xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
      <rdf:Description rdf:about=http://www.ThinqLinq.com/About.aspx
       dc:identifier="http://www.foo.com/Default.aspx" dc:Title="Thinq Linq"
       trackback:ping="http://ThinqLinq.com/Trackback.aspx?id=22050" />
    </rdf:RDF>
-->

In this case, notice that the XML is included inside of a comment block. The TrackBack Technical Specification indicates that this is required by some validators. Since we know that the site needs to include a node like this, we can issue a request to the page of the post that we are wanting to send a post to and see if it includes the appropriate rdf response information. We can't assume that the page will be XHTML compliant, so we will use another regular expression to find the <rdf:RDF></rdf:RDF> node and then use XML literals with VB 9 to parse it to get the value of the trackback:ping. Since the XML is strongly typed with namespaces, we'll start by including the appropriate imports to our class file. If we don't include these imports, our LINQ query will fail because the namespaces are required when querying XML.

Imports <xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
Imports <xmlns:dc="http://purl.org/dc/elements/1.1/">
Imports <xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">

With the namespaces in place, we can proceed with the rest of our code to find the TrackBack server's URI. This method will return the server's address or an empty string if the server is not found for any reason.

Private Function GetTrackbackServer(ByVal externalUrl As String) As String
    Try
        'Make sure that we have a valid external link
        Dim linkUri As Uri = Nothing
        If Not Uri.TryCreate(externalUrl, UriKind.Absolute, linkUri) Then
            Return ""
        End If
        Dim server As String = ""

        'Set up the HTTP request
        Dim req = DirectCast(WebRequest.Create(linkUri), HttpWebRequest)
        req.Referer = "http://www.thinqLinq.com"
        Dim client As New WebClient()
        client.UseDefaultCredentials = True

        'Get the page's contents
        Dim page = client.DownloadString(externalUrl)

        'Find the rdf tag
        Dim regexString = String.Format("<rdf:rdf(.*?)rdf:rdf>")
        Dim match = Text.RegularExpressions.Regex.Match(page, regexString, _
RegexOptions.IgnoreCase Or RegexOptions.Singleline).Value If Not String.IsNullOrEmpty(match) Then 'Use LINQ to XML to fet the trackback:ping attribute's value Dim rdf = XDocument.Parse(match) Dim url = rdf.Root.<rdf:Description>.FirstOrDefault.@trackback:ping If Not String.IsNullOrEmpty(url) Then Return url End If End If Catch ex As Exception Diagnostics.Trace.WriteLine(ex.ToString()) End Try 'Something didn't work right, or the site doesn't support TrackBacks. Return "" End Function

Now that we know the server, we can finish off the process of sending our request to the server that we started earlier. In this case, we create the request setting the method to "POST" and the ContentType to "application/x-www-form-urlencoded". We then build our form's values that we make sure to UrlEncode and place in the request's content stream.

Public Sub SendTrackback(ByVal postUrl As String, ByVal post As PostItem, ByVal externalUrl As String)

    Dim server = GetTrackbackServer(externalUrl)
    If server <> "" Then
        Dim req = DirectCast(WebRequest.Create(server), HttpWebRequest)
        req.Method = "POST"
        req.ContentType = "application/x-www-form-urlencoded"
 
        Dim content As New StringBuilder()
        content.AppendFormat("url={0}", HttpUtility.UrlEncode(postUrl))
        content.AppendFormat("&title={0}", HttpUtility.UrlEncode(post.Title))
        content.Append("&blog_name=ThinqLinq")
        content.AppendFormat("&excerpt={0}", _
                             HttpUtility.UrlEncode(StripHtml(post.Description, 200)))

        Dim contentBytes() = System.Text.Encoding.ASCII.GetBytes(content.ToString())
        req.ContentLength = contentBytes.Length

        Using reqStream = req.GetRequestStream
            reqStream.Write(contentBytes, 0, contentBytes.Length)
        End Using

        Dim resp = req.GetResponse()
        Using respStream = resp.GetResponseStream()
            Dim reader As New StreamReader(respStream)
            Dim response = XDocument.Parse(reader.ReadToEnd())
            'Check for errors
            If CDbl(response...<error>.FirstOrDefault()) > 0D Then
                Throw New InvalidOperationException(response...<message>.FirstOrDefault().Value)
            End If
        End Using
    End If
End Sub

Once we send the request, we make sure to check the response to see if there were any errors. As we mentioned yesterday, the TrackBack Technical Specification requires that the response be XML in the following format:

<?xml version="1.0" encoding="utf-8"?>
<response>
   <error>1</error>
   <message>The error message</message>
</response>

Since it is XML, it is easy to parse this using LINQ to XML. If an error is found, we raise an exception including the contained error message from the server.

Posted on - Comment
Categories: VB - VB Dev Center - LINQ - SEO -

Receiving Trackbacks

If you've been following along, I've been working on enhancing this site a bit recently. A couple of the most recent enhancements can be found in the following posts:

Continuing in this tradition, I wanted to include the ability to be notified when other sites post links to my posts. There are several such API's that support this kind of notification, including Trackbacks and Pingbacks. In this post, we'll look at receiving Trackbacks and saving them to our database (using LINQ of course).

The technical specification for Trackbacks is hosted at http://www.movabletype.org/documentation/developer/callbacks/ . To implement the listener part of the trackback, we simply need to be able to accept a HTTP Post which includes the post id in the URI and the trackback's details as form parameters. For example, if I wanted to send a trackback for my Paging with AJAX post, I would issue the following request:

POST http://ThinqLinq.com/Trackback.aspx?id=22040
Content-Type: application/x-www.form-urlencoded; charset=utf-8

title=Test+Postback&url=http://www.fansite.com/&excerpt=Good+post&blog_name=Fansite

In this request, the URI specifies the name of the trackback server including the ID of the post we are tracking: http://ThinqLinq.com/Trackback.aspx?id=22040. The trackback API specifies that the Content-Type should always be application/x-www.form-urlencoded; charset=utf-8. The body specifies the values we want the trackback server to know about. Each of these are optional. In this case, we want to send the server a trackback for a post called "Test Postback" which can be found at http://www.fansite.com on the blog that is named "Fansite". To be nice, we'll include an excerpt of our post with the value of "Good post". Because the content type needs to be urlencoded, we need to make sure that each value is encoded properly. To summarize, following parameter values would be sent for our test request:

  • title=Test Postback
  • url=http://www.fansite.com/
  • excerpt=Good Post
  • blog_name=Fansite

One tool to issue a raw HTTP request to test this is Fiddler. Inside Fiddler, we can select the Request Builder tab. Select "POST" as the method and enter the URI that we wish to post to (http://ThinqLinq.com/Trackback.aspx?id=22040). We then set the content type in the Request Headers and our post content in the Request Body. Below is a screen shot to send this request using Fiddler.

TrackbackFiddler

We'll discuss what we need to do to send this request from code in a later post. For now, we'll focus on receiving this request. While I wanted to do this with WCF, implementing it as a standard Web page is the easiest. As a result, we'll create a page called Trackback.aspx. Since there is no real UI on this, we'll remove everything from the page except for the pointer to the page's code file:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Trackback.aspx.vb" Inherits="Trackback" %>

On the page load, we need to clear our buffer because we're going to just send a simple XML response indicating any errors we may experience.

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Response.Buffer = True
        Response.Clear()
        Response.Cache.SetCacheability(HttpCacheability.NoCache)
        Response.ContentType = "text/xml"

Next, we need to create the object that we want to persist in our database. We already have a Comment table which maps to our Comments. In many ways Trackbacks are like Comments, so we'll use the same table. Since they do have different behaviors, we'll use LINQ to SQL's ability to support inheritance. Thus we'll add a discriminator column on our Comment table called CommentType and default the value to "C" since most of the items in that table will be comments.

Next, in our DBML we need to indicate the new mapping. Our existing comment class will now be an abstract base class called CommentBase. We'll change it's Inheritance Modifier to MustInherit as a result. We'll then add three derived types for Comment, Trackback, and Pingback to model the behaviors we'll be implementing now. We'll also need to make sure to Inheritance Discriminator values of each of the inheritance arrows. When we're done, this piece of our model now looks as follows:

TrackbackDbml

Now that we have our new Trackback type, we can instantiate it on our Page_Load with the form values that we get from our page's request fields.

      Dim trackback As New LinqBlog.BO.Trackback
      Dim id As Integer
      If Not Integer.TryParse(Request("id"), id) Then
          Return CreateFailureMessage("Id invalid")
      End If

      trackback.PostId = ID
      trackback.Creator = If(Request.Params("blog_name"), "")
      trackback.CreatorEmail = String.Empty
      trackback.Description = _
          String.Format("Trackback from &lt;a href={0}{1}{0}&gt;{2}&lt;/a&gt", _
                        ControlChars.Quote, _
                        If(Request.Params("url"), ""), _
                        HttpUtility.UrlDecode(If(Request.Params("title"), "")))
      trackback.EnteredDate = Now
      trackback.CreatorLink = If(Request.Params("url"), "")

We do need to decode the Url encoded values. We also need to watch out for missing values because each of the form values are optional. In this case, we'll use VB 9's support for ternary If. Also notice here that we aren't setting the CommentType field. Since we are using the discriminator column and set that in LINQ to SQL's metadata, when we save Trackback objects, it will automatically assign the type to "T" for us.

Now that we have our trackback object, adding it to the database with LINQ is trivial. However, we do need to make one additional check before saving the trackback. We don't want to save multiple trackbacks for a single post. Thus we'll check to see if there are any trackbacks for this post in the database already before saving this one:

            Using dc As NewLinqBlogDataContext
                'Make sure we don't already have a comment for this post from this url
               
If(Aggregatetb Indc.CommentBases.OfType(OfTrackback)() _
                   Wheretb.PostId = id And_
                        tb.CreatorLink = values.Url _
                    IntoCount()) = 0 Then

                   
'Add it
                   
dc.CommentBases.InsertOnSubmit(trackback)
                    dc.SubmitChanges()

                End If
            End Using

We're almost done. The last step is to send the appropriate response to the sending system as required by the Trackback API specification. This is a simple XML response containing any error messages. With XML Literals, this is a simple copy paste operation from the Trackback API:

 

    Private Function CreateSuccessMessage() As String
        Return <?xml version="1.0" encoding="utf-8"?>
               <response>
                   <error>0</error>
               </response>.ToString()
    End Function

    Private Function CreateFailureMessage(ByVal description As String) As String
        Return <?xml version="1.0" encoding="utf-8"?>
               <response>
                   <error>1</error>
                   <message><%= description %></message>
               </response>.ToString()
    End Function

With this in place, we just add the following inside of our If statement after we save the value to the database:

    Response.Write(CreateSuccessMessage)
    Response.End()

If there were any issues in creating or saving our trackback, we can send the Response.Write(CreateFailureMessage(error)).

Feel free to test this by tracking back to this post. Be aware that I am moderating the trackbacks to avoid comment spam that can be inevitable when exposing public known API's like this. Please don't abuse the ability to send trackbacks as I don't want to have to remove the functionality.

Posted on - Comment
Categories: VB - VB Dev Center - LINQ - SEO -

Entity Framework Samples in Visual Basic

For those Visual Basic users out that that have struggled with the fact that the samples were only available in C#, you can now rejoice. There are a number of projects that have now been translated into Visual Basic for your learning pleasure. You can find these samples on the MSDN Code Gallery’s Entity Framework page. At this point the following projects have been translated.

  • Entity Framework Query Samples Compatible with .NET Framework 3.5 SP1 and Visual Studio 2008 SP1 (Visual Basic and C# versions available)
    The Entity Framework Query Samples is a small Windows Forms program that contains several basic Entity SQL and LINQ to Entities queries against that NorthwindEF Entity Data Model (based on a modified version of Northwind). Its goal is to help you learn the features of the two query languages supported by EF and visualize how the results and the translated store query look like.
  • Entity Framework Lazy Loading Compatible with .NET Framework 3.5 SP1 and Visual Studio 2008 SP1 (Visual Basic and C# versions available)
    This sample shows how to use code generation to add support for transparent lazy loading to Entity Framework. It includes code generator (EFLazyClassGen), supporting library (Microsoft.Data.EFLazyLoading) and sample test applications.
  • Persistence Ignorance (POCO) Adapter for Entity Framework V1 Compatible with .NET Framework 3.5 SP1 and Visual Studio 2008 SP1 (Visual Basic and C# versions available)
    EF POCO Adapter enables Plain Old CLR Objects (POCOs) to be tracked using released version of Entity Framework V1 using automatically generated adapter objects. It consist of a code generator, supporting library and a test suite and examples.

There are several more on the way. I’ll try to update this post when they become available.

5/22: Update: Two more samples went online today:

  • EF Extensions Compatible with .NET Framework 3.5 SP1 and Visual Studio 2008 SP1 (Visual Basic and C# versions available)
    The ADO.NET Entity Framework Extensions library includes utilities that make querying stored procedures, creating typed results from DB data readers and state tracking external data much easier in the Entity Framework. A sample application demonstrates several patterns using these utilities, including stored procedures with multiple result sets, materialization of CLR types, and registering entities in the Entity Framework state manager.
  • ADO.NET Data Services IUpdateable implementation for Linq to Sql
    Sample implementation of ADO.NET Data Services IUpdateable interface for Linq to Sql Data Sources.
Posted on - Comment
Categories: Entity Framework - VB - VB Dev Center - LINQ - ADO.Net Data Services -

Paging with AJAX WCF and LINQ

These days, it seems that every web site needs to have some use of gratuitous AJAX in order to stay on the bleeding edge. Since we didn't have any here yet, I thought I would throw some in for good measure. I liked the lazy loading of records instead of paging found on some sites, including the Google RSS reader and thought I would see what it would take to add something like that here.

If you're not familiar with this paging option, instead of loading a new page of records each time the user gets to the end, they simply add to the end of the list via an AJAX (Asynchronous JavaScript and XML) call to get more records. My implementation is not nearly as fancy, but it gets the job done.

To try out the AJAX implementation we're going to discuss, browse to the AjaxPosts.aspx page. The implementation consists of three parts:

  • The web page that hosts the AJAX ScriptManager and provides the foundation of the page itself.
  • A JavaScript file which performs the client side paging functionality.
  • A WCF service which fetches the data and formats it for the client.

We'll start with the hosting page. The page itself is very simple. We'll make it easy to handle the formatting by continuing to use the same MasterPage that we use elsewhere on this site. That makes the content section rather concise.

The content section includes a ScriptManager which serves to push the AJAX bits down to the client. It also contains knowledge of our service using the asp:ServiceReference tag, and the client side JavaScript using the asp:ScriptReference tag. In addition, we include a blank div element which we will use to insert the content fetched from our service, and a button which is used to initiate requests for more posts from our service.

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="AjaxPosts.aspx.vb" 
Inherits="AjaxPosts" MasterPageFile="~/Blog.master" Title="ThinqLinq" %> <%@ Register
Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TagPrefix="asp" %> <asp:Content ID="content" runat="server" ContentPlaceHolderID="ContentPlaceHolder1"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="~/API/AjaxServices.svc" /> </Services> <Scripts> <asp:ScriptReference Path="~/AjaxServiceClient.js" /> </Scripts> </asp:ScriptManager> <div id="Posts"> </div> <button id="More" onclick="FetchPosts(); return false;">More Posts</button> </asp:Content>

With the plumbing out of the way, we can start to focus on the meat of the AJAX implementation. First off, we need to have a way to access our data. My first inclination was to use ADO.Net Data Services to serve up dynamic data from our LINQ sources. However in this case, I decided that the functionality was quite limited in scope and a dedicated service would be the better option. A dedicated service would also offer some additional level of caching should scalability become an issue on the site. Also, I wasn't sure my JavaScript skills would be quite suited to doing the necessary client side string parsing that would be necessary to build dynamic HTML content from the raw data. Thus in this case I decided to use a more standard WCF service.

Our WCF service takes as parameters the page number that we want to retrieve and the number of records that make up a page. We'll have our JavaScript pass these values. In response, it will send back a string containing the already formatted HTML that we will display. First we need to set up our class and method and decorate them with the necessary WCF attributes. When adding services that you want to AJAX enable, make sure to use the  "AJAX Enabled WCF Service" template from the Add New Item dialog box rather than the standard "WCF Service". This will set up the web.config differently to allow the service to expose a way to access a JavaScript client proxy. (Thanks goes to Wally for helping me figure that one out. For our service, we'll put it in the ThinqLinq namespace and call it AjaxServices. It will have one service method (indicated by the OperationContract attribute) called LoadFormattedPosts.


Namespace ThinqLinq
    <ServiceContract(Namespace:="ThinqLinq")> _
    <AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
    Public Class AjaxServices

        <OperationContract()> _
       Public Function LoadFormattedPosts(ByVal page As Integer, ByVal pagesize As Integer) As String
       End Function
    End Class
End Namespace

Inside the LoadFormattedPosts we'll get to use our LINQy goodness. In this case, we know that we are going to need our posts with their associated categories and comments. As an optimization, we'll add the appropriate load options to fetch all of those at the same time. We'll also include the appropriate Skip and Take methods to do the paging. Our resulting LINQ to SQL query is fairly standard.


Using dc As New LinqBlogDataContext
    Dim LoadOptions As New DataLoadOptions
    LoadOptions.LoadWith(Of PostItem)(Function(p) p.Comments)
    LoadOptions.LoadWith(Of PostItem)(Function(p) p.CategoryPosts)
    LoadOptions.LoadWith(Of CategoryPost)(Function(cp) cp.Category)
    dc.LoadOptions = LoadOptions

    Dim posts = From p In dc.PostItems _
                Order By p.PublicationDate Descending _
                Skip pagesize * page _
                Take pagesize

    Dim response As String = FormatPosts(posts)
    Return HttpUtility.HtmlDecode(response)
End Using

This query would be fine if we only wanted to send the raw data back to the AJAX client. However, we'll take an extra step in this implementation and do the formatting in a separate FormatPosts method. We'll actually add a separate method to format the Categories as well.


Private Function FormatPosts(ByVal posts As IEnumerable(Of PostItem)) As String
  Dim response = _
      From p In posts _
      Select val = <div class="post">
                     <h2>
                        <a href=<%= "Default/" & p.TitleUrlRewrite %>><%= p.Title %></a>
                     </h2>
                     <div class="story"><%= p.Description %></div>
                     <div class="meta">Posted on <%= p.PublicationDate %> - 
                        <a href=<%= "Default/" & p.TitleUrlRewrite %>>
                        Comments (<%= p.Comments.Where(Function(c) c.IsApproved).Count() %>)</a>
                        <br/>
                        <%= If(p.CategoryPosts.Count > 0, _                               "Categories:" & FormatCategories(p), _                               "") %>
                     </div>
                   </div>.ToString() _
        Select val  Return "<div class='posts'>" & String.Join("", response.ToArray) & "</div>"
End Function
Private Function FormatCategories(ByVal post As PostItem) As String
  If post.CategoryPosts.Count > 0 Then
    Dim response = _
       From catPost In post.CategoryPosts _
       Select val = <span>
                      <a href=<%= "http://www.ThinqLinq.com/Default.aspx?CategoryId=" & _                              catPost.Category.CategoryId %>>
                         <%= catPost.Category.Description.Trim %></a>
                    </span>.ToString()

    Return String.Join(", ", response.ToArray())
  Else
    Return ""
  End If
End Function

I'm not going to take the time to explain all of the LINQ to XML implementation here. I've discussed LINQ to XML in past posts. I do want to point out here a couple extra steps that need to be taken with this implementation.

First, we need to be careful in cases where we have posts without associated comments or categories. If we don't, we will run into issues with null results and the query will fail. Second, we have to watch how and when we are casting to strings and arrays. The easiest way to make sure that we are casting properly is to make sure you have Option Strict turned On at the file or project level.

Now that we have our service set-up, we can write the client side JavaScript code. Because we're using the AJAX ScriptManager and an AJAX enabled WCF service, we don't have to write any fancy plumbing code to access this service. To test this, we can browse to the service passing a /js or /jsdebug flag as follows: http://ThinqLinq.com/Api/AjaxServices.svc/js. That leaves just the task of writing the client side to access the service and place it in the AjaxServiceClient.js file for the ScriptManager to find.


var svcProxy;
var currentPage;
function pageLoad() {
    currentPage = 0;
    svcProxy = new ThinqLinq.AjaxServices();
    svcProxy.set_defaultSucceededCallback(SucceededCallback);
  
    FetchPosts();
}

function FetchPosts() {
    svcProxy.LoadFormattedPosts(currentPage, 5);
}

function SucceededCallback(result) {
    var postTag = document.getElementById("Posts");
    postTag.innerHTML += result;
    currentPage += 1;
}

if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

In this JavaScript, we set up two global variables: currentPage to manage the paging functionality and svcProxy to act as the instance of the proxy that accesses our service. In the pageLoad function, we initialize these values. Once initialized, we then set the asynchronous callback function for when values are retrieved. Finally, we invoke the method to fetch the posts for the first time that the page is loaded.

To fetch the posts, we simply call the LoadFormattedPosts method of our proxy which sends the request to our WCF service. Because this is performed asynchronously, we will just fire the request and let the callback handle the response.

In the SucceededCallback method, we grab the return value from the WCF service in the result parameter. Once we have that, we get a reference to the placeholder "Posts" div in the AjaxPosts.aspx document. To add the new results to the client, we concatenate the current contents with the new result value using +=. Finally, we increment the currentPage number so that the next request will fetch the next page of posts.

That's it. We're done. Jump over to http://ThinqLinq.com/AjaxPosts.aspx to see the result in action. There are a number of things that can be improved on this implementation, but it is a start. One definite drawback on this implementation is that it is not SEO friendly. You can see this by viewing the source to the resulting page. Notice that none of the post contents are included in the source.

I don't claim to be a JavaScript or AJAX expert and I'm sure there are other more elegant solutions. I'd love to learn from your experience, so feel free to post your recommendations and we'll see what we can do to improve this.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Ajax - WCF -

Adding Gravatar support to comments

Having a bit more free time than expected, I thought I would take a bit of time and add some features to this site based on some things I've seen at other sites. A quick one is adding Gravatar support to the comments. If you're not familiar with gravatar's, www.Gravatar.com describes them as a globally recognized avatar, is quite simply an image that follows you from site to site appearing beside your name when you do things.

To get a Gravatar, go to Gravatar.com and let them know your email address and the picture you want associated with your picture. Once you are done, any site that supports gravatar's will then show your picture to the world. That's your task.

My task is to enable this site to access your picture. They have a number of add-ins for various blogging engines, but since this one is custom, we'll have to implement it ourself. Luckly it is as simple as adding a img tag to our site with the source being a URI which includes information about the user that we want to display. Here's a sample URI which would show my picture:

<img src="http://www.gravatar.com/avatar.php?gravatar_id=58d453f6449cc9125948bd153bc4272b&rating=G&size=40" alt="Gravatar" />

Let's break the source attribute down a bit. Essentially it is a URI to a PHP site on the Gravatar server: http://www.gravatar.com/avatar.php. It includes three query string parameters: the gravatar_id, rating and size.

The rating and size are easy enough. For this site, we're going to keep it clean (although we do get Kinq-y at times) so we'll keep the site rated G. Other sites could use one of their other rating levels (g, pg, r, or x).

For the size, you can specify that the image be anywhere between 0 and 512 pixels. To keep the page load small here, I'll ask for images 40 px by 40 px and set the size=40.

With that out of the way, we need to generate the value for the gravatar_id paramter. In a nutshell, the id is just a MD5 hash of the commentor's email address. When we set-up the ability to add comments to this site, we made the email address a required field, so we are already storing that. All we need to do is convert it and bind to it in our custom img tag. To encapsulate that functionality and keep it with the comments themselves, we will add a partial class for Comments and put our new property in there. We don't add it directly to the Comment class that the dbml file generates as it will be deleted in the future if we ever decide to regenerate that file. With partial classes, we can retain parts of the class definition in multiple physical files and the compiler will combine them within the generated assembly. Here's the definition of this class and our new property:


Public Class Comment
    Public ReadOnly Property GravatarSource() As String
        Get
        End Get
    End Property
End Class

Notice here, we don't need to specify that this is a partial class because the one generated by our DBML designer already includes the partial destinction. As long as we're in the same namespace, in VB, we're fine. I should point out however that there are some limitations on how we can use this partial property in LINQ queries (see http://www.thinqlinq.com/Default/Projecting-into-an-unmapped-property-from-a-LINQ-to-SQL-query.aspx).

Now for the getting this value. To make binding simple, we'll just format the entire URI in this method (we're using a property here due to limitations in data binding to methods). Using the String.Format method, we can insert the hash into our uri using the following:

Return String.Format("http://www.gravatar.com/avatar.php?gravatar_id={0}&rating=G&size=40", GetEmailHash())

The body of the GetEmailHash function is where the meat of our work happens. In this, we will encode the value of the Commentor's email address which we can access from the other part of the partial class as the CreatorEmail property. To do that, we need to encode the string into a byte array. Then, using a MD5CryptoServiceProvider instance, we can compute the hash into a new byte array.


Dim enc As New UTF8Encoding()
Dim hashProvider As New MD5CryptoServiceProvider
Dim bytes() As Byte = hashProvider.ComputeHash(enc.GetBytes(Me.CreatorEmail))

Finally, we need to piece the encrypted array back into a string. In the case of the Gravatar system, each byte needs to be converted back to the HEX represntation and lower cased. We could use a for-each loop and iterate over the results building it up dynamically, but this is a great case of using LINQ to Objects to replace an iteration:

From b In bytes Select b.ToString("X2").ToLower()

We can then concatenate the resulting HEX strings using the String.Join. Here's the completed definition of this class:


Imports System.Security.Cryptography
Imports System.Text
Imports System.IO 

Public Class Comment
    Public ReadOnly Property GravatarSource() As String
        Get
            'We need the MD5 hash of the email address
            Return String.Format("http://www.gravatar.com/avatar.php?gravatar_id={0}&rating=G&size=40", GetEmailHash())
        End Get
    End Property
    Private Function GetEmailHash() As String
        Dim enc As New UTF8Encoding()
        Dim hashProvider As New MD5CryptoServiceProvider
        Dim bytes() As Byte = hashProvider.ComputeHash( _
                           enc.GetBytes(Me.CreatorEmail))
        Return String.Join("", _
                           (From b In bytes _
                            Select b.ToString("X2").ToLower()) _
                            .ToArray())
    End Function
 End Class

Now, to add this property to our UI. Since we are already set up to bind to the comment object in our CommentRepeater control, we just add a new line to specify the img tag:

<a href="http://www.gravatar.com" title="Get your avatar"><img width="40" height="40" style="float: right; padding-left: 10px;" src="<%# Eval("GravatarSource") %>" alt="Gravatar" /></a>

That's it. If you want to see the gravatar in action, head on over to their site and sign up. Then come back here and leave a comment on this post. I'd love to see the faces of people who enjoy this site.
Posted on - Comment
Categories: VB Dev Center - LINQ - VB - SEO -

Delegates and Lambdas in VB 10

Yesterday, I had the pleasure of demonstrating Delegates, Lambdas and Expressions at the Alabama Code Camp. This is not the first time I presented this. The original demo project is still available in the Downloads section of this site. This time however, I was able to round off the VB set of the demos to demonstrate all of the abilities available in C# 3.0 due to the new Statement and Multi-line Lambda language enhancements coming in VB 10. The complete VB 10 version of the project is available to download now as well.

Here are some of the added methods. (Note, this has been tested against the October 2008 beta release of Visual Studio 2010. Be aware of the evaluation time bomb in this release if you intend to use it.) The DoTrick method takes an Action delegate which means that it takes no parameters and returns no values. In VB this equates to a Sub and in VB 10 is refered to as a Statement Lambda.

'Anonymous delegate
animal.DoTrick(Sub() Console.WriteLine("Anonymous Method"))

' Lambda expression as a variable
Dim LiftOneLeg As TrickAction =
   Sub()
      animal.LegsOnGround -= 1
   End Sub
animal.DoTrick(LiftOneLeg)

'Lambda expression inline
animal.DoTrick(Sub()
      animal.LegsOnGround += 3
   End Sub)

'Multi-line lambda
animal.DoTrick(Sub()
      animal.LegsOnGround = 0
      Console.WriteLine("I'm Jumping now!")
      animal.LegsOnGround = 4
   End Sub)

I also included a nice consise combination of VB 9 function lambdas with VB 10 Statement lambdas. In this case, I find the animals that have broken business rules (Predicates which are delegates that return a boolean) and then iterate over them using the ForEach method that takes an Action delegate which can be fulfilled with a statement lambda.

animals _
   .Where(Function(item) Not item.IsValid).ToList _
   .ForEach(Sub(item) Console.WriteLine(item.ToString))

For this update, I also include a demonstration of a common use of Lambda's, particularly in Silverlight applications where all data access is asynchronous. Since all delegates actually inherit from MultiCastDelegate, all delegates by default offer asynchronous BeginInvoke/EndInvoke possibilities in addition to the Synchronous Invoke method.

With BeginInvoke, we use a lambda that takes an IAsynchResult object as a parameter. In the past we had to declare the call back as a separate method. With the inclusion of multi-line statement lambdas, we can now declare the callback directly inline with the BeginInvoke request as follows:

Public Sub BeginTrick(ByVal trick As Action)
   trick.BeginInvoke(Sub(result)
         Thread.Sleep(1000)
         Console.WriteLine("...Trick Completed for " & ToString())
      End Sub, Me)
End Sub

If you missed this presentation, I'll be doing it again at the South Florida Code Camp next week. Come on down and check it out.

Posted on - Comment
Categories: Code Camp - VB Dev Center - VB -

Adding a dynamic SiteMap for search engine optimization using LINQ

A couple months ago I added a feature to this site to build a Site Map for this site dynamically based on the information from the database for posts and files for the downloads. If your not familiar with how Sitemap files can help your site searchability, Google has a good documentation about Sitemaps in their Webmaster tools.

The SiteMap Protocal is a rather simple XML document consisting of a set of url nodes that consist of the following:

  • loc - URL for the page link
  • lastmod - Date the page was last modified
  • changefreq - How often the page is changed
  • priority - How high you think the page should be ranked relative to other pages on your site.

For this site, I decided to index the main (default.aspx) File, about and contact pages. In addition, I indexed each post as a separate url node. If you want to view the resulting data, browse to http://www.thinqlinq.com/sitemap.aspx. To do this, I used LINQ to XML with VB XML Literals. To begin, we need to add the XML Namespaces. At the top of our file, we enter the following imports:

Imports <xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
Imports <xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

We continue by adding the root urlset node and one child node representing the main page:

Dim map = _

    <?xml version='1.0' encoding='UTF-8'?>

    <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9

            http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"

        xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

 

        <url>

            <loc>http://www.ThinqLinq.com/default.aspx</loc>

            <lastmod>

               <%= (From p In dc.PostItems _

                    Order By p.PublicationDate Descending) _

            .First.PublicationDate.ToString("yyyy-MM-dd") %>

            </lastmod>

            <changefreq>daily</changefreq>

            <priority>1.0</priority>

        </url>

    </urlset>

 

Most of this is standard XML. The main difference is the use of a LINQ query to show the last modification date based on the most recent post from our database. In this case we just want the First date when the dates are ordered descending. We do need to format it properly so that our search engine (Google) will be able to recognize it.

Next up, we need to add the link for the Downloads page. We'll do this much the same way that we added the url for the default page. However, in this case the modification date won't come from the database, but rather use a LINQ to Objects query to get the most recent file in the downloads directory on this site.

<url>

    <loc>http://www.ThinqLinq.com/Files.aspx</loc>

    <lastmod>

        <%= (From f In New System.IO.DirectoryInfo( _

            Server.MapPath("~/Downloads")).GetFiles _

            Order By f.LastWriteTime Descending) _

            .FirstOrDefault.LastWriteTime.ToString("yyyy-MM-dd") %>

    </lastmod>

    <changefreq>weekly</changefreq>

    <priority>1.0</priority>

</url>

The About and Contact pages are relatively straight forward. The remaining url nodes are generated based on the records in the PostItems from our database. To populate them, we'll create a LINQ query pulling the data from the database using LINQ to SQL and projecting (Select) out individual url nodes for each row in the database:

<%= From p In dc.PostItems.ToList _

    Select <url>

               <loc>http://www.ThinqLinq.com/default/<%= p.TitleUrlRewrite %>.aspx</loc>

               <lastmod><%= p.PublicationDate.ToString("yyyy-MM-dd") %></lastmod>

               <changefreq>daily</changefreq>

               <priority>0.3</priority>

           </url> %>


As you can see, there isn't much here that is overly complex. It's just a series of LINQ queries filling the data from various sources. For reference purposes, Here's the complete code:

Imports <xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

Imports <xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 

Partial Class SiteMap

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Response.Buffer = True

        Response.Clear()

        Response.Cache.SetCacheability(HttpCacheability.NoCache)

        Response.ContentType = "text/xml"

        Response.AddHeader("Content-Disposition", "inline;filename=blog.rss")

        WriteRss()

        Response.End()

    End Sub

 

    Private Sub WriteRss()

        Try

            Using dc As New LinqBlog.BO.LinqBlogDataContext

                Dim map = _

                    <?xml version='1.0' encoding='UTF-8'?>

                    <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"

                        xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

 

                        <url>

                            <loc>http://www.ThinqLinq.com/default.aspx</loc>

                            <lastmod>

                                <%= (From p In dc.PostItems _

                                    Order By p.PublicationDate Descending) _

                                    .First.PublicationDate.ToString("yyyy-MM-dd") %>

                            </lastmod>

                            <changefreq>daily</changefreq>

                            <priority>1.0</priority>

                        </url>

                        <url>

                            <loc>http://www.ThinqLinq.com/Files.aspx</loc>

                            <lastmod>

                                <%= (From f In New System.IO.DirectoryInfo( _

                                    Server.MapPath("~/Downloads")).GetFiles _

                                    Order By f.LastWriteTime Descending) _

                                    .FirstOrDefault.LastWriteTime.ToString("yyyy-MM-dd") %>

                            </lastmod>

                            <changefreq>weekly</changefreq>

                            <priority>1.0</priority>

                        </url>

                        <url>

                            <loc>http://www.ThinqLinq.com/about.aspx</loc>

                            <lastmod>

                                <%= System.IO.File.GetLastWriteTime( _

                                    Server.MapPath("About.aspx")).ToString("yyyy-MM-dd") %>

                            </lastmod>

                            <changefreq>monthly</changefreq>

                            <priority>1.0</priority>

                        </url>

                        <%= From p In dc.PostItems.ToList _

                            Select <url>

                                       <loc>http://www.ThinqLinq.com/default/<%= p.TitleUrlRewrite %>.aspx</loc>

                                       <lastmod><%= p.PublicationDate.ToString("yyyy-MM-dd") %></lastmod>

                                       <changefreq>daily</changefreq>

                                       <priority>0.3</priority>

                                   </url> %>

 

                        <url>

                            <loc>http://www.ThinqLinq.com/Contact.aspx</loc>

                            <lastmod>2008-02-28</lastmod>

                            <changefreq>never</changefreq>

                            <priority>0.1</priority>

                        </url>

                    </urlset>

                Response.Write(map)

            End Using

        Catch ex As Exception

            Response.Write(<error><%= ex.ToString %></error>)

        End Try

 

    End Sub

End Class

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - VS 2008 - SEO - Linq to XML -

F Sharp and the Excel Financial Functions

With my focus on LINQ, I have been considering the functional implications of the changes to the standard imparitive languages. As a result, I've been trying to watch the changes coming with the new F# Functional programming language which will be part of VS 2010. When thinking about the use cases for F#, areas with heavy computational needs are often the best use case. In many ways, I would think one ideal place for using F# would be in Excel where many business people have no problems chaining function calls together with complex nested If() functions.

The team has gone one better and taken the financial functions in Excel and re-written them in F#. The code is available on the MSDN Code Gallery. While this may be a nice feature, I'm not sure it was absolutely needed other than proof of concept. Why? Because most of the typical financial functions are already available in the VisualBasic.Financial namespace. Indeed, when I started my most recent project, I had the choice of language and choose VB.Net in part because it supported a number of the functions I needed in the banking industry out of the box.

Below is a comparison of the methods included in each library. I do find it interesting that the F# implementation chose not to implement the Rate function which is one of the trickier functions to implement because it is essentially a goal-seek.

VisualBasic.Financial F# Library
PV PV
FV FV
PMT PMT
NPER NPER
IPMT IPMT
PPMT PPMT
CUMIPMT
CUMPRINC
ISPMT
FVSCHEDULE
IRR IRR
NPV NPV
MIRR MIRR
XIRR
DB
SLN SLN
SYD SYD
DDB DDB
VDB
AMORLINC
AMORDEGRC
COUPDAYS
COUPDAYSBS
COUPDAYSNC
COUPNUM
COUPPCD
COUPNCD
ACCRINTM
ACCRINTM
PRICE
PRICEMAT
YIELDMAT
YEARFRAC
INTRATE
RECEIVED
DISC
PRICEDISC
YIELDDISC
TBILLEQ
TBILLYIELD
TBILLPrice
DOLLARDE
DOLLARFR
EFFECT
NOMINAL
DURATION
MDURATION
ODDFPRICE
ODDLPRICE
ODDLYIELD
RATE

Posted on - Comment
Categories: VB -

VB 10 Samples and White-paper

If you want to get a head start on the new language features coming in VB 10, head on over to the MSDN Code Gallery and download the samples and white-paper. Some of the new features are:

  • Multi-line and statement lambdas
  • Auto-Implemented Properties
  • Collection and list initializers
  • No PIA (that's Primary Interop Assembly, not the other PIA)
  • Generic Variance
  • Implicit line continuation

We'll be showing these off at the MDC in a couple weeks. Make sure to come out and see what these are all about.

PS. For those who are saddened about the pleight of the downsized underscores, the http://www.unemployedunderscores.com/ website is dedicated to retraining them to be productive members of society. Please contribute.

Posted on - Comment
Categories: VB -

Updated source for ThinqLinq now available

It's been a while since I posted some serious content for which I apologize. I started this site a year and a half ago as a proof of concept around LINQ. When the site went live, I included the download version of the site from the presentations I've been doing on LINQ and Asp.Net. In all this time, I've made significant updates to the site, but haven't made them available, until now. If you're interested, you can download the updated bits from the file downloads here and play with them. I did take the liberty of changing the actual production database, removing some of the site metrics, and other sensitive personal information.

As the site has evolved, I tried to document the enhancements. Here's a copy of some of the related links to help you step through some of the changes.

For those that attended my session at the Philly Code Camp 2008.3, this is the version of the project that I was discussing. Of course, there's always more enhancements that I would like to do, including centralizing access to a more common DataContext, using CompiledQueries, and other performance enhancements. If you have any recommendations, I'm all ears to hear what you thinq.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Can and Should with Legacy Constructs

There are times where you wish you didn't have to worry about legacy code. This is particularly true with programming languages where constructs need to be supported even if they have long outlived their usefullness. Consider the following code that many of us "old-timers" learned to make the TRS-80 in the computer store go into an infinate loop (because the sales person didn't know how to break out of the loop).

Public Shared Sub Main()
     10:
Dim x As String = "This is a test" : Console.Write(x) : GoTo 10
End Sub

Ok, if you're paying attention, this isn't old VB code, but VB.Net (any version). Yes, you can still use line numbers, GoTo and the colon to put multiple statements in a single line. Repeat after me, "Just because you can doesn't mean you should."  Not only is this ugly code to maintain, but it's just sloppy. Please don't code like this.

Posted on - Comment
Categories: VB Dev Center - VB -

LINQ is not an excuse for sloppy code

A couple months ago, I was convinced to try Twitter. In the process, I found www.TweetBeep.com which sends me notifications whenever someone tweets the word LINQ. Today I saw the following:

"my visual studio crashed on retrieving 39,450 records via Linq.. what a shame.. looking for a workaround and a reason.." (name withheld to protect the guilty).

In some ways, this falls into the category of, "Just because you can doesn't mean you should." In this case, the fault lies in the business requirement. There shouldn't be any reason why you should fetch 39,000 records. What user in their right mind would page through that many results?

While admitedly, many demos (including some that I present) show queries such as the following, we do that knowing that the resulting rows will be relatively small.

Dim custs = From c In Customers _
                   Order By c.Name _
                   Select c

One of the great things about LINQ is the compositionality. In this, you can add qualifications to your query (like paging and filtering) without affecting the underlying query. If you are using queries that don't utilize paging and or filtering on your data, make sure you know the underlying data and that returning that many records is reasonable (and isn't likely to grow substantially in the future). As an example, we can extend the above query and add paging as follows:

Dim custs = From c In Customers _
                   Order By c.Name _
                   Select c

Dim pageSize = 10
Dim paged = custs _
                    .Skip(currentPageNumber * pageSize) _
                    .Take(PageSize)

Additionally, I strongly recommend limiting the results prior to fetching using a where clause. There are a number of sites out there that show how to progressivly filter results (for a ComboBox, a TextBox's AutoCompleteSource or the AJAX AutoComplete extender). Extending the functionality so that the suggested items don't appear until the results are sufficiently (depending on your data) filtered is equally easy with LINQ:

If SearchString.Length > 2 Then
     Dim custs = From c In Customers _
                   Where c.Name.StartsWith(SearchString)
                   Order By c.Name _
                   Select c _
                   Take 25
     CustName.AutoCompleteSource = custs
Else
     'Not sufficiently filtered. Keep the suggestion list blank.
     CustName.AutoCompleteSource = New String() {}
End If

In the case of the original question. LINQ isn't at fault here. It is a tool for you to use. Fetching 39,000 records using LINQ or ADO.Net are equally bad ideas. Use the tools to their best effect. Don't get sloppy in your coding practice.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

LINQ to Reflection IsNot LinqProvider

 

In one of the sessions I attended at DevLinq (er, DevLink), the presenter was discussing the providers that shipped with VS 2008. Among these, he included the standard LINQ to Objects, LINQ to XML, LINQ to SQL, LINQ to Entities and LINQ to Datasets. In addition, he added LINQ to Reflection which struck me as unusual, so I looked it up.

 

In this case, LINQ to Reflection isn't really a provider, but just a specific implementation of LINQ to Objects which happens to query reflection information. Consider the following query:

 

Dim query = From m In GetType(System.Linq.Enumerable).GetMethods _

                    Order By m.Name _

                    Select m

 

In this case, the underlying source (Type.GetMethods) returns an Ienumerable(Of MethodInfo) object. As such, it is just using the LINQ to Objects method. When I think of a LINQ provider implementation, I think of a mechanism that takes the LINQ expressions and translates the expressions or otherwise alters the underlying query implementation in some way. For example, LINQ to Sharepoint translates the LINQ expressions into OCAML and LINQ to Amazon uses custom query expressions to fetch results from an Amazon web service.

 

While I don't deny the power of being able to query over reflection, I would not want people to confuse it as a true provider.

Posted on - Comment
Categories: LINQ - VB -

Where clause optimized with VB 2008 SP1

There are subtle differences between VB and C# in terms of nullability. This caused a significant difference in the TSQL generated on even simple LINQ queries. Consider the following query from Northwind's Orders table where the Freight column is generated as a Nullable(Of Integer) type:

 Dim filtered = _
       From o In dc.Orders
       Where o.Freight > 100 
       Select o

First the bad news: with the RTM of VB 2008, this query resulted in the following TSQL:

SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE (COALESCE(
    (CASE
        WHEN [t0].[Freight] > @p0 THEN 1
        WHEN NOT ([t0].[Freight] > @p0) THEN 0
        ELSE NULL
     END),@p1)) = 1

In this case, I've highlighted the relevant portion of the Where clause. Notice here the simple comparison translates into a COALESCE(CASE WHEN... construct. This was done due to VB's handling of nullable type comparisons under the covers.

AND NOW THE GOOD NEWS:

With the VB 2008 SP1, the difference in nullablity was removed by the SQLProvider used by LINQ to SQL. As a result the above LINQ query now generates the following TSQL:

SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[Freight] > @p0

Notice in this case the where clause direcly reflects the statement ffrom the LINQ query and the performance from SQL Server's perspective is GREATLY improved! Who says LINQ to SQL is dead?

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

VB Ordering of Anonymous Type Properties change with VS 2008 SP1

The VS 2008 SP1 includes lots of new features (more than a typical service pack, but that's another matter). There are a number of smaller enhancements that could easily go un-noticed otherwise. One of these is to fix a bug in the way the VB compiler generates anonymous types.

In most cases, you will only notice this if you are binding an anonymous projection to a DataGridView or the ASP GridView. With these controls, you will find that the columns used to be generated alphabetically rather than in the order in which they were declared in the anonymous type projection. Consider the following query (using the Northwind Customers table of course):

Dim query = From cust In dc.Customers _
           Select cust.CompanyName, cust.ContactTitle, cust.ContactName, cust.Address

With VS 2008 RTM, a grid bound to these results would display the columns in the following order unless you explicitly set the columns: Address, CompanyName, ContactName, ContactTitle. Notice here that they are listed alphabetically. Interestingly if you use the same query in C#, the columns would be displayed retaining the order of the projection.

To determine the cause for the difference, one must view the actual IL using ILDASM. Comparing the C# with VB IL, you can see that the C# compiler retains the order where-as VB alphabetized it. No, you can't use Lutz's Reflector this time because he too alphabetizes the properties from the IL.

This was true until VS 2008 SP1 which fixed this bug. Now, the anonymous types are generated in the order in which they were declared and the column ordering is retained. Running the same query we had above results in the following column ordering with VB 2008 SP1: CompanyName, ContactTitle, ContactName, Address.

Thanks to the VB team for fixing this bug in the compiler.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - VS 2008 -

Filling an object from a DataReader with LINQ using DataContext.Translate

One of the key things that LINQ to SQL does for us is offers a quick way to fill a set of objects with data from a database. Typically this is done by setting up some mapping and calling the GetTable method on the DataContext. There are cases, particularly when you already have an infrastructure set-up to populate objects using a DbDataReader, where it would be nice if you could just populate the columns without the need to set-up a mapping.

The DataContext has a little known method called Translate which can take a DBDataReader as a parameter and fill an IEnumerable list of objects without the need for mapping structures. To use it, specify the type you want to populate and pass the instance of the reader and let it do it's magic. Here's a sample:

Using cn As New SqlClient.SqlConnection(My.Settings.NorthwindConnectionString)
  cn.Open()
  Using cmd As New SqlClient.SqlCommand("SELECT * FROM Region", cn)
    Dim reader = cmd.ExecuteReader()
    Using nwind As New NorthwindDataContext

      Dim RegionList = nwind.Translate(Of Region)(reader)

      For Each item In RegionList
        Console.WriteLine(" {0}: {1}", item.RegionId, item.RegionDescription)
      Next
   
End Using
 
End Using
End Using

In this case, we tell the context to translate the resultset of the reader into a generic IEnumerable(Of Region). There are number of caveats to keep in mind here:

  1. The column name in the result set must correspond to the property name.The translation is quite forgiving however. It is not case sensitive.
  2. If you have a row in the result set but no corresponding property, that row will be ignored (no exception will be thrown).
  3. If you have a property in your object with no corresponding row in the result set, that property's value will not be set.
  4. The translation must be done to a known type. You can not project into an anonymous type. You can return an object or simple IEnumerable if the type is not known and then use reflection to work with the results.
  5. Since the translate method returns an IEnumerable, make sure not to close the connection or the reader before iterating over the results.

The Translate method supports 3 overloads as follows:

    Public FunctionTranslate(Of TResult)(ByVal reader As DbDataReader) As IEnumerable(Of TResult)
    Public Function Translate(ByVal reader As DbDataReader) As IMultipleResults
    Public Function Translate(ByVal elementType As Type, ByVal reader As DbDataReader) As IEnumerable

Translate does not require any mappings to be set. It simply sets the public property values based on the column names. If you have business logic in your Property Set implementations, that logic will run. As far as I can see, there is no way to instruct Translate to use the private storage field instead of the public property.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Fetching child records using Stored Procedures with LINQ to SQL

You can consume stored procs rather than the standard dynamic sql for accessing child objects. To do this, set up your fetch stored procs and make sure that they return the correct data type (not the standard custom generated type for stored procedures). To load a child collection, create a method on the partial implementation of your context. Name the function "LoadCs" where "C" is the name of the child property accessor from the parent object in the designer. This function will take a type as the parent type as a parameter and return an IEnumerable of the Child type. The names you use must agree with the names of the types and properties in your entities in order for this to work.

      Public Class CustomDataContext

     ‘Load a child collection

     Public Function LoadCs(ByVal parent As T) As IEnumerable(Of C)

         Return Me.LoadCs(parent.ID)

     End Function

  End Class

The process to load a single child is similar. In this case, the function needs to be the singularized version of your entity and the return type will be the actual entity type rather than an IEnumerable as follows:

     ‘Load a single child

     Public Function LoadC(ByVal parent As P) As C

         Return Me.LoadC(parent.CId).SingleOrDefault

     End Function

Using these methods causes the context to lazy load the child objects. The default change tracking implementation will continue to work and if you have replaced the runtime behavior for the CUD operations with stored procedure implementations, they will be used just as if you fetched the objects through LINQ generated dynamic SQL.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Screen scraping and creating Word documents with LINQ to XML

At TechEd Developers 2008 in Orlando, I had the pleasure of competing in Speaker Idol. In that competition, we had the opportunity to present a topic in 5 minutes. Unfortunately, the topic I choose really needed 10 minutes to cover at the level of detail it needed. Instead of limiting the topic, I decided to go ahead and present it a bit too fast.

If you want to see the video, or see how to use VB 9's XML Literals and LINQ to XML to fetch data from a web page (that must be XHtml compilant), manipulate it and insert it into a Word 2007 file, it is now available on the  Developer Landing page, and the Library page. of the TechEd site. If you prefer, you can jump right to the video in either WMV or MP4 file formats. If you're not familiar with LINQ to XML, go ahead and download the video and just watch it at half speed ;-)

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Linq to XML -

LINQ to SQL support for POCO

One of the strengths that LINQ to SQL has over the upcoming Entity Framework is its support for POCO, or Plain Old Class Objects. With LINQ to SQL, the framework doesn't require any particular base classes, interfaces or even reliance on the 3.5 framework for the resulting objects. I demonstrated this in the talk I did at the Teched Tweener weekend. Download the demo project to see this in action.

In this sample, I created two separate projects. The first class library project, I created only targeting the 2.0 framework. As a result the project can not use any LINQ specific techniques. This will also allow us to consume the resulting objects in projects that do not have access to the newer framework, or to all of the namespaces. This is particularly important in cases like Silverlight. To call attention to the differences in the projects, I declared the 2.0 project in C# and the LINQ enabled project in VB.

The 2.0 class library project consists of a single class file. This represents the Subject entity from the Linq In Action database.

namespace UnmappedClasses
{
    public class Subject
    {
        public Guid ID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }

Notice here, there are no interfaces, base classes or custom attributes. Excluding the attributes is critical here because the standard <Table> and <Column> attributes reside in the System.Data.Linq.Mapping namespace which would not be supported in the 2.0 framework.

Admittedly, it consists of three auto-implemented properties. Auto-implemented properties are used for brevity here and are consumable by the .Net 2.0 Framework because it relies on compiler features rather than runtime features.

Because we can't allow the class structure to include the attributes, we can't use the LINQ to SQL designer classes or SQL Metal to generate our classes. We do need to have a way to indicate the mapping to our data store. Here is where the XML Mapping file comes in handy.

When instantiating the DataContext, we can either rely on the inline attributes, or an external mapping file. Luckily, the XML mapping file's structure is concise and very similar to the attributes that would have been applied to the class otherwise. The main difference we need to do is indicate the Type that is used for a given table since we are not directly annotating the class itself. The other difference you may notice is that I don't include the Storage attribute. While there is nothing to stop me from using that in a Mapping source, we can't identify the backing field when using auto-implemented properties.

<?xml version="1.0" encoding="utf-8"?>
<Database Name="lia" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
  <Table Name="dbo.Subject" Member="Subject">
    <Type Name="UnmappedClasses.Subject">
      <Column Name="ID" Member="ID"  DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" />
      <Column Name="Name" Member="Name" DbType="VarChar(100) NOT NULL" CanBeNull="false" />
      <Column Name="Description" Member="Description" DbType="VarChar(200)" />
    </Type>
  </Table>
</Database> 

Now, with that out of the way, we can get to the LINQ portion of the work. Actually, that is quite easy. In our 3.5 enabled project, we will create a XmlMappingSource, pass it into the constructor of the DataContext and then fetch the object from this context as we would any other LINQ enabled class.

Dim map = XmlMappingSource.FromXml(XDocument.Load("C:\Projects\LINQ\AdvancedLinqToSql\WinformDemo\lia.map").ToString)
 Using dc As New DataContext(My.Settings.liaConnectionString, map)
    Me.SubjectBindingSource.DataSource = dc.GetTable(Of UnmappedClasses.Subject)()
 End Using  
 
This example happens to bind the results to a Winform object binding source, but you could expose it to ASP directly, through an encapsulation layer, like a repository pattern, or a service interface.
Posted on - Comment
Categories: C# - LINQ - VB -

Anonymous Type property ordering in VB

Many people have noticed when binding an anonymous type to a grid in VB that the order of the properties does not reflect the order that they were specified in the projection (Select) clause. Instead, they appear alphabetized. Consider the following query:

Dim query = From c In Customers _
                    Select c.LastName, c.FirstName, c.BirthDate

If you bind this query to a DataGrid or DataGridView and allow the columns to be generated automatically, the results will be displayed with the following column ordering: BirthDate, FirstName, LastName. Notice that the columns are ordered alphabetically based on the property name.

I just received word that this behavior is changing in the next update to VB. After this release, the property order should be retained from the projection clause, just as it is in C#.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - VS 2008 -

Projecting into an unmapped property from a LINQ to SQL query

On page 216 of LINQ in Action, I made a comment that unmapped properties in a mapped class cannot be used in a LINQ to SQL projection. This was true with the beta bits, but only partially true with the release bits. To begin, let's consider the Author table we have in the book samples.

The Author class has separate fields for the first and last name. Each of these is mapped to the corresponding fields in the Author table. In the book, we show how you can create a read only property in a partial class (so that it won't get clobbered when we regenerate our classes in the designer). The new property is trivial:

   Partial Public Class Author
        Public ReadOnly Property FormattedName() As String
            Get
                Return Me.FirstName & " " & Me.LastName
            End Get
        End Property
    End Class

Notice here that there are no mapping attributes to this property. In part, that is because there is no corresponding field in the table. As we show in the book, you are free to query the author table and return Author objects. From there, you can display the FormattedName as follows:

           Dim authors = From a In context.Authors _
                          Select a
            For Each a In authors
                Console.WriteLine(a.FormattedName & "; " & a.WebSite)
            Next

This works fine because we are projecting the complete Author type. However, in early builds, we couldn't project the unmapped properties into an anonymous type like this:

            Dim authors = From a In context.Authors _
                          Select a.FormattedName, a.WebSite

If you tried to use this projection, you would get a runtime exception. In the RTM bits, the behavior was modified. Now, if you try to run the above query (sample 8.25 in the book samples for anyone following along). You will see that the query succeeds and the anonymous type is used. So how can they know how to populate the FormattedName when it is not mapped and doesn't exist in the table itself? No, the provider doesn't look inside the property, determine the mapped properties that are used, and fetch them. While that could work in our simple example, many unmapped properties  would use significantly more resources, many of which may not be members of our class, or methods without direct translation in TSQL. If you look at the generated SQL that is issued when the query is consumed, you might be able to figure out what is happening in this case.

SELECT [t0].[ID], [t0].[LastName], [t0].[FirstName], [t0].[WebSite], [t0].[TimeStamp]
FROM [dbo].[Author] AS [t0]

Notice here, our select clause to the database is not optimized to only return the fields we requested. Instead, all of the fields are returned. So what's going on? They discovered in evaluating the Select clause that there were unmapped properties. At that point, they just turned around and populated a full author object. Using this object, the provider turns around and generates the anonymous type from the object rather than directly from the underlying data store directly. It's a bit of smoke and mirrors at this point.

So the question that came up asks if the next printing of the book needs to be adjusted to remove the statement that you can't project an unmapped property. While you can indeed project these properties, you can't use them elsewhere in the query. Thus if you wanted to sort the data based on the unmapped property, the exception would be thrown. Consider the following query./p>

            Dim authors = From a In context.Authors _
                          Order By a.FormattedName _
                          Select  a.FormattedName, a.WebSite

In this case when we try to run it, we get the following error:

"System.NotSupportedException: The member 'LinqInAction.LinqBooks.Common.VB.SampleClasses.Ch8.Author.FormattedName' has no supported translation to SQL."

Because of this, I plan to leave the note in the chapter warning you of using the unmapped property in your query. Unfortunately, I don't have enough space in the book to insert this complete explanation at this time. I hope this explanation helps some of you who are confused at this point.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Joining composite keys with LINQ

LINQ makes working with data in its various guises easier. By intergating it into the language, we have rich integrated support for working with data. However, there are times where the syntax is slighly different from what you would typically expect with TSQL. Once case where this occurs is when trying to join two data sources that are related by more than one field (also know as a composite key). This differs from standard joins where one table has a primary key and the other table has a foreign key id. Here's a sample table structure for a standard join in Northwind between the Products and Categories:

With Linq, this join could be represented with the following query:

Dim query = _
     From p In dc.Products _
     Join c In dc.Categories _
     On p.CategoryID Equals c.CategoryID _
     Select p.ProductName, c.CategoryName

So far, there's not much new in this query. Here, "p" is the outer variable and "c" is the inner variable of the join. Likewise, p.CategoryID is the outerKeySelector and c.CategoryID is the InnerKeySelector in the Join extension method.

This works fine when we have single values that can be compared easily. However, how can we specify multiple fields for the KeySelectors on the join? In my work with reverse mortgages, we have a situation where the loan amount is based in part on the lending limits set forth by HUD. In their limits, they specify the State and County for each limit. In this case, I need to join those values against the loan property's state and county to come up with the limit amount. Let's consider the following partial table schemas.

In this case, we could join the tables in TSQL with the following query:

SELECT LendingLimits.Amount
FROM LendingLimits
INNER JOIN Property
ON LendingLimits.State=Property.State AND
      LendingLimits.County=Property.County
WHERE PropertyId=@SearchValue  AND
      EffectiveDate = @TargetDate

Unfortunately, the Join extension method does not support the ability to provide the InnerKeySelector/OuterKeySelector as a series of expressions. However, when dealing with objects, we can compare objects to see if they equal each other. Therefore, the solution in this case is to join two anonymous types and compare them against each other. Here's the corresponding LINQ query. Notice the difference in the On clause. If you understand working with objects, this syntax should make sense.

Dim query1 = _
    From l In dc.LendingLimits _
    Join p In dc.Properties _
    On New With {l.County, l.State} Equals _
          New With {p.County, p.State} _
    Where p.PropertyId = SearchValue And _
          l.EffectiveDate = TargetDate _
    Select l.Amount

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Querying the complete plays of Shakespeare using LINQ to XML

I was working to come up with some creative uses of LINQ to XML for my new talk I'm giving at the Huntsville, AL Code Camp. I figured it would be good to include a sample which queries a large XML document. Remembering that the complete works of Shakespeare were available in XML form, I did a quick search and found a version at http://metalab.unc.edu/bosak/xml/eg/shaks200.zip. This file separates each play out into separate XML files. Since I wanted to find out which parts had the most lines across all plays, I wanted to put them into a single XML file. Rather than doing this manually, I went ahead and whipped up a quick LINQ query to fetch the xml documents and load them up into an array of XElements:

Dim plays = _
    From file In New System.IO.DirectoryInfo("C:\projects\ShakespeareXml").GetFiles() _
   
Where file.Extension.Equals(".xml", StringComparison.CurrentCultureIgnoreCase) _
   
Let doc = XElement.Load(file.FullName) _
   
Select doc

Ok, now that out of the way, I really wanted to load up a single XML file with these resulting nodes. Pretty easy using XML Literals. Just wrap the query with a new root element:

Dim plays = _
  
<Plays>
   
<%= From file In New System.IO.DirectoryInfo("C:\projects\ShakespeareXml").GetFiles() _
   
Where file.Extension.Equals(".xml", String Comparison.CurrentCultureIgnoreCase) _
   
Let doc = XElement.Load(file.FullName) _
   
Select doc %>
  
</Plays>

Easy. Now I have a new XML document containing the complete plays of Shakespeare. Now, what can we do with it... Well, we can get a count of the plays in one line:

Console.WriteLine("Plays found: " & plays.<PLAY>.Count.ToString)

We could have done that without putting it into a new document. We do see that we have 37 plays represented, so we know the first query worked. Now, to count the number of lines (LINE) for each character (SPEAKER). The XML document groups each set of lines into a parent node called SPEECH. This SPEECH node then contains the SPEAKER element and a series of LINE elements. For example, here's the beginning of Juliet's fameous Romeo, Romeo speech:

<SPEECH>
   
<SPEAKER>JULIET</SPEAKER>
   
<LINE>O Romeo, Romeo! wherefore art thou Romeo?</LINE>
   
<LINE>Deny thy father and refuse thy name;</LINE>
   
<LINE>Or, if thou wilt not, be but sworn my love,</LINE>
   
<LINE>And I'll no longer be a Capulet.</LINE>
</SPEECH>

So to achieve the goal of counting our lines by character, we find the descendent nodes of the plays element (plays...<SPEECH>) and group them by the speaker. Then we project out the name of the speaker and the number of lines they have. We don't care about the bit roles, so we'll order the results in descending form based on the number of lines (LineCount). We'll limit the results to the top 50 entries. Here's the resulting query:

Dim mostLines = _
  
From speech In plays...<SPEECH> _
  
Group By key = speech.<SPEAKER>.Value Into Group _
  
Select Speaker = key, _
            LineCount =
Group.<LINE>.Count _
  
Order By LineCount Descending _
  
Take 50

The amazing thing with this process, running all three queries here, including the one which loads the full XML from the various files takes less than a second. I haven't had time to do a full performance test, including memory load, but the initial results are quite impressive!

If you have other creative uses of LINQ to XML, let me know, I'd love to include them in future presentations. Also, if you're in the Huntsville, AL area on 2/23/2008, head on over to the code camp and see the entire presentation in person.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Linq to XML -

Managing self referencing tables with LINQ to SQL

Using a single self referencing table is a common database pattern for trees of data. As an example of this concept, we can use the Employee table in Northwind. It has a self referential relationship set up using the ReportsTo field. If we drag this into the LINQ to SQL designer, it will infer the self relation and create the appropriate EntitySet/EntityRef relationship exposing it with the Employees (for subordinates of a given employee) and Employee (for the reference to the boss). The ReportsTo property contains the ID of the related property.

Inspecting the attributes used for Employees, we see that the association is mapped as follows:

<Association(Name:="Employee_Employee", Storage:="_Employees", OtherKey:="ReportsTo")> _
Public Property Employees() As EntitySet(Of Employee)

Similarly, Employee is mapped as follows:

<Association(Name:="Employee_Employee", Storage:="_Employee", ThisKey:="ReportsTo", IsForeignKey:=true)> _
Public Property Employee() As Employee

If we wish to traverse the subordinates of a given employee (boss), we can use the following:

Private Sub Main()
   Dim dc As New NWindDataContext
   Dim StartingEmp = (From emp In dc.Employees Where emp.ReportsTo Is Nothing).FirstOrDefault
   Console.WriteLine("{0}{1} {2}", Space(indentLevel * 5), StartingEmp.FirstName, StartingEmp.LastName)
   DisplaySubordniates(StartingEmp)
End Sub

Private indentLevel As Integer
Private Sub DisplaySubordniates(ByVal emp As Employee)
   If emp.Employees.Count > 0 Then
      indentLevel += 1
      For Each emp In emp.Employees
         Console.WriteLine("{0}{1} {2}", Space(indentLevel * 5), emp.FirstName, emp.LastName)
         DisplaySubordniates(emp)
      Next
      indentLevel -= 1
   End If
End Sub

Likewise, we can walk the supervisors for any given employee using the following:

Private Sub DisplayReportsTo(ByVal emp As Employee)
   If Not emp.Employee Is Nothing Then
     Console.Write("Reports to: {0} {1} ", emp.Employee.FirstName, emp.Employee.LastName)
     DisplayReportsTo(emp.Employee)
   End If
End Sub

Realize that using this implementation does have a cost. Each time we iterate over the Employee or Employees, we lazy load the resulting set. This can cause a rather chatty interaction with the data source. Because we are working with n levels of heirarchies, we can not optimize this interaction using the load options. If we were to try to add a LoadOptions, we get the following run-time exception: "Cycles not allows in LoadOptions.LoadWith type graph."

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

LINQ Migration hints

So, you're thinqing about convering existing code to use LINQ? Here are a couple quick tricks to get you started:

1) Have your regression tests ready. No warrantee is implied as to your success once completing the following.

2) Find any imports to System.Data.SqlClient including global imports and remove them. See what breaks in your application and re-write it using LINQ to SQL instead of ADO.

3) Search for iteration loops (For Each/foreach) or explicit calls to enumerator.MoveNext and see if you can replace them with declarative queries.

As an example of this last point, consider this bit of code from the Personal Web Starter Kit (in the Admin/Photo.aspx.vb file):

Dim d As IO.DirectoryInfo = New IO.DirectoryInfo(Server.MapPath("~/Upload"))
Dim enumerator As System.Collections.IEnumerator = CType(d.GetFiles("*.jpg"), System.Collections.IEnumerable).GetEnumerator
Do While enumerator.MoveNext
  Dim f As IO.FileInfo = CType(enumerator.Current, IO.FileInfo)
  Dim buffer() As Byte = New Byte((f.OpenRead.Length) - 1) {}
  f.OpenRead.Read(buffer, 0, CType(f.OpenRead.Length, Integer))
  PhotoManager.AddPhoto([Convert].ToInt32(Request.QueryString("AlbumID")), f.Name, buffer)
Loop
GridView1.DataBind()

If your source offers an ability to pass an array of items rather than requiring an explicit iteration, you may be able to simplify the process. In this case, I also chose to refactor out the logic inside the loop to further assist the maintainability. Here's the refactored code:

Sub Button1_Click(ByVal sender As Object, ByVal e As ImageClickEventArgs)
  Dim d As IO.DirectoryInfo = New IO.DirectoryInfo(Server.MapPath("~/Upload"))
  PhotoManager.AddPhotoList( _
     From f In New IO.DirectoryInfo(Server.MapPath("~/Upload")).GetFiles("*.jpg") _
     Select PhotoManager.CreatePhoto(CInt(Request.QueryString("AlbumID")), _
                f.Name, FileBytes(f)))
     GridView1.DataBind()
End Sub

Private Function FileBytes(ByVal source As IO.FileInfo) As Byte()
  Dim length As Integer = CInt(source.OpenRead.Length)
  Dim buffer() As Byte = New Byte(length - 1) {}
  source.OpenRead.Read(buffer, 0, length)
  Return buffer
End Function

Is the resulting code better? In this case, it is a toss-up. I'm just trying to show the possibility. It's up to you to test the applicability in your own applications. If you want more migration hints, check out my presentation at http://www.thinqlinq.com/Downloads/LINQMigrationStrategies.zip.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Personal Web Starter Kit LINQed up

In case anyone is interested, I have put together a sample port of the original Personal Web Starter Kit using LINQ rather than the standard ADO data tier in the PhotoManager.vb class. With this version, we can eliminate all of the stored procedures and rely on LINQ for our entire data access. In this implementation, I intentionally attempted to retain the original method signatures where possible to make migration more seamless. The project site is at http://code.msdn.microsoft.com/LinqPersonalWeb.

This is one of the sample projects I use in my LINQ Migration strategies talks, so if you attended that talk, check out the sample project for some more concrete examples. Because the original example is fairly basic and the tiers are separated out neatly, doing a migration really only requires replacing code in one file: PhotoManager.vb. Let's take a look at a couple of the refactorings we did for this example.

The meat of the original project is a solution to group images into albums and store them in a database. To start, we create a new mapping file by creating a new LINQ to SQL Classes file. Onto this surface, drag the Album and Photo tables to generate the entity classes and associated mappings. With that in place, we can move our attention to the PhotoManager class which abstracts all of the data access.

The PhotoManager class has separate methods to GetPhoto, GetPhotos, AddPhoto, EditPhoto and RemovePhoto. The same is true for albums. Each of these maps to corresponding stored procedures. Let's compare the original implementation of GetPhoto with the LINQ enabled version. In the original, we see familiar code to create a datareader and Fetch a scalar result from the function.

Public Overloads Shared Function GetPhoto(ByVal photoid As Integer, ByVal size As PhotoSize) As Stream
  Using connection As New SqlConnection(ConfigurationManager.ConnectionStrings("Personal").ConnectionString)
    Using command As New SqlCommand("GetPhoto", connection)
      command.CommandType = CommandType.StoredProcedure
      command.Parameters.Add(New SqlParameter("@PhotoID", photoid))
      command.Parameters.Add(New SqlParameter("@Size", CType(size, Integer)))
      Dim Filter As Boolean = Not (HttpContext.Current.User.IsInRole("Friends") Or HttpContext.Current.User.IsInRole("Administrators"))
      command.Parameters.Add(New SqlParameter("@IsPublic", Filter))
      connection.Open()
      Dim result As Object = command.ExecuteScalar
      Try
       
Return New MemoryStream(CType(result, Byte()))
      Catch
       
Return Nothing
     
End Try
   
End Using
 
End Using
End Function

The corresponding Stored Procedure is as follows:

CREATE PROCEDURE GetPhoto
 
@PhotoID int,
  @Size int,
  @IsPublic bit

AS
 
IF @Size = 1
    SELECT TOP 1 [BytesThumb] FROM [Photos] LEFT JOIN [Albums] ON [Albums].[AlbumID] = [Photos].[AlbumID] WHERE [PhotoID] = @PhotoID AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
  ELSE IF @Size = 2
    SELECT TOP 1 [BytesPoster] FROM [Photos] LEFT JOIN [Albums] ON [Albums].[AlbumID] = [Photos].[AlbumID] WHERE [PhotoID] = @PhotoID AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
  ELSE IF @Size = 3
    SELECT TOP 1 [BytesFull] FROM [Photos] LEFT JOIN [Albums] ON [Albums].[AlbumID] = [Photos].[AlbumID] WHERE [PhotoID] = @PhotoID AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
  ELSE IF @Size = 4
    SELECT TOP 1 [BytesOriginal] FROM [Photos] LEFT JOIN [Albums] ON [Albums].[AlbumID] = [Photos].[AlbumID] WHERE [PhotoID] = @PhotoID AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
  ELSE
   
SELECT TOP 1 [BytesPoster] FROM [Photos] LEFT JOIN [Albums] ON [Albums].[AlbumID] = [Photos].[AlbumID] WHERE [PhotoID] = @PhotoID AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)

RETURN

For those unfamiliar with the sample solution, realize that the photos table contains multiple copies of each image rendered in different resolutions. The procedure is responsible for determining which field to return based on the size parameter that is passed in. By limiting the fields returned, we can optimize the IO requirements, but this does mean that any time we want to access the photos, we need to repeat the same logic. Indeed, the same If block used in the GetPhoto procedure is copied and reused in the GetFirstPhoto procedure. This does not lead for the kind of code maintainability we would like to see.

Naturally, since your reading about it here, I'm sure you would like to see how LINQ may offer a better alternative. Starting with the GetPhoto method, we can eliminate the late bound ADO code and provide a more strongly typed version of the same method. We will also be able to refactor and reuse more pieces of the query through-out the application. Here is the code for our GetPhoto method.

Public Overloads Shared Function GetPhoto(ByVal photoid As Integer, ByVal size As PhotoSize) As Stream
  Dim dc As New PersonalDataContext
  Dim query = From p In dc.Photos _
                      Where (p.PhotoID = photoid) And _
                                 (p.Album.IsPublic Or IsFriend)
  Return GetPhotoBytes(query, size)
End Function

Get photo greatly reduces the amount of plumbing code and allows us to focus on the desired results. GetPhoto returns the actual image that corresponds to the requested ID and size. It also checks to see if the user is allowed to see that photo by checking to see if the album is marked as a public album, or if the user is considered a friend based on their login credentials. Here's the implementation of the IsFriend method.

Public Shared Function IsFriend() As Boolean
  
Return (HttpContext.Current.User.IsInRole("Friends") Or _
              HttpContext.Current.User.IsInRole("Administrators"))
End Function

Since the user's credentials are already cached for the current user, there is no need to requery that part of the database on every fetch.  The real key to this implementation lies in the GetPhotoBytes method. In this method, we evaluate the size parameter and dynamically extend our query to project just the field we want to consume.

Private Shared Function GetPhotoBytes(ByVal source As IQueryable(Of Photo), ByVal size As PhotoSize) As Stream
  Dim imageBytes As Byte()
  Select Case size
    Case PhotoSize.Large
      imageBytes = source.Select(Function(p) p.BytesFull).SingleOrDefault
    Case PhotoSize.Original
      imageBytes = source.Select(Function(p) p.BytesOriginal).SingleOrDefault
    Case PhotoSize.Small
      imageBytes = source.Select(Function(p) p.BytesThumb).SingleOrDefault
    Case Else
     
imageBytes = source.Select(Function(p) p.BytesPoster).SingleOrDefault
  End Select
 
If imageBytes IsNot Nothing Then
   
Return New MemoryStream(imageBytes)
  Else
   
Return New MemoryStream()
  End If
End Function

Here we extend the initial query and add custom projection to it. When we issue the query to the database, the resulting SQL statement wraps the functionality we declared in the GetPhoto with the GetPhotoBytes to create a single statement which only returns the image stream that we requested. What's better is that we can now reuse this same GetPhotoBytes method in the GetFirstPhoto implementation, passing a different baseline query.

Public Shared Function GetFirstPhoto(ByVal albumid As Integer, ByVal size As PhotoSize) As Stream
  Dim dc As New PersonalDataContext
  Dim query = From p In dc.Photos _
                      Where p.AlbumID = albumid And (p.Album.IsPublic Or IsFriend()) _
                      Take 1
  Return GetPhotoBytes(query, size)
End Function

There. Nicely refactored and no more copy-paste inheritance in the database.

If you're interested in looking at this implementation further, check out the project site at http://code.msdn.microsoft.com/LinqPersonalWeb. Also, let me know if you would like to see other starter kits migrated to LINQ and I'll see what I can do.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB -

Consuming a DataReader with LINQ

Last night at the Atlanta MS Pros meeting, I gave the first my new talks on LINQ Migration Strategies. If you missed it, you can catch me at the Raleigh, NC and Huntsville, AL code camps. Baring that, check out the presentation slides. This talk focuses on how you can extend existing structures using the power of LINQ. Among other things, this includes LINQ to DataSets and the XML Bridge classes.

During the presentation, fellow MVP, Keith Rome asked a question that I couldn't let sit. Is it possible to us LINQ with a data reader? I answered that it should be possible if you combine the power of C# (sorry, VB doesn't have this yet) iterators with the concept of using the fields collection in Datasets. Essentially an untyped dataset is an array of arrays. The first array is consumed by LINQ through the iterator.

The challenge here is that LINQ works on anything that implements IEnumerable, but the DataReader doesn't implement that; at least not natively. Here's where the fun of Extension Methods comes to play. With a C# extension method, we can expose an IEnumerable pattern as we iterate over the rows that we read.

To create an extension method in C#, we create a static method in a static class. We then decorate the first parameter of the method with the "this" keyword to indicate that we are extending that type. In this sample, I wanted to expose the results as an IEnumerable<IDataRecord>, but I couldn't figure out how to get a handle on the current record to yield it as we are iterating. I did find that you can push a row's data into a object collection, so that's what I did in this example. I welcome other recommendations to keep things more strongly typed. Here's the extension method implementation.

public static class DataReaderExtension
{
    public static IEnumerable<Object[]> DataRecord(this System.Data.IDataReader source)
    {
        if (source == null)
            throw new ArgumentNullException("source");
 
        while (source.Read())
        {
            Object[] row = new Object[source.FieldCount];
            source.GetValues(row);
            yield return row;
        }
    }
}

With this extension method, we can now create a data reader and query it using LINQ to Objects as follows:

Using cn As New System.Data.SqlClient.SqlConnection(MyConnectionString)
    cn.Open()
    Using cm = cn.CreateCommand
        cm.CommandType = Data.CommandType.Text
        cm.CommandText = "Select IsApproved, EnteredDate, Creator from Comments"
       
Using dr = cm.ExecuteReader
            Me.Listbox1.DataSource = _
                From row In dr.DataRecord _
                Where CBool(row(0)) _
                Order By CDate(row(1)) _
                Select CStr(row(2)) Distinct
           
Listbox1.DataBind()
        End Using
   
End Using
End Using

I am not happy about the excessive casting to and from object in this implementation. As a result of the extra casting, I suspect that it doesn't perform as well as more native implementations even though we are consuming a data reader, but I haven't had the chance to actually run performance comparisons on the alternatives. Alternative solutions are welcome.

Posted on - Comment
Categories: C# - LINQ - VB -

Dynamically extending LINQ queryies without building expression trees

As more content is added to this site, I wanted to add a searching function. The implementation here is relatively simple. We will parse the input string into the various words represented and perform a TSQL LIKE filter in the WHERE clause. Doing this on a single string is relatively simple. We just use the String.Contains method in the WHERE clause as follows:

Dim query = From p in dc.PostItems _
                    Where p.Description.Contains(InputValue) _
                    Select p

This LINQ query translates into a TSQL statement similar to the following::

SELECT * FROM PostItem WHERE Description LIKE @P0

Where @P0 = '%' + InputValue + '%'

However, we don't want to limit to our search when multiple words are entered. We would like to add multiple filters linked together with the AND logical expression as follows:

SELECT * from PostItem
WHERE Description LIKE @P0 AND
               Description LIKE @P1

Of course, we would need to be able to add as many of these as there are words in the search string. Although we could take the time to build up the necessary expression trees manually, doing so would be overkill and potentially less maintainable. Because LINQ is composable, there is an easier way. In this case, we can generate the baseline query which returns an IQueryable data structure. Once we have that, we can continue adding additional expressions  by just adding to the query. Using this method, we can create as many parameters we want (up to the server's limit on parameters)

Dim words() As String = SearchString.Split(" "c)
Dim query = dc.PostItems.AsQueryable
For Each word In words
   Dim thisWord As String = word
   query = query.Where(Function(post) (post.Description.Contains(thisWord)))
Next

Naturally, once we have this query, we could add projection, sorting, paging, and any of the other LINQ expressions. Realize here, we are not creating n-level of sub selects. Each of the LINQ where clauses we add are combined into a single TSQL WHERE clause with the various elements ANDed together. Thus if our search string were "Thinq Linq IQueryable search", the resulting TSQL would be,

SELECT [t0].[Id], [t0].[Title], [t0].[Description], [t0].[Author], [t0].[PublicationDate], [t0].[TimeStamp]
FROM [dbo].[PostItems] AS [t0]
WHERE ([t0].[Description] LIKE @p0) AND
             ([t0].[Description] LIKE @p1) AND
             ([t0].[Description] LIKE @p2) AND
             ([t0].[Description] LIKE @p3)

Nicely parameterized and consise, just like we want it. We could easily extend this example using a regular expression to parse the input string rather than using the string.Split. Notice in this example how we can use the OfType method to strongly type the results. If we didn't use it, the resulting matchItem would be of type Object and we would need to unduly cast the resulting type repeatedly.

Dim matches = System.Text.RegularExpressions.Regex.Matches(SearchString, "\w*")
Dim query = dc.PostItems.AsQueryable
For Each matchItem In matches.OfType(Of System.Text.RegularExpressions.Match)
   
Dim thisMatch As String = matchItem.Value
   
query = query.Where(Function(post) (post.Description.Contains(thisMatch)))
Next

Give the search functionality a try on this site and see how it works. At this point each word is a separate parameter. We do not combine words if they are enclosed in quotes like many search engines do. That is an exercise for another time.

Posted on - Comment
Categories: LINQ - VB -

Adding categories to the RSS feed using LINQ to XML

Last time, we added categories to the web view of the ThinqLinq site. This time, we're going to add them to the RSS feed. Because RSS is "Really Simple", adding the categories is fairly easy. According to the RSS specification, <category> is an optional sub-element of <item>. It can additionally contain the domain that contains that category. In our case, we will point the domain to our implementation that displays all posts for a given category by passing the category id to the query string of our default page. Thus we would want to insert a category like follows:

<category domain="http://www.ThinqLinq.com/default.aspx?CategoryId=1">LINQ</category>

To refresh your memory, we created last discussed creating RSS in the following post: http://www.thinqlinq.com/Default/Projecting_XML_from_LINQ_to_SQL.aspx. To add our comments, we need to inject an additional query before inside of each <item> element for the categories. To generate each of the categories for a post, we add a query to project (using the select statement) our new <category> nodes as follows:

     <%= From c In post.CategoryPosts _
              Select <category domain=<%= "Default.aspx?CategoryId" & c.CategoryID %>>
             
<%= c.Category.Title %></category> %>

Notice here, when we are creating the domain, we can use the CategoryID of the CategoryPosts object from the many-to-many table. To display the actual post's title, we need to drill through the CategoryPost to the child Category object's Title property (c.Category.Title). Putting this all together, Using the magic of LINQ to XML and VB, we arrive at the following statement:

Response.Write(<?xml version="1.0" encoding="UTF-8"?>
 
<rss version='2.0' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:slash='http://purl.org/rss/1.0/modules/slash/' xmlns:wfw='http://wellformedweb.org/CommentAPI/'>
 
<channel>
   
<title>Thinq Linq</title>
   
<link>http://www.ThinqLinq.com/default.aspx</link>
   
<description>Thoughts relating to LINQ and Language Integrated Query related topics.</description>
   
<dc:language>en-US</dc:language>
   
<generator>LINQ</generator>
   
<%= From post In query.ToArray _
            Select <item>
                        
<title><%= post.Title %></title>
                         <link><%= "http://www.thinqlinq.com/Default.aspx?Postid=" & post.Id.ToString %></link>
                         
<pubDate><%= post.PublicationDate.ToString("ddd, dd MMM yyyy hh:mm:ss GMT") %></pubDate>
                        
<guid isPermaLink="false">42f563c8-34ea-4d01-bfe1-2047c2222a74:<%= post.Id %></guid>
                        
<description><%= post.Description %></description>
                        
<%= From c In post.CategoryPosts _
                                  Select <category domain=<%= "Default.aspx?CategoryId" & c.CategoryID %>>
                                 
<%= c.Category.Title %></category> %>
                        
</item> %>
   
</channel>
  </rss>)

If you want to view the resulting feed, browse directly to http://www.thinqlinq.com/rss.aspx rather than using the standard RSS feed link which is managed through FeedBurner to allow me to gather additional statistics for this site.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Linq to XML -

Adding a RSS feed for file downloads

Ok, so I've been a bit busy this weekend adding some nice stuff for this site. One thing that I wanted to add was another RSS feed, this time for the file upload section. If you want to subscribe to the File RSS feed, direct your aggregator to the following link: http://www.thinqlinq.com/Files.aspx/Rss

Of course, since this is a learning site, I'll let you in on the code needed to accomplish the task. As you may guess, LINQ makes serving up XML from an object collection using a heterogeneous join to a database fairly easy. If you haven't seen how we display the files for this site, check out the podcast I did for Wally last year where we go over it in more detail.

To begin the task, we will set-up our initial query We will use two data sources for this task. The first data source is the object collection containing the FilInfo objects from the download directory for this site. (System.IO.DirectoryInfo(...).GetFiles). The second source is the FileClassic table returned using LINQ to SQL. LINQ allows us to easily join these two data sources and work with it as we would any other data source.

Dim fileDescriptions = dc.GetTable(Of FileClassic)()
Dim files = (From f In New System.IO.DirectoryInfo(Server.MapPath("~/Downloads")).GetFiles _
                  Join desc In fileDescriptions On f.Name Equals desc.FileName _
                  Order By f.LastWriteTime Descending _
                  Select URL = "Downloads/" & f.Name, _
                  Name = System.IO.Path.GetFileNameWithoutExtension(f.Name), _
                  f.LastWriteTime, f.Length, _
                  Description = Server.HtmlDecode(desc.Description), desc.Id).ToArray

With our query prepared, we can now use LINQ to XML with VB Literals to generate the RSS feed and output it to the response stream as follows:

Response.Write(<?xml version="1.0" encoding="UTF-8"?>
 
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
    <channel>
    <title>ThinqLinq samples and presentations</title>
    <link>http://www.ThinqLinq.com/Files.aspx</link>
    <description>Here are some of my presentation files available for you to use as you wish.  Just let me know if you like what you see and what you want to see more of.</description>
   
<%= From f In files _
            Select <item>
                       
<title><%= f.Name %></title>
                       
<link><%= "http://www.ThinqLinq.com/" & f.URL %></link>
                       
<pubDate><%= f.LastWriteTime.ToString("ddd, dd MMM yyyy hh:mm:ss GMT") %></pubDate>
                       
<guid isPermaLink="false"><%= "42f563c8-34ea-4d01-bfe1-2047c2222a74:" & f.Id %></guid>
                       
<description><%= f.Description %></description>
                      
<enclosure url=<%= "http://www.ThinqLinq.com/" & f.URL %>
                                        
length=<%= f.Length %>
                                         type="application/x-zip-compressed"
/>
                     
</item> %>
   
</channel>
 
</rss>)

The main difference between this example and the ones we are using for blog posts is the addition of the <enclosure> node. With enclosure, we specify the url to the file download, the file length, and the file type. In this site, I plan to always use ZIP files so I just hard code that. The other values come from our starting query. If you subscribe to this new feed, you should see each item including an enclosure icon so that you can download it.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Linq to XML -

Filtering items in the ThinqLinq aggregation feed

When I first released ThinqLinq, the only filtering I applied was to only select the top 20 posts. I was recently asked if I could extend the implementation so that it the aggregation feed could be filtered based on the categories. Since ThinqLinq uses LINQ for the data interaction, it is relatively easy to add filtering to the existing query.

However, in this case, the filtering is not a simple Where clause on the underlying table. That is because the table structure uses a Many to Many relationship between the Categories and PostItems. Here's the object relationships as created by the LINQ to SQL designer:

Typically when querying a database in a many to many relationship, we start on one end and work our way to the other. LINQ offers another option. Consider the following LINQ Query:

From catPost In dc.CategoryPosts _
Where catPost.Category.Title = Request.QueryString("Category") _
Select catPost.PostItem

In this query, we actually start in the middle. We can do it because we can use object trees rather than having to rely on joins. With LINQ, the many-to-many table contains a reference to the related objects on both sides. This way, we can use one side (the Category) in the Where clause and the other side (PostItem) for the Select clause. Naturally, we could also mix and match the results.

For the rss feed, we need to return the full results if no query string is supplied, but filter it if there is one. In addition, we will replace the spaces with underscores so that we can include them in the query string. With VB's Replace method, we can easy convert back from the underscores to the spaces. Here's the first query that the example will use:

Dim query As IQueryable(Of PostItem)
If Request.QueryString("Category") <> "" Then
   
query = From catPost In dc.CategoryPosts _
           Where catPost.Category.Title = Replace(Request.QueryString("Category"), "_", " ") _
           Select catPost.PostItem
Else
   
query = dc.PostItems
End If

We declare the query as IQueryable(Of PostItem) so that we can further refine the query results later. Regardless of whether we use the filtered or unfiltered version, we still want to limit the results to the most recent 20 items. The composability of IQueryable allows us to further refine our query as follows:

query = From post In query _
            Order By post.PublicationDate Descending _
            Take 20

Notice that we don't include the Select clause as it is optional in VB. Now that we have our target results, we can generate our XML as we did before in this post.

Posted on - Comment
Categories: VB Dev Center - VB - LINQ -

Using LINQ to SQL to return Multiple Results

In the LINQ in Action forum, a user asked about returning multiple result sets from a single stored procedure. Below is one way of dealing with this issue.

In the procedure, we used multiple results rather than a result with a return value (through RETURN or an OUTPUT parameter). Here we need to use the IMultipleResult rather than the default ISingleResult implementation. It appears that the designer does not map IMultipleResult in the final build, so we are going to need to do it ourselves. We mention this interface in chapter 8 but didn't have a chance to include a sample. Here's a sample implementation on returning the Subjects and Books from the Book sample database. First the stored proc:

CREATE PROCEDURE dbo.GetSubjectAndBooks
AS

 Select * from subject
 
 IF @@RowCount>0 BEGIN
  Select * from Book
 END

Now for the function mapping. We want to create a function that can return both the Subjects and the Books. To do this, we will create a function that returns the MultipleResult. Simlar to the standard stored procedure mapping, you create a function in a custom partial for the DataContext. The function will return a value of type IMultipleResults. Decorate the function with the FunctionAttribute including the name of the function. Here's the implementation in VB:

    <FunctionAttribute(Name:="dbo.GetSubjectAndBooks")> _
    <ResultType(GetType(Book))> _
    <ResultType(GetType(Subject))> _
    Public Function GetSubjectAndBooks() As IMultipleResults
        Dim result As IExecuteResult = Me.ExecuteMethodCall(Me, CType(MethodInfo.GetCurrentMethod, MethodInfo))
        Dim results As IMultipleResults = DirectCast(result.ReturnValue, IMultipleResults)
        Return results
    End Function

Notice, the main difference here is the addition of two attributes identifying the possible ResultTypes (Book and Subject). The rest of the function should be self explanitory. To consume the function, we call the GetResult method of IMultipleResults passing in the generic type we want to return as follows:

    Dim context As New LinqBooksDataContext

    ObjectDumper.Write(context.GetSubjectAndBooks.GetResult(Of Subject))
    ObjectDumper.Write(context.GetSubjectAndBooks.GetResult(Of Book))

Posted on - Comment
Categories: VB - LINQ - VB Dev Center -

Projecting XML from LINQ to SQL

Among the new cool features in Visual Studio 2008, one of the best may be the XML Literal support with VB 9 and LINQ. In my last post, I mentioned some changing features from the Beta to RTM. One that could easily be overlooked is a change to the way LINQ to SQL can now directly project into XML literals.

Through the Beta cycle, there was an issue with projecting XML elements directly from a LINQ to SQL query. If you haven't seen LINQ to SQL with XML, here's a code sample that explains what I'm referring to:

Dim dc As New LinqBlogDataContext
'Formulate the Query to get the last 10 blog posts
Dim query = (From p In dc.PostItems _
                     
Order By p.PublicationDate Descending _
                     
Take 10 _
                      
Select p).ToArray

'Create a root Site node with 10 child "item" nodes.
'Each node will be filled in through a LINQ query
Dim fooShort = _
 
<site>
       
<%= From p In query _
                
Select _
            
<item>
                 
<title><%= p.Title %></title>
                 
<link>http://ThinqLinq.com/Default.aspx?Postid=<%= p.Id %></link>
                 
<pubDate><%= p.PublicationDate %></pubDate>
                 
<guid isPermaLink="false">42f563c8-34ea-4d01-bfe1-2047c2222a74:<%
p.Id %></guid>
                 
<description><%= p.Description %></description>
                
</item> %>
 
</site>

In this code, I'm performing two queries. The first one sets up the LINQ to SQL query and pre-fetches the results into an Array. In the beta builds, if we didn't include the pre-fetching ToArray, the second query which projects the results of the first into individual <item> nodes. What is the difference between these queries? The first query uses LINQ to SQL and projects results directly from the database. Because we pre-fetch the results into an array of objects, the resulting query only uses LINQ to Objects rather than the direct LINQ to SQL implementation.

With the final RTM of Visual Studio, we no longer need to pre-fetch the results from the query. Instead, we can directly project our desired XML from the select statement without needing the intermediary step. Here is the revised code. Notice, we can now perform the same result with a single LINQ query rather than two.

Dim fooNew = _
 
<site>
      
<%= From p In dc.PostItems _
                Order By p.PublicationDate Descending _
               
Take 10 _
                
Select _
           
<item>
               
<title><%= p.Title %></title>
               
<link>http://ThinqLinq.com/Default.aspx?Postid=<%= p.Id %></link>
               
<pubDate><%= p.PublicationDate %></pubDate>
               
<guid isPermaLink="false">42f563c8-34ea-4d01-bfe1-2047c2222a74:<%= p.Id %></guid>
               
<description><%= p.Description %></description>
           
</item> %>
   
</site>

The result is more concise. You may find you want to continue separating your query definition from your XML creation in order to improve maintainability. If this is the case, simply keep the first code sample and remove the call to .ToArray. Because LINQ to SQL is composable, you can separate the queries into two code sets. When the query is evaluated, the two expressions will be combined into a single query to the database and the projection will continue to work.

Enjoy working with VB 9 and XML. In my opinion it is one of the killer features of Visual Studio 2008. If you give it a try, I think you might find the same.

Posted on - Comment
Categories: VB - LINQ - Linq to XML -

Creating HTML emails using VB 9 and LINQ

Today, I'm not looking at sending mass spam using LINQ to pull a list of recipients. I'm actually referring to the ability to generate the message body using XML Literals. Using the System.Net.Mail.MailMessage object, we can easily send emails to an SMTP server.

The body of the email can either be plain text or HTML. Dynamically generating the text is often a laborious task involving a string builder and lots of method calls. The body corresponds to the body portion of a HTML page. If you use well formed XHTML in the body, you are actually generating a specialized version of XML. Once we are working with XML, we can use XML Literals in VB to format our output.

I recently had to do this on a project to send lists of updated values from an external source. In the body, I needed to dynamically fill a HTML table with the new values. The table consists of 4 columns: State, County, Limit, Effective Date. I begin by laying out the content in a HTML editor (like Visual Studio 2008...) Here's the results:

<body>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur eros purus, suscipit ac, pulvinar vel, aliquet vehicula, pede. Duis eros dolor, iaculis non, aliquam sed, tincidunt ac, diam.
   
<table>
     
<tr><th>State</th>
           
<th>County</th>
           
<th>New Limit</th>
           
<th>Effective Date</th>
     
</tr><tr><td>XX</td>
                     
<td>Foo</td>
                    
<td>$123</td>
                     
<td>1/1/2000</td>
               
</tr>
   
</table>
 
</body>

I know what you must be thinking by now: Gee Jim, how could you come up with such a beautiful page. As Bones would say, "D@mmit Jim, I'm programmer not a designer." We'll keep it clean for now to focus on what is yet to come.

Realize that our body tag is actually the root of a well-formed XML document. As such, we can copy it as a template directly into our tool (which is a console application by the way), add a reference to System.Linq and System.Xml.Linq, and paste it into our VB module assigning a variable, let's call it "body" to the XML.

While we're at it, we'll go ahead and insert new rows into the table based on the results of an object query. In this query, we'll iterate over the records we are adding which is an IEnumerable(Of Limit). We'll project a new row (<tr>) for each object in our iteration. Rather than imperatively iterating, we'll use LINQ's declarative syntax In addition, we'll insert our values using the <%= %> place holders. Here's the resulting declaration:

Friend Shared Sub SendUpdate(ByVal newItems As IEnumerable(Of FhaLimit))
Dim body = _
  <body>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur eros purus, suscipit ac, pulvinar vel, aliquet vehicula, pede. Duis eros dolor, iaculis non, aliquam sed, tincidunt ac, diam. 
    <table>
     
<tr><th>State</th>
           
<th>County</th>
           
<th>New Limit</th>
           
<th>Effective Date</th>
     
</tr><%= From limit In newItems _
                      Order By limit.State, limit.CountyName _
                      Select <tr><td><%= limit.State %></td>
                                      
<td><%= limit.CountyName %></td>
                                      
<td><%= limit.Units1.Value.ToString("c0") %></td>
                                      
<td><%= limit.LimitTransactionDate.ToShortDateString %></td>
                               
</tr> %>
   
</table>
 
</body>

If you've coded ASP.NET, the resulting declaration should look very familiar. Realize that this is being done in a VB module in a console application. We are not coding in a .ASPX file! The resulting maintainability of this code is much better than the old way using string builders or XSLT.

To finish off the task, we are going to send the message with our new XHTML body. This is very easy with .NET as well.

Dim message As New System.Net.Mail.MailMessage("from@ThinqLinq.com", "to@ThinqLinq.com", "Limits Updated", body.ToString)
message.IsBodyHtml = True
Dim server As New System.Net.Mail.SmtpClient(My.Settings.SmtpServer)
server.Send(message)

There you go, a quick and painless way to create HTML emails using VB 9 and LINQ. Let me know what you Thinq.

Posted on - Comment
Categories: LINQ - VB - VB Dev Center - Linq to XML -

Adding RSS posts to ThinqLinq using System.ServiceModel.Syndication.SyndicationFeed

When I originally started the ThinqLinq project I began by loading the RSS feed from my DevAuthority blog, and iterating over the results adding them to the PostItems table in the data context. With LINQ this is relatively easy. Loading the XML from the feed is done with a single line:

Dim Feed As System.Xml.Linq.XDocument = _
    XDocument.Load("http://www.ThinqLinq.com/rss.aspx")

The xml document consists some basic informational elements which are not terribly important in this instance as we are only pulling from a single blog. Following the initial elements, the document contains a series of "item" elements that contain the actual post information. We can easily query the document and return an IEnumerable(Of XElement) object that we can iterate over and create new post items. Below is an excerpt from my original implementation.

For Each post As XElement In Feed...<item>
   
Dim DataPost As New LinqBlog.BO.PostItem
    DataPost.Author =
"Jim Wooley"
   
DataPost.Description = post.Element("description").Value
    DataPost.PublicationDate = CDate(post.Element("pubDate").Value)
    DataPost.Title = post.Element("title").Value
    dc.PostItems.Add(DataPost)
Next

Once the records are added to the table, we can commit them to the database with a single call to SubmitChanges as follows:

dc.SubmitChanges()

Ok, so that is easy enough. There are a couple of things to mention before we continue on. The .Add method will be changed to .InsertOnSubmit when LINQ and the .NET 3.5 Framework is released. This will be a breaking change for anyone who is currently working with the beta builds.

Another item of note: this implementation does not bother importing the various sub-collections, including attachments, comments, categories, etc. We will address some of those in a future update.

In looking back at the code and being more familiar with LINQ, it is about time to update this code taking advantage of some of LINQ's more interesting features. First VB 9 allows us to eliminate some of the functional construction syntax. Instead of weakly accessing the post.Element("description").Value, we can refer to post.<description>.Value. If we import the namespace, we will even get intellisense on the xml document.

In addition, rather than iterating over the item elements explicitly, we can use a  LINQ query to create an IEnumerable(Of PostItem) list using the object initializers in the select projection. We then fill the entire collection using the table's InsertAllOnSubmit. With this change, we eliminate the entire for each loop. Below is the revised code:

Dim Feed As System.Xml.Linq.XDocument = XDocument.Load("http://ThinqLinq.com/rss.aspx")

Dim dc As New LinqBlogDataContext()

dc.PostItems.InsertAllOnSubmit(From post In Feed...<item> _
    Select New PostItem With { _
    .Author = "Jim Wooley", _
    .Description = post.<description>.Value, _
    .PublicationDate = CDate(post.<pubDate>.Value), _
    .Title = post.<title>.Value})

dc.SubmitChanges()

That's it. We've read the feed from the site, filled the object collection and saved the resulting objects to the database. Clean and simple.

But hold on... The title of this post refers to the System.ServiceModel.Syndication.SundicationFeed object. This is a new object as part of the WCF enhancements in the .NET 3.5 Framework. To use it, add a reference to the System.ServiceModel.Web library. This object lets you create and consume feeds in both RSS and ATOM formats and use a single object model against both options. It also gives easy access to a number of child object structures, including Authors, Categories, Contributors, and Links. Additionally it strongly types the results so that we don't need to explicitly cast the values ourselves (for example with the PublicationDate). Here is the complete code to load the feed using the SyndicationFeed.Load method, fill the PostItem collection and submit them to the database.

Dim feed As SyndicationFeed = SyndicationFeed.Load( _
   
New System.Uri("http://ThinqLinq.com/rss.aspx"))

Dim dc As New LinqBlogDataContext()

dc.PostItems.InsertAllOnSubmit(From p In feed.Items _
    Select New PostItem With _
    {.Author = If(p.Authors.Count > 0, p.Authors(0).Name, "Jim Wooley"), _
    .Description = p.Summary.Text, _
    .PublicationDate = p.PublishDate, _
    .Title = p.Title.Text})

dc.SubmitChanges()

The code is substantially the same as the revised version using the XML Literals above. The advantage of using the Syndication services implementation is that it abstracts the feed structure (RSS/ATOM), giving direct and strongly typed access to the contents.

Now that we've set this up, maybe I can work on using the SyndicationFeed to generate the feeds in ThinqLinq and present that in a future post. Stay tuned.

Posted on - Comment
Categories: LINQ - VB -

Code Camp 2007 downloads

I've uploaded the files for my presentations for the fall Code camp season which I just presented last weekend at the Birmingham, Alabama code camp. If you missed the talks, you can pick up the downloads at the following links. Also, I will be at the Charleston, South Carolina code camp this coming weekend (10/13) so you can catch me there. Additionally, the ThinqLinq talk is still available on the aspnetpodcasts.com. Links to all three parts of the webcasts are available on the file download page.

Below are the links to each of the downloads for my three talks.

These and all of my demos are available via my downloads page.

Posted on - Comment
Categories: Code Camp - LINQ - VB - VS 2008 -

Code Snippets and Partial Methods

In my VB 9 language enhancements talks, I do them withalmost all coding on the fly as I find people often can comprehend the code. I start by building a quick class that is used throughout the demos. To assist, I do use the snippet functionality in VB. For example, if you type "property" and then tab twice, the designer will generate a private field with public property accessors. The if you change the highlighted values, any associated names will be changed as well.

Private newPropertyValue As String
Public Property NewProperty() As String
    Get
       
Return newPropertyValue
    End Get
    Set(ByVal value As String)
        newPropertyValue = value
    End Set
End Property

Personally, if you are not doing anything within your properties, there isn't much that you buy in using properties as compared to just exposing the field publically. I want a bit more functionality built into my properties. In the very least, I want to be able to include some change tracking. Once nice feature of the snippets is the fact that they are quite easy to modify and create your own.

To begin, we need to find where the supplied snippets are located on your disk. We can find this by clicking "Tools" and then  the "Code Snippets Manager". We can find the location by drilling into the "Code Patterns" then "Properties, Procedures, Events" and find the "Define a Property" snippet. The location window will show you where this one is located. In the default install, it will be in your c:\Program Files\Microsoft Visual Studio 9.0\Vb\Snippets\1033\common code patterns\properties and procedures\ folder. Navigate to this folder and copy the DefineAProperty.snippet. Paste it as a new file and name it whatever you want keeping the .snippet extension.

The snippet file is just a XML document. Open it with visual studio to edit it. The top is a Header which includes the description information that will show up in the snippet manager. One change you will need to make is to alter the "Shortcut" tag so that it will use the key combination you want to use to invoke your custom snippet. In my demos, I use "propertycc", thus I change the header as follows:

<Title>Define a Property with PropertyChanging</Title>
<
Author>Jim Wooley</Author>
<
Description>Defines a Property with a backing field.</Description>
<
Shortcut>Propertycc</Shortcut>

The key is to change the info in the Snippet node. In my case, I like to use a convention where the private field is the same name as the public property with the exception that it is prepended by the underscore. Thus, my field may be called _Foo and the property is called Foo. Due to this, I can eliminate the PrivateVariable node and just keep the PropertyName and PropertyType nodes.

With these changes in place, we can actually define our new generated code. This can be found in the CDATA section in the Code node. I use the following in my snippet declaration:

<![CDATA[Private _$PropertyName$ As $PropertyType$
Public Property $PropertyName$() As $PropertyType$
    Get
        Return _$PropertyName$
    End Get
    Set(ByVal value As $PropertyType$)
        If Not _$PropertyName$.Equals(value) Then
            _$PropertyName$ = value
            OnPropertyChanged("$PropertyName$")
        End If
    End Set
End Property
]]>

With this definition, any time we change the starting PropertyName, all associated values will be changed for each snippet. When we save our changed snippet and open a class libarry, we can start to use our new snippet by typing "propertycc" and the following code will be generated for us:

Private _NewProperty As String
Public Property NewProperty() As String
    Get
       
Return _NewProperty
    End Get
   
Set(ByVal value As String)
        If Not _NewProperty.Equals(value) Then
           
_NewProperty = value
            OnPropertyChanged("NewProperty")
        End If
   
End Set
End Property

Now our property has a detection as values change and we can then do something with it. In this case, we will call an OnPropertyChanged(propertyName as string) method, assuming we have defined one in our class. If we don't have one defined, we won't be able to compile our application. We have several options to provide the OnPropertyChanged method. The class could inherit from a base class implementtation. The additional complexity level may not necessary in many cases. Additionally, we could implement a concrete method in our class. This will mean a slight performance hit if we don't actually do anything in the method.

As an alternative, we can use the new partial methods in VS 2008. The great thing about partial methods is that if they are not implemented they are compiled away. Additionally, we can place the partial stub in a partial class for generated code and then put the implementing method in the other half of a partial class which is isolated to the custom business functionality. With this architecture in mind, we can define our partial method in the class with the rest of our generated code properties:

Partial Private Sub OnPropertyChanged(ByVal propertyName As String)

End Sub

In the other half of our partial class pair of files, we can implement the method as follows:

Private Sub OnPropertyChanged(ByVal propertyName As String)

RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))

End Sub

Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

If we don't need the implementation, the OnPropertyChanged method call in the property setters will be compiled away, otherwise we already have the stubs in place with our snippet in order to handle the functionality as necessary.

If you are interested in trying out this snippet, I'm attaching it to this post. Simply unzip it to your snippets directory and try it out.

Posted on - Comment
Categories: VB - VB Dev Center -

Stop using IIF

For a long time, VB has had an operator called IIF which allows you to evaluate a condition and return a true value or false value as a single line evaulation. I'm sure some of you out there have used the IIF function at some point in the past. If you're unsure, here's a quick sample piece of code.

    Console.WriteLine(IIf(x > 1, Evaluate(True), Evaluate(False)))

In this case, we evaulate the expression x > 1. If it is true, we call a method called Evaluate passing true and return that result. Here's the definition of this function:

    Private Function Evaluate(ByVal value As Boolean) As Boolean
        Debug.WriteLine("Evaluating: " & value.ToString)
    End Function

If it is false, we call the Evaluate method passing false. This evaluate method simply outputs the value and returns it. I use the method to log the output. IIf has one big problem. It evaluates both sides of the expression regardless of the result of the condition. If we run the line above setting x to 2, we get the following output:

Evaluating: True
Evaluating: False
False

As you can see, even though our condition evaluates to false, we still run the Evalute function for the true case in addition to the false case. Other than the fact that we are un-necessarily burning excess cycles to run the method needlessly, there is a deeper downside for this version. Consider if we were to increment a module level variable in the Evalute method that variable would be incremented twice rather than once for this single function. It gets worse if other functions are done inside of the evaluation.

Finally with VB 9, we will get a true ternary If operator. With this new operator, only the true or false side of the evaluation will be processed. Rather than changing the implementation of the existing IIf operator, we have a new If(condition, truePart, falsePart). Why? Because the VB team didn't want to break existing applications which relied on having both sides always evaluated. To use the revised operator, we simply need to remove an "I" as follows:

     Debug.WriteLine(If(x > 1, Evaluate(True), Evaluate(False)))

Unlike the previous example, this version only evaluates the side which agrees with the condition. If the value of x is 2, the following output results:

If (ternary):Evaluating: True
False

The result is not limited to Boolean. Because of type inference, as long as both the True and False sides of the evaluation result in the same type, the compiler can infer the type and respond appropriately. You can even return a If delegate as the result of an If evaluation. Thus you can nest complex evaulations in a functional manner.

The VB team didn't stop there with If however. They also implemented a version for nullable types which take the condition and tries to evaluate it. If the result is Nothing, the false side of the expression is evaluted. Thus in the following example, if Y is nothing, the result will be False. If Y is 1, the result outputs as True.

Debug.WriteLine(If(y > 0, False))

As a result, If(You.Uses = VB9,"UseIf","AvoidIIf")

Posted on - Comment
Categories: VB -

Playing with fire simulating extension members via Extension Methods

As I was listening to Scott Hanselman's Hanselminutes episode on LINQ to XML, he made a statement insinuating that you could add stateful behavior to objects via extension methods. As I was adding a comment stating that it was not possible, I started thinking and figured out a way. I DO NOT RECOMMEND DOING THIS. It is possible, but will not scale. That being said, here's a possible implementation to set and retrieve a MiddleName value to a Person object that does not have a middle name property defined.

DON'T DO THIS AT HOME!!! (you have been warned)

First the class definition for my person. It will have a FirstName and LastName and a read-only Guid to uniquely identify the instance. I use the following definition only for sake of example. You should not expose fields outside of your classes.

Public Class Person
    Public ReadOnly Id As Guid = Guid.NewGuid
    Public FirstName As String = ""
    Public LastName As String = ""
End Class

Next, we can create a couple extension methods. I'll use the VB syntax. Naturally, the same can be done in C# 3.0 as well. To create an extension method, we decorate a Module with the Extension attribute which resides in the System.Runtime.CompilerServices namespace.

<Extension()> _
Module Extension

We then set-up a private dictionary of values that we will set and retrieve based on the Guid exposed by the person class.

   Private _Names As New Dictionary(Of Guid, String)

The extension attribute can not be applied to a Property, thus we set up separate methods for the Set and Get portions. Each method will be an extension method as indicated by the custom attribute. The first parameter of each method will need to be the instance of the type that we are extending. Thus, we can set a value in our dictionary using the following method:

    <Extension()> _
    Public Sub SetMiddleName(ByVal instance As Person, ByVal value As String)
        If _Names.Keys.Contains(instance.Id) Then
            _Names(instance.Id) = value
        Else
            _Names.Add(instance.Id, value)
        End If
    End Sub

Likewise, we can retrieve the value from the dictionary using the following function:

    <Extension()> _
    Public Function GetMiddleName(ByVal instance As Person) As String
        If _Names.Keys.Contains(instance.Id) Then
            Return _Names(instance.Id)
        Else
            Return String.Empty
        End If
    End Function

Ok, now we are ready to consume our classes and the new extension method. We'll begin by creating a list of people that we will add the authors of our LinqInAction book.

Sub Main()
    Dim People as new List(of Person)

To this list, we can add person instances. Using the new object initializer, we can set the public fields easily. Unfortunately, we have to take a separate step to set the new extension "property":

        Dim myself As Person = New Person With {.FirstName = "Jim", .LastName = "Wooley"}
        myself.SetMiddleName("Bruce")
        people.Add(myself)

Note that although the Person type didn't have a method called SetMiddleName, we can consume it as long as the extension method is in scope. We can add the other authors and output the results as follows:

        Dim Author2 As Person = New Person With {.FirstName = "Steve", .LastName = "Eichert"}
        people.Add(Author2)

        For Each item In people
            Console.WriteLine(item.FirstName & " " & item.GetMiddleName & " " & item.LastName)
        Next
        Console.ReadKey()
    End Sub

If we run this code, the following output results:

Jim Bruce Wooley
Fabrice Unknown Marguire
Steve  Eichert

Since we pushed the values into the private dictionary in our extension class, we were able to set different values for each instance based on the ID (or you could use the GetHashCode).

Mission accomplished. What's wrong with the code? The biggest problem is that it will not scale! Since the dictionary lives for the life of the appdomain, it will constantly eat up memory as more values are set and never let go of it until your application has closed. Because of this, I'm not even going to speculate on when you might actually want to use it.

So, why did I do this? Why does any curious programmer do stuff? Because we can. Please don't use this code. If you do, don't tell anyone I told you how to do it ;-)

Posted on - Comment
Categories: VB -

LINQ to SQL Compiled Queries

As LINQ nears release, people are starting to consider the performance implications that the extra overhead brings. Currently there are two threads on this: thread1, thread2. For those that are intested in the performance implications, I highly recommend checking out the outstanding series of posts by Rico Mariani.

Ultimately if you want to get the best performance, you need to use the Compile function of the CompiledQuery class. Let's consider the following query (Note, turn this into C# by adding a semi-colon at the end if necessary):

From p In context.Products() _
            Where (p.Price >= minimumPrice) _
            Select p)

In this query, we are searching for the products that are "Expensive" in that their price exceeds a price value that we set. If we regularly consume this, we can eliminate the overhead of building the query pipeline. See the Matt Warren talk about this pipeline on the deep dive video at on Charlie Calvert's blog for more information regarding the overhead that is necessary to evaluate a query.

To compile the query, we can leverage the CompiledQuery.Compile method. This method takes an argument list as input and a result type. It returns a delegate as a variable that we will be able to consume. Thus in this case, we can pass the DataContext instance and the minimumPrice variable in. We will return a IQueryable(of Product) object. thus we can start the definition of our compiled query as follows:

VB: 
     CompiledQuery.Compile( _
         Function(context As MyDataContext, minimumPrice As Decimal) _
            From p In context.Products() _
            Where (p.Price >= minimumPrice) _
                    Select p)

C#:
     CompiledQuery.Compile(
            (MyDataContext context, decimal minimumPrice) =>
                    from p in context.Products
                    where p.Price >= minimumPrice
                    select p);

In this case we are defining our query as a Lambda function which the Compile can convert to the corresponding expression tree representation. If you are unfamiliar with Lambdas in VB, check out Timothy Ng's recent MSDN Magazine article.

With the delegate functions declared, all that is left is to actually assign them to a variable that we can consume later. To do this, we define a static/shared function which returns the Func anonymous delegate type. By defining it as a static/shared function, the compilation will only occur once per AppDomain and will remain cached through the rest of the application's lifetime. Notice, we are defining the signature of the query, not the results. We are free to change the parameter without needing to re-compile the query's structure. Here's the completed function calls in VB and C#:

Public Shared ExpensiveProducts As Func(Of MyDataContext, Decimal, IQueryable(Of Product)) = _
       CompiledQuery.Compile(Function(context As MyDataContext, minimumPrice As Decimal) _
            From p In context.Products() _
            Where (p.Price >= minimumPrice) _
            Select p)

   public static Func<MyDataContext, decimal, IQueryable<Product>>
         ExpensiveProducts =
           
 CompiledQuery.Compile((MyDataContext context, decimal minimumPrice) =>
                    from p in context.Products
                    where p.Price >= minimumPrice
                    select p);

The syntax for using the compiled query takes a bit of thinking to get your head around. We are essentially creating a function which returns a function rather than returning a value. If you're familiar with functional programming such as OCaml and F#, this concept should be easy to grok. For the rest of us, piece out the individual method components as laid out above and you should be able to understand it after a while ;-)

To consume our new function, we simply instantiate a DataContext instance and pass it along with the minimumPrice we want to set as our minimum value.

  Dim context As New MyContext(My.Settings.MyConnectionString)
  Dim Items = ExpensiveProducts(context, minimumPrice)

Posted on - Comment
Categories: LINQ - VB - C# -

Use the new LINQ Contains extension method for the SQL IN clause

For a while, users were requesting a way to map the SQL "IN" clause as in the following:


SELECT Customer.Name
FROM Customer
WHERE Customer.State IN ('GA', 'FL', 'AL')

Prior to Beta 2, this would mean either separate OR clauses for each item, or worse yet a heterogeneous join between the database and an in memory array. Why do I say, worse yet? Because the heterogeneous join option meant bringing all of the records from the database and filtering on the client.

Beta 2 introduced a new "Contains" extension method which converts to the TSQL "IN" clause. Below is an example that I put together for one of my first production apps that is already live.

In this case, I fetch a list of items that the user has selected in a CheckBoxList and use the values from that for my IN clause. The selected items are declared as follows:

Dim channels = From channel As ListItem In Me.CheckBoxList1.Items _
               Where channel.Selected _
               Select CStr(channel.Value)

Next, we need to set-up a lambda expression that will serve as a filtered table set in my join clause.

Dim companies = dc.Companies.Where(Function(c As Company) channels.Contains(c.Channel))

Here I am identifying an IQuerable<Company> which consists of the company table filtered by the declared function. In case this syntax is new to you, the "Function" clause is VB's implementation of a Lambda expression. I'll post more on this soon. Basically, the function states that, given a company that we will call "c", return true if the channels collection contains the channel for this company.

Because of the IQuerable composability, we can then leverage this object as part of a larger query as follows:


Dim users As IEnumerable(Of String) = From user In dc.Users _
   Join company In companies On user.CompanyId Equals company.CompanyId _
   Order By user.UserName _
   Select user.UserName Distinct

Here's the great part. When we look at the generated SQL, not only is the Contains expression translated into the IN clause, but the separate portions of the query are pieced together into a single query. Take a look:

SELECT DISTINCT [t0].[UserName]
FROM [dbo].[User] AS [t0] INNER JOIN 
     [dbo].[Company] AS [t1] ON [t0].[CompanyId] = [t1].[CompanyId]
WHERE (CONVERT(NVarChar(MAX),[t1].[Channel])) IN (@p0, @p1)

Notice also, the VB team has added a number of query expressions that are not available in C#. This query uses the Distinct expression at the end of the select clause which is likewise translated directly as part of the TSQL select statement. You no longer have to call the .Distinct method on the query to get the desired results, it is now a native query expression.

Ah, feel the VB love...

Posted on - Comment
Categories: LINQ - VB -

Option Infer in VB

With the upcoming language enhancements in VB and C#, some leads are concerned with code maintainability when not explicitly declaring the resulting type on an anonymous type. If you are not familiar with local variable type inference, here are a couple examples:

VB:

dim i = 5

dim j = "foo"

C#:

var i = 5;

var j = "foo";

In both cases, the first variable (i) is inferred as an integer and the second is inferred as a string. In some cases, particularly in a RAD environment, we want to view object results without needing to declare a specific type for each desired result set.

In some cases, relying on inferred types makes code maintainability more difficult. Although the type may be easily understandable when the code is first written, groking it when you have to revisit the code in a year could cause more time than it would have taken to explicitly declare it in the first place. To assist with this, a new Option declaration has been added to help "force" the developers to declare the type if you prefer. In this case, you would probably want to make the following declaration:

Option Strict On
Option Explicit On
Option Infer Off

With this, you will be forced to declare your type. By default Option Infer will be On for new projects and Off for existing projects.

One word of warning. If you specify Option Infer off and Option Strict Off, your objects will be automatically inferred as Object. For instances of type Object, rather than using extension methods, VB will try to call the method via reflection. In that case, if you try to apply an extension method (like "Take"), you can likely get a runtime exception rather than compile time check. This is easily fixable by requiring Option Strict On along with Option Infer Off which will force you to declare your type (other than object) and allow the compiler to match up the proper extension method.

I realize there are plenty of cases where Option Infer needs to be turned on, particularly in the case of using Anonymous types, but at least we have the ability to turn it on only when it is essential.

Posted on - Comment
Categories: VB -

Changed order of LINQ operators for VB 9

With the March Orcas CTP, the order of operations has changed for VB LINQ Queries again. No, they have NOT moved Select back to the beginning. In this case, they have moved the Order By clause before the Select. In case you prefer a bit of code consider the following:

May 2006 CTP:
dim res = From fi in New System.IO.DirectoryInfo("C:\").GetFiles() _
Select fi _
Order By LastAccessTime

March 2007 CTP:
dim res = From fi in NEw System.IO.DirectoryInfo("C:\").GetFiles() _
Order By fi.LastAccessTime _
Select fi

Although it seems that this is simply just a reordering, when we consider scope, this change was crutial. In the older version, in order to order the results, we were forced to include the target column in the resultset (Select). By moving the Order by clause up, we can apply the ordering and not require the field to be included as part of the result set. This is key if you are dealing with a public api which doesn't expose the field you want the results to be sorted on. In addition, I found that in some cases the TSQL mapping differed between the VB and C# implementation due to the older placement of the select and order by clauses.

Unfortunately this change means that my test code will need to be manually updated. Ah the joys of working on the bleeding edge. Yet another reason why you shouldn't be developing production applications on the code base (yet).

Posted on - Comment
Categories: VB - LINQ -

Querying Winforms with LINQ

A couple of months ago, someone asked on one of the forums how you could dynamically switch a control from a textbox to a label based on the editability of the record based on business requirements. The best solution was to change properties on the textboxes to make them look like labels. Below is a quick method to do this:

Private Sub SwitchControl(ByVal box As TextBox)
If box.ReadOnly Then
box.BorderStyle = BorderStyle.Fixed3D
Else
box.BorderStyle = BorderStyle.None
End If
box.ReadOnly = Not box.ReadOnly
End Sub

From here, we need to process all of the controls to make this change to the textboxes (but skip the other controls as they may not implement some of the methods used here, particularly .ReadOnly. Thus the standard code would do something like the following:

For Each ctl As Control In Me.Controls
If TypeOf ctl Is TextBox Then
SwitchControl(DirectCast(ctl, TextBox))
End If
Next

The question was recently raised if you can query the actual page model with winform development using LINQ. This can be done with the MAY CTP of LINQ by leveraging the Cast and OfType extension methods as follows:

Dim textboxes As IEnumerable(Of TextBox) = _
From c In Me.Controls.Cast(Of Control).OfType(Of TextBox)() _
Select c

For Each box As TextBox In textboxes
SwitchControl(box)
Next

In the LINQ example, we need to do a bit of extra casting (using Cast<T> because the ControlCollection class does not directly implement IEnumerable<T>. Once we have it converted into the generic enumerator, we can apply the rest of the standard query operators. In this case, instead of using "Where TypeOf c Is TextBox", we can leverage the .OfType<T> extension method to only yield the controls which we want to manipulate. Note in the LINQ example, we don't have to worry about the cast during the iteration as we have already done it in the generics before.

For those of you who are interested, I did some simple performance testing using a form with 100 textboxes and 30 checkboxes. Both methods performed equally as well. I did not see any significant performance difference between the two methods. That being the case, choosing which mechanism you would want to use would be up to your personal preference. I do suspect that if the ControlCollection natively supported IEnumerable(of Control), the LINQ version would outperform the older machismo due to the ability to leverage the generic support and avoid the casting. This is a relatively simple implementation, but hopefully helps to demonstrate some different functionality you might not have thought of using which LINQ allows.

Posted on - Comment
Categories: VB - LINQ -

Single Instance Winform in Citrix published application

About a year ago I one of the first blog posts I wrote related to Single Instance Winform applications. While these are much easier to do with VB 2005, I didn't expect to run into issues with it after it was working fine for a year. In our production environment, my current company uses Citrix with Terminal Services to serve the desktop to all users. We have one application which we wanted to serve out as a published application. We set it up and it appeared to work fine. As deployments go, it worked fine until an end user got their hands on it.

Citrix requires a low latency connection in order to keep the connection active. If a user's connection is erratic, they Citrix will sense that they are disconnected and drop the session to the end user. Their session is kept active on the server however. This causes the first instance to continue running on the server even though it is not running on the client. Normally, a user would just be able to log back into their existing session.

Unknown to me, our network support changed the Citrix configuration to only allow one instance of an application to be running at a time. Normally, this would be fine. However, if you are using a single instance Winform application, the single instance is not truly what happens under the covers. To avoid rehashing the previous post, I will simply state here that a second instance of the application is temporarily initiated and sends notification to the first instance that it is being started again and then closes the second instance bringing the first instance back to the foreground. Unfortunately, since the Citrix published application was set to only allow for a single instance of the application, the second temporary instance was blocked and the user was notified that they couldn't log in again (even if they were just trying to re-establish a dropped session).

Long story short. If you are using Single Instance Winform applications in VB 2005, don't enable the allow single instance for a published application instance in Citrix as well. I only lucked upon the solution to this one this time. Hopefully, this post can help someone out there suffering from the same issue.

Posted on - Comment
Categories: VB -

ASP Security is more than just SQL Injection

Last night's Atlanta Microsoft Database Forum meeting had another discussion of SQL Injection and how it is a bad thing. In the end, the best thing to do to avoid it is to use parameterized queries (which include, but are not limited to Stored procedures). In short, if you write your data access code in your application like the following, you are prime for an attack:

dim stSql as string = "select * from users where userid='" & Request("UserId") & "'"

Instead, take a little more care and use the following (please pardon any typo's as CS's intellisense is not working at the moment ;-):

dim cmd as SqlCommand = cn.CreateCommand()
cmd.CommandText = "select * from users where userid=@userid"
cmd.Parameters.AddWithValue("@userid", Request("UserId"))

This takes care of the issue of SQL injection. Naturally, if you take a parameter into a stored procedure which uses SP_ExecuteSQL internally, you are still owned. Regardless, avoiding SQL injection is just the tip of the iceberg.

If you are not validating your input values to only accept valid values (don't waste your time trying to filter out the wrong values as you will likely miss somthing like unicode encoding/decoding issues), you are still suspect to cross-site scripting attacks and the like.

For a quick video of what can be done, I strongly recommend you check out Rocky Heckmann's Assembly Hijacking Attack screen cast. It's only about 20 minutes and he goes as far as showing how to replace a server side dll. It's one of the best security video's I've seen so far.

Posted on - Comment
Categories: LINQ - VB -

LINQ Webcast online

Last month, WROX press recorded several of the sessions at the Atlanta Code Camp, including mine on how the language changes in VB 9 and C# 3 lead to LINQ. If you missed the talk, you can now watch it online at http://www.wrox.com/WileyCDA/Section/id-291776.html. I haven't had a chance to watch the whole thing yet, but from what I saw so far it looks like they did a pretty good job with it, including indexing the talk. Check it out and let me know what you think.

Posted on - Comment
Categories: LINQ - VB -

LINQ over Datasets or the Bang is back in VB9

One of the features that was added to the May CTP of LINQ was the ability to query over DataSets. There are some minimal methods of manipulating data in existing implementations of the DataSet, including filtering with DataViews, the .Filter method and using DataTable.Select(). If you wanted to work with multiple tables, you needed to use a DataViewManager object. The overview of these options is online on Msdn.

One of the new features of the May CTP of LINQ includes the ability to create queries directly against datasets, including multiple datatables. The preview includes 2 white papers on the subject, one for VB and the other for C#. In order to work with LINQ with datasets, you need to populate the dataset as normal. Assuming you have a dataset (ds) with 2 datatables, Orders and Customers, fill them as usual using the ds.Fill method.

Once you have the data in memory, querying it is a relatively simple task. The first hurdle overcome is the fact that the DataTable does not implement IEnumerable<T>. To solve this, use the .ToQueryable() method as follows on each datatable:

Dim customers = ds.Tables("Customer").ToQueryable()

Dim orders = ds.Tables("Orders").ToQueryable()

Now that we have the results, we should be able to use the standard LINQ querying methods to get a resultset. We can now do the following:

Dim results = From e In Employees _
Select New {FirstName := e.Field(Of String)("FirstName"), _
LastName := e.field(Of String)("LastName")}

In this case we are still dealing with a weakly typed fields collection. (Support does exist for strongly typed datasets, but that's the subject of another post). As a result, we query the field property of the datarow. The field is a generic type which handles the type casting for us. The above code is in essence the same between VB and C#.

As it did with XLINQ, the VB team has included another syntax option for us to simplify the above expression. By returning to the syntax from DAO, we can simplify the .Field("FieldName") syntax to a simple "!" (often referred to as a bang). Thus the above query can be re-written as follows:

Dim results = From e In Employees _
Select New {FirstName := e!FirstName, _
LastName := e!LastName}

While the syntax is indeed simpler, and has precedence from VB prior to .Net, I'm not sure it is a step a forward in the goal of making VB a more English like language rather than using symbolic representations typical of c#. Interestingly, the C# implementation is not implementing the Bang syntax, instead preferring the more verbose .Field<T> syntax. In addition, be aware that the bang syntax still uses late binding as it is just syntactic sugar for the .Fields method.

Do you think VB should bring the bang back? Let me know, or better yet. Tell the team in the LINQ forums.

Posted on - Comment
Categories: LINQ - VB -

LINQ to XML Rocks Because

I’m in the process of finalizing a number of presentations on LINQ. I will be posting the demos and slides soon. As a teaser, here’s a quick snippet from the XLinq demo. I begin by showing the new functional construction syntax for XLINQ.

'Uses Functional Construction
Dim x As New XElement("LinqEssentials", _
New XElement("Category", "LINQ"), _
New XElement("Category", "DLINQ"), _
New XElement("Category", "XLINQ"))
Dim y As New XElement("LanguageFeatures")
y.Add(New XElement("release", New XAttribute("version", "2.0"), _
New XElement("feature", "Generics"), _
New XElement("feature", "Iterators"), _
New XElement("feature", "Anonymous Delegates"), _
New XElement("feature", "Nullable Types") _
))
y.Add(New XElement("release", New XAttribute("version", "3.0"), _
New XElement("feature", "Implicit Types"), _
New XElement("feature", "Extension methods"), _
New XElement("feature", "Lambda Expressions"), _
New XElement("feature", "Object initializers"), _
New XElement("feature", "Anonymous Types"), _
New XElement("feature", "Expression Trees") _
))
y.Add(New XElement("release", New XAttribute("version", "9.0"), _
New XElement("feature", "dynamic interfaces"), _
New XElement("feature", "dynamic identifiers"), _
New XElement("feature", "XML Literals") _
))
Dim z As New XElement("XLinqRocksBecause")
z.Add(x)
z.Add(y)

Debug.Write(z)

While it is elegant and lets you work more directly with the document structure, the c# method is not quite as cool as the VB one. In the demo, I run the first code snippet, then copy the output from the debug.write method which sends out the XML nicely formatted. Then you create a new variable and paste in the output from the debug.write call as follows:

Dim x = <VBXLinqRocksBecause onDate=<%= Today %>>
    <LinqEssentials>
        <Category>LINQ</Category> 
        <Category>DLINQ</Category> 
        <Category>XLINQ</Category> 
    </LinqEssentials> 
    <LanguageFeatures> 
        <release version="7.0"> 
            <feature>Generics</feature> 
            <feature>Iterators</feature> 
            <feature>Anonymous Delegates</feature> 
            <feature>Nullable Types</feature> 
        </release> 
        <release version="8.0"> 
            <feature>Implicit Types</feature> 
            <feature>Extension methods</feature> 
            <feature>Lambda Expressions</feature> 
            <feature>Object initializers</feature> 
            <feature>Anonymous Types</feature> 
            <feature>Expression Trees</feature> 
        </release> 
        <release version="9.0"> 
            <feature>dynamic interfaces</feature> 
            <feature>dynamic identifiers</feature> 
            <feature>XML Literals</feature> 
        </release> 
    </LanguageFeatures> 
</VBXLinqRocksBecause> 

Notice, there are no quotes around any of this. Accessing an element can be as simple as the following (note, you will need to turn Option Strict OFF for this one to work).:

Console.WriteLine(CStr(x.@onDate)

While I think LINQ and XLINQ are cool, I must applaud the VB/XML/DATA teams for their efforts on this one. Finally XML in VB ROCKS!

If you want to learn more, head on over to the LINQ center on MSDN, or come to my talks at the Alabama Code Camp, Atlanta Dotnet User Group, or Atlanta Code Camp over the next few weeks.

Posted on - Comment
Categories: Linq to XML - VB -

Rounding in .Net

A while back I was stung by the rounding "bug" and forgot to blog about it.

I was unaware of the fact that Round by default uses accounting rounding where you round to the nearest EVEN value. Thus round(1.5,0)=2 and round(0.5,0) = 0. Although this agrees with the ISO standard, it does not agree with the behavior we are taught to expect in elementary math, nor does it agree with the functionality of .ToString where 0.5.ToString("n0") = "1". This discrepancy can cause your displayed values not to agree with the calculated values if you have interim calculations. For instance, if you show the values of each order item using .ToString("n2") but sum your values with Math.Round(val,2). If you want to use the more expected rounding function, you need to explicitly add the overload for MidpointRounding. I put together a small console app to demonstrate.

Sub Main
Console.WriteLine("round(1.5,0)=" & Math.Round(1.5, 0).ToString)
Console.WriteLine("round(0.5,0)=" & Math.Round(0.5, 0).ToString)
Console.WriteLine("round(0.5,0,AwayFromZero)=" & Math.Round(0.5, 0, MidpointRounding.AwayFromZero).ToString)
Console.WriteLine("round(1.5,0).ToString=" & 1.5.ToString("n0"))
Console.WriteLine("round(0.5,0).ToString=" & 0.5.ToString("n0"))
Console.ReadLine()
End Sub

This code has the following results.

round(1.5,0)=2
round(0.5,0)=0
round(0.5,0,AwayFromZero)=1
round(1.5,0).ToString=2
round(0.5,0).ToString=1

Note the second line where .5 rounds to 0 not 1. The third line is more expected and agrees with the .ToString implementation. It is a hastle explicitly adding the MidpointRounding parameter, but a necessary evil I suppose.

Posted on - Comment
Categories: VB -

ERL in VB.Net

A while back I posted that the ERL function is still available in Vb.Net. I was prompted to re-look at the code from a recent newsgroup post and realized that, while it is possible to use ERL, there is a definite performance penalty. Consider the original sample as below:

10: REM This program doesn't do much
20: Try
30: REM Throw an error
40: Throw New DivideByZeroException
50: Catch ex As DivideByZeroException
60: Console.WriteLine("Error occured in line: " & Erl())
70: End Try
80: Console.ReadLine()

Using Lutz Roeder's excellent reflector, we can see that the VB compiler does some changes behind the scene. Here is the code as decompiled from the IL:

Dim num1 As Integer = 10
num1 = 20
Try
num1 = 30
num1 = 40
Throw New DivideByZeroException
Catch exception2 As DivideByZeroException
ProjectData.SetProjectError(exception2, num1)
Dim exception1 As DivideByZeroException = exception2
num1 = 60
Console.WriteLine(("Error occured in line: " & Conversions.ToString(Information.Erl)))
num1 = 70
ProjectData.ClearProjectError
End Try
num1 = 80
Console.ReadLine

It becomes obvious that the VB compiler is adding a tracking variable (num1) and updating it similar to a trace.write method. I highlighted the original code segments using an old Commodore 64 color scheme. There is additional overhead as well to push the line number into a storage mechanism for ERL to be able to grab it as displayed by the highlighted code segments.

Conclusion: while it is possible to use ERL, there are often better ways of achieving the same result, most notably a well designed tracing mechanism with trace level switches.

Posted on - Comment
Categories: VB -

Change VB9 to B Sharp

Over on the MSDN Forums, there is a post pondering changing the name of VB.Net to B# (see: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=301770&SiteID=1). Here's my tongue-in-cheek take.

As a programmer and musician, there is a problem with B#. In music (or at least on the keyboard) B#=C. Even if we go with the idea that such a change would put B# on the same level as C, we would still be behind the times in languages (we would need B++ and B## or Bx (x=double sharp) to get to the same level as C# version wise.

Maybe we should go with Bb (or B-flat) as most elementary musicians are more used to playing Bb than B# (or for brass players B-Natural even). Downside here is Bb is lower than B, thus it doesn't sound like an improvement.

Maybe the best option is to move beyond B or C and go for the next letter: Visual Delphi (or VD)... Then again, maybe not in more ways than one.

Posted on - Comment
Categories: VB -

Decimal.TryParse with Currency input values

I found an issue (or rather the issue recently found me) concerning my advice advocating using Decimal.TryParse on currency items. It turns out if you use the base implementation of Decimal.TryParse, it will not work when presented with currency values by default. Instead, you need to use the overload and specify the NumberStyle explicitly as below:

Dim res As Decimal

If Decimal.TryParse("$1.00", Globalization.NumberStyles.Currency, Nothing, res) Then

Console.WriteLine(res.ToString)

Else

Console.WriteLine("Parse failed")

End If

Console.ReadKey()

Posted on - Comment
Categories: VB -

DataGridView binding with abstract base classes

I recently ran into one of the most frustrating issues to face someone debugging a released application: a bug which only appears intermittently. In the instance, I have a collection of business objects that are being bound to a DataGridView. Periodically, the grid would throw repeated TargetInvocationExceptions when being bound.

In my case, the collection contained both objects directly implementing a base class and other objects inheriting from the base class and extending upon it. I found that if the first item in the list was in instance of the base class, the grid would render correctly. However, if the first item was a special instance type inheriting from this base class, the DataGridView would bomb out. I suspected the framework infers the type of the first object and tries to cast any subsequent objects to this specific type. It does not fall back to a base class type.

I confirmed my suspicions by testing a collection of objects inheriting from an abstract base class. In the code below, I’m using an abstract base class of Animal. From this, I have two implementing classes: Dog and Cat.

Public MustInherit Class Animal

Private _numFeet As Integer

Private _name As String

Public Property numFeet() As Integer

Get

Return _numFeet

End Get

Set(ByVal value As Integer)

_numFeet = value

End Set

End Property

Public Property Name() As String

Get

Return _name

End Get

Set(ByVal value As String)

_name = value

End Set

End Property

Public Overridable ReadOnly Property PetType() As String

Get

Return "Unknown"

End Get

End Property

Public Sub New()

End Sub

Public Sub New(ByVal petName As String, ByVal numFeet As Integer)

_name = petName

_numFeet = numFeet

End Sub

End Class

Public Class Dog

Inherits Animal

Public Sub New(ByVal petName As String, ByVal numFeet As Integer)

MyBase.New(petName, numFeet)

End Sub

Public Overrides ReadOnly Property PetType() As String

Get

Return "Dog"

End Get

End Property

End Class

Public Class Cat

Inherits Animal

Public Sub New(ByVal petName As String, ByVal numFeet As Integer)

MyBase.New(petName, numFeet)

End Sub

Public Overrides ReadOnly Property PetType() As String

Get

Return "Cat"

End Get

End Property

End Class

I then created a collection of “animals” as follows:

Public Class PetList

Inherits CollectionBase

Implements System.ComponentModel.IBindingList

Public Sub Add(ByVal pet As Animal)

List.Add(pet)

End Sub

#Region " IBindingList Implementation "

‘Implementation omitted for brevity. This must be implemented for binding purposes

#End Region

End Class

The form implementation is rather simple. Add a DataGridView to the form and the following code on the Form Load event:

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim animalList As New PetList

animalList.Add(New Cat("Fluffy", 4))

animalList.Add(New Dog("Woofie", 4))

Me.PetCollectionBindingSource.DataSource = DirectCast(animalList, System.ComponentModel.IBindingList)

End Sub

By default, this code should error when rendering the second pet, the Dog, because it can’t cast Dog as a Cat, rather than trying to cast Dog and Cat as Animal. To fix the problem, you need to strongly type the collection. I have found 3 workarounds to solve the problem.

1) Replace the PetList with a collection that from System.ComponentModel.BindingList(Of Animal)

2) Use a strongly typed Item accessor as follows:
Public ReadOnly Property Item(ByVal index As Integer) As Animal
Get
Return Me.InnerList.Item(index)
End Get
End Property

3) Implement System.ComponentModel.ITypedList as follows:
Public Function GetItemProperties(ByVal listAccessors() As System.ComponentModel.PropertyDescriptor) As System.ComponentModel.PropertyDescriptorCollection Implements System.ComponentModel.ITypedList.GetItemProperties

Return System.ComponentModel.TypeDescriptor.GetProperties(GetType(Animal))

End Function

Public Function GetListName(ByVal listAccessors() As System.ComponentModel.PropertyDescriptor) As String Implements System.ComponentModel.ITypedList.GetListName

Return "Animal"

End Function

Hopefully if you have run into this insidious error, the above information can help. Also, feel free to vote on this item at the feedback center: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=7849a669-fe1e-469d-b02e-b36f3191c65d. I have included a sample application in that feedback item as well since I can’t upload sample projects to this blog at the moment.

Posted on - Comment
Categories: VB -

Advantage of TryParse

I recently had the opportunity of showing the Altanta VB group the advantages of using the new TryParse method introduced in .Net 2.0. The presentation materials along with a sample project are available at the group's website.

In early versions of .Net, in order to check the validity of a data type, you had to go to some excess measures. There are a number of options:

1) Don't check the data. The user wouldn't be silly enough to try to type their name in a date field, or would they. Oh, they typed "1=0'drop table employees" in the order number field... oh well. I'll try casting it anyway. What do you mean InvalidCastException thrown? Seriously, if you consider this an option, you need to be working in another field.

2) As an alternative, you can try to cast the value into the desired data type (ex. Integer.Parse(MyValue)). The downside to this option is the fact that you need to wrap the parse inside of Try..Catch block. This option may be viable if you are not processing millions of values and require any performance, or if the use of an invalid data type is indeed an exceptional case. If dealing with user entered values, it is better to assume that the user is NOT going to enter the expected values and thus an invalid user entry is not an exceptional situation. As I will demonstrate shortly, the performance of this option is reasonable when a valid value is entered, but astoundingly unacceptable when an invalid value is entered (eg. trying to cast "a" as an Integer).

3) Use the VB IsNumeric or IsDate methods to check your values prior to working with them. This gives a level of protection. You can still get overflow exceptions and other potential problems. In addition, the VB 1.x internally uses the above method of simply wrapping an attempt to parse within a try catch block. The 2.0 implementation uses the prefered method of TryParse internally. There is a small performance penalty using this wrapper, but the main performance penalty is caused by a double casting of the value that is required if you want to test the value and then set it. Here is a sample implementation using IsNumeric:

Dim MyTestValue as String = "A"
Dim MyWorkValue as Integer
If IsNumeric(MyTestValue)
MyWorkValue = Integer.Parse(MyTestValue)
End If

The real issue here is the internal implementation of IsNumeric on 2.0 as seen below

If Dim text1 As String = TryCast(Expression,String)
If (Not text1 Is Nothing) Then
Dim int1 As Integer
Return Conversions.TryParseInteger(text1, int1)
'Note, we just throw away the result of int1
End If
End If
Return False

Here, you can see that the value is parsed interally, but the resulting value is just thrown away. Why not simply use the TryParse method directly as follows:

Dim MyTestValue as String = "A"
Dim MyWorkValue as Integer

If Integer.TryParse(MyTestValue, MyWorkValue) then

'do the processing of the value

End If

Because MyWorkValue is passed ByRef, the value is set to the parsed version and you can work with it. If the parse does not succeed, the value is left at it's previous value and you can save cycles by not having to worry about processing values if it is not a valid value anyway. A comparison of the various options clearly show that TryParse is the best option. My sample test rig show the following results:

Success
Failure

Type.Parse
2487
260655

IsNumeric
5563
3739

Integer.TryParse
2054
2441

I encourage you to test these results yourself. Feel free to download my samples and let me know any errors or ommissions I made.

Posted on - Comment
Categories: VB -

VB.ReallyOld features still in VB.Net

While typing some code, I noticed that REM is still supported as a way to comment code. The only reason I can see why one would want to do this is to retain legacy code. There are some other really old features that haven't been documented since VB3, most notably the useful ERL() function. (It is back in the official documentation as well.) This means the following is valid VB.Net code:

10: REM This program doesn't do much
20: Try
30: REM Throw an error
40: Throw New DivideByZeroException
50: Catch ex As DivideByZeroException
60: Console.WriteLine("Error occurred in line: " & Erl())
70: End Try
80: Console.ReadLine()

The output is:

Error occurred in line: 40

The great thing about this, is that the line number is retained in a release build. I don't recommend using this globally in your applications as there is a performance hit (along with application bloat) but it is useful in selected circumstances. Naturally using the trace methods would be a better option.

Posted on - Comment
Categories: VB -

Disposing a user control within a DataGridViewComboBoxColumn

By default, User controls dispose of all of the controls as part of their cleanup process. However, when using a DataGridViweComboBoxColumn, the column is still bound to the data source. While disposing you can encounter multiple exceptions as the values in each bound ComboBox cell is disposed if the ComboBox's datasource is disposed prior to the grid's binding source. To avoid this issue, make sure to force your BindingSource that the data grid is bound to to Nothing/Null at the beginning of the control's Dispose method. Below is a code excerpt.

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
Me.MyGridViewBindingSource.DataSource = Nothing
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub

Note the third line. If this line is missing, the dispose of the datasources and the DataGridViewComboBoxColumn may not unbind in the correct order and thus raise unexpected exceptions. Remember that the Dispose is now in the hidden .Designer file. Naturally, this advice applies to VS2005 winforms.

Posted on - Comment
Categories: VB -

Property as string Nullable by default

It appears that the string parameter of a method is Nullable by default under 2.0. I am having cases where my UI using the new object binding is returning Nothing to a property Set declared as below:

Public Property MyValue() as String

Set(ByVal value as string)

'value may be Nothing/Null here rather than an empty string

End Set

...

End Property

Thus any action you take on the value will need to check for nothing first (including Trim, ToUpper, etc). This is particularly problematic when binding to comboboxes which allow for no selection. In 1.0/1.1 no selection allowed for an empty string. 2.0 returns a null string.

Posted on - Comment
Categories: VB -

Accessing Private methods via reflection

At a recent Atlanta VB Study Group meeting, the topic of Reflection was presented. As part of the discussion, I mentioned that it is possible to call private methods from external classes. Unfortunately I stumbled briefly trying to demonstrate how to accomplish this. In the meeting, I attempted to modify the existing code. Below are the appropriate code snippets for demonstration purposes.

  Public Class MyClass
    Private Sub YouCantSeeMe()
      MessageBox.Show("You shouldn't be here.")
    End Sub
  End Class


  Public Class MyImplementer
    Public Sub Main()
      Dim obj As New MyClass

        'Get a reference to the type of the object we can reflect on
        Dim t As Type = GetType(MyClass)

        'Get a handle on the method in question
        'The next line doesn't work. See below for the correction
        Dim mi As MethodInfo = t.GetMethod("YouCantSeeMe", _
            BindingFlags.NonPublic + BindingFlags.Instance)

        'Call the method
        mi.Invoke(obj, Nothing)
    End Sub
  End Class

We weren't too far off. The key was we used the wrong operator to combine the binding flags. Instead of Anding (+) them, we should have ORed them. If we modify the mi instantiation line as below, we can successfully call into the private method from an external class, thereby breaking our object's encapsulation.

       Dim mi As MethodInfo = t.GetMethod("YouCantSeeMe", _
            BindingFlags.NonPublic OR BindingFlags.Instance)
Posted on - Comment
Categories: VB -

Single Instance Winform Issue

In the simplest terms, a single instance application is an application which will only display one copy to a user at any time. This can be simply accomplished by a calling application by checking to see if a process is already running. The System.Diagnostics.Process namespace offers a number of ways of getting a handle on an existing process, including GetProcessByName("ProcessName"), GetProcessById(MyId), and GetProcesses(). Once you have a handle on it, you can inquire about the process's status, Close it (CloseMainWindow) or terminate it (Kill). Unfortunately, or perhaps fortunately from a security perspective, you can not interact with the running process natively. Additionally, acquiring the correct process can be problematic when using XP fast user switching or Terminal Services in which multiple users can be running their own instance of an application on the same machine. Simply killing a process could be dangerous if you don't acquire the correct instance and thus could terminate an instance of a process another user is using.

In addition to the single instance requirement, the desired behavior is to have a running instance respond to outside requests. Simply put, MyApplication should to be able to DoSomething when TheirApplication tells it to. A common example would be Internet Explorer, which opens a new web site in an already open instance when clicking on a url from another application. Using ActiveX Executables made grabbing a running process and calling methods in it easy using CreateObject. Even better, CreateObject worked fine with Terminal Server giving the instance from the current user's environment.

With the release of .Net, Microsoft removed the concept of the ActiveX Exe. Unless you know the correct keywords to search on, finding a solution is not easy. After much searching, I decided to try looking under the covers of Whidbey (using Lutz Roder's Reflector) to try to identify Microsoft's solution for SingleInstance in Whidbey. I soon decided against pursuing this as I didn't want to try to reverse engineer Generics. (More on the Widbey implementation will come later).

The reflecting exercise did lead me to a number of samples by searching on SingleInstance, in particular a sample on CodeProject by Reto Ravasio peaked my interest. I took the liberty of re-writing his C# sample into VB.Net which is available here. The core concepts are as follows:

  1. Try to start the application.
  2. Try to get a Mutex for the application's thread.
  3. Check the CreatedNew parameter of the Mutex's constructor to determine if this is the first instance (for this user), if it is then:
    1. Create a new TCP channel passing 0 as a parameter to get an available channel, and open this as a remoting listener for subsequent requests.
    2. Register this channel into HKeyCurrentUser so that future requests from this user will get routed to the correct remoting instance.
    3. Hand off execution to your main form and let it process the command line args as necessary using Environment.GetCommandLineArgs()
  4. If this is not the first instance then:
    1. Get the previously entered channel from HKeyCurrentUser
    2. Hook into the remoted instance with Activator.GetObject
    3. Invoke the exposed method (ActivateInstance) passing it the current commandline arguments as a parameter
    4. The first instance will respond via it's handling of the InstanceActivate event.
    5. Kill the second instance.

Stepping through the code in EndInit in the sample will show both processes identified above. Special care needs to be taken in using the combination of technologies mentioned above, specifically Remoting, and Registry access which both require special Code Access Security handling.

Additionally, a minimum of 3 threads need to be synchronized when a second instance calls into the first: the thread the first instance of the form was created in, the thread of the remoting channel and the thread of the temporary second instance. To demonstrate this, place breakpoints on the following lines:

  1. The RaiseEvent InstanceActivate(Me, e) on SingleInstance.OnInstanceActivate (will be on the Remoting channel's event).
  2. The first line of ShowNewLabel on Form1
  3. The OnInstanceShutdown line of EndInit

Start the first instance through the VS IDE. Using the command line, start a second instance of the tester executable passing in the following parameter: "error". When the first breakpoint is hit, attach to the second instance of Form1 using Debug|Processes, find the non-shaded copy of the Tester process and click Attach. (You can't attach to the process prior to this point when running the program from the command line. Step through the code watching the thread window (Debug|Windows|Threads) and you will see 3 distinct thread ID's used.

Special care needs to be taken with these threads. Among the pitfalls, adding a control to a form from an outside thread will cause an exception. The sample application handles this issue by utilizing the special MethodInvoker delegate of the form using the Me.Invoke(Me.MethodInvokerDelegate) to make an outside method call execute on the form's thread (ME) rather than the calling thread. To assist, you can check the form's InvokeRequired property (not visible with intellisense) to see if the MethodInvoker is required.

SingleInstance in VB.Net 2.0

Life becomes much simpler with VB.Net 2.0. Actually it is as simple as opening the winform project property window and checking the SingleInstance option. The executable will automatically become single instance without any additional custom code. (A sample project is included in the linked download in the SingleInstance05 directory).

In order to handle the command line args that are passed in on a second instance, some additional code will be necessary. First, you click the option to show all files. Next, drill into the My Project node through Application.myapp into Application.Designer.vb. From here, add the following method:

Private Sub MyApplication_StartupNextInstance(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
If TypeOf Me.MainForm Is Form1 Then
Dim Args(e.CommandLine.Count) As String
e.CommandLine.CopyTo(Args, 0) DirectCast(Me.MainForm, Form1).showArgs(Args)
End If
End Sub

The Form1 can then handle the args from a method with the following signature:
Friend Sub showArgs(ByVal e As String())

If you are interested in digging under the covers, use Reflector and drill into the following method: Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run. (This namespace changed between beta 1 and beta 2 and may change once the final version is released.) A quick investigation of the framework code vindicates the use of the Mutex and remoting. Additionally, notice the explicit permissions assertions to handle Code Access Security concerns. Interestingly, the cross threading issue seems to be automatically handled.

For those C# people out there, Pedro Silva has a blog entry detailing how to take advantage of the SingleInstance functionality otherwise available only in VB.

The number of technologies necessary to do such a simple thing as have an already running application "do something" when called by an external application is somewhat bewildering. Things will become much simpler with VB.Net 2.0, but one must wonder if simpler options exist. I'm still open to other options if anyone has a better recommendation.

Posted on - Comment
Categories: VB -