Strategy Design Pattern with C#

Strategy design pattern is a behavioral design pattern. It is a particular software design pattern where algorithms are selected at runtime.

According to the book of Design Pattern (Gang of Four) – “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. “

The key phrases of definition are “Family of algorithms”, “encapsulate”, and “interchangeable”. Actually, Strategy Pattern encapsulates a collection of functions that do similar yet not identical jobs. Client is not bound to call fixed methods; rather it can change its strategy dynamically at run time. Client don’t call any methods directly by instantiating concrete classes. It sets its strategy via context class.

There are three main parts in strategy pattern:

  1. Strategy – An interface that defines how the algorithm will be called.
  2. Concrete Strategy – The implementation of the strategy.
  3. Context – It holds the concrete strategy.

StrategyPattern

Implementation:

Suppose you have two lists of items. Item here integer numbers. Now, if you want to search an item from either of the lists. You can use either one of the algorithms from Linear Search or Binary search. Since binary search algorithm cannot search data without sorted list, we take here a sorted list. Now the strategy of client to use which one – Binary search or linear search. Let’s implement the problem by strategy pattern using c#.

Step 1: Create an Interface for Strategy

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

namespace StrategyPattern
{
///
/// Strategy defines how algorithm will be called
///

public interface ISearchStrategy
{
int Search(int[] list, int item);
}
}

Step 2: Create concrete strategy (Linear Search)

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

namespace StrategyPattern
{
///
/// Concrete strategy(Linear Search Algorithm)
///

public class LinearSearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Linear Search");
int position = 0;

for (int i = 0; i < list.Count(); i++)
{
if (list[i] == item)
{
position = i;
break;
}
}

return position;
}

#endregion
}
}

Step 3: Create concrete strategy (Binary Search)

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

namespace StrategyPattern
{
///
/// Concrete strategy(Binary Search Algorithm)
///

public class BinarySearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Binary Search");

int beg = 0;
int end = list.Count() - 1;
int mid = (int)((beg + end)/2);
int position = 0;

while (beg <= end && list[mid] != item)
{
if(item < list[mid])
end = mid - 1;
else
beg = mid + 1;

mid = (int)((beg + end)/2);
}

if (list[mid] == item)
position = mid;
else
position = 0;

return position;
}

#endregion
}
}

Step 4: Create a context class

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

namespace StrategyPattern
{
///
/// Concrete strategy(Linear Search Algorithm)
///

public class LinearSearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Linear Search");
int position = 0;

for (int i = 0; i < list.Count(); i++)
{
if (list[i] == item)
{
position = i;
break;
}
}

return position;
}

#endregion
}
}

Step 5: Client class to demonstrate strategy pattern

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

namespace StrategyPattern
{
///
/// Client class
///

class Program
{
static void Main(string[] args)
{

int[] sortedList = { 1, 2, 3, 4, 5, 6, 7, 8 };

//Instance of context to follow different strategies
SearchList objSearchList = new SearchList();

objSearchList.SetSearchStrategy(new BinarySearch());
objSearchList.Search(sortedList, 4);

objSearchList.SetSearchStrategy(new LinearSearch());
objSearchList.Search(sortedList, 7);

Console.ReadLine();
}
}
}

Output:
output_strategyPattern

Abstract Factory Pattern with C#

Abstract factory pattern is a creational design pattern. Creational design pattern is deals with object creation mechanism. Object creation mechanism is changed on the basis of problem. Abstract factory pattern provides an interface to create families of related or dependent objects without specifying their concrete class. It is identified on the basis of problem complexity. It is encapsulated the process of instantiation of family of classes. Abstract factory pattern is widely used in framework and libraries to encapsulate the family of classes.

Elements of Abstract Factory Pattern:

  1. Abstract Factory – An Interface to create families of related or dependent item object.
  2. Concrete Factory – Implement the interface to create families of related item object.
  3. Abstract Item – An interface to create concrete item object.
  4. Concrete Item – Implement the interface to create concrete item object.
  5. Client – Uses Interface (abstract Item) provided by abstract factory and access concrete object by this interface.

Implementation:

Here I implemented abstract factory pattern in International Cricket Team by C#. The UML diagram is given below.

AFP-1

Step 1: Create interface for Item class

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

namespace AFP
{
///
/// Interface for Item class
///

public interface ICricketer
{
string BattingStrength();
string BowlingStrength();
string AllroundingStrength();
string IconPlayer();
}
}

Step 2: Create Factory Interface

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

namespace AFP
{
///
/// A Factory interface
///

public interface ICricketerFactory
{
ICricketer GetCricketer(CricketerBase cricketerBase);
}
}

Step 3: Define the type of Base object

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

namespace AFP
{

///
/// Define the type of Base Object
///

public enum CricketerBase
{
AustralianCricketer,
BangladeshiCricketer,
EnglishCricketer,
IndianCricketer,
PakistaniCricketer
}

}

Step 4: Create Concrete factory class for Asian Cricketer

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

namespace AFP
{

///
/// Concrete factory class for Asian Cricketer
///

public class AsianCricketerFactory : ICricketerFactory
{

#region ICricketerFactory Members

public ICricketer GetCricketer(CricketerBase cricketerBase)
{
ICricketer objICricketer = null;

switch (cricketerBase)
{
case CricketerBase.BangladeshiCricketer:
objICricketer = new BangladeshiCricketer();
break;
case CricketerBase.IndianCricketer:
objICricketer = new IndianCricketer();
break;
default:
break;
}
return objICricketer;
}

#endregion
}
}

Step 5: Create Concrete factory class for European Cricketer

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

namespace AFP
{
///
/// Concrete factory class for European Cricketer
///

public class EuropeanCricketerFactory : ICricketerFactory
{

#region ICricketerFactory Members

public ICricketer GetCricketer(CricketerBase cricketerBase)
{
ICricketer objICricketer = null;

switch (cricketerBase)
{
case CricketerBase.EnglishCricketer:
objICricketer = new EnglishCricketer();
break;
default:
break;
}
return objICricketer;
}

#endregion
}
}

Step 6: Create Item class for Bangladeshi Cricketer

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

namespace AFP
{

///
/// Item class for Bangladeshi Cricketer
///

public class BangladeshiCricketer : ICricketer
{
#region ICricketer Members

public string BattingStrength()
{
return "60%";
}

public string BowlingStrength()
{
return "70%";
}

public string AllroundingStrength()
{
return "85%";
}

public string IconPlayer()
{
return "Shakib Al Hasan";
}

#endregion
}
}

Step 7: Create Item Class for Indian Cricketer

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

namespace AFP
{

///
/// Item class for Indian Cricketer
///

public class IndianCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "85%";
}

public string BowlingStrength()
{
return "60%";
}

public string AllroundingStrength()
{
return "70%";
}

public string IconPlayer()
{
return "Shachin Tendulkar.";
}

#endregion
}
}

Step 8: Create Item class for Pakistani Cricketer

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

namespace AFP
{

///
/// Item class for Pakistani Cricketer
///

public class PakistaniCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "75%";
}

public string BowlingStrength()
{
return "85%";
}

public string AllroundingStrength()
{
return "75%";
}

public string IconPlayer()
{
return "Shahid Afridi.";
}

#endregion
}
}

Step 9: Create Item class for English Cricketer

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

namespace AFP
{

///
/// Item class for English Cricketer
///

public class EnglishCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "75%";
}

public string BowlingStrength()
{
return "80%";
}

public string AllroundingStrength()
{
return "70%";
}

public string IconPlayer()
{
return "Kavin Pietersen";
}

#endregion
}
}

Step 10: Create a client class

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

namespace AFP
{

///
/// Client Class
///

class Program
{
static void Main(string[] args)
{
AsianCricketerFactory objAsianFactory = new AsianCricketerFactory();
ICricketer objIAsianCricketer = objAsianFactory.GetCricketer(CricketerBase.BangladeshiCricketer);
Console.WriteLine("Bangladesh Cricket Team\nBatting Strength:" + objIAsianCricketer.BattingStrength());
Console.WriteLine("Bowling Strength:" + objIAsianCricketer.BowlingStrength());
Console.WriteLine("Allrounding Strength:" + objIAsianCricketer.AllroundingStrength());
Console.WriteLine("Icon Player:" + objIAsianCricketer.IconPlayer());

Console.WriteLine();

EuropeanCricketerFactory objEuropeanFactory = new EuropeanCricketerFactory();
ICricketer objIEuropeanCricketer = objEuropeanFactory.GetCricketer(CricketerBase.EnglishCricketer);
Console.WriteLine("England Cricket Team\nBatting Strength:" + objIEuropeanCricketer.BattingStrength());

Console.WriteLine("Bowling Strength:" + objIEuropeanCricketer.BowlingStrength());
Console.WriteLine("Allrounding Strength:" + objIEuropeanCricketer.AllroundingStrength());
Console.WriteLine("Icon Player:" + objIEuropeanCricketer.IconPlayer());

Console.ReadLine();

}
}
}

Output:
AFP-Output

Retrieve Store Procedure’s Output parameter by C# (ASP.net)

How to retrieve store procedure’s output parameter by C#? Here I have explained with a simple example. I created a simple store procedure with output parameter. Then I catch it from code behind page of asp.net and displayed it to a label. Here I used a class DBConnector to connect with database. Lets look on the demo.

Step 1: Set connection string in web.config.


     


Step 2: Create a store procedure with output parameter.

CREATE PROCEDURE [dbo].[sp_output_param]
(
     @input_param VARCHAR(200)
    , @Response VARCHAR(250) OUTPUT
)
AS
    --DECLARE @myName
BEGIN  
    SET @Response = 'Welcome ' + @input_param
END

Step 3: Create a DBConnector Class to retrieve data from database.

using System;
using System.Data;
using System.Configuration;
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.Data.SqlClient;
 
public class DBConnector
{
    private string connectionString = null;
    private SqlConnection sqlConn = null;
    private SqlCommand cmd = null;
 
    public DBConnector()
    {
        connectionString = ConfigurationManager.ConnectionStrings["SQLServerConnectionString"].ToString();
    }
 
 
    public SqlCommand GetCommand()
    {
        cmd = new SqlCommand();
        cmd.Connection = sqlConn;
        return cmd;
    }
 
    public SqlConnection GetConn()
    {
        sqlConn = new SqlConnection(connectionString);
        return sqlConn;
    }
 
}

Step 4 : Create a label name lblMsg in asp page. Then in a button event, write the following code. You will see your desired output in the lebel which is actually the value of output parameter. Here btnGetOutputParam_Click is the click event of Button btnGetOutputParam.

protected void btnGetOutputParam_Click(object sender, EventArgs e)
{
        SqlConnection sqlConn;
        SqlCommand cmd;
 
        DBConnector objDBConnector = new DBConnector();
        sqlConn = objDBConnector.GetConn();
 
        cmd = objDBConnector.GetCommand();
 
        SqlDataReader rdr = null;
 
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "sp_output_param";
        cmd.Parameters.AddWithValue("@input_param", "Mahedee");
        cmd.Parameters.Add("@Response", SqlDbType.VarChar, 250);
        cmd.Parameters["@Response"].Direction = ParameterDirection.Output;
 
        try
        {
            if (sqlConn.State == ConnectionState.Closed)
                sqlConn.Open();
 
            rdr = cmd.ExecuteReader();
 
            string outputValue = cmd.Parameters["@Response"].Value.ToString();
            this.lblMsg.Text = outputValue;
        }
        catch (Exception exp)
        {
            throw (exp);
        }
        finally
        {
            if (sqlConn.State == ConnectionState.Open)
                sqlConn.Close();
        }
 
    }

You will see in label – Welcome Mahedee which is provided by output parameter of store procedure.

Generate image on the fly by ASP.NET

Generating image on the fly is not difficult in asp.net. Here I have created national flag of Bangladesh on the fly and displayed this as JPEG image format in asp.net web form. So let’s start to draw an image on the fly.

Step 1: Add a new web form in ASP.net website.

Step 2: In the Page_Load of the web form write the following code

protected void Page_Load(object sender, EventArgs e)
{
//Define the rectangle with (x co-ordinate, y co-ordinate, width, height)
RectangleF rectF = new RectangleF(0, 0, 400, 200);
Bitmap img = new Bitmap(400, 200, PixelFormat.Format24bppRgb);
Graphics grphs = Graphics.FromImage(img);
SolidBrush bgBrush = new SolidBrush(System.Drawing.Color.Green);

grphs.FillRectangle(bgBrush, rectF);

SolidBrush elpsBgBrush = new SolidBrush(System.Drawing.Color.Red);

//Fill the interior of an ellipse by the pair of co-ordinates and height and width
grphs.FillEllipse(elpsBgBrush, 140, 40, 130, 130);

int fontSize = 20;
string fontName = "Arial" + ".ttf";
PrivateFontCollection privateFontCollection = new PrivateFontCollection();
privateFontCollection.AddFontFile(@"C:/WINDOWS/Fonts/" + fontName);

FontFamily fontFamily = privateFontCollection.Families[0];

// Set font style
int fontStyle = Convert.ToInt32(Request.Form.Get("fontstyle"));
string text = "Bangladesh";

SolidBrush fgBrush = new SolidBrush(System.Drawing.Color.Yellow);
FontStyle style = FontStyle.Bold;

StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.DirectionRightToLeft;

Font font = new Font(fontFamily, fontSize, style, GraphicsUnit.Pixel);

grphs.DrawString(text, font, fgBrush, rectF, format);

Response.ContentType = "image/jpeg";
img.Save(Response.OutputStream, ImageFormat.Jpeg);

// Dispose objects
img.Dispose();
}

Here RectangleF stores a set of four floating-point numbers that represent the location and size of a rectangle. Here first pair is (x,y) co-ordinate and second pair is width and height. SolidBrush define a brush of single color. FillRectangle and FillEllipse is responsible for both Filling rectangle and Ellipse. Graphics.DrawString is used to draw text in the rectangle.

Now run the website. Yes! You have drawn your desired National Flag of Bangladesh and its look like this.

Output:

National Flag bangladesh

Factory Design Pattern with C#

Factory design pattern implements the concept of real world factories. Factory pattern is a creational design pattern. It deals with creating object without specifying exact class. In general, actors of factory patterns are a client, a factory and a product. Client is an object that requires another object for some purposes. Rather than creating the product instance directly, the client delegates this responsibility to the factory. The factory then creates a new instance of the product, passing it back to the client. Figure shows the whole process.

FP-1

Application

For an example, a banking application works with accounts. In this application there are different types of account like saving account and checking account. All accounts are derived from an abstract account name IAccount. The IAccount defines the withdraw, deposit and interest rate which must be implemented by the concrete accounts (saving account, checking account). If clients want to know the interest rate of the Saving Account. It just invoke the factory to create an instance of Saving account.  Being invoked factory, it creates an instance of the saving account and then client just get the interest rate by invoking interest method. The client uses the object as casted to the abstract class without being aware of the concrete object type. Over all implementation of this scenario is given below.

The advantage is in here that new account can be added without changing a single line of code in the client code. Here an object is created without exposing instantiation logic to the client. The object generation is centralized here.

Benefits:

  • Factory Pattern is the mostly used pattern.
  •  Decoupled the classes i.e eliminates the need to bind application specific class
  • The code only deals with the Interface.
  •  Factory Pattern provides the way to create multiple instances of classes.
  •  This provides a hook so that we can derive a sub-class to create different controls to display the data.
  •   Factory method connects the class hierarchies with minimum coupling.
  •  Product implementation may change over time but client remains unchanged.

Implementation

Step 1: Create an Interface – IAccount

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

namespace FactoryPattern
{
public interface IAccount
{
string Withdraw(int amount);
string Deposit(int amount);

double InterestRate();
}
}

Step 2: Create concrete classes

Saving account

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

namespace FactoryPattern
{
///
/// Concrete class SavingsAccount
///

public class SavingsAccount : IAccount
{
#region IAccount Members

public string Withdraw(int amount)
{
throw new NotImplementedException();
}

public string Deposit(int amount)
{
throw new NotImplementedException();
}

public double InterestRate()
{
return 12.5;
}

#endregion
}
}

Checking Account

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

namespace FactoryPattern
{

///
/// Concrete class CheckingAccount
///

public class CheckingAccount : IAccount
{
#region IAccount Members

public string Withdraw(int amount)
{
throw new NotImplementedException();
}

public string Deposit(int amount)
{
throw new NotImplementedException();
}

public double InterestRate()
{
return 10.24;
}

#endregion
}
}

Step 3: Create a Factory Object Enum

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

namespace FactoryPattern
{
///
/// FactoryObject Enum to configure object
///

public enum FactoryObject
{
SavingAccount,
CheckingAccount
}
}

Step 4: Create a factory class

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

namespace FactoryPattern
{
///
/// Factory class to create object
///

public static class Factory
{
public static IAccount CreateObject(FactoryObject factoryObject)
{
IAccount objIAccount = null;

switch (factoryObject)
{
case FactoryObject.SavingAccount:
objIAccount = new SavingsAccount();
break;

case FactoryObject.CheckingAccount:
objIAccount = new CheckingAccount();
break;

default:
break;
}

return objIAccount;
}
}
}


Step 5: Access from client

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

namespace FactoryPattern
{
public class Program
{
public static void Main(string[] args)
{
//Create object by factory pattern
IAccount objSavingAccount = Factory.CreateObject(FactoryObject.SavingAccount);
IAccount objCheckingAccount = Factory.CreateObject(FactoryObject.CheckingAccount);

//Access object
Console.WriteLine("Saving Account Interest Rate: " + objSavingAccount.InterestRate());
Console.WriteLine("Checking Account Interest Rate: " + objCheckingAccount.InterestRate());

Console.ReadLine();

}
}
}

Crystal Report with ASP.net Step by Step

For business or other managerial purpose, it is very important to prepare reports. We use SAP crystal reports in asp.net often for reporting purpose. Before going to the details, I hope you already know how to prepare a crystal report (something.rpt file). Here I used SAP crystal report; data is retrieved by a stored procedure which required two parameters. I used SAP Crystal Report 13.0.5 with visual studio 2012. A stored procedure is responsible to provide data to crystal report. So, let’s implement crystal report in asp.net.

Step 1: Create a report file

Create a report file (rpt_get_employee_info_dept_id_team_id.rpt). Write a stored procedure (rsp_get_employee_info_by_dept_id_team_id) to retrieve data. Set the stored procedure as crystal report data source. Design crystal reports.

Step 2: Add Assemblies

Add the following references to your web site. Version of the assembly is most important. I used assembly version: 13.0.2000.0

CrystalDecisions.CrystalReports.Engine;

CrystalDecisions.Shared;

CrystalDecisions.Web

Step 3: Create a report base class

This is a custom class, responsible to generate crystal report document. Some global variable is used in this class for configuration purpose. Server name, database name, user id, password is hard coded here for easily understand but I recommend, it should come from web configuration file.

string ServerName = "MAHEDEE-PC"; //Database server name to which report connected
string DataBaseName = "TestDB"; //Database name to which report connected
string UserID = "sa"; //Database user name to which report connected
string Password = "sa"; //Database user password to which report connected
ReportDocument crReportDocument = new ReportDocument(); //Crystal report document object

In this class some methods are used for different purposes.

  •  public ReportDocument PFSubReportConnectionMainParameter(string ReportName, ArrayList ParamArraylist, string ReportFolder)  – This is the base method to generate report document
  • public void PassParameter(int ParameterIndex, string ParameterValue) – Set parameter value in crystal report on corresponding index
  • private bool Logon(CrystalDecisions.CrystalReports.Engine.ReportDocument cr, string server, string database, string user_id, string password) – Cystal report login check to the server
  • private bool ApplyLogon(CrystalDecisions.CrystalReports.Engine.ReportDocument cr, CrystalDecisions.Shared.ConnectionInfo ci) – Supporting method of “Logon” to login check.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using CrystalDecisions.CrystalReports.Engine;
using System.Collections;
using CrystalDecisions.Shared;
///
/// The base class to generate report document
///

public class ReportBase
{

string ServerName = "MAHEDEE-PC"; //Database server name to which report connected
string DataBaseName = "TestDB"; //Database name to which report connected
string UserID = "sa"; //Database user name to which report connected
string Password = "sa"; //Database user password to which report connected

ReportDocument crReportDocument = new ReportDocument();

public ReportBase()
{
}
///
///Base method to generate report document.
///

public ReportDocument PFSubReportConnectionMainParameter(string ReportName, ArrayList ParamArraylist, string ReportFolder)
{
int ObjArrayA, ObjArrayB, Paraindex;
string Paravalue;
ObjArrayB = 0;

string path = ReportFolder + @"\" + @ReportName; //Full path of report

try
{
crReportDocument.Load(path); //Load crystal Report
}
catch (Exception ex)
{

string msg = "The report file " + path +
" can not be loaded, ensure that the report exists or the path is correct." +
"\nException:\n" + ex.Message +
"\nSource:" + ex.Source +
"\nStacktrace:" + ex.StackTrace;
throw new Exception(msg);
}

//Ensure login to the database server
if (!Logon(crReportDocument, ServerName, DataBaseName, UserID, Password))
{
string msg = "Can not login to Report Server " +
"\nDatabase Server: " + ServerName +
"\nDatabase:\n" + DataBaseName +
"\nDBUser:" + UserID +
"\nDBPassword:" + Password;
throw new Exception(msg);
}

Logon(crReportDocument, ServerName, DataBaseName, UserID, Password);

//To Check Parameter Feild Array have the Same Amount of Parameter Feild in the Report
int ParamArrayCount, ParameterFieldCount;
//Getting Value from the Array

if (ParamArraylist.Count != 0)
{
ParamArrayCount = (ParamArraylist.Count / 2);

//Getting Value From the Report (Parameter and Formula Feild)
ParameterFieldCount = crReportDocument.DataDefinition.ParameterFields.Count;

//Parameter on The Report and Array List Parameter Amount is not the same
ParamArrayCount = ParameterFieldCount;

for (ObjArrayA = 0; ObjArrayA < ((ParamArraylist.Count / 2)); ObjArrayA++)
{
Paraindex = (int)ParamArraylist[ObjArrayB]; //Parameter index
Paravalue = (string)ParamArraylist[ObjArrayB + 1]; //Paramter Value
PassParameter(Paraindex, Paravalue);
ObjArrayB = ObjArrayB + 2;
}
}

return crReportDocument;

}

///
/// Set parameter value in crystal report on corresponding index
///

public void PassParameter(int ParameterIndex, string ParameterValue)
{
// '
// ' Declare the parameter related objects.
// '
ParameterDiscreteValue crParameterDiscreteValue;
ParameterFieldDefinitions crParameterFieldDefinitions;
ParameterFieldDefinition crParameterFieldLocation;
ParameterValues crParameterValues;

crParameterFieldDefinitions = crReportDocument.DataDefinition.ParameterFields;
crParameterFieldLocation = (ParameterFieldDefinition)crParameterFieldDefinitions[ParameterIndex];
crParameterValues = crParameterFieldLocation.CurrentValues;
crParameterDiscreteValue = new CrystalDecisions.Shared.ParameterDiscreteValue();
crParameterDiscreteValue.Value = System.Convert.ToString(ParameterValue);
crParameterValues.Add(crParameterDiscreteValue);
crParameterFieldLocation.ApplyCurrentValues(crParameterValues);
}

//Check whether crytal report can login to the server
private bool Logon(CrystalDecisions.CrystalReports.Engine.ReportDocument cr, string server, string database, string user_id, string password)
{
// Declare and instantiate a new connection info object.
CrystalDecisions.Shared.ConnectionInfo ci;
ci = new CrystalDecisions.Shared.ConnectionInfo();

ci.ServerName = server;
ci.DatabaseName = database;
ci.UserID = user_id;
ci.Password = password;//password;
// ci.IntegratedSecurity = false;

// If the ApplyLogon function fails then return a false for this function.
// We are applying logon information to the main report at this stage.
if (!ApplyLogon(cr, ci))
{
return false;
}

// Declare a subreport object.
CrystalDecisions.CrystalReports.Engine.SubreportObject subobj;

// Loop through all the report objects and locate subreports.
// If a subreport is found then apply logon information to
// the subreport.
foreach (CrystalDecisions.CrystalReports.Engine.ReportObject obj in cr.ReportDefinition.ReportObjects)
{
if (obj.Kind == CrystalDecisions.Shared.ReportObjectKind.SubreportObject)
{
subobj = (CrystalDecisions.CrystalReports.Engine.SubreportObject)obj;
if (!ApplyLogon(cr.OpenSubreport(subobj.SubreportName), ci))
{
return false;
}
}
}

// Return True if the code runs to this stage.
return true;

}

///
///This function is called by the "Logon" function. It loops through the report tables and applies the connection information to each table.
///

private bool ApplyLogon(CrystalDecisions.CrystalReports.Engine.ReportDocument cr, CrystalDecisions.Shared.ConnectionInfo ci)
{
// This function is called by the "Logon" function
// It loops through the report tables and applies
// the connection information to each table.

// Declare the TableLogOnInfo object and a table object for use later.
CrystalDecisions.Shared.TableLogOnInfo li;
// For each table apply connection info.

foreach (CrystalDecisions.CrystalReports.Engine.Table tbl in cr.Database.Tables)
{

li = tbl.LogOnInfo;
li.ConnectionInfo.ServerName = ci.ServerName;
li.ConnectionInfo.DatabaseName = ci.DatabaseName;
li.ConnectionInfo.UserID = ci.UserID;
li.ConnectionInfo.Password = ci.Password;
tbl.ApplyLogOnInfo(li);
tbl.Location = ci.DatabaseName + ".dbo." + tbl.Name;

// Verify that the logon was successful.
// If TestConnectivity returns false, correct table locations.
if (!tbl.TestConnectivity())
{
return false;

}
}
return true;
}

}

Step 4: Create Report Viewer pages

In this project, I have created a report viewer page – ViewReport.aspx. Here some steps need to follow.

a. Register Assembly – Register assembly CrystalDecisions.Web to the page directive

<%@ Register Assembly=”CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304″ Namespace=”CrystalDecisions.Web” TagPrefix=”CR” %>
b. Add crystal report viewer – Add crystal report viewer to view report.

<CR:CrystalReportViewer ID=”CrystalReportViewer1″ runat=”server” AutoDataBind=”True” 

HasPrintButton=”True”HasRefreshButton=”True” ReuseParameterValuesOnRefresh=”True” 

Height=”50px” Width=”350px”OnReportRefresh=”CrystalReportViewer1_ReportRefresh” PrintMode=”ActiveX” />

c. Manually config CSS file – Sometimes crystal report shows blank page due to some technical problem so add the following css link in between head tag

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

A button (btnViewReport) is used to display report

Source file of ViewReport.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”ViewReport.aspx.cs” Inherits=”ViewReport” %>

<%@ Register Assembly=”CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304″

Namespace=”CrystalDecisions.Web” TagPrefix=”CR” %>

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

rel=”stylesheet” type=”text/css” />

HasRefreshButton=”True”ReuseParameterValuesOnRefresh=”True” Height=”50px” Width=”350px”

OnReportRefresh=”CrystalReportViewer1_ReportRefresh” PrintMode=”ActiveX” />

Code behind of ViewReport.aspx

Some methods are used in code behind file for different purpose.

  • protected void btnViewReport_Click(object sender, EventArgs e) – Click event handler of btnViewReport button. In this method two parameters of crystal report are used as hardcoded. In real application, it should come as input control dynamically.
  • private void GetReportDocument() – Responsible to generate report document using ReportBase class.
  •  private void ViewCystalReport() – Set generated report document as Crystal Report viewer report source and display report in report viewer.
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Web;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ViewReport : System.Web.UI.Page
{

ArrayList ParameterArrayList = new ArrayList(); //Report parameter list
ReportDocument ObjReportClientDocument = new ReportDocument(); //Report document

protected void Page_Load(object sender, EventArgs e)
{

}

protected void btnViewReport_Click(object sender, EventArgs e)
{
/*The report with two parameters. */
ParameterArrayList.Add(0);
ParameterArrayList.Add("1"); //Parameter 1 with input 1. This is actually dept id according to report parameter
ParameterArrayList.Add(1);
ParameterArrayList.Add("1"); //Parameter 2 with input 1. This is actually team id according to report parameter

GetReportDocument(); //Generate Report document
ViewCystalReport(); //View report document in crystal report viewer

}

/*Generate report document*/
private void GetReportDocument()
{
ReportBase objReportBase = new ReportBase();
string sRptFolder = string.Empty;
string sRptName = string.Empty;

sRptName = "rpt_get_employee_info_dept_id_team_id.rpt"; //Report name
sRptFolder = Server.MapPath("~/Reports"); //Report folder name

ObjReportClientDocument = objReportBase.PFSubReportConnectionMainParameter(sRptName, ParameterArrayList, sRptFolder);

//This section is for manipulating font and font size. This an optional section
foreach (Section oSection in ObjReportClientDocument.ReportDefinition.Sections)
{
foreach (ReportObject obj in oSection.ReportObjects)
{
FieldObject field;
field = ObjReportClientDocument.ReportDefinition.ReportObjects[obj.Name] as FieldObject;

if (field != null)
{
Font oFon1 = new Font("Arial Narrow", field.Font.Size - 1F);
Font oFon2 = new Font("Arial", field.Font.Size - 1F);

if (oFon1 != null)
{
field.ApplyFont(oFon1);
}
else if (oFon2 != null)
{
field.ApplyFont(oFon2);
}
}
}
}
}

protected void CrystalReportViewer1_ReportRefresh(object source, ViewerEventArgs e)
{
//OnInit(e);
//ViewCystalReport();
}

///
/// To view crystal report
///

private void ViewCystalReport()
{

//Set generated report document as Crystal Report viewer report source
CrystalReportViewer1.ReportSource = ObjReportClientDocument;
}

}

Cr-empdept-team-wise