Wednesday, January 11, 2012

4 real time uses of Partial classes and partial methods..

Introduction
Fundamentals of partial classes
Fundamentals of partial methods
Use number 1:- ASP.NET auto generated code
Use number 2:- LINQ and Entity framework
Use number 3:- Better maintenance by compacting large classes
Use number 4:- Multiple people working on the same class
Introduction

Recently I was hunting about partial classes and the real time use of the same. Many of those postings found on google talked about the concept of partial classes and partial methods, but in what scenarios to use them very few highlighted.

In this article we will first start with fundamentals of partial classes and methods and then discuss the 4 real time use of the same.

I have also created a video of the same here where I have discussed about partial classes and shown the real time use of the same.

Fundamentals of partial classes

A partial class allows a single class to be divided in to two separate physical files. During compile time these files get compiled in to single class. For instance you can see in the below figure we have the customer class divided in to two different files “customer1.cs” and “customer2.cs”.

During compilation these files gets compiled in to single class internally. So when you create an object of the customer class you will be able to see methods lying in both the physical files. For instance you can see “Add” method belongs to “customer1.cs” and “Delete” method belongs to “customer2.cs” , but when the customer object is created we can see both “Add” and “Delete” methods.

Fundamentals of partial methods

There is one more important concept in partial classes called as partial methods. Partial methods helps us to define a method definition in one of the physical files and we can implement that method in the other physical files as shown in the below figure.

In the below figure you can see we have defined “Validate” method in “Customer1.cs” and this validate method is implemented in “Customer2.cs”. Please note the partial keywords attached to both of these methods.

Use number 1:- ASP.NET auto generated code

The biggest use of partial classes is in technologies where there is code generation. Microsoft team themselves use partial classes in ASP.NET, LINQ and EF code generation. For instance when we look at ASP.NET there are two parts one is the auto generated code of a page and the other is behind code where you write your custom logic.

The custom logic is written in the “.aspx.cs” file while the auto generated logic is in “.aspx.designer.cs” file as shown in the below figure.

As a developer you would like the auto generated code to do his work i.e. generate code when you drag and drop a button the ASP.NET designer.

Below is how the code snippet of the auto generated code looks like.
Collapse | Copy Code

public partial class WebForm1 {

///
/// form1 control.
///
///
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
///

protected global::System.Web.UI.HtmlControls.HtmlForm form1;

///
/// Button1 control.
///

///
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
///

protected global::System.Web.UI.WebControls.Button Button1;

///
/// Label1 control.
///

///
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
///

protected global::System.Web.UI.WebControls.Label Label1;
}

At the same time you would also like to customize the code in some other file so that the auto generation part is not disturbed. For the same ASP.NET provides the “.aspx.cs” file which is a partial class where in you can go put your own custom logic.
Collapse | Copy Code

public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Your custom logic
}
}

This is only possible when the class is split in two physical files but united via the partial keyword. So if you see any ASP.NET behind code class files it’s marked by the word partial.

So by using the partial keyword in ASP.NET the Microsoft team has made VS and developer work side by side thus not fiddling with each other’s code and thus increasing productivity.

Use number 2:- LINQ and Entity framework

LINQ and EF also use partial classes and methods heavily because of the auto generation nature of these technologies. So when you drag tables in these framework they create auto generated classes as shown in the below figure.

In the below figure you can see how the auto generated code has partial classes and partial methods.

The partial methods later can be extended to put custom logic. For instance you can see in the below code for the above autogenerated class “tblCustomer” we have used partial methods to override the “OnCustomerCodeChanged” event to ensure that customer code is not more than 8 length.
Collapse | Copy Code

public partial class tblCustomer
{
partial void OnCustomerCodeChanged()
{
if (_CustomerCode.Length > 8)
{
throw new Exception("Customer code can not be greater than 8");
}
}
}

So by using partial classes and partial methods, LINQ and EF framework keep auto generating classes and by using partial methods we can customize the class with our own logic.
Use number 3:- Better maintenance by compacting large classes

The other important use of partial classes is for better maintenance of the project. If you have large classes with lots of methods as shown in the below figure , it’s a bit pain to maintain those classes.

By using partial classes you can split them in to physical files as shown in the below figure thus making your project better and easy to maintain.

Use number 4:- Multiple people working on the same class

The last and final real time I see of partial classes is when we want simultaneously two developers to work in the same class. I agree this can be a very rare use as there are better options like using a version control software like TFS or Sub version, but in case you want something quick and local this option is not bad at all.

forgot password and sending recovery link as Email in C#

protected void btnSubmit_Click(object sender, EventArgs e)
{


DataSet ds_sendmail = new DataSet();
SqlDataAdapter da_sendmail = new SqlDataAdapter("select * from LOGIN_USERDETAILS where EmailAddress='" + txtEmailAddress.Text.Trim() + "'", con);
da_sendmail.Fill(ds_sendmail);
if (ds_sendmail.Tables[0].Rows.Count > 0)
{
string Username = ds_sendmail.Tables[0].Rows[0]["Username"].ToString();
int Uid = int.Parse(ds_sendmail.Tables[0].Rows[0]["Uid"].ToString());
string Email=ds_sendmail.Tables[0].Rows[0]["EmailAddress"].ToString();
string resetdate=DateTime.Now.ToString();

string Empname = ds_sendmail.Tables[0].Rows[0]["Firstname"].ToString() + " " + ds_sendmail.Tables[0].Rows[0]["Lastname"].ToString() + ",";
string Title = "Password Recovery Link";

if (Username != null)
{
Guid guid;
guid = Guid.NewGuid();
using (SqlCommand command = new SqlCommand())
{
command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString);
command.CommandText = @"insert into [Password_Reset](Uid, Username, EmailAddress, Guid, Pwddate,active)
values(@Uid, @Username, @Email, @Guid, @Pwddate,@active)";
command.Parameters.Add("@Uid", SqlDbType.Int).Value =Uid;
command.Parameters.Add("@Username", SqlDbType.NVarChar, 50).Value = Username;
command.Parameters.Add("@Email", SqlDbType.NVarChar, 200).Value = Email;
command.Parameters.Add("@Guid", SqlDbType.UniqueIdentifier).Value = guid;
command.Parameters.Add("@Pwddate", SqlDbType.DateTime).Value = resetdate;
command.Parameters.Add("@active", SqlDbType.Int).Value = 1;
command.Connection.Open();
command.ExecuteNonQuery();
}
string pwdlink = "Click this link to reset your Password";

ToEmailId = txtEmailAddress.Text.Trim();
Description = "

Password Reset :

" + "\r\n";
Description += "

You are receiving this email because you filled out a form on alphastaff indicating that you had forgotten your password

" ;
Description += "

You can reset your Password using following link :

" + "\r\n";
Description += "

"+pwdlink+"

";
Description += "

This link can be used for only once

";
Description += "

This link will be expired after 24 hours

";
Description += "

Thanks & Regards

Alphastaff Team

";
Sendmail.Send(Empname,ToEmailId, Title, Description, FromEmaiId);
lblMsg.Visible = true;
lblMsg.Text = "* Password reset link has sent to your Email address";
txtEmailAddress.Text = "";
}
}
else
{
lblMsg.Visible = true;
lblMsg.Text = "* Given Emailaddress is Invalid !";
}

}

Password Reset Page :


using System;
using System.Data;
using System.Data.SqlClient;
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;
using System.Net.Mail;
using Common.BOL;
using Login_Page.BOL;

public partial class PEO_PasswordReset : System.Web.UI.Page
{
SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.AppSettings["dbstring"].ToString());
Login_Page_frm ap = new Login_Page_frm();
string Uid;
string ResetID;
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["ResetID"] != null)
{
ResetID = Request.QueryString["ResetID"].ToString();

DataSet ds_sendmail = new DataSet();
SqlDataAdapter da_sendmail = new SqlDataAdapter("select * from Password_Reset where Guid='" + ResetID + "' and active=1", con);
da_sendmail.Fill(ds_sendmail);
if (ds_sendmail.Tables[0].Rows.Count > 0)
{
DateTime dTFrom;
DateTime dTo;
string sFrom = ds_sendmail.Tables[0].Rows[0]["Pwddate"].ToString();
string sTo = DateTime.Now.ToString();
if (DateTime.TryParse(sFrom, out dTFrom) && DateTime.TryParse(sTo, out dTo))
{
TimeSpan TS = dTo.Subtract(dTFrom);
int diff_total_seconds = int.Parse(TS.TotalSeconds.ToString());

if (diff_total_seconds>86400)
{
Response.Redirect("~/LinkExpiry.aspx");
}

}
string Username = ds_sendmail.Tables[0].Rows[0]["Username"].ToString();
Uid = ds_sendmail.Tables[0].Rows[0]["Uid"].ToString();
string Email = ds_sendmail.Tables[0].Rows[0]["EmailAddress"].ToString();
string resetdate = DateTime.Now.ToString();

}
else
{
Response.Redirect("~/LinkExpiry.aspx");
}
}
else
{
Response.Redirect("~/LinkExpiry.aspx");
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{

ap.Action = 2;
ap.Password = Common.BOL.Common_Details.Encrypt(txtNewpwd.Text);
ap.Pwddate = Convert.ToDateTime(System.DateTime.Now.ToString("d"));
ap.UserId =int.Parse(Uid);
Login_Page_frm.Add_Update_delete_Login_Page_Pwd(ap);

using (SqlCommand command = new SqlCommand())
{
command.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString);
command.CommandText = @"update [Password_Reset] set active=@active where Guid='" + ResetID + "'";
command.Parameters.Add("@Uid", SqlDbType.Int).Value = Uid;
command.Parameters.Add("@active", SqlDbType.Int).Value = 0;
command.Connection.Open();
command.ExecuteNonQuery();
}

lblErrmsg.Text = "* Password has been reset!";
lblErrmsg.Visible = true;
Response.Redirect("~/Login.aspx");


}
}

Export Datatable to Excel in C#

public void ExportExcel(DataTable dt, string fileName)
{


// string attachment = "attachment; filename=city.xls";
Response.ClearContent();
Response.AddHeader("content-disposition", string.Format("attachment;filename={0}.xls", fileName));
Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in dt.Columns)
{
Response.Write(tab + dc.ColumnName);
tab = "\t";
}
Response.Write("\n");
int i;
ClearViewstate();
foreach (DataRow dr in dt.Rows)
{
tab = "";
for (i = 0; i < dt.Columns.Count; i++)
{
Response.Write(tab + dr[i].ToString());
tab = "\t";
}
Response.Write("\n");
}
Response.End();
ClearViewstate();


}

sub totals in Gridview

protected void grdByDetail_RowDataBound(object sender, GridViewRowEventArgs e)
{
DataTable dt = new DataTable();
if (ViewState["dt_Detail"] == null)
{
DataView dv = (DataView)grdProspectDet.DataSource;
dt = dv.ToTable();
DataRow workRow = dt.NewRow();
dt.Clear();

}
else
{
dt = (DataTable)ViewState["dt_Detail"];

}

if (e.Row.RowType == DataControlRowType.DataRow)
{
Label lblPremum = ((Label)e.Row.FindControl("lblPremium"));
double Premium = Convert.ToDouble(lblPremum.Text.ToString());
lblPremum.Text = Premium.ToString("C", new System.Globalization.CultureInfo("en-US"));

if (e.Row.RowIndex == 0)
{

Carrier = ((Label)e.Row.FindControl("lblCarrier")).Text.ToString();

CarrierPremium = Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));
CarrierPremium2 = Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));

TotalPremium = CarrierPremium2;

DataRow workRow = dt.NewRow();
workRow["ClientID"] = ((Label)e.Row.FindControl("lblClientID")).Text.ToString();
workRow["ClientName"] = ((Label)e.Row.FindControl("lblClientName")).Text.ToString();
workRow["Vendor"] = Carrier.ToString();
workRow["Premium"] = CarrierPremium2.ToString();
workRow["CurrentMonth"] = ((Label)e.Row.FindControl("lblCurrentMonth")).Text.ToString();
workRow["CurrentYear"] = ((Label)e.Row.FindControl("lblCurrentYear")).Text.ToString();
dt.Rows.Add(workRow);
}
else
{

if (Carrier == ((Label)e.Row.FindControl("lblCarrier")).Text)
{

CarrierPremium += Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));
CarrierPremium2 = Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));
TotalPremium += CarrierPremium2;

DataRow workRow = dt.NewRow();
workRow["ClientID"] = ((Label)e.Row.FindControl("lblClientID")).Text.ToString();
workRow["ClientName"] = ((Label)e.Row.FindControl("lblClientName")).Text.ToString();
workRow["Vendor"] = Carrier.ToString();
workRow["Premium"] = CarrierPremium2.ToString();
workRow["CurrentMonth"] = ((Label)e.Row.FindControl("lblCurrentMonth")).Text.ToString();
workRow["CurrentYear"] = ((Label)e.Row.FindControl("lblCurrentYear")).Text.ToString();
dt.Rows.Add(workRow);
}
else
{
// Carrier = ((Label)e.Row.FindControl("lblCarrier")).Text.ToString();

DataRow workRow = dt.NewRow();
workRow["Vendor"] = "Total Premium for " + Carrier.ToString();
workRow["Premium"] = CarrierPremium.ToString();
dt.Rows.Add(workRow);

Table tblTemp = (Table)this.grdProspectDet.Controls[0];
int intIndex = tblTemp.Rows.GetRowIndex(e.Row);
GridViewRow gvrSubTotal = CreateGridViewRowByDetail(intIndex,"aliceblue",grdProspectDet.Columns.Count,"" + CarrierPremium.ToString("C", new System.Globalization.CultureInfo("en-US")),
20,"Total Premium for "+""+Carrier+"");
tblTemp.Controls.AddAt(intIndex, gvrSubTotal);
Carrier = ((Label)e.Row.FindControl("lblCarrier")).Text.ToString();

CarrierPremium = Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));
CarrierPremium2 = Convert.ToDouble(((Label)e.Row.FindControl("lblPremium")).Text.TrimStart('$'));
TotalPremium += CarrierPremium2;

DataRow workRow2 = dt.NewRow();
workRow2["ClientID"] = ((Label)e.Row.FindControl("lblClientID")).Text.ToString();
workRow2["ClientName"] = ((Label)e.Row.FindControl("lblClientName")).Text.ToString();
workRow2["Vendor"] = Carrier.ToString();
workRow2["Premium"] = CarrierPremium2.ToString();
workRow2["CurrentMonth"] = ((Label)e.Row.FindControl("lblCurrentMonth")).Text.ToString();
workRow2["CurrentYear"] = ((Label)e.Row.FindControl("lblCurrentYear")).Text.ToString();
dt.Rows.Add(workRow2);
}
if (iRowsCount == e.Row.RowIndex)
{
DataRow workRow3 = dt.NewRow();
workRow3["Vendor"] = "Total Premium for" + Carrier.ToString();
workRow3["Premium"] = CarrierPremium.ToString();
dt.Rows.Add(workRow3);

Table tblTemp = (Table)this.grdProspectDet.Controls[0];
int intIndex = tblTemp.Rows.GetRowIndex(e.Row) + 1;

GridViewRow gvrLast = CreateGridViewRowByDetail(intIndex, "aliceblue", grdProspectDet.Columns.Count, "" + CarrierPremium.ToString("C", new System.Globalization.CultureInfo("en-US")), 20, "Total Premium for " + "" + Carrier + "");
GridViewRow gvrLast2 = CreateGridViewRowByDetail(intIndex, "cornsilk", grdProspectDet.Columns.Count, "" + TotalPremium.ToString("C", new System.Globalization.CultureInfo("en-US")), 20, "Total Premium");
tblTemp.Controls.AddAt(intIndex, gvrLast);
tblTemp.Controls.AddAt(intIndex + 1, gvrLast2);

DataRow workRow = dt.NewRow();
workRow["Vendor"] = "Total Premium";
workRow["Premium"] = TotalPremium.ToString();
dt.Rows.Add(workRow);



}
}

//if (e.Row.RowType == DataControlRowType.Footer)
//{
// Label lblTotalPremium = (Label)e.Row.FindControl("lblTotalPremium");
// lblTotalPremium.Text = CarrierPremium.ToString("C", new System.Globalization.CultureInfo("en-US"));



//// lblTotalAP.Text = TotalAP.ToString("C", new CultureInfo("en-US"));

//}
}
ViewState["dt_Detail"] = dt;
}

Calculating Totals in Footer in Gridview example

protected void grdByCarrier_RowDataBound(object sender, GridViewRowEventArgs e)
{

if (e.Row.RowType == DataControlRowType.DataRow)
{
double rowpremiumTotal = Convert.ToDouble(DataBinder.Eval(e.Row.DataItem, "Premium"));
grdPremiumTotal = grdPremiumTotal + rowpremiumTotal;

}
if (e.Row.RowType == DataControlRowType.Footer)
{
Label lblPremiumTotal = (Label)e.Row.FindControl("lblPremiumTotal");
lblPremiumTotal.Text = grdPremiumTotal.ToString("c");
}
}


Design :




























Export Gridview Data to Excel

public void ExportGridToExcel(GridView grdGridView, string fileName)
{
Response.Clear();
Response.AddHeader("content-disposition", string.Format("attachment;filename={0}.xls", fileName));
Response.Charset = "";
Response.ContentType = "application/vnd.xls";
StringWriter stringWrite = new StringWriter();
HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
HtmlForm hForm = new HtmlForm();
grdGridView.Parent.Controls.Add(hForm);
hForm.Attributes["runat"] = "server";
hForm.Controls.Add(grdGridView);
hForm.RenderControl(htmlWrite);
Response.Write(stringWrite.ToString());
Response.End();

}

button ExcelExport function

protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
string filename = "ClaimsDataYearwiseReport_" + ddlFromYear.SelectedItem.Value + "_to_" + ddlToYear.SelectedItem.Value + "";
ExportGridToExcel(grdProspectDet, filename);
}