Search This Blog

Saturday, October 31, 2009

What is the Difference between ObjectDataSource and.SqlDataSource


 The SqlDataSource control enables you to use a Web control to access data located in a relational data base, including Microsoft SQL Server and Oracle databases, as well as OLE DB and ODBC data sources. You can use the SqlDataSource control with other controls that display data, such as the GridView, FormView, and DetailsView controls, to display and manipulate data on an ASP.NET Web page, using little or no code.

The SqlDataSource control uses ADO.NET classes to interact with any database supported by ADO.NET. This includes Microsoft SQL Server (using the System.Data.SqlClient provider), System.Data.OleDb, System.Data.Odbc, and Oracle (using the System.Data.OracleClient provider). Using a SqlDataSource control allows you to access and manipulate data in an ASP.NET page without using ADO.NET classes directly. You provide a connection string to connect to your database and define the SQL statements or stored procedures that work with your data. At run time, the SqlDataSource control automatically opens the database connection, executes the SQL statement or stored procedure, returns the selected data (if any), and then closes the connection.

The ASP.NET ObjectDataSource control represents a middle-tier object with data retrieval and update capabilities. The ObjectDataSource control acts as a data interface for data-bound controls such as the GridView, FormView, or DetailsView controls. You can use these controls to display and edit data from a middle-tier business object on an ASP.NET Web page.

The ObjectDataSource control uses reflection to call methods of a business object to select, update, insert, and delete data. You set the ObjectDataSource control's TypeName property to specify the name of the class to use as a source object. For details on how to create a source data object to be used with the ObjectDataSource control, see Creating an ObjectDataSource Control Source Object.

Sorting and Paging
The ObjectDataSource control can support additional sorting and paging capabilities by passing sort and page information in requests from a data-bound control, such as a GridView control, to the data object for processing. The source data object or the data source control itself can then sort data and return data in pages.

For information on passing sorting and paging parameters to an ObjectDataSource control's data object, see Using Parameters with the ObjectDataSource Control.

Caching
The ObjectDataSource control can cache objects returned by the underlying business object. However, you should not cache objects that hold resources or that maintain state that cannot be shared among multiple requests, such as an open DataReader object.

Filtering
If the object returned to the ObjectDataSource control by the source data object is a DataSet or DataTable object, the ObjectDataSource control supports filtering using the syntax of the Expression property of the DataColumn class. Filtering enables you to expose only rows that match particular search criteria, without having to re-query the data source with new selection criteria. For more information, see Filtering Data Using Data Source Controls.

Conflict Detection
By setting the ObjectDataSource control's ConflictDetection property to true, you can specify that the ObjectDataSource control should include original values when calling update methods of the source data object. The original values can then be included in checks for optimistic concurrency. For more information, see Using Parameters with the ObjectDataSource Control. For information on optimistic concurrency checking, see Optimistic Concurrency (ADO.NET).

Each has its own merits and demerits...If using SQL Server as backend SqlDataSource is much preferable



* Type Name
For ObjectDataSource, the property TypeName includes the class name, that will responsible to manage data, this may NOT be the data object collection. The select, insert etc methods will use the mentioned methods to access or retrieve data. For SqlDataSource, a built-in data collection is used, which can be bound to data data controls.

* Connection String
For ObjectDataSource, there is NO connection string needed, as it is used middle tier. For SqlDataSource, connection string is needed.

* CRUD Method
For ObjectDataSource, there is NO method (select, insert etc) type, as the methods are being used from a class of middle tier. For SqlDataSource, there are two types of methods StoredProcedure and Text. note, in SqlDataSource, for parameters, in the execution time the system automatically includes a '@' before the name as specified in the name property.



DataSources in general and ObjectDataSources in particular are a new feature within ASP.NET 2.0.
At first glance ObjectDataSources raise the expectation that this is a means to support layered architectures that feature a cleanly separated business layer (consisting of business services that exchange business data – either plain class structures or data sets). But this hope dies very fast.
At second glance they appear to support layered architectures that feature data objects (classes that represent the domain specific data model and implement a part of the business interfaces – all in one package). This hope lives longer before it, too, diminishes.
Finally one has to accept that they support about the same conceptual features that a SqlDataSource with DataSets supports: A view into the data that works best if it is closely tied to the current page.
Once you have accepted that you can start thinking about what ObjectDataSources actually can do for you – which is more than this introduction may suggest.
To understand what ObjectDataSources can and cannot do, let’s start with understanding SqlDataSources. On a page you may have a SqlDataSource configured to provide data for your grid view. Thus it would contain a SELECT statement asking for the columns you would like to show and upon databinding of the grid it would issue that statement against the database. Another SqlDataSource an the same page may be configured to select a distinct row, e.g. the one selected within the gridview, to be used by a form view (i.e. providing a master/detail page). This data source would contain a SELECT statement asking for the columns you would like to show/edit (perhaps different columns than in the grid view) and adding a WHERE clause for the id. It also would contain respective UPDATE, INSERT, and DELETE statements. The word “contain” in this context means “buried into the page”, as in this excerpt:
<asp:SqlDataSource ID=”SqlDataSource2″ runat=”server” ConnectionString=”<%$ ConnectionStrings:ConnectionString %>
        SelectCommand=”SELECT * FROM [Authors] WHERE ([Id] = @Id)”
        UpdateCommand=”UPDATE [Authors] SET [fname] = @fname, [lname] = @lname, [phone] = @phone WHERE [Id] = @Id”>
    <SelectParameters>
        <asp:ControlParameter ControlID=”GridView1″ Name=”Id” PropertyName=”SelectedValue” Type=”Object” />
    SelectParameters>
    <UpdateParameters>
        <asp:Parameter Name=”fname” Type=”String” />
        <asp:Parameter Name=”lname” Type=”String” />
        <asp:Parameter Name=”phone” Type=”String” />
        <asp:Parameter Name=”Id” Type=”Object” />
    UpdateParameters>
    [...]
asp:SqlDataSource>

Let’s make that clear: Every databound control (grid view and form view in our example) has its own private datasource control. This means in particular:
  1. The datasource controls are independent of each other, going directly to the database. If one datasource control issues an UPDATE statement the other one will reflect those changes only if its SELECT comes after the UPDATE.
  2. The datasource controls are tailored to the specific needs of the databound control, i.e. giving access to exacly the data that is shown/manipulated. E.g. if a datasource selected/updated a column “street”, yet this column is not bound within the form view, it will not be left as is on update, rather it will be overwritten with NULL (best case).
And here is the point: The only relevant difference between SqlDataSources and ObjectDataSources is that ObjectDataSources issue method calls rather than SQL statements.
Now, this is crucial for the understanding and the implications are both good and bad.

  • For one thing, calling a method means abstraction. Having SQL statements within the pages ties the database structures directly into your UI code. A method can hide some of these details.
    :arrow:  ObjectDataSource is good!
  • C# classes are indivisible. While a SQL statement can explicitely state which columns to access, a class cannot be asked to please contain only a subset (i.e. a partition) of its properties. (Well, not unless we have LINQ support.) Thus we cannot use class instances for insert or update methods if we are only working on a partition of that object. In these cases we will have to provide methods like UpdateMainData(Customer), UpdateAddress(Customer), UpdateContactData(Customer), … with the name implying the partition of the Customer data type (or conceptually equal methods with single field parameters rather than customer objects). Can you spell “maintenance”?
    :arrow:  ObjectDataSource has its problems!
  • ObjectDataSources create the configured data object class on demand, each datasource its own data object. Again, those data objects know nothing of each other, no change yet.
    :arrow: ObjectDataSource does not address all problems!
  • However, there is the possibility to subscribe to certain events and customize the behaviour. One could register for the ObjectCreating event and rather than creating a new data object return a reference to a previously created object. One could also register for the Updating event and implement logic that updates exactly the provided fields.
    :arrow:  ObjectDataSource provides better oportunities to address arising problems!
For small point&click applications, SqlDataSource may be the way to go. It’s fast, it is supported by designers and wizards (always good for quality and maintenance), it avoids unnecessary coding overhead, it is pure ASP.NET and therefore the application code has a steep learnig curve. No need to bother with the additional overhead an ObjectDataSource introduces.
For not so small, non-trivial, or enterprise applications, e.g.
  • consisting of many pages,
  • needing more sophisticated business logic,
  • having a business logic layer that is (in principle) independent of UI specifics,
  • having to comply with database access restrictions/policies,
  • requiring a more sophisticated UI, e.g. maintaining changes in state before they are explicitely saved,
  • being subject to versioning,
SqlDataSource is probably not the way to go. Rather it is prone to become a development problem and a maintenance nightmare.
ObjectDataSource in its plain form may not be the way to go either. Yet it offers the extensibility to roll your own additional logic. The farther you deviate from vanilla web applications, the more work you have to do – but you can do it.
Ergo: Use the right tool for the job at hand and know how to handle the tool. ObjectDataSource is a good tool if you know when to use it, how to use it, and what not to expect.
That’s all for now folks,

Friday, October 30, 2009

Reset the Controls In recursive fashion

protected void btnReset_Click(object sender, EventArgs e)
    {
        cleanFields(this);
    }
 
    protected void cleanFields(Control container)
    {
        foreach (Control c in container.Controls)
        {
            if (c is TextBox)
            {
                ((TextBox)c).Text = string.Empty;
            }
            if (c is DropDownList)
            {
                ((DropDownList)c).SelectedIndex = 0;
            }
            if (c is RadioButtonList)
            {
                ((RadioButtonList)c).ClearSelection();
            }
            this.cleanFields(c);
        }
        pnlConferenceCall.Visible = false;
        pnlParticipants.Visible = false;
    }

Monday, October 26, 2009

Building a Database Driven Hierarchical Menu using ASP.NET

Introduction

This tutorial will show you how to store hierarchical menu data in a single database table and how to retrieve and transform that data for display in Microsoft's Menu.

Each step is explained and illustrated so that you can quickly extrapolate from this article to build your web application's menu.

Note: This tutorial requires Visual Studio 2005 and SQL Server.



Step 1 - Create and Fill a Database Self Join Table

Our menu's table will use a self-join relationship which is the simplest method of storing hierarchical data. Child rows will use ParentID to establish a relationship with the MenuID of a parent row as shown below.

Figure 1 - Table Overview

Let us start by creating a database called MenuDb and a Table called Menu. This can be done by running the following script from Microsoft's Query Analyzer.

Listing 1 - Database Script

CREATE DATABASE MenuDb
GO
USE MenuDb
GO
CREATE TABLE [Menu] (
[MenuID] [int] IDENTITY (1, 1) NOT NULL ,
[Text] [varchar] (50) COLLATESQL_Latin1_General_CP1_CI_AS NULL ,
[Description] [varchar] (255) COLLATESQL_Latin1_General_CP1_CI_AS NULL ,
[ParentID] [int] NULL ,
CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED
(
[MenuID]
) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT INTO MENU
Select 'Product','A List of Products', NULL
UNION ALL Select 'Applications','Appliations',NULL
UNION ALL Select 'Document','Documentation', NULL
UNION ALL Select 'Support','Support', NULL
UNION ALL Select 'Download','Download', NULL
UNION ALL Select 'Background','ProductBackground', 1
UNION ALL Select 'Details','Product Details', 1
UNION ALL Select 'Mobile Device','Mobile DeviceApplications', 2
UNION ALL Select 'Portal','Portal Applications',2
UNION ALL Select 'Web Applicaitons','WebApplications', 2
UNION ALL Select 'Demo','Demo Applicaitons', 2
UNION ALL Select 'Performance Tests','ApplicationPerformance Tests', 2
UNION ALL Select 'Tutorials','TutorialDocumentation', 3
UNION ALL Select 'Programmers','ProgrammDocumentation', 3
UNION ALL Select 'FAQ','Frequently AskedQuestions', 4
UNION ALL Select 'Forum','Forum', 4
UNION ALL Select 'Contact Us','Contact Us', 4
UNION ALL Select 'InternetRestrictions','Internet Restrictions', 6
UNION ALL Select 'Speed Solution','Speed Solutions',6
UNION ALL Select 'Application Center Test','Application Center Test Results', 12
UNION ALL Select 'Modem Results','Modem Results',12
GO

The table you created, displayed below, uses self-join relationships. Rows that have a MenuID between 1 through 5 do not have parents and are considered root menu nodes. Rows with MenuID of 6 and 7 are children of MenuID 1, and so on.

Figure 2- Parent, Child Relationships

Step 2 - Add a Web Page That Implements a Menu and an XmlDataSource

Add a new WebForm to your web application. Drag and drop a Menu and an XmlDataSource from the toolbar onto the WebForm with the following properties.

Listing 2 - Menu and XmlDataSource Web Controls

<asp:Menu ID="menu"DataSourceID="xmlDataSource" runat="server"
BackColor="#FFFBD6"DynamicHorizontalOffset="2" Font-Names="Verdana"
ForeColor="#990000"StaticSubMenuIndent="10px" StaticDisplayLevels="1" >
<DataBindings>
<asp:MenuItemBindingDataMember="MenuItem" NavigateUrlField="NavigateUrl"
TextField="Text" ToolTipField="ToolTip"/>
DataBindings>
<StaticSelectedStyleBackColor="#FFCC66" />
<StaticMenuItemStyleHorizontalPadding="5px" VerticalPadding="2px" />
<DynamicMenuStyle BackColor="#FFFBD6"/>
<DynamicSelectedStyleBackColor="#FFCC66" />
<DynamicMenuItemStyle HorizontalPadding="5px"VerticalPadding="2px" />
<DynamicHoverStyleBackColor="#990000" Font-Bold="False"ForeColor="White"/>
<StaticHoverStyle BackColor="#990000"Font-Bold="False" ForeColor="White" />
asp:Menu>
<asp:XmlDataSource ID="xmlDataSource"TransformFile="~/TransformXSLT.xsl"
XPath="MenuItems/MenuItem"runat="server"/>

At runtime, the XmlDataSource object is assigned an XML string (shown in step 3) which is then transformed by the XSLT file, TransformXSLT.xsl to another XML format (XSLT is covered in step 4). The transformed XML is then consumed by the Menu as specified by the Menu's DataSourceID property.

Note: We are using the XmlDataSource property, XPath, to introduce an optional way to exclude the XML root node, MenuItems. If the root node is not excluded then the menu will contain an extra level which can be controlled using the menu property StaticDisplayLevels. The MenuItems root nodes can also be excluded in XSLT.

Step 3 - Retrieve Data and Create Nested Relationships

Now it is time to retrieve and begin formatting the menu data for use by Microsoft's menu. The challenge is to establish parent child relationships and then create a hierarchical representation of the data. A DataSet object is perfect for this because it can store the structure of an entire database, including relationships, and then convert that relational data into nested XML.

Add the following C# code to your Page_Load method. This code uses a DataAdapter to retrieve data from the single database table and to fill a DataSet. Once filled, a DataRelation is applied to the DataSet to establish MenuID and ParentID dependencies. Finally, a call to GetXML() retrieves a hierarchical XML representation of all relational data within the dataset.

Listing 3 - The C# Code

using System;
using System.Xml;
using System.Data;
using System.Data.SqlClient;

public partial class _Default:System.Web.UI.Page
{
protected void Page_Load(object sender,EventArgs e)
{
DataSet ds = new DataSet();
string connStr = "server=localhost;Trusted_Connection=true;database=MenuDb";
using(SqlConnection conn = newSqlConnection(connStr))
{
string sql = "Select MenuID, Text,Description, ParentID from Menu";
SqlDataAdapter da = newSqlDataAdapter(sql, conn);
da.Fill(ds);
da.Dispose();
}
ds.DataSetName = "Menus";
ds.Tables[0].TableName = "Menu";
DataRelation relation = newDataRelation("ParentChild",
ds.Tables["Menu"].Columns["MenuID"],
ds.Tables["Menu"].Columns["ParentID"], true);

relation.Nested = true;
ds.Relations.Add(relation);

xmlDataSource.Data = ds.GetXml();

if (Request.Params["Sel"] != null)
Page.Controls.Add(newSystem.Web.UI.LiteralControl("You selected " +
Request.Params["Sel"]));
}
}

Note: You will have to supply your relevant SQL Server name, Username and Password in the above database connection string, connStr.

As shown in the screenshot below, the call to ds.GetXml() correctly displays the nested hierarchy.

Figure 3 - XML Generated By Using DataSet Relationships

Step 4 - Using XSLT to convert XML for Microsoft's Menu

The XML returned from ds.GetXml() now needs to be reformatted for Microsoft's Menu. XmlDataSource is perfect for this task because it can use XSLT to transform the above XML to another XML format and then provide that to Microsoft's menu.

The below XSLT code does just this. It first finds the root node called Menus and applies the MenuListing template to its root children. Next, each Menu node's elements are converted to MenuItem attributes. Finally, each Menu node is checked for the existence of children. If children exist, then the MenuListing will be recursively called until all children are processed.

Add an XSLT file to your project named TransformXSLT.xsl with the following code.

Listing 5 - XSLT

xml version="1.0"encoding="utf-8"?>
<xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"indent="yes" encoding="utf-8"/>



<xsl:template match="/Menus">
<MenuItems>
<xsl:call-templatename="MenuListing" />
MenuItems>
xsl:template>


<xsl:templatename="MenuListing">
<xsl:apply-templatesselect="Menu" />
xsl:template>

<xsl:template match="Menu">
<MenuItem>

<xsl:attributename="Text">

xsl:attribute>
<xsl:attributename="ToolTip">
<xsl:value-ofselect="Description"/>
xsl:attribute>
<xsl:attributename="NavigateUrl">
<xsl:text>?Sel=xsl:text>
<xsl:value-ofselect="Text"/>
xsl:attribute>


<xsl:if test="count(Menu) >0">
<xsl:call-templatename="MenuListing" />
xsl:if>
MenuItem>
xsl:template>
xsl:stylesheet>

Note: You can interactively debug an XSLT and an XML file from the IDE's XML Menu.

The XmlDataSource object's transformed XML that is provided to Microsoft's Menu is shown below.

Figure 4

Step 5 - Run the Web Page

Run your web page to display the following menu.

Figure 5 - The Final Output

Downloads

[Download Sample]

Conclusion

This article shows how to create a menu using a self-join database table, SqlDataAdapter, DataSet, DataRelation, XML, XmlDataSource and XSLT using just a few lines of code. The self-join table stores parent child menu relationships. The SqlDataAdapter fills the Dataset. The DataSet employs a DataRelation which is used to create a nested XML. XmlDataSource then applies the XSLT to the nested XML transforming it for use by Microsoft's Menu.

My next article will build upon this example and show how to create a WebForm that manipulates a database driven hierarchical menu.

Please provide feedback, letting me know how you liked this article. Happy coding!

References

Use the below references to learn how to create table relationships, format menu styles and convert XML using XSLT.

Deploying ASP.NET Web Applications in the Windows SharePoint Services 3.0 _layouts Folder

Windows SharePoint Services 3.0 uses the following folder to deliver SharePoint administration pages to each site in the site collection:

%ProgramFiles%\Common Files\Microsoft Shared\Web server extensions\12\Template\Layouts

The layouts folder is a special directory that gets "virtualized" for each SharePoint site. That is, each SharePoint site will have a /_layouts path from the root of the Web. For example http://servername/sites/sitename/_layouts. You can make an ASP.NET 2.0 Web application available under each SharePoint site by deploying the application to the layouts folder. This How To illustrates deploying ASP.NET Web applications in the Windows SharePoint Services 3.0 _layouts folder.

Code It

The following sections use Visual Studio 2005 to create a simple ASP.NET 2.0 Web site that you can deploy to the SharePoint _layouts folder. The process includes four major steps:

  • Creating a Web site project in Visual Studio 2005.

  • Adding a reference to the SharePoint Services assembly to the Visual Studio project.

  • Modifying the Web site to use the SharePoint master page.

  • Copying the Web site to the SharePoint _layouts folder.

To create a Web site project in Visual Studio 2005

  1. Start Visual Studio.

  2. On the File menu, click New, and then click Web site. The New Web site dialog box appears.

  3. In the Visual Studio installed templates pane, select ASP.NET Web site.

  4. Select File System for the Location and specify a path and name for the project.

    NoteNote:
    You can select the SharePoint _layouts folder as the parent folder for the folder containing the new Web site. Doing this removes the need to copy the Web site to the _layouts folder. For the purposes of illustration, this How To takes the approach of creating the new Web site in a separate folder and then copying it to the _layouts folder.
  5. Select Visual C# or Visual Basic for the Language and click OK. Visual Studio generates an ASP.NET Web Site project and opens the default.aspx page in the editor.

    ASP.NET site in Windows SharePoint Servi

    Figure 1. Create New Web site

The sample code shown below uses the SharePoint SPWeb and SPContext classes to illustrate that the Web site is running in the SharePoint context. You can use these classes by adding a reference to the SharePoint Services assembly to the project.

If Visual Studio is running on a computer that has SharePoint Services installed, do the following:

To add a reference to the SharePoint Services Assembly

  1. From the Context menu, right-click the default.aspx file in the code editor and click Add Reference. The Add Reference dialog box is displayed.

  2. In the Add Reference dialog box, click the .NET tab, then locate and select the following component:

    Windows SharePoint Services component (Microsoft.SharePoint.dll)

  3. Click OK to add the reference.

    If Visual Studio is running on a computer that does not have Windows SharePoint Services or Office SharePoint Server installed on it then the SharePoint Services assembly is not available. In this case, you can copy the assembly from a computer with SharePoint Services installed to a local project folder on the development computer. The assembly file you need to create the sample Web site is Microsoft.SharePoint.dll. By default this assembly is located in the following folder on a computer that has SharePoint Services installed:

    C:\Program Files\Common Files\Microsoft Shared\Web server extensions\12\ISAPI

    After you make a local copy of the assembly, you can add the necessary reference to the Web site project by browsing for the local file.

  4. In Visual Studio Solution Explorer, right-click the Web site project name and click Add Reference. The Add Reference dialog box is displayed.

  5. Click the Browse tab then navigate to the local folder containing the copy of the SharePoint assembly.

  6. Select the Microsoft.SharePoint.dll file.

  7. Click OK to add the reference to the project.

Master pages are a feature of ASP.NET 2.0; they work the same way in Windows SharePoint Services 3.0 and Office SharePoint Server 2007 as they do in ASP.NET 2.0. Using master pages, you can create a single page template and then use it as the basis for multiple pages, instead of having to build each new page from scratch. SharePoint uses master pages to provide a consistent look and feel for the site. You need to modify the default.aspx page to make the sample Web site fit seamlessly into the SharePoint site by using the SharePoint master page.

The first step is to add the following MasterPage attribute to the page directive at the top of the default.aspx file:

MasterPageFile="~/_layouts/application.master"

This specifies that the default.aspx page uses the SharePoint application.master page for a master page. The application.master page is provided with SharePoint and provides the master page functionality for the administrative related pages that are located in the _layouts folder.

Master pages make use of content placeholder controls. These placeholder controls define regions where replaceable content will appear. In turn, the replaceable content is defined in content pages. Modify the default.aspx page to make it work with two of the content placeholder controls provided with the SharePoint master page by doing the following:

To modify the Website to use the SharePoint Master Page

  1. Add the following directives to the top of the default.aspx file, just below the Page directive modified previously:

    <%@ Assembly Name="Microsoft.SharePoint.ApplicationPages,
    Version=12.0.0.0, Culture=neutral,
    PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="SharePoint"
    Namespace="Microsoft.SharePoint.WebControls"
    Assembly="Microsoft.SharePoint, Version=12.0.0.0,
    Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="Utilities"
    Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0,
    Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  2. Replace the default.aspx HTML markup generated by Visual Studio with the following:



    Title of this site:




    ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
    Test ASP.NET 2.0 Application

    This new code uses two of the master page content placeholders, PlaceHolderMain and PlaceHolderPageTitleInTitleArea, to display its content. PlaceHolderMain displays the main content of the page and PlaceHolderPageTitleInTitleArea displays a title for the application. After you make the changes described above, the dafault.aspx should look like the following:

    Modified default.aspx page

    Figure 2. Modified Default.aspx

    Visual Studio tags the content placeholder IDs and MasterPage directive as invalid because it cannot locate the master page. You can ignore these warnings since you will locate the master page when the Web site is copied to the _layouts folder.

To set the text of the Label control used in the PlaceHolderMain content placeholder, modify the code file for the page by doing the following:

To set the text of the Label control

  1. From the Context menu, right-click the default.aspx file in the code editor and click View Code. Visual Studio displays the default.aspx.cs or default.aspx.vb code file, depending on the language selected when the Web site project was created.

  2. Add the following Imports or using statement to the top of the code file. For the C# case, add the using statement after the using statements generated by Visual Studio.

    Visual Basic
    Imports Microsoft.SharePoint

    C#
    using Microsoft.SharePoint;
  3. Modify the contents of the page load event handler method and add code to set the text of the Label control to display the title of the current Web site. For the Visual Basic case, add the page load event handler by selecting Page Events from the Class Name dropdown list and then selecting LoadMethod Name dropdown list. from the

    Adding the event handler

    Figure 3. Adding Page_Load Event Handler

  4. Add the following code to the body of the Page_Load method:

    Visual Basic
    Dim Web As SPWeb = SPContext.Current.Web
    LabelTitle.Text = Web.Title

    C#
    SPWeb Web = SPContext.Current.Web;
    LabelTitle.Text = Web.Title;

    The default.aspx page currently uses the application.master page as the master page. This master page makes the page look and feel like the other SharePoint pages that are located in the _layouts folder. To make the default.aspx page use a different SharePoint master page, add the following override of the OnPreInit method:

    Visual Basic
    Protected Sub Page_PreInit(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles Me.PreInit
    MyBase.OnPreInit(e)

    Dim Web As SPWeb = SPContext.Current.Web
    Dim strUrl As String = _
    Web.ServerRelativeUrl(+"/_catalogs/masterpage/default.master")

    Me.MasterPageFile = strUrl

    End Sub

    C#
    protected override void OnPreInit(EventArgs e)
    {
    base.OnPreInit(e);

    SPWeb Web = SPContext.Current.Web;
    string strUrl =
    Web.ServerRelativeUrl + "/_catalogs/masterpage/default.master";

    this.MasterPageFile = strUrl;
    }

The preceding code modifies the page at runtime to use the default.master master page that is located in the SharePoint Master Page Gallery. You can use the same technique to select other master pages from the gallery.

To deploy the Web site to the SharePoint _layouts folder, do the following:

To deploy the Web site to the SharePoint layouts folder

  1. Modify the contents of theWeb.config file of ASP.NET Web site and comment out the section. For example:


  2. Save the modified Web.config file.

  3. Copy the folder containing the ASP.NET 2.0 Web site to the following folder on the server running SharePoint:

    %ProgramFiles%\Common Files\Microsoft Shared\Web server extensions\12\TEMPLATE\LAYOUTS

    For example, if the folder containing the Web site files is named MyWebSite, the full path to the folder after you copy it to the SharePoint server would be:

    %ProgramFiles%\Common Files\Microsoft Shared\Web server extensions\12\TEMPLATE\LAYOUTS\MyWebSite

    The Web site is now available and running within the SharePoint context. Navigating to it displays the default.aspx page that shows the title of the site and uses the SharePoint default.master master page.

    ASP.NET site in Windows SharePoint Services

    Figure 4. ASP.NET Site in SharePoint

Read It

Creating a SharePoint application by deploying to the SharePoint _layouts folder has the following benefits:

  • It is an easy way to make functionality available in every site.

  • It is just like developing a regular ASP.NET Web site using the familiar Visual Studio environment.

  • It allows for context sensitive access to the SharePoint object model.

This approach does have some drawbacks, specifically that the deployment of the site is not managed via the SharePoint solution deployment mechanism.

It is best to use a _layouts based application when the goal is to extend every site with some functionality such as additional administration pages.

This article explores how to use Visual Studio 2005 to create a simple ASP.NET 2.0 Web site that you can deploy to the SharePoint _layouts folder. The following steps were performed:

  • Creating a Web site project in Visual Studio 2005.

  • Adding a reference to the SharePoint Services assembly to the Visual Studio project.

  • Modifying the Website to use the SharePoint master page.

  • Copying the Web site to the SharePoint _layouts folder.

Sunday, October 11, 2009

Should you Use DataSet or DataReader

Should you use a DataReader or DataSet?


In the beginning, there was the recordset, a central feature of classic ADO. Like a Swiss army knife, it wasn’t the perfect tool for every job, but given the correct configuration, it could do whatever you needed it to do.

The recordset wasn’t always pretty to watch, however, and it came into prominence at a time when client/server applications for which it was optimized were being replaced by web applications. Its dark side included an amazing level of complexity and the number of special cases when it was used with particular providers.

So while the recordset could do almost any task, most code did not use it correctly—in some cases using inappropriate default values, and in others explicitly setting parameters in ways that were not optimal for the application at hand.

Enter ADO.NET


When I was first introduced to ADO.NET, then called ADO+, I was a little concerned: Calling this new technology by the same name as what we now know as classic ADO would cause no end of confusion. I was also troubled by the lack of scrollable cursors and a number of other features not supported in ADO.NET.

My concerns were well founded. Many classic ADO developers new to ADO.NET were befuddled by the lack of anything called a recordset. They expected a 2.0 sort of upgrade to classic ADO. Instead, ADO.NET was a totally new set of components, and it was optimized for the Internet world.

Access through DataReader


When accessing data with ADO.NET, you can use either a DataReader or a DataSet. I’ll start with the DataReader.

There are a number of data providers, such as SqlClient, included with ADO.NET, and each has its own implementation of the DataReader. All of the DataReader classes implement the IDataReader interface. While having different classes for the DataReader in each data provider might seems troublesome, you can usually specify a parameter or return value as an IDataReader and ignore the specific type of the DataReader. Unfortunately, there are a number of occasions when this is not possible. I’ll go into this a bit later.

So, what is a DataReader? It is a one-way, forward-only method of reading data. A common use of the DataReader to read through a result set would look like the following:



while ( DataReader.Read() )
{
Console.WriteLine(“Name: “ + DataReader[“Name”].ToString();
}



When you get the results into the DataReader, it’s important to note that the “cursor” or logical pointer into the returned data is just before the first row. You need to call .Read() once to read any data. .Read() will return true as long as there is an additional row to be read.

This pattern results in better code than the standard patterns used for classic ADO recordsets. When working with recordsets, the logical pointer is initially placed at the first row of data. To read records you must create a loop that contains a call to .MoveNext at the bottom of the loop. I cannot tell you the number of times I forgot this when working with recordsets in classic ADO. Whenever my application stopped when it should be reading data, I knew I had forgotten or misplaced the .MoveNext call.

A common complaint on the newsgroups related to classic ADO recordsets was the lack of a reliable row count. The availability of a proper row count was dependent on the cursor location and a number of other factors. In the DataReader, even the pretense of a row count is gone. In fact, in the 1.0 implementation, there was no way to know if the DataReader had any data without reading it. And reading the DataReader actually consumed the row. Fortunately, version 1.1 implementations contain a .HasRows property.

Note: There is no IDataReader2 interface that includes the .HasRows property. If you want to use .HasRows, you need to cast it to the implementation class that supports it.

Access through DataSet


Another way to access data with ADO.NET is to use a DataSet. A DataSet is a database-independent, in-memory data store that enables the developer to directly access all rows and columns of one or many tables that a DataSet can contain. The DataSet has a Tables collection of DataTable objects, and the DataTable has a Rows collection that can be indexed to get to a particular row by number. The Rows collection has a .Count property that enables the developer to determine the number of rows in any of the tables in a DataSet.

One thing missing in the classic ADO recordset was the ability to control exactly how an update would take place. The DataSet enables you to update the in-memory copy of the data, and use a DataAdapter specific to a data provider to have those changes persisted back in the database.

If you run a shop where database updates are done using stored procedures, you can use a properly configured DataAdapter to ensure that changes to the database are made using stored procedures. The important thing to remember is that the DataSet is independent of any particular database; the only connection that exists is when the DataSet is used in conjunction with a DataAdapter.

Which to use?

Which of the data access classes should you use in your application?

If you need read-only access to the data, something often done inside an ASP.NET application, using a DataReader makes sense. Unless you are going to persist the data between postbacks, the data that you use to, say, populate a grid, will not be present when someone clicks on one of the rows of that grid.

The ASP.NET application model is that there will be a number of independent requests, and between requests, a client will not maintain a connection to the database. ASP.NET provides session state, a way of maintaining the appearance of a stateful application, but storing a client-specific DataSet in session state is not considered good form and may limit the scalability of your application.

When updates to the data are required, you can either directly execute UPDATE, INSERT or DELETE SQL statements, or you can call a stored procedure. While this seems like more work that just updating data in a DataSet, it gives you more control over exactly how the updates take place, and works very well in a web environment.

One possible disadvantage of using a DataReader is that the connection must be open while you are accessing the data. If you will be doing lengthy processing with each row of returned data, a DataSet might be a better idea. The DataSet can be filled (using a DataReader under the covers, by the way), and then you can use the data in the DataSet at your leisure without consuming a connection.

If you are building a Windows Forms application (or a “Smart Client”), DataSets offer some advantages. Since the application will maintain its state over the entire time it is running, and client context does not tie up server resources, using a DataSet can be very convenient for Windows Forms applications. The model for how it is used is very similar to a classic ADO recordset configured to use client cursor, except that rather than moving a logical cursor, the DataTable’s Rows collection is indexed to reach a particular row.

The dark side of using DataSets is that the data remains in memory for as long as you use it. If you are retrieving thousands or millions of rows, a DataSet is probably not an ideal solution.

Some exceptions…

My predisposition to using DataReaders for ASP.NET applications and DataSets for Windows Forms applications has many exceptions. One of the features of the DataSet that makes it flexible is that it can be easily serialized into XML. It is often convenient to use the .WriteXml method to write out the contents of the DataSet. You cannot write out a single DataTable in a DataSet in the 1.x version of ADO.NET, however.

In addition to writing the DataSet to an XML file, .NET Web Services accepts parameters of type DataSet and return values of type DataSet. While this can be powerful, it does limit your application to .NET consumers of your web service, since the DataSet is not accepted by web services created with any other tools I am aware of. Many people consider it evil to return a DataSet from a web service, but it can be a good idea, especially if you are certain that only .NET consumers will ever need to access your web service.

DataSets can also easily be passed between layers in an application, even if those layers are not in the same process space. For instance, an application server can get the data from a database and then send off the DataSet across process space, or even across a wire to a separate server doing presentation services.

There is one special case where DataSets are essential in an ASP.NET application. When you have data that is accessed by a number of users and can reasonably be cached for at least a short period of time, the cache system (in the System.Web namespace, but actually usable in Windows Forms applications) can be used on a DataSet. Caching can have a dramatic impact on the performance of a heavily used application.

If you are passing results between logical layers inside the same process address space, you can still use DataReaders. How then, you may wonder, do you ensure that the connection is closed? You can’t close it in the method for creating the DataReader, nor can you close it in the method for returning the DataReader since the DataReader will be closed as well.

When you create a DataReader, you call .ExecuteDataReader. This method accepts a parameter that can be CommandBehavior.CloseConnection. This parameter tells the DataReader that when it is closed, the underlying connection should be closed as well. This is an example function that shows how you can return a DataReader and ensure that it is closed by the calling method:




public static IDataReader SelectByRoyalty(int Percentage)
{
SqlDataReader dr=null;
SqlConnection cn=new SqlConnection("Server=Aron1;Database=pubs;Trusted_Connection=True;");
cn.Open();
try
{
SqlCommand cmd=new SqlCommand("byRoyalty",cn);
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("@Percentage",Percentage);

dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch ( Exception Ex )
{
if ( dr!=null )
{
dr.Close();
cn.Close();
}
throw Ex;
}
return (IDataReader)dr;
}

Then, you could call the method as follows:

IDataReader dr=Coatings.SelectCoating(CoatingID);
try
{
// Use the DataReader..
}
Finally
{
dr.Close();
}



Failure to use a pattern like this will lead to a great deal of difficulty with connections that are not closed in a timely fashion. I believe that Microsoft initially pushed DataReaders as the preferred way to do database access, at least for ASP.NET applications. As time went on, I think the company discovered that many developers misused DataReaders, not properly closing the connection. Recent Microsoft presentations have often emphasized DataSets even for ASP.NET applications.

Securing connection strings and making secure authentication method

Introduction:

In this article we will see that how we can secure our connection string by encrypting it and we will also see how we can make secure login screens.
Saving connection String without Encryption:

Let's see a small example where we store the connection string in the web.config file without encrypting it.





value="server=localhost;uid=sa;pwd=;database=DBPerson" />



















This is one of the worst ways of storing the connection string. As you can see we can easily see the userid and the password for this database connection and anyone can easily access the database without authentication.

Let's see a little better approach of saving the connection string:



value="server=(local);Integrated Security=SSPI;database=northwind"/>




As you see above that the connection string is now saved without displaying the username and the password. This is better than the last connection string but still we can see what database is being used. In this case its northwind database.

Now we will see that how we can encrypt the connection string so hackers are not able to see the important information about the database. We will make a small method that will take the connection string as the parameter and it will return the encrypted connection string. We can place the returned encrypted connection string back in the web.config file. I will also tell you that how you can decrypt the connection string when using in your application.

Encrypting Connection Strings:

Let's see the method which encrypts the connection string.



// This method is used to encrypt the connection string

private string EncryptConnectionString(string connectionString)
{

Byte[] b = System.Text.ASCIIEncoding.ASCII.GetBytes(connectionString);

string encryptedConnectionString = Convert.ToBase64String(b);

return encryptedConnectionString;
}



Explanation of the Code:

1) The method EncryptConnectionString takes in the connectionString and returns the encrypted ConnectionString

2) In this case we have used the ASCIIEncoding which gets the bytes representation of the connection string and store it in an array.

3) Finally, we encrypt the connection string using the ToBase64String method of the Convert class and the connection string is returned to the caller.

If you print out the connection string you will find something like this:

ZGF0YSBzb3VyY2U9Llx2c2RvdG5ldDtpbml0aWFsIA0KICAgY2F0YWx

Once you got the encrypted connection string you can copy and paste it in the web.config file.




value="ZGF0YSBzb3VyY2U9Llx2c2RvdG5ldDtpbml0aWFsIA0KICAgY2F"/>




As you can see now the connection string has been encrypted and saved in the web.config file. You can no longer read the connection string by just looking at the encrypted string.

Lets see that how we can decrypt the connection string so that we can use it in our applications.


// This method is used to decrypt the connection string

private string DecryptConnectionString()
{

Byte[] b = Convert.FromBase64String(ConfigurationSettings.AppSettings["ConnectionString"]);

string decryptedConnectionString = System.Text.ASCIIEncoding.ASCII.GetString(b);

return decryptedConnectionString;

}


Explanation of the Code:

1) First we get the byte representation of the connection string. You can see that we are retrieving the encrypted connection string from the web.config file.

2) Later we decrypt the connection string using the same method that we first used to encrypt it. And finally we returned the decrypted connection string to the caller.

There are many more complex algorithms that you can use to encrypt and decrypted the connection strings. But this is surely one of the most simple encryption and decryption algorithms.
Making secure authentication:

Let's now talk about making a secure authentication. First let's see what we mean by bad authentication. For this purpose we will make a simple login page which consists of username and the password. Your user interface will look something like this:

As, you can see this is a simple login page with two textboxes, two labels and a login button. Lets see some bad login code:



// This is the login button click code

private void Button1_Click(object sender, System.EventArgs e)
{

if(txtUserName.Text == "vikram" && txtPassword.Text == "takkar")
{

// print the message welcome to the website.

}
else
{

// print the message. you are not authorized to visit this website

}

}



This is the absolute worst login code. The developer has hardcode the username and the password in the presentation layer file. This not only gives the direct interaction of the user to the business logic but this code is also very hard to maintain. Suppose, in 2 weeks some new users have registered for this website. Now you have to go back to the file and edit the if-else checks. If you have 100 users you will have 100 if-else checks which is the worst scenario.

Let's see a some important points to make a better login page:

1) You must validate the input of the user. If the fields are necessary it should be check at the interface level using the required field validator web controls provided by the Microsoft.net framework.

2) If you are checking authentication of the users its always a good idea to store the users in the database rather than hard code it in the file.

3) Always check for the SQL Injections. Users can put anything in the textbox that can make your application crash. All the dangerous user input much be catch.

4) Never and never give the user ability to directly communicate with the business logic. Also always store the business logic in a separate class files.

5) If you are planning to use the Login control on each and every page of you application it's a better idea to make the login control as a User Control in this way you can easily modify it without having to go to all the pages.

6) Finally, don't give too much information to the user. What I mean to say is that if the users enters the wrong password don't tell him that the password is 6 digits long and its your favorite pet name. Always give the message which is to the point like "Invalid password".