Search
Wednesday, August 20, 2008 ..:: Home ::.. Register  Login
   Minimize

1. What language code would you like to see on our articles?

2. Are you implementing SQLXML on your applications?

3. How do you use XSLT's translations?

Submit Survey  View Results
  

 XML News Minimize

What If I Don’t Call Dispose() on my LINQ to SQL DataContext Object?

I’ve written a few posts about LINQ to SQL and am generally a big fan of the technology (even with its weaknesses) since it’s very productive.  After creating a custom DataContext object using the LINQ to SQL designer (or one created by hand) I always ensure that the object is wrapped in a “using” statement so that the Dispose() method is called:

using (MyDataContext context = new MyDataContext())
{

//Perform query }

I had assumed that not properly disposing of the DataContext object would lead to orphan SQL connections which is of course bad and will likely lead to your DBA holding a grudge against you for life. :-)

Steven Walther recently posted on the subject of disposing of DataContext objects and provided some interesting insight into what actually happens.  From what he says it sounds like the DataContext object acts much like the SqlDataAdapter class.  It opens the connection right before a query is executed and closes it immediately after.  I don’t want to steal Steven’s thunder so check out his post on the subject (the last part of the article talks about the consequences…or lack of consequences…of not calling Dispose()). 

I haven’t had time to verify the details in Reflector yet, but given that Steven’s one of the more intelligent people I know I’m confident that the details he presents are accurate.  It still feels more correct to wrap “using” statements around any object that implements IDisposable or explicitly call Dispose() in my opinion, but it’s good to know how the DataContext object works behind the scenes.

 Posted by dwahlin | Permanent link to this post Wed, 20 Aug 2008 05:51:33 GMT |  Comments (0)

My Latest Silverlight Articles

Over the past few months I've been writing articles for the .NET Insight insight newsletter covering various ASP.NET AJAX concepts.  You can read those article here.  I've wrapped up that series and have started writing about Silverlight 1.0 and 2.  Each week (or so) a new article will be published and I'll update them here so check back.  The articles are designed to be focused and concise and get straight to the topic without a lot of fluff. 

If you're interested in learning more about Silverlight 2.0 you can view 8 video tutorials that I put together here.

A video of a talk I gave on integrating Silverlight 1.0 with ASP.NET AJAX and Web Services can be viewed here for those who are interested. 

 

Need to display OrgCharts, site maps or other hierarchies in your ASP.NET applications?  Check out SmartChartPro.

 Posted by dwahlin | Permanent link to this post Tue, 19 Aug 2008 03:30:00 GMT |  Comments (31)

Using LINQ to SQL XML Mapping Files – Step by Step

.NET 3.5’s LINQ to SQL functionality provides a great way to write data access layer code that automatically handles mapping relational data to object properties.  Although I generally prefer to use stored procedures when performing insert, update or delete operations against a database (see my previous post on this), I still use LINQ to SQL in projects since it eliminates the time I used to spend creating SqlParameter objects or writing AddWithValue() parameter statements.  Overall, LINQ to SQL has made me much more productive as a developer.

Most of the samples involving LINQ to SQL involve using the designer built-into Visual Studio 2008 since it’s very productive.  The LINQ to SQL designer is a great way to go and normally what I use when doing my ORM mapping.  I recently had someone ask if using the LINQ to SQL designer was required in order to leverage LINQ to SQL in their applications.  They had existing data entity classes that they wanted to use and didn’t want to re-create them using the designer.  In situations like this you can use built-in XML mapping features available in LINQ to SQL to get around using the designer if desired.  Going this route leads to writing more custom code and XML mapping files but also provides the ultimate in control especially if your data entity classes are created by another tool, you don’t want your classes littered with LINQ to SQL attributes, or you have some other reason for not wanting to use the designer.  In this article I’ll provide a step by step introduction to working with LINQ to SQL XML mapping files.


Step 1. Create the Data Entity Class

If you’re not using the LINQ to SQL designer then you’ll need to create your own data entity classes (or use a 3rd party tool to create them) that can hold data from the target database.  If you already have existing data entity classes that you want to use then you can skip this step.  Here’s a simple Customer class capable of holding some of the data found in the Customer table in the AdventureWorksLT database.  A diagram of the Customer table follows.

namespace Model
{
    public class Customer
    {
        public int CustomerID { get; set; }
        public string Title { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime ModifiedDate { get; set; }
    }
}


image 

2. Create the XML Mapping File

Visual Studio 2008 provides a LINQ to SQL intellisense schema located at Program Files\Microsoft Visual Studio 9.0\Xml\Schemas\LinqToSqlMapping.xsd.  The schema contains a namespace of http://schemas.microsoft.com/linqtosql/mapping/2007 in it that can be used in your custom LINQ to SQL XML mapping files to get intellisense as you create your XML mappings.  Start by creating an XML file in your Visual Studio 2008 project.  Once the file is created add a Database element that defines the http://schemas.microsoft.com/linqtosql/mapping/2007  namespace on it (see the XML code below for an example).  Doing this will give you intellisense for the XML mapping file as you type in additional tags.  Within the Database element add one or more Table elements.  Each Table element will contain child Column elements that define how the individual table columns map to class properties.  In addition to defining table mappings, stored procedures can also be defined using a Function tag. 

Here’s an example of mapping the Customer class shown earlier to the Customer table in AdventureWorksLT.  Notice that the intellisense xsd schema namespace mentioned earlier is defined on the root element in the mapping file. While the namespace isn’t required, having intellisense definitely speeds up the process of creating the mapping file.

<?xml version="1.0" encoding="utf-8" ?>
<Database Name="AdventureWorksLT" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
  <Table Name="SalesLT.Customer" Member="Model.Customer">
    <Type Name="Model.Customer">
      <Column Name="CustomerID" Member="CustomerID" IsDbGenerated="true" IsPrimaryKey="true" />
      <Column Name="Title" Member="Title" />
      <Column Name="FirstName" Member="FirstName" />
      <Column Name="LastName" Member="LastName" />
      <Column Name="ModifiedDate" Member="ModifiedDate" />
    </Type>
  </Table>
  <Function Name="dbo.ap_GetCustomerByLastName" Method="GetCustomerByLastName">
    <Parameter Name="lastNameLetter" Parameter="LastNameLetter" />
    <ElementType Name="Model.Customer" />
  </Function>
</Database>

Looking through the file you’ll see that the Model.Customer class is mapped to the SalesLT.Customer table and that each field is mapped as appropriate.  The primary key in the table is defined using the IsPrimaryKey attribute along with the IsDbGenerated attribute.  The XML mapping file also includes a reference to a stored procedure named ap_GetCustomerByLastName which looks like the following:

CREATE PROCEDURE dbo.ap_GetCustomerByLastName
    (
        @LastNameLetter char(1)
    )
AS
    BEGIN
        SELECT CustomerID, Title, FirstName, LastName, ModifiedDate 
        FROM SalesLT.Customer
        WHERE LastName LIKE @LastNameLetter + '%'
    END


The mapping file maps the stored procedure to a custom method named GetCustomerByLastName which accepts a single parameter named lastNameLetter.  Data returned from the stored procedure call is automatically mapped to the Model.Customer class using the mapping file’s ElementType element. 

Note:  The SqlMetal.exe command-line tool can be used to automatically generate the XML mappings for a database quickly and easily (it can generate code as well if desired).  Although it won’t handle mapping the database fields to your custom data entity classes, it can be used to generate initial XML mapping code that can be modified quickly.  To generate the mapping file you can run the following command using the Visual Studio 2008 command prompt.  This command generates an XML mapping file for the entire AdventureWorksLT database and includes functions and stored procedures in the output.

sqlmetal.exe  /server:YourDBServer  /database:AdventureWorksLT  /dbml:AdventureWorksLT.dbml  /functions  /sprocs  /namespace:Data


3. Create a Custom DataContext Class

If you’ll be querying the database directly using LINQ or Lambda expressions you can use the built-in System.Data.Linq.DataContext class directly to run your queries and skip this step.  However, if you also need to query a stored procedure defined in a mapping file then you’ll want to create a custom class that derives from the DataContext class.  This is necessary since you’ll need to access the protected ExecuteMethodCall() method found in DataContext which can be used to call stored procedures.  Here’s the signature for the ExecuteMethodCall() method:

//
// Summary:
//     Executes the stored database procedure or scalar function associated with
//     the specified CLR method.
//
// Parameters:
//   instance:
//  The instance of the method invocation (the current object).
//
//   methodInfo:
//     Identifies the CLR method that corresponds to a database method.
//
//   parameters:
//     The array of parameters to be passed to the command.
//
// Returns:
//     The result (the return value and output parameters) of executing the specified
//     method.
protected internal IExecuteResult ExecuteMethodCall(object instance, MethodInfo methodInfo, params object[] parameters);

Creating a custom DataContext class is a bit of extra work, but I normally create a custom class that inherits from DataContext or my LINQ to SQL designer class if I’m using the Visual Studio 2008 designer anyway so that I can control things like logging and connection strings in a more centralized place.  Here’s a simple example of a custom class named CustomDataContext that derives from DataContext and exposes a GetCustomerByLastName() method that is used to call the ap_GetCustomerByLastName stored procedure shown previously.  Notice that the method calls the DataContext class’s ExecuteMethodCall() method and passes in the name of the method to call (contained within the System.Reflection.MethodInfo object) as well as the parameter data to pass to the stored procedure.

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Reflection;

namespace ConsoleApplication1
{
    public class CustomDataContext : DataContext
    {

        public CustomDataContext(string connStr, XmlMappingSource xmlMap) : base(connStr, xmlMap) { }

        public IEnumerable<DAL.Customer> GetCustomerByLastName(string lastNameLetter)
        {
            IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lastNameLetter);
            return result.ReturnValue as IEnumerable<DAL.Customer>;
        }
    }
}


Step 4. Load the XML Mapping File into the DataContext Object

Once the data entity class, XML mapping file and custom DataContext class have been created you can use the DataContext class to query the database and automatically map the appropriate database fields to their corresponding Model.Customer properties.  When using the LINQ to SQL designer you can simply create a new instance of the DataContext class and be on your way since the designer generates code that includes C# or VB.NET mapping attributes.  When using XML mapping files you’ll need to load the mapping file into the DataContext object so that it knows the proper mappings to use.  Here’s an example of creating a CustomDataContext object instance and loading the XML mapping file.  Notice that the mapping file is loaded by using System.Data.Linq.Mapping.XmlMappingSource class’s FromUrl() method.  XML mapping files can also be loaded from a string, stream or XmlReader.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Text;

namespace LINQAndXMLMapping
{
    class Program
    {
        static void Main(string[] args)
        {  
            string connStr = "server=.;database=AdventureWorksLT;integrated security=true;";
            using (CustomDataContext context = new CustomDataContext(connStr, XmlMappingSource.FromUrl("CustomerMapping.xml")))
            {
//Perform query

} Console.Read(); } } }


Step 5. Query the Database Using the DataContext Object

Once the XML mapping file is loaded into the DataContext object you can query the database using LINQ or Lambda expressions.  Here’s an example of grabbing all of the customer records that have a last name starting with “M”:

IEnumerable<DAL.Customer> custs = from c in context.GetTable<DAL.Customer>()
                                  where c.LastName.StartsWith("M")
                                  select c;
foreach (DAL.Customer cust in custs)
{
     Console.WriteLine(cust.FirstName + " " + cust.LastName);
}

The ap_GetCustomerByLastName stored procedure can be called using the CustomDataContext object’s GetCustomerByLastName() method as shown next:

IEnumerable<DAL.Customer> custs2 = context.GetCustomerByLastName("A");
foreach (DAL.Customer cust in custs2)
{
    Console.WriteLine(cust.FirstName + " " + cust.LastName);
}

The results of the two queries are shown next:

image

Although the LINQ to SQL designer provides the biggest bang for the buck as far as productivity goes when working with LINQ to SQL, the XML mapping features discussed here (although not as productive from a time standpoint) allow you to have more control over the classes that are used in an application and the manner in which they’re mapped to database tables.  Regardless of which route you choose to go, LINQ to SQL will definitely provide a productivity boost for many applications especially when compared to writing data access code from scratch.

 

Downloads

 Posted by dwahlin | Permanent link to this post Mon, 18 Aug 2008 07:20:51 GMT |  Comments (8)

Introduction to Layout Controls in Silverlight 2

Arranging controls on a user interface in a flexible manner is key to building successful applications.  Silverlight 2 provides three main controls that can be used for layout management:

· Canvas Control

· StackPanel Control

· Grid Control

In this post I'll provide an introductory look at these controls and show how they can be defined in XAML.  Future articles will use the layout controls to arrange controls that are capable of displaying data retrieved from remote sources.  Let's start out by examining the Canvas control.

The Canvas Control

HTML developers use various types of container tags to group related content in a Web page.  The div element is especially popular now days since it can be combined with CSS to provide a flexible layout for Web pages without requiring tables.  Although Silverlight 2 doesn't support the div element, it does provide a Canvas element that can be used to group related content.  The Canvas element acts like the div element in many regards and can have children nested inside of it.  It's typically used when children need to be positioned at exact x and y coordinates.

The Canvas object derives from a base class called Panel and exposes several properties such as Name, Background, Cursor, Height, Width, HorizontalAlignment, VerticalAlignment, Opacity, OpacityMask, RenderTransform and Visibility (to name a few).  Children can be positioned within a Canvas by using attached properties such as Canvas.Left, Canvas.Top and Canvas.ZIndex.  An example of using a Canvas to arrange two TextBlock controls and a Rectangle is shown next:

<Canvas x:Name="ShapesCanvas" HorizontalAlignment="Left" VerticalAlignment="Top"
    Height="200" Width="600" Background="LightGray" Margin="20">
    
    <TextBlock Canvas.Top="20" Canvas.Left="5" FontSize="40" Foreground="Navy" 
        Text="Canvas Text" />

    <Rectangle Canvas.Top="50" Canvas.Left="50" Height="100" Width="200" 
        Fill="Yellow" Canvas.ZIndex="-1" />

    <TextBlock Canvas.Top="150" Canvas.Left="300" FontSize="30" Foreground="Green" 
        Text="More Text..." />

</Canvas>


The Canvas object shown here is positioned to the top left of its parent container, is 200 X 600 pixels in size, has a LightGray background and a margin of 20 pixels applied uniformly to its left, top, right and bottom margins.  The children within the Canvas are positioned using the Canvas.Top and Canvas.Left attached properties.  Because Rectangle is defined after the first TextBlock it would normally be positioned above the text.  By using the Canvas.ZIndex attached property, however, you can change how items are arranged and place objects above or below other items quite easily.  By moving the Rectangle before the TextBlock in the XAML code the Canvas.ZIndex property could be removed though. 

Figure 1 shows how the Canvas and its child objects render at runtime in a Silverlight application.

Figure1

Figure 1

Multiple Canvas objects can be defined in a XAML file just like multiple div tags can be placed in a HTML file.  The XAML code that follows shows how multiple Canvas objects can be used as place holders for controls that are created during runtime:

 

<UserControl x:Class="AlbumViewer2.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="800" Height="650">
    <Canvas x:Name="MainCanvas">
        <Canvas.Background>
            <ImageBrush ImageSource="Images/NavyBg.jpg" Stretch="Fill" />
        </Canvas.Background>

        <!-- Search controls go here -->

        <Canvas x:Name="LoadingCanvas" Canvas.Top="225" Canvas.Left="150" 
         Background="Red">

            <!-- Loading data info objects go here -->

        </Canvas>

        <Canvas x:Name="AlbumsCanvas" Canvas.Top="50" Visibility="Collapsed">

            <!-- Albums go here -->
            
        </Canvas>

        <Canvas x:Name="NavCanvas" Canvas.Top="425" Canvas.Left="300" Width="300" 
          Visibility="Collapsed">

            <!-- Navigation controls go here -->

        </Canvas>

        <Canvas x:Name="AlbumDetailsCanvas" Canvas.Top="495" Canvas.Left="15" 
          Visibility="Collapsed">

            <!-- Album details controls go here -->

        </Canvas>
    </Canvas>

</UserControl>

Figure 2 shows how the Canvas objects and associated child objects are rendered at runtime.

Figure2

Figure 2


The StackPanel Control

The Canvas control can be used when child objects need to be absolutely positioned.  While absolute positioning may be useful in some Silverlight 2 applications, others can benefit from having controls that are dynamically laid out based upon the size of the Silverlight interface.  By using dynamic control layout you allow users to switch to full-screen mode without writing a lot of code to adjust control coordinates.  Silverlight 2 provides the StackPanel control that can be used to stack objects horizontally or vertically and provide more flexible layouts.  By using the StackPanel you can arrange controls on an interface without defining absolute positions for each control.

The StackPanel control acts much like the ASP.NET DataList control.  Data can be displayed horizontally or vertically by assigning a value to the DataList control's RepeatDirection property.  RepeatDirection accepts one of two enumeration values including Horizontal and Vertical.   The StackPanel control provides an Orientation property that is used to determine how to layout controls on an interface (the default layout is vertical).  Like the DataList control's RepeatDirection property, the Orientation property also accepts Horizontal and Vertical values

Although StackPanel and DataList are similar in some ways, they differ in the way data is wrapped when child controls exceed the size of the parent container.  The DataList control provides a RepeatColumns property that determines how many columns are displayed before creating a new row.  The StackPanel doesn't provide that functionality unfortunately.  As a result, child controls that exceed the bounds of the StackPanel will not display properly on the user interface. 

WPF provides a WrapPanel control that handles wrapping child controls when they exceed the size of the parent container.  Silverlight doesn't provide a built-in WrapPanel control, however, several WrapPanel controls have been created by members of the Silverlight community that can be found using your favorite search engine.

The code that follows shows how to arrange two TextBlock controls horizontally by setting the StackPanel control's Orientation property to Horizontal.

<StackPanel Orientation="Horizontal" Background="LightGray" Margin="10">

    <TextBlock Text="Horizontal StackPanel - First Control" FontSize="20" 
        Foreground="Navy" Margin="10" />

    <TextBlock Text="Horizontal StackPanel - Second Control" FontSize="20" 
        Foreground="Red" Margin="10" />

</StackPanel>


Controls can also be arranged vertically by changing the Orientation property to a value of Vertical:

<StackPanel Orientation="Vertical" Background="LightGray" Margin="10">

    <TextBlock Text="Vertical StackPanel - First Control" FontSize="20" 
        Foreground="Navy" Margin="10" />

    <TextBlock Text="Vertical StackPanel - Second Control" FontSize="20" 
        Foreground="Red" Margin="10" />

</StackPanel>


Figure 3 shows the result of the horizontal orientation while Figure 4 shows the result of the vertical orientation. Both figures demonstrate how a StackPanel control automatically fills the width of its parent container.  This default behavior can be changed by assigning a value to the control's Width property.

Figure3

Figure 3

Figure4

Figure 4


The Grid Control

Web designers have been accustomed to arranging data and controls in tables for years.  Although there's been a general shift to CSS and div tags for page layout, table tags are still quite popular.  If you're coming from a Web development background you'll find Silverlight's Grid control easy to use and quick to comprehend since it's similar to what you've already been using.  It acts much like HTML's table tag and allows data and controls to be arranged in a tabular-style view.

The Grid control allows rows and columns to be defined much more concisely compared to HTML.  With the HTML table tag you're forced to repeat multiple tr and td tags to create rows and columns.  The Grid control allows rows and column information to be defined in one location using RowDefinition and ColumnDefinition tags.  An example of XAML code that creates a simple Grid with 2 rows and 2 columns is shown next:

<Grid x:Name="myTable" Background="White" ShowGridLines="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>|
    
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".25*" />
        <ColumnDefinition Width=".75*" />
    </Grid.ColumnDefinitions>
</Grid>

This example sets the Grid's ShowGridLines attribute to True which is nice for seeing the initial layout of a Grid control.  Figure 5 shows how the Grid looks in Visual Studio 2008 when ShowGridLines is set to True.

Figure5

Figure 5

The XAML code also sets the first row's height to 100 pixels and the second row's height to the remaining space available in the user interface When you use the * character to define a row height you're essentially telling the Grid to assign the row 100% of the remaining space.  You could also omit the Height attribute entirely in this case and achieve the same affect.  In addition to the row definitions, the two columns defined have widths of 25% and 75% respectively. 

It's important to note that the ColumnDefinition tag's Width attribute and RowDefinition tag's Height attribute do not accept the typical values assigned to HTML tr and td tags.  For example, assigning the Width attribute a value of 25% will result in an error.  If you've spent a lot of time creating Web pages you may struggle with this initially (I know I did!) since using the % character is so common in HTML and CSS.  In Silverlight, percentage based widths are assigned by defining a decimal value between 0 and 1 followed by the * character.  However, you can also assign whole numbers such as 1* and 9* for 10% and 90% respectively.  In addition to numeric values, the Height and Width attributes also accept a value of Auto which causes the appropriate row or column to automatically figure out its size based on available space.

Once rows and columns are defined, controls can be placed inside of a Grid using Grid.Row and Grid.Column attributes.  The following XAML shows how 4 TextBlock controls can be defined and assigned to different rows and columns of a Grid:

<Grid x:Name="myTable" Background="White" ShowGridLines="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".25*" />
        <ColumnDefinition Width=".75*" />
    </Grid.ColumnDefinitions>

    <TextBlock Text="0,0" Grid.Row="0" Grid.Column="0" Margin="5" />
    <TextBlock Text="0,1" Grid.Row="0" Grid.Column="1" Margin="5"  />
    <TextBlock Text="1,0" Grid.Row="1" Grid.Column="0" Margin="5"  />
    <TextBlock Text="1,1" Grid.Row="1" Grid.Column="1" Margin="5"  />
</Grid>

 

Figure 6 shows what the Grid control and associated child controls look like at runtime:

Figure6 

Figure 6

In situations where you need a control to span multiple rows or columns you can use the Grid.RowSpan or Grid.ColumnSpan attributes.  For example, the following button would be placed in the first row and span two columns:

<Button Content="Button" Grid.Row="0" Grid.ColumnSpan="2" />


In summary, Silverlight 2 offers several different controls that can be used to layout data and child controls on a user interface.  The Canvas control allows for exact positioning whereas the StackPanel control provides more flexible control layout.  The Grid control provides a simple way to arrange controls in a tabular-style on a user interface.  In cases where you need additional layout flexibility such as arranging controls vertically or horizontally within a Grid cell, you can also combine layout controls such as the StackPanel (covered in a previous article) or Canvas with a Grid. 

 Posted by dwahlin | Permanent link to this post Tue, 12 Aug 2008 22:25:15 GMT |  Comments (8)

Syncing a Windows Mobile Device Emulator with Vista’s Mobile Device Center

I started working on a Windows Mobile application on Vista and couldn’t get the emulator to sync property with the Mobile Device Center.  I’d synced device emulators long ago on XP with ActiveSync but just couldn’t get it working like I wanted on Vista.  I had the different 6.0 and 6.1 SDKs installed, had the Cellular Emulator working perfectly with the device emulator but couldn’t sync to save my life.  I needed to move over a C++ dll that needed to live in the device emulator’s Windows directory.  After a lot of searching it turns out that all I had to do was enable DMA in the connection settings for the Mobile Device Center as shown next:

image

 

 

 

 

 

 

 

 

 

 

You can get to this dialog by going to Windows Mobile Device Center | Mobile Device Settings | Connection Settings.  Once I had the DMA connection setup properly the Mobile Device Center was able to locate the emulator and allow me to get to the file system.  Simple…once you know the trick. :-)

 Posted by dwahlin | Permanent link to this post Sun, 03 Aug 2008 22:46:00 GMT |  Comments (0)

Looking for more?

Browse all of the entries in the Dan Wahlin&#39;s WebLog archives

  

 Favorite Links Minimize
  

Copyright 2005 CodersOasis.com and HotMediaStudios.net   Terms Of Use  Privacy Statement
Portal engine source code is copyright 2002-2008 by DotNetNuke. All Rights Reserved