Friday, June 27, 2008

Use a Web.Config connection string in your Data Access Layer with LINQ To SQL

My applications have the Business and Data Access Layers in a separate DLL from the presentation. This makes it so that everything that wants to do a certain function uses the same library. I also like to pre-compile my web sites which means that I can't get at the app.config if I need to make changes to the connection string (moving around dev, test, prod, etc). I found this from Jason Gaylord that worked quite well.

As I worked with it, I began to think that there might be a better way to handle it. My answer was a simple factory pattern class to create my datacontext. I'd like to claim the idea but I really got it from the Enterprise Application Block's DatabaseFactory.

Instead of adding an additional constructor I simply create a class that has the responsibility for creating the datacontext. The CreateDataContext method determines the correct connection string and then uses the predefined constructors. I place this class in the code file for the LINQ To SQL since I consider it part of the DAL.

Public Class AdventureWorksDataContextFactory    
    Public Shared Function CreateDataContext() As AdventureWorksDataContext        
        Dim connStr = ConfigurationManager.ConnectionStrings("AdventureWorksConnectionString").ConnectionString        
        Return New AdventureWorksDataContext(connStr)    
    End Function
End Class

When I want to create my datacontext I simply need to issue the following command.

Dim dc = AdventureWorksDataContextFactory.CreateDataContext

The nice part about this is that I can have my method do all sorts of stuff and it's neatly separated from the datacontext itself. I can overload the method if needed.

Enjoy.

Subscribe in a reader

Friday, June 13, 2008

Silverlight Master Page

Since I'm old school and so are most of my users, I wanted to create a simple Silverlight app that had a title bar across the top, nav menu on the left side and a content area on the right. You can modify this for mutiple zones and do some pretty slick stuff. Note: This is Silverlight 2 Beta 2 and VS 2008.

image

The key is to create a Canvas that gets changed when you want to make changes. Here's the code for the above -- notice the Canvas named ContentHolder.

<UserControl x:Class="SilverLightMasterPageTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SilverLightMasterPageTest">
    <Grid x:Name="LayoutRoot" Background="#FF5C7590">
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border Grid.Row="0" CornerRadius="10" Background="#FFDEDEDE" Margin="2,2,2,2" Padding="10,2,10,2">
            <TextBlock Text="Master Page Test" VerticalAlignment="Center" Foreground="#FF14517B" />
        </Border>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="110" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <local:NavBar Grid.Column="0" />
            <!-- This canvas is what we change -->
            <Canvas x:Name="ContentHolder" Grid.Column="1">
                <local:Page1 />
            </Canvas>
        </Grid>
    </Grid>
</UserControl>

We need to use a Canvas because it has the Children property that allows us to add / remove child controls. This code shows how to use the Children property to change the page.

Partial Public Class Page
    Inherits UserControl

    Public Sub New()
        InitializeComponent()
    End Sub

    Public Sub ChangePage(ByVal newPage As UserControl)
        ' Removes the currently displayed page
        ' (including from memory)
        Me.ContentHolder.Children.RemoveAt(0)
        ' Adds our new page
        Me.ContentHolder.Children.Add(newPage)
    End Sub
End Class

The Remove option gets rid of the currently displayed control while Add shows the new control. Now all we need to do is have our navigation bar create the correct control and call ChangePage. This is encapsulated in PagePicker (in the code behind for NavBar).

' Encapsulate the logic to select
' the page to display
Private Sub PagePicker(ByVal pageId As PageIds)
    ' Make sure this goes to the top page so that you can get
    ' to your change method.
    ' We're nested in two grids at this point so we need
    ' to go back up the tree.
    Dim pg As Page = CType(CType(Me.Parent, Grid).Parent, Grid).Parent
    Dim newPage As UserControl = Nothing
    Select Case pageId
        Case PageIds.Page1
            newPage = New Page1
        Case PageIds.Page2
            newPage = New Page2
        Case PageIds.Page3
            newPage = New Page3
        Case PageIds.Page4
            newPage = New Page4
    End Select
    ' This is where the actual change
    ' occurs.
    pg.ChangePage(newPage)
End Sub

Private Sub Page1Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page1)
End Sub

Private Sub Page2Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page2)
End Sub

Private Sub Page3Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page3)
End Sub

Private Sub Page4Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    PagePicker(PageIds.Page4)
End Sub

' Just makes it easy to identify
' our pages
Private Enum PageIds
    Page1
    Page2
    Page3
    Page4
End Enum

Notice that PagePicker has to get a reference to the top control so that it can call ChangePage. This will probably be one of the things that bites you as you change the layout. Here's the XAML for NavBar and one of the pages.

<UserControl x:Class="SilverLightMasterPageTest.NavBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Border CornerRadius="10" Background="#FFDEDEDE" Width="110" Padding="4,4,4,4">
        <StackPanel>
            <Button x:Name="Page1Button" Content="Page 1" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page1Button_Click" />
            <Button x:Name="Page2Button" Content="Page 2" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page2Button_Click" />
            <Button x:Name="Page3Button" Content="Page 3" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page3Button_Click" />
            <Button x:Name="Page4Button" Content="Page 4" Foreground="#FF14517B" 
                BorderThickness="0" BorderBrush="#FFDEDEDE" Click="Page4Button_Click" />
        </StackPanel>
    </Border>
</UserControl>
<UserControl x:Class="SilverLightMasterPageTest.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot">
        <Border CornerRadius="10" Background="AliceBlue" Width="300"
         HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10,10,10,10" Padding="5" >
            <TextBlock Text="This is page 1" FontSize="22" />
        </Border>
    </Grid>
</UserControl>