Saturday, August 23, 2008

Why LINQ?

Why LINQ?

  • Increases productivity compared to using ADO.NET
  • SQL has many vendor-specific dialects and data types.
  • Integration with C# and VB. Syntax of the LINQ query would remain similar when query against different data sources, such as
    • Database
    • XML
  • Parametrization is automatic and type-safe.
  • Extensive IntelliSense support / Debugger support
  • Strongly typed queries - compile-time checking for all queries.
  • Not just for queries

Current version of LINQ to SQL

  • LINQ to SQL works only with SQL Server
  • Does not directly support CTEs and FullText search
  • Targeted for Rapid Development - 1:1 relationship between table and object

The Entity Framework

  • Support more database engines than just SQL Server
  • LINQ to entities is more "enterprise" targeted
  • You can map a single class to multiple tables, or map multiple classes to the same table.

Other Usage

References:

Why LINQ will succeed

LINQ in Action

LINQ to SQL vs LINQ to Entities, where should we spend our time?

Difference between LINQ to SQL and the Entity Framework

Tuesday, August 19, 2008

Composite Key

  • This is a very basic SQL topic but I think it is necessary to clarify the concept.
  • A Primary Key uniquely identifies each row in a table, it is not always a single-column key,it could be
    • a single-column key
    • or a composite key
  • A primary key can consist of one or more columns of a table. When two or more columns are used as a primary key, they are called a composite key. Each single column's data can be duplicated but the combination values of these columns cannot be duplicated.
  • For example, if you have a Student table and a Course table, and one student can select many courses and one course can be selected by many students, so this is a many-to-many relationship. So you need to create the third table to define the relationship, say it's called StudentCourse. It is important to note that you only need the StudentID and CourseID in this table as a composite key. You do not need an extra identity ID column in this table to uniquely identifies each row because only having an ID column to uniquely identifies each row is not sufficient. It cannot prevent the same student selecting the same course from being inserted into this table.

Reference:

Composite Primary Keys

Primary Key

Sunday, August 17, 2008

LINQ to SQL

DataContext Class

  • It establishes a connection to a database
  • It contains a Table(Of T) public property for each table you have mapped in the database
  • You should use a class derived from the DataContext class, this class should be named as [DatabaseName]DataContext
Insert Data

  • Create a DataContext object
  • Create an entity class object
  • Call InsertOnSubmit of the DataContext object to insert the entity object into System.Data.Linq.Table(Of T)
  • Call SubmitChanges of the DataContext object

Demo:

1. Create a VS2008 project, add a LINQ to SQL Classes (DataClasses1.dbml) to the project.

2. Drag and drop the database table from the Server Explorer to the dbml design surface. In this case, I will drag a Course Table which contains a CourseID and a CourseName column from a Database named Test. VS2008 automatically generates the DataClasses1DataContext class which is derived from the DataContext class. VS2008 also generates the Course entity class. Here is DataClasses1.designer.vb

'------------------------------------------------------------------------------

' <auto-generated>

' This code was generated by a tool.

' Runtime Version:2.0.50727.1433

'

' Changes to this file may cause incorrect behavior and will be lost if

' the code is regenerated.

' </auto-generated>

'------------------------------------------------------------------------------

Option Strict On

Option Explicit On

Imports System

Imports System.Collections.Generic

Imports System.ComponentModel

Imports System.Data

Imports System.Data.Linq

Imports System.Data.Linq.Mapping

Imports System.Linq

Imports System.Linq.Expressions

Imports System.Reflection

<System.Data.Linq.Mapping.DatabaseAttribute(Name:="Test")> _

Partial Public Class DataClasses1DataContext

Inherits System.Data.Linq.DataContext

Private Shared mappingSource As System.Data.Linq.Mapping.MappingSource = New AttributeMappingSource

#Region "Extensibility Method Definitions"

Partial Private Sub OnCreated()

End Sub

Partial Private Sub InsertCourse(ByVal instance As Course)

End Sub

Partial Private Sub UpdateCourse(ByVal instance As Course)

End Sub

Partial Private Sub DeleteCourse(ByVal instance As Course)

End Sub

#End Region

Public Sub New()

MyBase.New(Global.System.Configuration.ConfigurationManager.ConnectionStrings("TestConnectionString").ConnectionString, mappingSource)

OnCreated()

End Sub

Public Sub New(ByVal connection As String)

MyBase.New(connection, mappingSource)

OnCreated()

End Sub

Public Sub New(ByVal connection As System.Data.IDbConnection)

MyBase.New(connection, mappingSource)

OnCreated()

End Sub

Public Sub New(ByVal connection As String, ByVal mappingSource As System.Data.Linq.Mapping.MappingSource)

MyBase.New(connection, mappingSource)

OnCreated()

End Sub

Public Sub New(ByVal connection As System.Data.IDbConnection, ByVal mappingSource As System.Data.Linq.Mapping.MappingSource)

MyBase.New(connection, mappingSource)

OnCreated()

End Sub

Public ReadOnly Property Courses() As System.Data.Linq.Table(Of Course)

Get

Return Me.GetTable(Of Course)()

End Get

End Property

End Class

<Table(Name:="dbo.Course")> _

Partial Public Class Course

Implements System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged

Private Shared emptyChangingEventArgs As PropertyChangingEventArgs = New PropertyChangingEventArgs(String.Empty)

Private _CourseID As Integer

Private _CourseName As String

#Region "Extensibility Method Definitions"

Partial Private Sub OnLoaded()

End Sub

Partial Private Sub OnValidate(ByVal action As System.Data.Linq.ChangeAction)

End Sub

Partial Private Sub OnCreated()

End Sub

Partial Private Sub OnCourseIDChanging(ByVal value As Integer)

End Sub

Partial Private Sub OnCourseIDChanged()

End Sub

Partial Private Sub OnCourseNameChanging(ByVal value As String)

End Sub

Partial Private Sub OnCourseNameChanged()

End Sub

#End Region

Public Sub New()

MyBase.New()

OnCreated()

End Sub

<Column(Storage:="_CourseID", AutoSync:=AutoSync.OnInsert, DbType:="Int NOT NULL IDENTITY", IsPrimaryKey:=True, IsDbGenerated:=True)> _

Public Property CourseID() As Integer

Get

Return Me._CourseID

End Get

Set(ByVal value As Integer)

If ((Me._CourseID = value) _

= False) Then

Me.OnCourseIDChanging(value)

Me.SendPropertyChanging()

Me._CourseID = value

Me.SendPropertyChanged("CourseID")

Me.OnCourseIDChanged()

End If

End Set

End Property

<Column(Storage:="_CourseName", DbType:="VarChar(50)")> _

Public Property CourseName() As String

Get

Return Me._CourseName

End Get

Set(ByVal value As String)

If (String.Equals(Me._CourseName, value) = False) Then

Me.OnCourseNameChanging(value)

Me.SendPropertyChanging()

Me._CourseName = value

Me.SendPropertyChanged("CourseName")

Me.OnCourseNameChanged()

End If

End Set

End Property

Public Event PropertyChanging As PropertyChangingEventHandler Implements System.ComponentModel.INotifyPropertyChanging.PropertyChanging

Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Protected Overridable Sub SendPropertyChanging()

If ((Me.PropertyChangingEvent Is Nothing) _

= False) Then

RaiseEvent PropertyChanging(Me, emptyChangingEventArgs)

End If

End Sub

Protected Overridable Sub SendPropertyChanged(ByVal propertyName As [String])

If ((Me.PropertyChangedEvent Is Nothing) _

= False) Then

RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))

End If

End Sub

End Class


3. Here is a demo page to show how to add/delete courses:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="TestLinq._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:dropdownlist ID="ddlCourse" runat="server"></asp:dropdownlist>

<asp:Button ID="btnAdd" Text="Add Course" runat="server"/>

<asp:Button ID="btnDelete" Text="Delete Course" runat="server"/>

</div>

</form>

</body>

</html>


Partial Public Class _Default

Inherits System.Web.UI.Page


Dim dc As New DataClasses1DataContext()


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

If Not IsPostBack Then

ddlCourse_Bind()

End If

End Sub


Private Sub ddlCourse_Bind()

Dim courses = From c In dc.Courses _

Select c

ddlCourse.DataTextField = "CourseName"

ddlCourse.DataValueField = "CourseID"

ddlCourse.DataSource = courses

ddlCourse.DataBind()

End Sub


Private Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.Click

Dim c As New Course()

c.CourseName = DateTime.Now.ToString()

dc.Courses.InsertOnSubmit(c)

dc.SubmitChanges()

ddlCourse_Bind()

End Sub


Private Sub btnDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDelete.Click

'This will throw the following exception

'Unable to cast object of type 'System.Data.Linq.DataQuery`1[TestLinq.Course]' to type 'TestLinq.Course'.

'Dim course = From c In dc.Courses _

' Where c.CourseID = ddlCourse.SelectedValue _

' Select c

'dc.Courses.DeleteOnSubmit(course)

'dc.SubmitChanges()

'ddlCourse_Bind()

Dim course = dc.Courses.Single(Function(c) c.CourseID = ddlCourse.SelectedValue)

dc.Courses.DeleteOnSubmit(course)

dc.SubmitChanges()

ddlCourse_Bind()

End Sub

End Class

Tuesday, August 12, 2008

Best Practices in VB.NET

Optional parameters

  • Do not use the Optional keyword when defining a public method in a public class.
  • Use overloading to support methods with different numbers of arguments
  • Even though Optional is CLS-compliant, they are not visible to C# clients.
  • For example, if a VB.NET method takes one regular argument and three optional ones, a C# client always must pass four arguments

DirectCast operator

  • Use the DirectCast operator instead of CType/CInt when you unbox a value type, such as convert a object to an Integer.
    • This is inefficient => CInt(object) or CType(object, Integer)
    • Use this => DirectCast(object, Integer)
  • Unlike CType, the DirectCast operator is never translated to a call into the CLR library and is therefore more efficient.
  • The CType operator should be used only to perform conversions - for example, from string to Integer or DateTime.

Reference:

Practical Guidelines and Best Practices for Microsoft Visual Basic and Visual C# Developers

Saturday, August 9, 2008

Sandcastle - ASP.Net Documentation

Sandcastle

Example:

1. Firstly, you will need to comment your code properly using the summary tag, for methods the param tag, returns tag etc. If you want Sandcastle to exclude a class use


''' <exclude/>



2. After installation, open up Sandcastle Help File Builder. Select the assembly file that you want to document in the bin folder by clicking the Add button. It will automatically pick up the assembly XML file as well.


3. If the dll have other dependencies referenced in the Visual Studio project, you can specify them in the Dependencies property (highlighted in red).
4. You can also specify the copyright text, the document window title and the document file name etc.
5. I have created a sperate xml file (API_NS.xml). This purpose of this file is to provide the summary comments for namespaces since it is not automatically generated. Add this xml to the Builder.

6. Click the Build button on the top menu to build the document. The generated document is named API.chm and here is what it looks like:

Thursday, August 7, 2008

ClientScriptManager

ClientScriptManager Methods

Example:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ClientScriptManager.aspx.cs" Inherits="Demo4_ClientScriptManager" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>ClientScriptManager</title>

</head>

<body>

<form id="form1" runat="server">

<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />

</form>

</body>

</html>


using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

public partial class Demo4_ClientScriptManager : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

}

protected void Button1_Click(object sender, EventArgs e)

{

ClientScriptManager cs = this.ClientScript;

cs.RegisterArrayDeclaration("NewArray", "1, 2, 3");


if (!cs.IsClientScriptIncludeRegistered(this.GetType(), "IncludeFile"))

{

cs.RegisterClientScriptInclude(this.GetType(), "IncludeFile", ResolveClientUrl("~/HelloWorld.js"));

}


cs.RegisterExpandoAttribute(this.Button1.ClientID, "value", "Submit");


cs.RegisterHiddenField("MyHiddenField", "HiddenValue");


ClientScriptManagerHelper.RegisterStartupScript("HelloWorld", "<script>alert('Calling RegisterStartupScript')</script>");


cs.RegisterClientScriptBlock(this.GetType(), "HelloWorld", "alert('Calling RegisterClientScriptBlock');", true);

}

}


You can also use a helper class:

using System;

using System.Data;

using System.Configuration;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

Public Class ClientScriptManagerHelper

{

public static void RegisterStartupScript(string key, string script)

{

Page p = HttpContext.Current.Handler as Page;

if (p != null)

{

ClientScriptManager cs = p.ClientScript;

if (!cs.IsStartupScriptRegistered(p.GetType(), key))

{

cs.RegisterStartupScript(p.GetType(), key, script);

}

}

}

}


Result:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>ClientScriptManager </title>

</head>

<body>

<form name="form1" method="post" action="ClientScriptManager.aspx" id="form1">

<div>

<input type="hidden" name="MyHiddenField" id="MyHiddenField" value="HiddenValue" />

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTQ2OTkzNDMyMWRkvBqH01KLDoGJ1Xt5N2w3nQeGoRM=" />

</div>

<script src="../HelloWorld.js" type="text/javascript"></script>

<script type="text/javascript">

//<![CDATA[

alert('Calling RegisterClientScriptBlock');

//]]>

</script>

<input type="submit" name="Button1" value="Button" id="Button1" />

<script type="text/javascript">

//<![CDATA[

var NewArray = new Array(1, 2, 3);

//]]>

</script>

<script type="text/javascript">

//<![CDATA[

var Button1 = document.all ? document.all["Button1"] : document.getElementById("Button1");

Button1.value = "Submit";

//]]>

</script>

<div>

<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgLGgea2CAKM54rGBgJqlPv4pQBR4CG20xV8nc5Nkpaa" />

</div>

<script>alert('Calling RegisterStartupScript')</script>

</form>

</body>

</html>


Note: Even though RegisterStartupScript is calling before RegisterClientScriptBlock in the above code, but at run time the alert will show RegisterStartupScript last. Also you can see the html result, the RegisterStartupScript script was added to the page last.

Reference:
ClientScriptManager Methods

Saturday, August 2, 2008

Sharepoint Architecture - IIS 6.0, ASP.NET & ISAPI

IIS 6.0

  • ASP.NET & WSS rely on IIS 6.0 to supply the underlying listening mechanism to process incoming HTTP requests and supply a management infrastructure for launching and running worker processes on the web server.
  • IIS can handle request coming in over:
    • A specific IP address
    • Port number
    • Host header

IIS Market Share

  • Since April 1996 Apache has been the most popular HTTP server on the World Wide Web. As of June 2008 Apache served 49.12% of all websites.
  • Microsoft Internet Information Services is a set of Internet-based services for servers using Microsoft Windows. It is the world's second most popular web server. As of June 2008 it served 35.39% of all websites.

IIS 6.0 installation

  • When you install IIS 6.0 on Win Server 2003, the following files and directories are installed:
    • C:\windows\System32\InetSrv
    • C:\InetPub
    • C:\windows\Help\IISHelp
  • The following accounts will be created:
    • IUSR_computername
    • IWAM_computername

Account

  • For classic ASP applications:
    • The account which anonymous users are running under is IUSR_computername.
    • If Application Protection is set to High (Isolated ) and you are using Anonymous Access, the account that IIS is using is the IWAM_computername account.
  • For ASP.NET applications:
    • ASP.NET will run under ASPNET account. This account will be used by the ASP.NET worker process (aspnet_wp.exe). On Windows Server 2003, ASP.NET will run under "Network Service".
    • With ASP.NET Impersonation Disabled, the account which anonymous users are running under is ASPNET or Network Service account.

ISAPI Extensions & Filters

  • The Internet Server API (ISAPI) is an N-tier API of Internet Information Services (IIS). ISAPI consists of two components: Extensions and Filters, and they must be written in unmanaged C++.
  • When a request comes into Microsoft's IIS Web server its extension is examined and, based on this extension, the request is either handled directly by IIS or routed to an ISAPI extension.
    • Simple scenario: IIS simply maps an incoming request to a physical file within the root directory of an IIS web site or virtual directory, such as loading a static html page or an image file.
    • Sophisticated routing scenario: IIS also supports ISAPI, so that an incoming request triggers the execution of custom code on the web server.
  • ISAPI Extension
    • An ISAPI extension is a DLL. IIS can map incoming requests to a set of endpoints that trigger the execution of code within an ISAPI extension DLL.
    • Whenever an extension is accessed (e.g., http://www.test.com/myextension.dll?ID=1), IIS checks to see whether the DLL is loaded into memory. If it is not, then IIS will load the DLL which will be loaded to memory once, no matter how many clients are going to use it at the same time.
    • Can be configured at level of an IIS web site or virtual directory
    • When you install the .NET Framework, an ISAPI extension named aspnet_isapi.dll is automatically registered for handling requests for the .aspx extension. When a user makes a request for a page with the aspx extension, IIS will pick up the request and passes it to the aspnet_isapi.dll ISAPI extension. (Image 1)
  • ISAPI Filter
    • An ISAPI filter is a DLL the server calls on every HTTP request. It plays the role of an interceptor
    • Usage:
      • Custom authenticatio
      • Request logging
    • Can be configured at the level of the IIS web site

(Image 1)

IIS 5 vs IIS 6

  • IIS 5
    • When a request comes in, inetinfo.exe process in IIS 5 hosts aspnet_isapi.dll and forwards the request to it. The aspnet_isapi.dll will create a new instance of aspnet_wp.exe worker process. This process will host the .NET runtime and forward the request to it.
    • Because the aspnet_isapi.dll and .NET runtime are in two separate processes, they use a named pipe to communicate.
  • IIS 6
    • IIS 6 doesn’t directly host aspnet_isapi.dll, instead IIS 6 always creates a separate instance of w3wp.exe worker process and all processing occurs inside of this process which hosts both aspnet_isapi.dll and the .NET runtime.This improves the performance because no named pipe is needed.
    • IIS uses a device driver named HTTP.SYS to route incoming requests to the proper application pool.


References:
Apache HTTP Server
Internet Information Services
Internet Server Application Programming Interface
What an ISAPI extension is?
A low-level Look at the ASP.NET Architecture
Inside Microsoft Windows SharePoint Services 3.0
How Do I Determine the Security Account that IIS Uses to Run My Web Site?
Professional ASP.NET 2.0 Server Control and Component Development