Uploading files

| Posted in

0

While this article is placed in the upload subsection, it might not be the best place for ot. Because it's not a regular "how-to-upload- files-with-ASP.NET" article.

I might write such an article in the future but this is dealning with a problem you might encounter when using some sort of template-system on your site. I mean basically, all requests goes to a single ASPX page, such as default.aspx and depending on the context (for example sent in by a request variable) you load different user controls (ASCX) files.

For example:
default.aspx?page=start - might show start page
default.aspx?page=clientupload - might show a page when the client could upload a file to your server

Now, back to file upload. To upload a file you need to do two things:
1. Throw in a input type=file control






2. Set your forms enctype to multipart/form-data
<form enctype="multipart/form-data" runat="server">

Now what's the problem? Well some people might argue that it's no problem at all but the fact is that since you only have one single default.aspx file the form:s type will be always be multipart/form-data - even for the "start"-page. I won't get into that discussion but simple show you how to fix it

Lets say that page=start loads the ucStart.ascx user control. And page=ucClientUpload loads ucClientUpload.ascx

First remove the enctype="multipart/form-data" from the default.aspx form and open up ucClientUpload.ascx

What we are gonna do is from within ucClientUpload.ascx change the form enctype attribute:



protected void EnsureEncType()
{
System.Web.UI.Control oParent = Parent;
while( oParent != null && oParent.GetType() != typeof( System.Web.UI.HtmlControls.HtmlForm ) && oParent.GetType().FullName != "System.Web.UI.Page" )
{
oParent = oParent.Parent;
}
System.Web.UI.HtmlControls.HtmlForm oForm = oParent as System.Web.UI.HtmlControls.HtmlForm;
if ( oForm != null )
oForm.Enctype = "multipart/form-data";
}


And then just call EnsureEncType() from your Page_Load function. There you have it. Forms enctype set from within a usercontrol.

I'll be honest with you and say I didn't find out this myself, but it has been in my "toolbox" for quite a while and now when writing this article I was trying to look up who did it, but came up with a lot of chinese pages when googling. Anyway, just saying that so you understand that I don't take any credit for the solution, just trying to spread it.

Creating a demo version of your ASP.NET application

| Posted in

0

Setting up a live demo on your website is often important for your business - people want to see how the application looks and get a feeling of it and not all people are willing to download a trial version and go through a (painful?) install process just to get the first look.

However, the problem is that you need to strip down the demo version a little bit. You don't want visitors to be able to change login password etc (after that noone would have access to the demo) or change information in your underlying database.

Here's how I have solved it for my demosites for AdMentor and KBMentor.

In short : I compile the application with an extra flag defined (DEMOVERSION) and in my code I insert some extra conditional code to behave differently when that flag DEMOVERSION is defined.

First step is to create a custom project context

Then we add the conditional variable (called DEMOVERSION):

Now we can insert some conditional code.We do that by using the #if directive in our code.

#if (DEMOVERSION)
here we can add code which only will be compiled in the special demoversion
#endif

I want to throw up a JavaScript when the user tries something not allowed - for example when trying to change password:

So, this is done by adding a JavaScript alert box to the onclick event:

private void Page_Load(object sender, System.EventArgs e)
{
EnsureEncType();
EnsureChildControls();
if ( !IsPostBack )
{

#if (DEMOVERSION)
btnUpdate.Attributes.Add("onclick", "alert('Not possible in demo version'); return false;");
btnDelete.Attributes["onclick"] = "alert('Not possible in demo version'); return false;";
#endif
Now, this is done in Page_Load and while this example is pretty easy to understand you might have a more finegrained structure of how to enable/disbale controls, for example based on current user rights, and/or after a lot of postbacks a certain button might be enabled etc. The easiest way to override such code without needing to make the original code much more complex is to leave it at is and make your changes in OnPreRender:
protected override void OnPreRender(EventArgs e)
{
#if (DEMOVERSION)
btnDelete.Enabled = false;
btnDoUpload.Enabled = false;
btnOK.Enabled = false;
#endif
Here it doesn't matter what code has been executed and checked against all different kind of state - we just disable the buttons regardless of which. Now, the last thing to do. Not all people have JavaScript enabled - so those people must also be stopped. Here we need to add some serverside code in the actual handler functions:
private void btnOK_Click(object sender, System.EventArgs e)
{
#if (DEMOVERSION)
return;
#endif

..regular code to save etc

Screenscraping with HttpWebRequest

| Posted in

0

While I bet you all know how to (from your own webpage) read another webpage, even located on another site/server, so while I will show you the code for it, I also want to show you a very practical use of it.

Background

As you might have seen I have created a new layout for this site, ASPCode.net. I am using the beta version of KBMentor but that's not what I want to talk about here. However, for reasons I won't get into, I wanted to create the site in directory aspcode.net/articles/ and therefore I naturally created a vdir (own application) in the articles drectory and thereaftter installed my KBMentor CMS.

Problem

One of the functions of KBMentor is to produce a Google SiteMap out of all the articles and pages. So I wanted to test it out - but ran into a big problem. The page to submit to Google SItemap is http://www.aspcode.net/articles/googl...map.ashx - but it wouldn't let me - simply because it is not located in the root of my domain. Moving the ashx page to the root wouldn't help at all, simply because another application is installed in that location.

Solution

Now to the solution. I did add a new ashx page in the root domain - and what is does is simply "screenscrape" the ashx file in the articles directory.



public void ProcessRequest (HttpContext context)
{
//Screenscrape
CookieContainer CC = new CookieContainer();

HttpWebRequest Req = (HttpWebRequest) WebRequest.Create("http://www.aspcode.net/articles/googlesitemap.ashx");
Req.CookieContainer = CC;

WebResponse webResponse = Req.GetResponse();
string sTxt = new System.IO.StreamReader(webResponse.GetResponseStream(),
System.Text.Encoding.Default).ReadToEnd();
webResponse.Close();



context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Write( sTxt);

//
// TODO: Add constructor logic here
//
}

ASP.NET 301 redirect

| Posted in

2

When moving your pages from one place to another it is very tempting to handle old inlinks by creating a simple Response.Redirect( sNewPage, true );

This sure will work, but this type of redirect is a 302 and is meant for temporary relocations of pages. But your pages are permanently moved and therefore you should use a 301 Moved Permanently status code. This should preserve your search engine rankings for that particular page.

To solve it you could install some sort of redirect filter(ISAPI dll). I was looking into those type of solutions and found IISMods URL Rewrite Filter for IIS.

Such a solution is very flexible and since it is a IIS filter it is possible to rewrite URL:s for all kind of filetypes, not only for aspx pages but say images (ex http://www.hello.com/*.gif could be transferred to http://www.hello.com/test/*gif ).

It is however not possible for everyone to install a ISAPI filter on their website, therefore I here present a solution on how you can achieve 301 redirects with pure ASP.NET code instead.

In your old page you can write code such as

private void Page_Load(object sender, System.EventArgs e)
{
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location","http://www.aspcode.net/newpage");
}


For me who wanted to redirect all calls to http://kbmentor.aspcode.net/whatever/it/could/be/foo.aspx to http://www.aspcode.net/articles/whatever/it/could/be/foo.aspx took and didn't have to think about pictures, cause they were "base" linked with the application took the idea one step further.

I created a new web application to install on kbmentor.aspcode.net. Basically it only contains a global.asax which handles Application_BeginRequest like this:



protected void Application_BeginRequest(Object sender, EventArgs e)
{
string sOldPath = HttpContext.Current.Request.Path.ToLower();


string sPage = "http://www.aspcode.net/articles/" + sOldPath;
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location",sPage);
Response.End();
}

ASP.NET - caching control

| Posted in

0

The ASP.NET cache is simply fantastic, but there are some shortcomings. While it is so easy to create a cache item dependent on, say for example a XML file (meaning the cache item will expire when the file xxx.xml is changed) it is not so common for such scenarios in my opinion. Also, now in .NET 2.0 you can create SqlCacheDependencys, meaning an cached item will be expired (and therefore a fresh read fromthe database will be executed) when something in the database is changed (could be set on query level actually).

However, to me such solutions are so much overkill, lots of overhead and also (for SqlCacheDependency ) you tie your solution pretty much to SQL 2005.
Most often you just want to cache some data in your application, example

string sTxt = "";
if ( context.Cache["RSSFEED123"] == null )
{
sTxt = BuildXmlString(context);
context.Cache.Insert( "RSSFEED123", sTxt, ..some depencency object... );
}
else
sTxt = context.Cache["RSSFEED123"].ToString();

work with txt...


My point is that most often YOU have the control of knowing when the Cache item should expire. In 99.99% of my cases it should trigger when an administrator enters a new/changes an existing article or whatever in the admin GUI.
So, my solution (here I show it with no cachedependency at all, living for the lifetime of the whole application) but you can of course use it in conjunction with a cachedependency.

Code using it:

string sTxt = "";
if ( context.Cache["RSSFEED123"] == null )
{
sTxt = BuildXmlString(context);
context.Cache.Insert( "RSSFEED123", sTxt );
}
else
sTxt = context.Cache["RSSFEED123"].ToString();

Admin GUI:

private void btnUpdate_Click(object sender, System.EventArgs e)
{
//Save to database, then call global static function
HelpClasses.Context.InvalidateAllCache();
}



HelpClasses.Context:

public static void InvalidateAllCache()
{
if ( System.Web.HttpContext.Current.Cache["RSSFEED123"] != null )
System.Web.HttpContext.Current.Cache.Remove("RSSFEED123");
}

So inessence, when the administrator clicks the Save button we go to HelpClasses.Context.InvalidateAllCache() and it simply removes the item(s) from the cache.

I know I could maybe create a specialized cache dependency class derived from CacheDependency - but then the problem is that the GUI needs to communicate with it. I always take the easy way out, cause in the end it is all about delivering a working solution for the customer - not creating the most .NETed solution possible :)

List of Request.ServerVariables

| Posted in

0

I'm publishing this list for my own sake actually, never seem to remember which variable gives you what. Sourcecode and description behind the scenes to generate this table is available in Related articles.



ALL_HTTP HTTP_CONNECTION:Keep-Alive HTTP_ACCEPT:*/* HTTP_ACCEPT_ENCODING:gzip, deflate HTTP_ACCEPT_LANGUAGE:sv HTTP_HOST:localhost:1229 HTTP_USER_AGENT:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)
ALL_RAW Connection: Keep-Alive Accept: */* Accept-Encoding: gzip, deflate Accept-Language: sv Host: localhost:1229 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)
APPL_MD_PATH
APPL_PHYSICAL_PATH D:\code\web\demos\membership\
AUTH_TYPE NTLM
AUTH_USER SYSTEMEN-D9AE02\Stefan Holmberg
AUTH_PASSWORD
LOGON_USER SYSTEMEN-D9AE02\Stefan Holmberg
REMOTE_USER SYSTEMEN-D9AE02\Stefan Holmberg
CERT_COOKIE
CERT_FLAGS
CERT_ISSUER
CERT_KEYSIZE
CERT_SECRETKEYSIZE
CERT_SERIALNUMBER
CERT_SERVER_ISSUER
CERT_SERVER_SUBJECT
CERT_SUBJECT
CONTENT_LENGTH 0
CONTENT_TYPE
GATEWAY_INTERFACE
HTTPS
HTTPS_KEYSIZE
HTTPS_SECRETKEYSIZE
HTTPS_SERVER_ISSUER
HTTPS_SERVER_SUBJECT
INSTANCE_ID
INSTANCE_META_PATH
LOCAL_ADDR 127.0.0.1
PATH_INFO /membership/servervariables.aspx
PATH_TRANSLATED D:\code\web\demos\membership\servervariables.aspx
QUERY_STRING
REMOTE_ADDR 127.0.0.1
REMOTE_HOST 127.0.0.1
REMOTE_PORT
REQUEST_METHOD GET
SCRIPT_NAME /membership/servervariables.aspx
SERVER_NAME localhost
SERVER_PORT 1229
SERVER_PORT_SECURE 0
SERVER_PROTOCOL HTTP/1.1
SERVER_SOFTWARE
URL /membership/servervariables.aspx
HTTP_CONNECTION Keep-Alive
HTTP_ACCEPT */*
HTTP_ACCEPT_ENCODING gzip, deflate
HTTP_ACCEPT_LANGUAGE sv
HTTP_HOST localhost:1229
HTTP_USER_AGENT Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)

Last second HTML changes in your ASP.NET page

| Posted in

0

While this solution might seems a little odd (or more correctly the problem might seem very odd) but this technique has sure solved a lot of problems for me.

What I'm gonna show you is a was to manipulate the resulting HTML and ASP.NET page has generated just before it's sent to the browser.

Now you might ask, isn't that what ASP Server controls are made for? To generate the HTML for you? Because there are certain times when the HTML or JavaScript it generates are not right and you might even not (if using a third party control) be able to modify the underlying control generating the code.

For example I've had problems with some thirdparty components where I was unable to get it to render the correct paths for including images etc (it simply couldn't point to the specific location I had them stored).

So, the plan is to somehow intercept the rendering, make my modifications to the HTML generated and then just pass my modified copy on to the browser.

One other example (which I actually have used in some projects) is to create some sort of "template replacer", where others can create their own templates and also write some special tags that your application is supposed to replace with some meaningful - for example
$currentarticle_name might be replaced with
the name of the current article (the one the user is browsing)

Thats the type of example I am gonna show you, consider this layout:

Now, we are supposed to replace the $CURRENT_DATETIME text with current date and time.

I.e we want this result when running:


So first the code - all the magic happens in Render:



protected override void Render(HtmlTextWriter writer)
{
using(System.IO.MemoryStream msOur = new System.IO.MemoryStream())
{
using(System.IO.StreamWriter swOur = new System.IO.StreamWriter(msOur))
{
HtmlTextWriter ourWriter = new HtmlTextWriter(swOur);
base.Render(ourWriter);
ourWriter.Flush();
msOur.Position = 0;
using(System.IO.StreamReader oReader = new System.IO.StreamReader(msOur))
{
string sTxt = oReader.ReadToEnd();
sTxt = sTxt.Replace("$CURRENT_DATETIME", DateTime.Now.ToString());
Response.Write(sTxt);
oReader.Close();
}
}
}
}

What are we doing? Our overridden Render method gets called (not the Page.Render - which would render it to the browser). We create a new HtmlTextWriter ourWriter - which we send to the base.Render (i.e Page.Render()). However, ourWriter is connected to the streamwriter swOur - which in turn is connected to the memorystream msOur (instead of the outputstream of the response object). This way, ASP.NET does handle all the rendering the way it usually does - but the resulting HTML ends up in the memorystream msOur.

We then set the reading position of msOur to 0 - which means we can read from it from the beginning.And now we read everything from it (using the streamreader object) to our sTxt variable.

And now we have all the rendered HTML in sTxt - we can just replace the fabricated template tag $CURRENT_DATETIME with the current time.

And finally send it to the browser by Response.Write.

While there aren't much code for you to copy to get it going in your own project I have included a download zip file containing the solution and code files.

Get current page name

| Posted in

0

This function can be used to retrieve the current page:s name, i.e default.aspx, hello.aspx or whatever.


public string GetCurrentPageName()
{
string sPath = System.Web.HttpContext.Current.Request.Url.AbsolutePath;
System.IO.FileInfo oInfo = new System.IO.FileInfo(sPath);
string sRet = oInfo.Name;
return sRet;
}


By going through System.Web.HttpContext.Current object we are able to have this function in a generic dll or class - and not in each and every page needing to call it.

ASP.NET, MySQL and paging

| Posted in

0

In this article we will create a simple one page ASP.NET web application, implementing paging using the cool MySQL feature LIMIT and SQL_CALC_FOUND_ROWS.

One of the coolest things about MySQL is some of its non standard features. It might sound like a weird thing to say, but being a web developer I just love the simplicity and performance MySQL gives me when it comes to paging. Cause in the typical web app you need paging.

The two problems a developer faces in such a paged web application

1. Two questions.

It's pretty neat to present a list of links to all pages available to the user, instead of just a next/prev link. Typically that means two questions.

select count(*) from bla bla ALL WHERE CONDIITIONS

select * from bla bla ALL WHERE CONDIITIONS

2. Just retrieving the rows for current page from the database.

It a waste memory to read 100000 records into a dataset and the use a pagedatasource. It's of course better to let the database engine do the filtering and having it just return the actual records to be displayed on the current page.

And also - you probably need to show the total number of pages available.

However when using the LIMIT clause in MySQL you solve the problem number two. As for number one - since we still need to get the total number of records, there is a feature for that as well, SQL_CALC_FOUND_ROWS.

So in short here's the code for reading the data:



public DataTable GetData
{
get
{
//Where to start???
long lStart = 0;
if (Request["p"] != null && Request["p"].Length > 0)
{
lCurrentPage = Convert.ToInt32(Request["p"]);
}
if ( lCurrentPage < 1 )
lCurrentPage = 1;
lStart = (lCurrentPage * lPageSize) - lPageSize;

string sSQL = "select SQL_CALC_FOUND_ROWS table_schema, table_name from information_schema.tables ";
sSQL += " order by table_schema, table_name ";
sSQL += "limit " + lStart.ToString() + "," + lPageSize.ToString() + ";";
sSQL += "select found_rows();";
DataSet ds = MySql.Data.MySqlClient.MySqlHelper.ExecuteDataset(System.Configuration.ConfigurationManager.AppSettings["ConnectionString"],
sSQL);
m_Data = ds.Tables[0];
lTotalCount = Convert.ToInt32(ds.Tables[1].Rows[0][0]);
return m_Data;
}
}


We add the SQL_CALC_FOUND_ROWS select modifier before the column list. This will tell MySQL to calculate the TOTAL number of rows and make it available in a special variable - which we get with select found_rows(). As you can see we do send both the queries in one command top the server and get them back in a dataset with the result in one table and the count in the second. That's so cool.

The rest of the code is just a matter of some math to calculate the current page (`query params ?p=12 etc) and of course rendering (the example uses a simple repeater)




Getting started with ADO.NET Entity Framework in .NET 3.5

| Posted in

0

ADO.NET Entity Framework is an object-relationship management (ORM) tool like Hibernate in java or N Hibernate for .net. ADO.NET Entity Framework is included with .NET Framework 3.5 Service Pack 1 and Visual Studio 2008 Service Pack 1. Please make sure you have and Visual Studio 2008 Service Pack 1 installed in your system. For more information about ADO.NET Entity Framework you can refer to Microsoft site.

One practical is worth more than a thousand words. So let us start with creating a very simple example.

Step 1: Create a database table.

Create a database in SQL Server 2005 and name it as Payroll.

On the payroll database create an Employee table as follows.

USE [Payroll]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[Employee](

[EmployeeID] [int] IDENTITY(1,1) NOT NULL,

[Name] [nvarchar](50) NOT NULL,

[Title] [nvarchar](50) NOT NULL,

[BirthDate] [datetime] NOT NULL,

[MaritalStatus] [nchar](1) NOT NULL,

[Gender] [nchar](1) NOT NULL,

[HireDate] [datetime] NOT NULL,

CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED

(

[EmployeeID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

Step 2: Data Layer

In the visual studio 2008 Make a new Blank solution and name it as Payroll. In the solution add a new class library project. Name it as Payroll.Entities as shown in following image.

Remove the class1.cs from project. Add a new item to project a select. ADO.NET Entity data Model.

Rename it as Payroll.edmx. Click on add. Select generate from the database and click on next choose database connection and the given textbox for connection string rename it with PayrollDAO

From the next screen select the employee table and click on finish. Compile the project. Now data layer is ready for you.

Step 3: Business/Service Layer

In the solution Payroll add a new class library project. Name it as Payroll.Service. Rename the class1.cs as EmployeeService.cs. Make the reference to System.Data.Entity. and also add the refrence to Payroll.Entities project we have created. Now add two methods GetEmployee and AddEmployee. Your class should look like this

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Payroll.Entities;

using System.Data.Objects;

using System.Data.Objects.DataClasses;

namespace Payroll.Service

{

public class EmployeeService

{

public List<Employee> GetEmployee()

{

PayrollDAO payrollDAO = new PayrollDAO();

ObjectQuery<Employee> employeeQuery = payrollDAO.Employee;

return employeeQuery.ToList();

}

public string AddEmpoyee(Payroll.Entities.Employee e1)

{

PayrollDAO payrollDAO = new PayrollDAO();

payrollDAO.AddToEmployee(e1);

payrollDAO.SaveChanges();

return "SUCCESS";

}

}

}

Compile the project. Service layer is ready for you.

Step 4: Presentation Layer

Add a new web site with name "WebApp" to the payroll solution and set it as startup project. In the default.aspx add a gridview and button as shown in following figure

Set button text to Add Employee. Make the reference to System.Data.Entity and also add the refrence to Payroll.Service project we have created in step 3.

Add the code on page load and buttion1_click, Default.aspx.cs should look like this

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using Payroll.Service;

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

{

protected void Page_Load(object sender, EventArgs e)

{

EmployeeService es= new EmployeeService();

GridView1.DataSource = es.GetEmployee();

GridView1.DataBind();

}

protected void Button1_Click(object sender, EventArgs e)

{

EmployeeService es = new EmployeeService();

DateTime dt = new DateTime(2008, 12, 12);

Payroll.Entities.Employee e1 = Payroll.Entities.Employee.CreateEmployee(0, "Anand", "Thakur", dt, "M", "M", dt);

es.AddEmpoyee(e1);

}

}

Copy the connectionStrings from App.config of Data Layer(Payroll.Entities) project and paste in web.config of web application

<connectionStrings>
<add name="PayrollDAO" connectionString="metadata=res://*/Payroll.csdl|res://*/Payroll.ssdl|res://*/Payroll.msl;provider=System.Data.SqlClient;provider connection string="Data Source=ATHAKUR;Initial Catalog=Payroll;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
connectionStrings>

Now build and run the web application.

Click on add employee, new employee should be added to database.

Conclusion:

This is a very basic example with single table. In the next part, I will try to include more tables with CRUD operations.

Getting started with ADO.NET Entity Framework in .NET 3.5 - Part II

| Posted in

0

In my last article "Getting started with ADO.NET Entity Framework in .NET 3.5", we have done select and add operations, now let us extend with update and delete operations.

Now I have added there textboxes fro employee ID, name and title as follows. (you can find it with attached project)

Update:

There is no change in Data layer

In the business layer add the UpdateEmployee method

public string UpdateEmployee(Payroll.Entities.Employee e1)

{

PayrollDAO payrollDAO = new PayrollDAO();

try

{

Employee e2 = null;

e2 = (from emp in payrollDAO.Employee

where emp.EmployeeID == e1.EmployeeID

select emp).First();

e2.Name = e1.Name;

e2.Title = e1.Title;

payrollDAO.SaveChanges();

}

catch

{

return "ERROR";

}

return "SUCCESS";

}

In the Presentation layer, add the following code in update button click

protected void Button2_Click(object sender, EventArgs e)

{

EmployeeService es = new EmployeeService();

DateTime dt = new DateTime(2008, 12, 12);

Payroll.Entities.Employee e1 = Payroll.Entities.Employee.CreateEmployee(Convert.ToInt32(empID.Text), empName.Text, empTitle.Text, dt, "M", "M", dt);

Result.Text = es.UpdateEmployee(e1);

GridView1.DataSource = es.GetEmployee();

GridView1.DataBind();

}

Delete:

There is no change in Data layer

In the business layer add the DeleteEmployee method

public string DeleteEmployee(Payroll.Entities.Employee e1)

{

try

{

PayrollDAO payrollDAO = new PayrollDAO();

Employee e2 = (from emp in payrollDAO.Employee

where emp.EmployeeID == e1.EmployeeID

select emp).First();

payrollDAO.DeleteObject(e2);

payrollDAO.SaveChanges();

}

catch

{

return "ERROR";

}

return "SUCCESS";

}

In the Presentation layer, add the following code in delete button click

protected void Button3_Click(object sender, EventArgs e)

{

EmployeeService es = new EmployeeService();

DateTime dt = new DateTime(2008, 12, 12);

Payroll.Entities.Employee e1 = Payroll.Entities.Employee.CreateEmployee(Convert.ToInt32(empID.Text), "", "", dt, "M", "M", dt);

Result.Text = es.DeleteEmployee(e1);

GridView1.DataSource = es.GetEmployee();

GridView1.DataBind();

}

Now our CRUD operations are over, in next article we will try to include more tables with relationships.

Getting started with ADO.NET Entity Framework in .NET 3.5 - Part III

| Posted in

0

Now in the example given in last tutorial update the GetEmployee method as follows

public static List<Employee> GetEmployee()
{
int skipValue = 50;
int limitValue = 25;
PayrollDAO payrollDAO = new PayrollDAO ();
ObjectQuery<Employee> employeeQuery = payrollDAO.Employee
.Where("it.Name = @eName", new
ObjectParameter ("eName", "aaa"))
.Where("it.EmployeeID > @EmpID1 ", new
ObjectParameter("EmpID1", 20083))
.Where("it.EmployeeID < @EmpID2 ", new
ObjectParameter("EmpID2", 20099))
.Skip("it.Name", "@skip", new
ObjectParameter("skip", skipValue))
.Top("@limit", new ObjectParameter("limit", limitValue));
return employeeQuery.ToList();
}

Conditional Query

As you can see from the code WHERE condition

.Where("it.Name = @eName", new ObjectParameter("eName", "aaa"))

Select the name whose value equal to eName parameter and next is the parameter passed in case it is 'aaa'. Please note that "it" is the default name given by Entity Framework. This will select all the employees with name 'aaa'.

You can add as much as WHERE conditions as you can see in the above example.

More information http://msdn.microsoft.com/en-us/library/bb896238.aspx

Paging

Paging in Entity framework is done by SKIP and TOP.

SKIP tells that from where the data should be picked up and TOP tells how many rows to be selected

int skipValue = 50;
int limitValue = 25;
.Skip("it.Name", "@skip", new
ObjectParameter("skip", skipValue))
.Top("@limit", new
ObjectParameter("limit", limitValue));

In this example it will skip first 50 rows, then starting from 51st row; it will show up to 75th row .You can also explore LIMIT method for paging

Data binding techniques using Visual Studio.NET and JDeveloper

| Posted in

0

Introduction

Today data binding techniques are very easy to apply using IDE such as Microsoft Visual Studio.NET and Oralce JDeveloper. In this article, I will show how to develop a client/server enterprise application by applying the Model-View-Controller (MVC) design pattern and using development tools such as Microsoft Visual.NET and Oracle JDeveloper.

Data binding in Visual Studio.NET

In this section, we're going to build a two-tier enterprise application using Visual Studio.NET and the underlying data binding framework. The first step is to start the Visual Studio.NET, and then create a connection to the underlying database using Data Connection tree in the Server Explorer. Go to the Server Explorer window, right-click on the Data Connections node and choose Add Connection from the context menu. In the Add Connection dialog, enter the information to connect to the AdventureWorks database shipped with the installation of Microsoft SQL Server 2005 (see Figure 1).



Figure 1

Now let's create a solution and two projects: one as class library to package the business logic layer's components (see Figure 2) and the other as Windows Application (see Figure 3) to package the presentation layer's components.



Figure 2



Figure 3

Now we're going to create the business components for the business logic module. As illustrative, we're going to use the Production.Product and Production.ProductModel tables in the AdventureWorks. For this purpose, we're going to create the business entities using Dataset object model. In the Solution Explorer window, right-click on the BusinessLogicCompPkg project, select Add | New Item from the context menu and select Dataset item from the Add New Item dialog box (see Figure 4).



Figure 4

Once the DataSet designer is open, you can define business entities by right-clicking on the DataSet designer and selecting Add | TableAdapter option from the context menu. When the Table Adapter Configuration Wizard appears, in the Step 1, you choose the created data connection (see Figure 5). Click on Next button.



Figure 5

In the Step 2, you specify how to store the connection string in the configuration file. Click on Next button. In the Step 3, you can specify the access method to the database. In this case, we're going to write SQL statements (see Figure 6).



Figure 6

In the Step 4, you must write the underlying SQL SELECT statement (see Figure 7). Click on the Next button.



Figure 7

The final step is for choose the methods associated to the Data Adapter in order to interact with the data source (see Figure 8).



Figure 8

Repeat this step in order to create the ProductModel entity. After that, the data set resembles as in Figure 9.



Figure 9

Finally, compile this project and we're read to use these business components. Now let's move on to the presentation project. Let's add a MenuStrip control from the Toolbox onto the main form. In the menu, create a sub-menu named Entities with two inner child menus named Product and Product Model. Finally, let's add an event handler for the Click event for the Product and Product sub-menu (see Figure 10).



Figure 10

Now let's add two child forms to display data of the Product and ProductModel entities and a reference to the BusinessLogicCompPkg assembly in order to invoke its objects (see Figure 11).



Figure 11

Now let's work on the ProductForm. Go to the Data Sources window and click on Add New Data Source icon in order to open the Data Source Configuration Wizard. In the first step, we choose to consume the data from the objects (the business entities created before). Click on Next button. In the Step 2, choose the data objects to bind to the GUI application, in this case the ProductDS object (see Figure 12).



Figure 12

Now you can see the Product and ProductModel entities in the Data Sources window. The next step in the application is to configure the Product to be displayed in details mode (see Figure 13) and the.



Figure 13

You must configure the ProductModelID attribute as a combo box (Figure 14).



Figure 14

Drag and drop the ProductModel node from the Data Sources window onto the ProductModelID attribute.

Now we need to add the business logic using C# to fill the data set and update the data source from the changes from the data set (see Listing 1)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BusinessLogicCompPkg;
using BusinessLogicCompPkg.ProductsDSTableAdapters;

namespace AppGUI
{
public partial class ProductForm : Form
{
public ProductForm()
{
InitializeComponent();
}

private void ProductForm_Load(object sender, EventArgs e)
{
ProductTableAdapter taProduct = new ProductTableAdapter();
taProduct.Fill(productsDS.Product);

ProductModelTableAdapter taProductModel = new ProductModelTableAdapter();
taProductModel.Fill(productsDS.ProductModel);
}

private void productBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.productBindingSource.EndEdit();

ProductTableAdapter taProduct = new ProductTableAdapter();
taProduct.Update(productsDS.Product);
}
}
}

Listing 1

Now let's go to the ProductModelForm form how to create a master/detail oriented form. Let's configure the ProductModel node as Details (see Figure 15).



Figure 15

Then drag and drop the ProductModel onto the ProductModelForm. Then, drag and drop the Product node inside the ProductModel node onto the ProductModelForm. Now we need to add the business logic to fill and update the Product and ProductModel (see Listing 2).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BusinessLogicCompPkg;
using BusinessLogicCompPkg.ProductsDSTableAdapters;

namespace AppGUI
{
public partial class ProductModelForm : Form
{
public ProductModelForm()
{
InitializeComponent();
}

private void ProductModelForm_Load(object sender, EventArgs e)
{
ProductTableAdapter taProduct = new ProductTableAdapter();
taProduct.Fill(productsDS.Product);

ProductModelTableAdapter taProductModel = new ProductModelTableAdapter();
taProductModel.Fill(productsDS.ProductModel);
}

private void productModelBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.productModelBindingSource.EndEdit();
this.productBindingSource.EndEdit();

ProductTableAdapter taProduct = new ProductTableAdapter();
taProduct.Update(productsDS.Product);

ProductModelTableAdapter taProductModel = new ProductModelTableAdapter();
taProductModel.Update(productsDS.ProductModel);
}

}
}

Listing 2

Data binding in JDeveloper

In this section, we're going to build a two-tier enterprise application using ADF Business Components as the business layer containing the business logic, validations and business rules and ADF Swing as the presentation layer for gathering and displaying information.
The first step is to start the JDeveloper, and then create a connection to the default ORCL database (shipped with Oracle database installation) using JDBC as the main API to access the relational data source from your application. Go to the Connections Navigator window, right-click on the Database node and choose New Database Connection from the context menu. The Create Database Connection Wizard appears then; click on Next button and in the Step 1 set a name for the connection (see Figure 16). Then click on the Next button.



Figure 16

In the Step 2, you must enter the authentication information (see Figure 17). Click on Next button.



Figure 17

In the Step 3, you must specify the connection details (see Figure 18). Click on Next button.



Figure 18

And finally, you test the created connection.

Now let's create the application by going to the Applications Navigator, right-click on the Applications node and select New Application from the context menu. In the Create Application dialog box, enter the name for the application, the working directory and the application package prefix (see Figure 19).



Figure 19

Then, create a project for the business logic components (see Figure 20).



Figure 20

Now we're going to create the business components for the business logic module. As illustrative, we're going to use the SCOTT schema shipped with the default installation of Oracle. For this purpose, we're going to create the business entities using ADF Business Components based on tables. In the Application Navigator window, right-click on the business_logic project and select New from the context menu and select Business Components from Tables from the New Gallery dialog box (see Figure 21). Click on OK button.



Figure 21

Then, a window appears where you have to select the connection to the database and click on OK button and then the Create Business Components Wizard appears. Click on Next button; and in the Step 1, you must select a list of tables for which you want to create entity objects. You can also change the name of the business entities by clicking on Selected list and typing the new name in the Entity Name field (see Figure 22). Click on the Next button.



Figure 22

In the Step 2, you can create the views associated to the entities created in the Step 1. Select all the entities and change the name of the views as well as to add them to a new package (see Figure 23). Click on the Next button.



Figure 23

In the Step 3, you can create read-only business entities. In our example, we don't need to create this kind of view. Then click on the Next button. In the Step 4, you set the name for the application module (see Figure 24). The application module bundles together the components and enables transaction support as well as other important data-centric services. Click on the Next button.



Figure 24

In the Step 5, you can specify the diagram of the components and their relationships (see Figure 25).



Figure 25

Click on the Next button, and you can see the result of the Wizard, and finally click on the Finish button.

Before you create to the presentation layer, let's implement several business logic, format and validation code according to our business requirements. Go to the Applications Navigator and double-click on the Department entity and the Entity Object Editor window appears. Go to the Attributes node to select the attributes to be customized then go the Control Hits tab which enables to specify its format for the graphical presentation of the entity.

For the Deptno attribute, we have (see Figure 26).



Figure 26

And for the Dnam attribute, we have (see Figure 27).



Figure 27

Finally, for the Loc attribute, we have. We can go on using the same approach for the rest of the attributes of the Employee entity (see Figure 28).



Figure 28

Now let's develop the Presentation Layer components. Go to the Application Navigator and add a new project named client_presentation (see Figure 29).



Figure 29

The right-click on the project and select New from the context menu, go to the Client Tier/ ADF Swing node and select Empty Form as the main form (see Figure 30).



Figure 30

Disable the Generate a menu bar checkbox (because we're going to create a customized menu bar) and set a name for the main form in the Wizard such as MainForm (see Figure 31).



Figure 31

Now let's design the main menu of the application by drag and drop JMenuBar from Components Palette to the form. Then, create a sub-menu named Entities with inner child menus named Employee and Department. Finally, let's add an event handler for the actionPerformed event for the Employee and Department sub-menus (see Figure 32).



Figure 32

Now it's time to add the child forms by right-clicking on the project and selecting New from the context menu (see Figure 33 and Figure 34).



Figure 33



Figure 34

Let's work on the EmployeeForm. First of all, select the navigation bar (this is generic for each table) and delete it. Now, go to the Data Control palette, and drag and drop the EmployeeVO1 onto the form, and from the Context Menu select Add Child | Navigation Bar. The go to the Data Control palette and drag and drop the Empno attribute from the EmployeeVO1 node onto the form, and from the Context Menu select Child | Text Field. Repeat this step for each attribute of the EmployeeVO1 node.

Now let's add a label for each text field to describe it. Go to the Component Palette, select the ADF Swing Controls library, and drag and drop a JULabel onto the form in front of the Empno textfield. Right-click on the JULabel and select Create Binding | Label For from the context menu in order to bind this control to metadata defined on the Business Component Entity Object. When the Attribute Binding Editor window is open, then go to the EmployeeVO1, and choose the Empno attribute (see Figure 35).



Figure 35

Now let's repeat this step for each attribute of the EmployeeVO1 node. It's remarkable to say that in the case of the Depno attribute, actually we don't want to display the department number, instead we want to display the department name using a combo box control which allows to select a from a list of department name. Drag and drop the Deptno attribute on EmployeeVO1 from the Data Control Palette onto the form and then choose Add Child | Combo box. If you run the application, you can see a list of department number.

In order to bind the department number to department name, you need to set up the underlying binding. Go to the Applications Navigator window, and navigate to the EmployeeFormPageDef.xml and then go to the Structure window, and double-click on the EmployeeVO1Deptno node and the List Binding Editor appears. Select the Dynamic List option, then click on Add… button and inside the Add Data Source window, select the DepartmentVO1 node (see Figure 36).



Figure 36

Next, you have to map the attributes from the Base Data Source and the List Data Source. Finally, set the Display Attribute to Dept to DName (see Figure 37).



Figure 37

When you run this application which resembles as shown in Figure 38.



Figure 38

The last part of this solution is to show how to create a master/detail oriented form. The first step is to create a form to display department data along with the associated employees using the master/detail concepts related to data binding. This approach is similar to the previous data binding tasks, the only difference is that you will base the binding on the DepartmentVO1 and its inside view EmployeeVO2 (see Figure 39).



Figure 39

After the form is created, we drag and drop the DepartmentVO1 onto the form and select Add Edit Form from the context menu (see Figure 40).



Figure 40

Then, in order to add a child entity in this case the employees associated to their department (the parent), drag and drop the EmployeeVO2 inside the DepartmentVO1 node onto the form and select Add Child | Table from the context menu. In order to navigate inside the table as well, we need to drag and drop the EmployeeVO2 inside the DepartmentVO1 node onto the form and select Add Child | Navigation Bar. Now let's test the application and see how it resembles as shown in Figure 41.



Figure 41

As you can see the last column of the table (showing the department number) is displaying a number and not the department name. We can solve this problem like we did before. Right-click on the Table control and select ADFm Binding Properties and then the Table Binding Editor appears. Then go to the Attribute Properties tab and select the Deptno and map it to a combo box. Finally, click on the configuration button, and the Editor Properties appears (see Figure 42).



Figure 42

By clicking on Create button, the List Binding Editor window appears, and we can configure the same way as we did in the employee form (see Figure 43).



Figure 43

The final step is to deploy the solution to the production environment using a Java Archive file (JAR). To create JAR in JDeveloper, you have to go to the client_presentation project, right-click over it and choose New from the context menu. In the New Gallery window, go to the Deployment Profiles node and select JAR file (see Figure 44).



Figure 44

Then a new profile with the specified name is created on the project and you have to edit it to customize your deployment. In order to create the JAR file from this customized deployment, you go to the project, right-click on the deploy extension file inside the Resources folder and select Deploy to JAR file option (see Figure 45).



Figure 45

Conclusion

In this article, I explain how to create data binding oriented applications using Microsoft Visual Studio.NET and Oracle JDeveloper. You can compare both solutions and apply this techniques to your own business scenario.

Add an autonumber column in a DataGridView

| Posted in

0

How to add an autonumber column in a DataGridView control that is populated with a DataTable in simple steps ?

an autonumber column in a DataGridView

Figure.1

The first column in Figure.1 displays sequential row numbers. I have achieved this output by using the following function.

private DataTable AutoNumberedTable(DataTable SourceTable)

{

DataTable ResultTable = new DataTable();

DataColumn AutoNumberColumn = new DataColumn();

AutoNumberColumn.ColumnName="S.No.";

AutoNumberColumn.DataType = typeof(int);

AutoNumberColumn.AutoIncrement = true;

AutoNumberColumn.AutoIncrementSeed = 1;

AutoNumberColumn.AutoIncrementStep = 1;

ResultTable.Columns.Add(AutoNumberColumn);

ResultTable.Merge(SourceTable);

return ResultTable;

}

Refer http://msdn.microsoft.com/en-us/library/yctw654b.aspx on How to: Create an Autonumber DataColumn

Explanation

The function receives a DataTable as parameter. It create a Data Table, ResultTable. Then add a Data Column,AutoNumberColumn with auto incrementing behaviour. Then the SourceTable is merged with the ResultTable. The Merge method will add the rows of the source table to the destimation table one by one. Consequently, autonumber column values are generated as sequential row numbers

Implementation

In a few minutes, we will create a Windows Forms Application to test the case. Create a Windows Form and add a DataGridView. Write the following code in the Load event of the form.

private void Form1_Load(object sender, EventArgs e)

{

using(SqlConnection Connection=new SqlConnection(this.ConnectionString))

{

using (SqlCommand Command= Connection.CreateCommand())

{

Command.CommandText = "SELECT * FROM [myTable]";

SqlDataAdapter dataAdapter=new SqlDataAdapter(Command);

DataTable dataTable = new DataTable();

dataAdapter.Fill(dataTable);

this.dataGridView1.DataSource = AutoNumberedTable(dataTable);

}

}

}

Then add the ConnectionString property given below and AutoNumberedTable function given above in the body of the form. Run the program. See what happens!

private string ConnectionString

{

get

{

SqlConnectionStringBuilder ConnectionBuilder = new SqlConnectionStringBuilder();

ConnectionBuilder.DataSource = "myDataSource";

ConnectionBuilder.InitialCatalog = "myDatabase";

ConnectionBuilder.UserID = "myUserID";

ConnectionBuilder.Password = "myPassword";

return ConnectionBuilder.ToString();

}

}

SqlConnectionStringBuilder provides a simple way to create and manage the contents of connection strings.

Refer http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder(VS.80).aspx on SqlConnectionStringBuilder Class

Details of Sample Application Seen in Figure.1

Database : Pubs

Query : "SELECT au_fname + ' ' + au_lname as [Name of Author],City FROM AUTHORS"

Add the following namespaces on top.

using System;

using System.Data;

using System.Data.SqlClient;

using System.Windows.Forms;

Happy Coding! Happy Dotneting!

C# Image Button

| Posted in

1

.NET Image Button

Adding a C# image button became incredibly easy with .NET Framework 2.0 and up. An image-button is a way to create a user-friendly .NET user interface.

As with many .NET controls, the key is setting the correct Properties.

Image Property

The first property you want to modify is Image. The image will have to be a resource of the Form. However it is a good idea in most cases to let it be a project resource so the image can accessed anywhere in the project.

TextImageRelation

This is a great .NET control property: TextImageRelation. It has 5 options and they are pretty self-explanatory. Basically it denotes the order in which text and image of a C# button are rendered. Here is some different looks that can be achieved:

C# image button

It is not a good idea to set TextImageRelation to Overlay if your .NET button has both text and an image since the text won't be readable. However if the button has no text, it looks good:

c# image button

Of course since these are .NET control properties we are talking about, they can updated run-time, opening up a world of possibilites. For example, a series of menu buttons can have the option of displaying text along side each icon or just displaying the icon.

.NET Button

So as you can see it does not take too much work to have a great looking .NET image button. Starting from the .NET Framework 2.0 these image buttons are fairly constant with different FlatStyle and versions of Windows.

However one "problem" is that the button is tied to Windows' version. An image button might look very good in Windows Vista or Windows 7 but might not look as eye-candy in older versions of Windows. For those looking for a more constant look across versions would have to turn to code-generated .NET buttons.

And finally, in order to get a good-looking C# image button you are going to need good icons. Here is where many programmers considering investing in professional icons.

Create Dynamic Image Buttons

| Posted in

0

Introduction

We've all had that problem - designing our web sites to have a certain look and feel. Unfortunately, not every visitor will view the site the way you intended. This is due to the fact that different operating systems render native browser controls differently. The buttons in OS X have the aqua look while the buttons in Windows 2000 look gray and outdated.

Using the AnyButton

Until now, to enforce a consistent look, a popular option is using images as buttons. This is a great alternative except that when it comes time to add new buttons or modify existing ones, you better have Photoshop [and the time] handy to get it done.

I've created a control called the AnyButton which derives from System.Web.UI.WebControls.ImageButton. This button uses image templates as skins. It will take a .jpg, .gif or .png as a template. It is really easy to use, and best of all, looks just like a real button.

The control takes in a single image as a template. The button supports 3 different states - default, hover, and press. Moreover, each button supports 3 different skins - 1 for each state. This allows you to create as many types of buttons as you'd like by subclassing the base Button class. For instance, you could have an XPButton, AquaButton, AmazonComButton, etc. The best part is, you don't have to use Photoshop to create your buttons - if you see a button on a site you like, screen shot it, crop out the middle part and you're pretty much ready to go.

Here's an example using the XP button as a skin:

This is the default state template that I will assign to the button

This is the hover state template that I will assign to the button

And this is the press state template that I will assign to the button

As you can see, the red lines dictate how to slice the button. These lines must be the exact RGB color 255, 0, 0 or #FF0000.

Each button has a ButtonConfig class as a property. The ButtonConfig class contains all the information about the button templates. Here's an example using all button states, generating a button that resembles the XP Silver button:

///


/// Default button templated to resemble the XP Button
///

public class XPButton : AnyButton
{
public
XPButton()
{
this.EnableHover = true
;
this.EnablePress = true
;
}
public
XPButton(Page page)
{
this
.Page = page;
this.EnableHover = true
;
this.EnablePress = true
;
}
protected override void
OnInit(EventArgs e)
{
Initialize();
base
.OnInit(e);
}
protected override void
OnLoad(EventArgs e)
{
base
.OnLoad(e);
}
protected void
Initialize()
{
Font f = new
Font("Tahoma", 8, FontStyle.Regular);
ButtonConfig buttonConfig = new
ButtonConfig();
buttonConfig.TemplatePath = this
.AbsResourcesPath + "/default.png";
buttonConfig.Font = f;
buttonConfig.VerticalTextOffset = 1;
buttonConfig.FontColor = Color.Black;
this
.Config = buttonConfig;
ButtonConfig hoverConfig = new
ButtonConfig();
hoverConfig.TemplatePath = this
.AbsResourcesPath + "/hover.png";
hoverConfig.Font = buttonConfig.Font;
hoverConfig.VerticalTextOffset = buttonConfig.VerticalTextOffset;
hoverConfig.FontColor = buttonConfig.FontColor;
this
.HoverConfig = hoverConfig;
ButtonConfig pressConfig = new
ButtonConfig();
pressConfig.TemplatePath = this
.AbsResourcesPath + "/press.png";
pressConfig.VerticalTextOffset = buttonConfig.VerticalTextOffset + 1;
pressConfig.HorizontalTextOffset = buttonConfig.VerticalTextOffset + 1;
pressConfig.Font = hoverConfig.Font;
pressConfig.FontColor = buttonConfig.FontColor;
this
.PressConfig = pressConfig;
}
}

This example is pretty straight forward. One thing to note is the VerticalTextOffset and HorizontalTextOffset properties being utilized in the press config. To get a true pressed effect, the text should move to the bottom right 1 pixel by 1 pixel.

This XPButton class comes packaged along with the AnyButton assembly. When the buttons are requested, they need to be saved to a directory. The path to this output directory is defined in the web.config file as follows:

<appSettings>
<
add key="Oxford.Web.AnyButton.OutputPath" value="~/resources/"
/>
appSettings>

In this example, I'm setting the output path to be the in the /resources folder of my web application root. This setting must exist or a null reference exception will be thrown. The ASPNET user must have read/write access to this directory.

So far so good, right? Using the control is the easiest part. Have a look:

<%@ Register TagPrefix="btn" Namespace="MyNamespace" Assembly="MyAssembly" %>
<btn:XPButton Runat="server" Text="Click Me"/>

The last thing you need to do is add This is the result of the previous call:

As you can see, 3 images where created; 1 for each state. Any subsequent requests for an XPButton with text "Click Me" will now be redirected to the already-generated button image. To clear the cache of images, simply delete the output directory.

Additional Properties:

  • AlphaPng
    If you are using png files and you want to enforce transparency, set the AlphaPng setting to true. This is necessary because IE does not support alpha png (right on MS). When AlphaPng is true, a special css filter will be added only to IE users (Firefox, Safari, etc users will not be affected).
  • TextWidth
    Use this property when you want to enforce a certain width regardless of actual width of the text.
  • OnClientClick
    Handy little property that can be set in the markup adding client side function call when the button is pressed.
  • AntiAliasText
    True by default, applies anti-aliasing and ClearType effect.
  • CausesPostback
    By default, an ImageButton (from which this control derrives) is a submit button. To disable posting back, set this CausesPostback to false.

File uploader in C#

| Posted in

0

This is very basic level small user control, in which we can discuss how to create web user control.

To create user controls follow the steps:

  1. Right click on project
  2. Click on Add
  3. Select New Item
  4. Select Web User Control
  5. Specify some Name

I have given name to this file as "uploader.ascx" and kept this file under "userControl" for simplicity purpose.

On this page I am having following controls:

  1. <INPUT id="fileUpload" type="file" Runat="server" NAME="fileUpload">

  2. <asp:label id="lblMessage" runat="server" Width="416px" Font-Size="10" Font-Name="verdana">asp:label>

  3. <asp:button id="btnSave" runat="server" Text="Upload..">asp:button>

At the code behind of above file I am having following function

public string uploadFile(string fileName,string folderName)

{

if(fileName=="")

{

return "Invalid filename supplied";

}

if(fileUpload.PostedFile.ContentLength==0)

{

return "Invalid file content";

}

fileName = System.IO.Path.GetFileName(fileName);

if(folderName=="")

{

return "Path not found";

}

try

{

if (fileUpload.PostedFile.ContentLength<=2048000)

{

fileUpload.PostedFile.SaveAs(Server.MapPath(folderName)+"\\"+fileName);

return "File uploaded successfully";

}

else

{

return "Unable to upload,file exceeds maximum limit";

}

}

catch(UnauthorizedAccessException ex)

{

return ex.Message + "Permission to upload file denied";

}

}

The above function takes care of following things before uploading file to the folder

  1. Invalid file name supplied.
  2. If file not exists or content length 0.
  3. Folder name exists.

Error Handling

While uploading done with UnauthorizedAccessException and returned with the message

On upload button click I am having following code

private void btnSave_Click(object sender, System.EventArgs e)

{

string strFilename, strMessage;

strFilename = fileUpload.PostedFile.FileName.ToString();

strMessage = uploadFile(strFilename,ConfigurationSettings.AppSettings["folderPath"]);

lblMessage.Text = strMessage;

lblMessage.ForeColor = Color.Red;

}

I have made use of Web.config file, in which I have added attribute as follows under:

<configuration>
<appSettings>
<add key="folderPath" value="Images">add>
appSettings>

i.e. I have set up path of folder to upload image

To access control in project, I have added page called as "uploadTester.aspx" to the project in which I have added following line:

<%@ Register TagPrefix="img" TagName="Uploader" src="userControl/uploader.ascx"%>

Which says that this control is register to this page with specified source.

And in HTML code I have added following code inside form tag:

<img:Uploader runat="server" id="Uploader1">img:Uploader>

That's all about

General:

To upload any of the file in respective folder user need to have permission for writing to the folder so please follow the following steps to prevent from the error.

Set permission to virtual directory by following steps in IIS

  • Right Click on virtual directory which you have created for this project. Under directory Tab you will find
    1)Read
    2)Log Visits
    3)Index this resources
    Are marked as checked (enables) in addition to this make
    4)Write access enabled or checked
  • Click on apply
  • Click on ok

This will set right permission to entire virtual directory, this way we can minimize error from the front end for permission / access denied.

Other way to solve permission denied issue is to go to actual folder "images" by using physical path and follow these steps:

  • Right click folder
  • Sharing Tab
  • Enable share this folder radio button
  • Click Apply
  • Click Ok

If u are using this code on 2000 server you should do following:

  • Right click respective folder
  • Go to security tab
  • Select Everyone user
  • Apply full control
  • click on ok

Presenting Child Data along with Parent Row in Data Grid

| Posted in

0

Introduction

Data Grid gives a richer UI presentation for the web applications. Most of the time there may be requirement to show one or more child data that belong to the parent row in a column with in the Data Grid. Though this article doesn't explain how to have hierarchal layout in the Data Grid itself. It gives the sample code for defining a Repeater control inside the Template Column and have that Repeater bind to the child data of the parent row.

Data Grid HTML Code:

<asp:datagrid id="dataGrid1" runat="server" Width="792px"
OnItemDataBound="dataGrid1_ItemDataBound" AutogenerateColumns="False"
cellpadding="0" PagerStyle-Mode="NumericPages" PagerStyle-PageButtonCount="20"
PageSize="20" AllowPaging="True"AllowSorting="True"
OnSortCommand="dgAccountBalance_Sort">

<Columns>

-- First Column With ID as hidden column -->

<asp:BoundColumn DataField="ID" Visible="False" HeaderText="ID">
<
HeaderStyle Width="190px" HorizontalAlign="Center" >HeaderStyle>
asp:BoundColumn>

-- Second Column defined as Check Box in a Template Column -->

<asp:TemplateColumn HeaderText="Select" HeaderStyle-Width="40px" >
<
ItemStyle Width="40px">ItemStyle>
<
ItemTemplate>
<
input type="checkbox" runat="server" id="chkSelected"
checked ='<% # DataBinder.Eval(Container.DataItem, "Selected") %>' NAME="chkSelected"/>
ItemTemplate>
asp:TemplateColumn>

-- Third Column bound to the Field Description -->

<asp:BoundColumn DataField="Description" SortExpression="Description"
HeaderText="Description">
<
HeaderStyle HorizontalAlign="Center">HeaderStyle>
<
ItemStyle Wrap="True" Width="2000px">ItemStyle>
asp:BoundColumn>

-- Fourth Column a Numeric column for displaying Currenty with DataFormat -->

<asp:BoundColumn DataField="Amount" SortExpression="Amount" ReadOnly="True"
HeaderText="Amount" DataFormatString="{0:$#,##0.0000;($#,##0.0000)}">
<
HeaderStyle HorizontalAlign="Center" Width="70px">HeaderStyle>
<
ItemStyle HorizontalAlign="Right" Wrap="False">ItemStyle>
asp:BoundColumn>

-- Fifth Column That displays the child record of the row inside a Repeater control -->

<asp:TemplateColumn HeaderText="Child Data" HeaderStyle-HorizontalAlign="Center">
<
ItemStyle HorizontalAlign="Left" Wrap="True">ItemStyle>
<
ItemTemplate>
<
asp:Repeater ID="rptChild" OnItemDataBound = "rptChild_ItemDataBound" runat = "server"
DataSource = '<%# ((System.Data.DataRowView)Container.DataItem).Row.GetChildRows("relationParentChild") %>'>
<
ItemTemplate>
<
asp:LinkButton ID="linkChild" Runat="server"
CommandArgument=<%# DataBinder.Eval(Container.DataItem, "[\"ChildID\"]")%>
OnClick="linkChild_Click">
<%# DataBinder.Eval(Container.DataItem, "[\"ChildFieldNameToDisplay\"]")%>
asp:LinkButton>
ItemTemplate>
asp:Repeater>
ItemTemplate>
asp:TemplateColumn>

Columns>

<PagerStyle PageButtonCount="20" Mode="NumericPages">PagerStyle>
asp:datagrid>

Code Required in the Code Behind Page:

private void Page_Load(object sender, System.EventArgs e)
{
System.Data.DataSet ds = Get Data Set();
// This Data Set should be populated with two tables one for the Parent Row Data
// and the second for the child data to be displayed in the repeater control
ds.Relations.Add("relationParentChild",ds.Tables[0].Columns["ID"],ds.Tables[1].Columns["FKID"]);
DataView dv = ds.Tables[0].DefaultView;
dataGrid1.DataSource = dv;
}

Code Explanation:

Add the data grid control to the page and set it's properties like width,autogeneratecolumns, the events etc, as required. Then define the Bound Column and the DataField Name for those columns. These columns will be just displayed as Text. If some data needs to be presented in special controls like the Check Box as shown in the example have it defined in the Item Template Column. The code also shows how we can set the Data Format String for the column.

The Repeater should be declared inside the Item Template column in the grid.(inside a Item Template). The data source for the Repeater is set as ((System.Data.DataRowView)Container.DataItem).Row.GetChildRows("relationParentChild") inside the Server Tag. This will get the child rows of the row to which the Data is being Bound

In this example we are displaying a link button inside the Repeater and clicking on the link will take to appropriate page as required. This can be changed to as per the need. To access the child table's field this syntax is used DataBinder.Eval(Container.DataItem, "[\"ColumnNameinChildTable\"]")%

CommandArgument attribute used in the example is used to get the querystring to open up the page for the selected child link.

SOAP, .NET, and COM - An Introduction: Part I

| Posted in

0

SOAP is a protocol specification to invoke methods on servers, services, components and objects. The available procedure of using XML and HTTP as a method invocation mechanism is implied by SOAP. A small number of HTTP headers that facilitate firewall/proxy filtering are authorized by the SOAP specification. The SOAP specification also mandates an XML vocabulary that is used to represent method parameters, return values, and exceptions.

To exchange structured and typed information between peers in a decentralized, distributed environment using XML, SOAP presents an uncomplicated mechanism. SOAP defines a simple mechanism for expressing application semantics by providing a modular packaging model and encoding mechanisms for encoding data within modules instead of defining any application semantics such as a programming model or implementation specific semantics. This allows SOAP to be used in a large variety of systems ranging from messaging systems to RPC.

An Overview to SOAP

SOAP, (the Simple Object Access Protocol), is XML syntax to exchange messages. Moreover, since it is XML, it is independent from both language and platform. In addition, SOAP is a fundamental part of .NET, Microsoft's new development platform, and to understand what SOAP is and how it works it will be important for developers to move towards .NET.

In SOAP, there are four parts:

* The SOAP envelope construct: Defines an overall framework to express what is in a message, who should deal with it, and whether it is optional or mandatory.
* The SOAP encoding rules: Defines a serialization mechanism that can be used to exchange instances of application-defined datatypes.
* The SOAP RPC representation: Defines a convention that can be used to represent remote procedure calls and responses.
* The SOAP binding: Defines a convention to exchange SOAP envelopes between peers using an underlying protocol for transport.

Simply, SOAP is a well-documented wire protocol. Microsoft is getting behind SOAP and in future, probably will offer some type of implementation. However, other vendors can also do the same. For instance, the Perl implementation of SOAP is not tied to COM or Windows in any way, and if a modern version of Perl is available, can be used on any platform where. SOAP does not attach anyone to a particular platform. It provides a practical way to communicate over the Internet that is easy to implement on any platform.

Functionally, SOAP is very similar to IIOP which the underlying protocol used by most CORBA products. DCOM has additional protocol functionality such as garbage collection, causality that is not present in IIOP or SOAP. However, DCOM's extended functionality generally only needed in server-server communications and is not required in client-server communications. An advantage of both IIOP and DCOM side, SOAP packets be likely to be larger on the wire and can be somewhat more resource intensive to parse/generate.

A set of conventions for exchanging XML messages defined by the specification, such as rules for encoding data structures, an extensibility mechanism, a binding to the HTTP protocol, and conventions for RPC style invocations. For all SOAP messages that are exchanged between a web service and its client, SOAP defines the outer element. Namespace indicates to an XSLT processor that the XML is in fact a transform, just as the stylesheet element in the XSLT.

Moreover, the Envelope element in the SOAP namespace indicates to a SOAP processor that the XML is in fact a SOAP message. After that the processor can seek the individual pieces of the message, such as a mandatory Body element that has the actual request and an elective Header element that has extension elements. Below, a framework SOAP message is demonstrated.



<-- Headers go here -->
soap:Header>

<-- Request goes here -->
soap:Body>
soap:Envelope>

An extensibility mechanism is provided in the Header element in SOAP. This element can have any number of namespace qualified child elements. To the base SOAP protocol, each of these elements is some form of extension. Possibly one element holds data associated with conversation or session management between a client and a server. Another element might contain authentication information or even information pertaining to an ongoing transaction and another may contain locale information. Whatever their content or semantics each header element modifies the SOAP protocol in some way, also they providing extra context for the processing of the body of the message. It will be important to the client that the server honors them for some extensions; authentication is a good example to this.

SOAP Basics

At first, SOAP was based on HTTP, in Version 1.0 of the specification. Later on this changed, to allow for a wider variety of transport protocols (such as SMTP), or messaging protocols in the latest revision of the specification, Version 1.1 and Version 1.2. Two major design goals are outlined in the original SOAP specification: 1) Provide a standard object invocation protocol built on Internet standards, using HTTP as the transport and XML for data encoding, and 2) Create an extensible protocol and payload format that can evolve. Simplicity and extensibility are very important goals for SOAP. SOAP completely avoids several additional aspects of distributed object architectures.

* Distributed garbage collection-orphaned objects
* Pipelined messages or multiple call requests.
* Remote object activation
* Bi-Directional HTTP communications-callbacks
* Objects-by-reference
* Security

The individual SOAP implementation's architect designs the areas which the specification has not addressed, into a specific implementation. To solve some challenging real world issues that encumber existing distributed protocols and architectures is SOAP's objective. While existing protocols do address the items mentioned, and SOAP does not, SOAP addresses areas in which existing protocols fall short, such as scalability and the capability to share disparate yet interoperable using SOAP architectures.

SOAP Fundamentals

Actually, SOAP is based upon its technical worth; it is mainly the mixture of textual information shared via the Internet. SOAP processing is very much aligned with the Internet if you use HTTP as your SOAP transport protocol. SOAP specifies a stateless programming model with this processing. That means, object clients request services from a remote entity, which responds with the pertinent information. Currently, HTTP is a persistent technology and if a business interacts with the Internet in any meaningful fashion, it has to handle HTTP data. At the very least, HTTP processing is well understood and widely put into action. Some aspects of using SOAP, as with any tool, can be seen as advantages. In following list you may find some of the advantages of using SOAP.

* SOAP is built upon technologies, rather than vendor-specific technologies, and facilitates true distributed interoperability. At least not at this time, the SOAP market is not conquered by single vendor.
* The SOAP specification can ultimately consolidate the various HTTP tunneling protocols (IIOP and RMI to name two) into a single specification. This makes implementations easier and potentially more interoperable. SOAP typically uses HTTP but at least with the 1.2 version of the specification, it does not require its use.
* SOAP will likely work out of the box in a wide range of user locations that enable HTTP port 80 POST access.
* Loosely Coupled distributed applications are encouraged by SOAP.
* Unless significant serialization changes are made to the SOAP specification, changes to the SOAP infrastructures will likely not affect applications using the protocol.

When you choose remoting architecture, possibly there are many design facets that you need to consider about them. The following list includes some of them.

1. Scalability
2. Performance
3. Activation
4. State Management
5. Garbage Collection
6. Security

The wire protocols are not necessarily responsible for any or every design facet of the entire remoting architecture. For instance, not all of them implement security. However, for some or all these design facets, each protocol provides some level of support. Some protocols transmit security information as an integral part of their data packets, whereas others rely upon external systems to assure a secure connection. Beginning with scalability, each of these design issues is discussed to try to apply the same definition to all the wire protocols. SOAP simply is a wire protocol, unlike the other distributed object architectures. To compare SOAP with these other architectures; you need to apply the SOAP protocol as part of a distributed architecture of its own. On the other hand, even as a wire protocol, SOAP offers many advantages.





Figure 3.1 - SOAP Architecture

SOAP Messages

Since now we have covered SOAP at a high level, let us examine the most important detail of SOAP: the structure of a message. For messages, SOAP primarily uses XML syntax. A SOAP message contains a payload, the application-specific information. Here is an example of a SOAP message as an actual XML document:

<soap:Envelope xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/
soap:encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/">
<
soap:Header>
<
h:from xmlns:h="http://www.ets-
oftware.com/Header">
testuser@mydomain.comh:from>
soap:Header>
<
soap:Body>
<
w:GetMainIdentity xmlns:w="http://www.ets-software.com/Authors/">
<
w:nickname>XSLT-Authorw:nickname>
w:GetMainIdentity>
soap:Body>
soap:Envelope>


Figure 3.2 - SOAP Messages Architecture

Let us take a quick look at the XML of the message before we go into the contents of the SOAP message. As you may know, SOAP messages heavily rely on XML Namespaces. All of the elements in this document are prefixed with a namespace, and there is a good reason why the SOAP specification uses namespaces so extensively. All the elements of the message must be scoped in some fashion to avoid conflicts in the names of elements in order for a SOAP message to carry any arbitrary XML payload.

The namespace prefix soap is used on most of the elements in the above message. In the fallowing example, the prefix is associated with the namespace URI http://schemas.xmlsoap.org/soap/envelope/. It identifies the elements that are part of a standard SOAP message. The choice of soap is not relevant like all namespace prefixes. As in the fallowing, the namespace prefix could have been something else entirely:

<trial:Envelope xmlns:trial =http://schemas.xmlsoap.org/soap/envelope/
trial:encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/">
<
trial:Header>
<
h:from xmlns:h="http://www.ets-
software.com/Header">
testuser@MyDomain.comh:from>
trial:Header>
<
trial:Body>
<
w:GetMainIdentity xmlns:w="http://www.ets-software.com/Authors/">
<
w:nickname>XSLT-Authorw:nickname>
w:GetMainIdentity>
trial:Body>
trial:Envelope>

If the namespace is the default namespace for the document, the namespace prefix could also be eliminated. As shown below, the default namespace is assigned using just the xmlns attribute:

<Envelope xmlns=http://schemas.xmlsoap.org/soap/envelope/
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<
Header>
<
h:from xmlns:h="http://www.ets-
software.com/Header">
testuser@MyDomain.comh:from>
Header>
<
Body>
<
w:GetMainIdentity xmlns:w="http://www.ets-software.com/Authors/">
<
w:nickname>XSLT-Authorw:nickname>
w:GetMainIdentity>
Body>
Envelope>

All three of these messages are acceptable and equivalent. It is better to use the soap namespace prefix for elements for better readability. All of the elements in the message that are associated with the soap namespace are standard elements of a SOAP message, as are the attributes. Any other elements are related to either message extensions or the message payload.

A traditional versioning model is not defined in SOAP based on major and minor version numbers. A SOAP message MUST have an Envelope element associated with the "http://schemas.xmlsoap.org/soap/envelope/" namespace. The application MUST treat a message as a version error and discard it if this is received by a SOAP application in which the SOAP Envelope element is associated with a different namespace. However, if the message is received through a request/response protocol such as HTTP, the application MUST respond with a SOAP VersionMismatch faultcode message using the SOAP "http://schemas.xmlsoap.org/soap/envelope/" namespace.

<soap:Envelope xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/
soap:encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/">
<
soap:Header>
<
h:from xmlns:h="http://www.ets-
software.com/Header">
testuser@MyDomain.comh:from>
soap:Header>
<
soap:Body>
<
w:GetMainIdentity xmlns:w="http://www.ets-software.com/Authors/">
<
w:nickname>XSLT-Authorw:nickname>
w:GetMainIdentity>
soap:Body>
soap:Envelope>

How WebParts on a page communicate with each other

| Posted in

0

Introduction:

In this tutorial we will describe how to make WebParts on a WebParts Page communicate with each other. So will see how to use ConnectionsZone and how to enable WebParts to talk to each other by connecting them.

Assumptions:

This tutorial assumes that you know how to work with web forms, creating user controls and connecting to data sources using SqlDataSource Control. Also you should know how to use WebPartZone control and to know what are WebParts and WebParts Pages.

How to implement connections between 2 WebParts:

The scenario is, we have 2 web parts, one display a drop down list of publishers, and the other display grid view of titles related to a specific publisher. So whenever I change the selection from the drop down list, the grid view should repopulated with the titles related to the selected publisher. This is very simple scenario just to show you how to implement WebParts Connections.

Preparing the WebParts Page:

  1. Create new WebForm, Name it WebPartsConnections.aspx, Also create 2 user controls, name them as UCPublishers.ascx & UCTitles.ascx.

  2. Open UCPublishers.ascx, drag and drop SqlDataSource control -name it sdsPubs- into it as well as a DropDownList -name it cmbPubs- and set its AutoPostBack Property to ture.

  3. Configure the SqlDataSource to select [pub_id] and [pub_name] from publishers table in pubs Database sample.



  4. Open UCTitles.ascx, drage and drop SqlDataSource control -name it sdsTitles- into it as well as a GridView -name it dvTitles-. Also drag and drop a HiddenField Control -name it hfSelectedPublisherID-

  5. Configure you SqlDataSource to select [title], [price] and [pubdate] from [titles] table in Pubs sample database, with pub_id as parameter. Configure the parameter to be a control parameter, and its value populated tom the HiddenField Control.



  6. Now Open your WebPartsConnections.aspx, Insert table with one column and one row.

  7. Drag and drop WebPartManager Control into the page-name it wpManager-

  8. Drag and drop 2 WebPartZone controls into the table, name them as wpzTop & wpzBottom.

  9. Drag and drop the UCPublishers.ascx from the solution explorer into the wpzTop. Do the same for UCTitles.ascx but drop it into wpzBottom. You can configure the Zones to use AutoFormat Professional Style.

  10. You can now Test the page. Notice that there is nothing happens when you change the publisher.

Building the Connection:

To implement the connection functionality between WebParts, we should create an Interface. This interface would be implemented by both UCPublishers.ascx as Connection Provider, and UCTitles.ascx as Connection Consumer. This interface serves as a contract for the communication between the provider and consumer.
We will name our Interface as ISelectedPublisher:
  1. Right click on App_Code and select New Item. (Create ISelectedPublisher.cs)

    public interface ISelectedPublisher
    {
    //ID of the selected publisher
    string
    SeletedPublisherID{get;}
    }

  2. Now open your UCPublishers.ascx in Code-View and implement the ISelectedPublisher as the following

    public partial class UCPublishers : System.Web.UI.UserControl, ISelectedPublisher
    {
    #region ISelectedPublisher Members
    //Get the Selected Value from the DropDownList that holds Publishers
    public string
    SeletedPublisherID
    {
    get { return cmbPubs.SelectedValue; }
    }
    #endregion
    [ConnectionProvider("SelectedPublisher", "SelectedPublisher")]
    public ISelectedPublisher GetSelectedPublisher()
    {
    return this;
    }
    }

    Essentially, we are implementing the ISelectedPublisher interface and creating a provider connection point by using the ConnectionProvider attribute. So we implemented the SelectedPublisherID property to return the selected publisher id from the DropDownList.

    Also we created the GetSelectedPublisher method. It is marked as ConnectionProvider, The first parameter to the ConnectionProvider attribute assigns a friendly name to the provider connection point. The second parameter assigns a unique ID to the provider connection point. Note the returned object is "this", which mean to consider the control instance itself as the connection provider.

  3. It is time to implement the Consumer now, so open the Code-View of your UCTitles.ascx and Consume the connection provided by the Provider:

    public partial class UCTitles : System.Web.UI.UserControl
    {
    private ISelectedPublisher _publisher = null;

    [ConnectionConsumer("SelectedPublisher", "SelectedPublisher")]
    public void SetSelectedPublisher(ISelectedPublisher selectedPublisher)
    {
    _publisher = selectedPublisher;
    }
    protected override void OnPreRender(EventArgs e)
    {
    base.OnPreRender(e);
    if (_publisher != null)
    {
    hfSelectedPublisherID.Value = _publisher.SeletedPublisherID;
    }
    }
    }


    Essentially, we are using the ConnectionConsumer attribute to define a consumer connection point -The SetSelectedPublisher Method-, and allowing it to act as a receiver of the ISelectedPublisher interface. The publisher that is received is then appended to the hidden field in the UCTitles.ascx Control on the PreRender event. The first parameter to the ConnectionConsumer attribute assigns a friendly name to the consumer connection point. The second parameter assigns a unique ID to the consumer connection point.

  4. Now Select the WebPartManager Control in your page -wpManager-

  5. From the property window, select ellipses beside the StaticConnections property. Configure it as the following.



    The ConsumerID is the ID of the Consumer Control, in our case it is the UCTitles Control which has the default ID UCTitles1.

    The ProviderID is the ID of the Provider Control, in out case it is the UCPublishers Control which has the dfault ID UCPublishers1.

    ConsumerConnectionPointID and ProviderConnectionPointID are the Attributes parameters mentioned earlier.



  6. Now its time to test your Page. Run it and change the publisher, you will notice that the Titles is changed in the GridView to display the publisher's Titles.

Working with ConnectionsZone:

Now we will Connect and Disconnect the WebParts Connections on the fly during runtime. To do so we need to use ConnectionsZone.

  1. Drag and drop ConnectionsZone Control into your page any place

  2. Add LinkButton to you page, -name it btnEditConnection- and set the text to "Edit Connection".

  3. Double click on it to implement its click event handler.

    protected void btnEditConnection_Click(object sender, EventArgs e)
    {
    if (btnEditConnection.Text == "Edit Connection")
    {
    wpManager.DisplayMode = WebPartManager.ConnectDisplayMode;
    btnEditConnection.Text = "View Page";
    }
    else
    {
    wpManager.DisplayMode = WebPartManager.BrowseDisplayMode;
    btnEditConnection.Text = "Edit Connection";
    }
    }

  4. Again run your page and click on the button. From the any of the WebParts Menu on the top right corner of the WebPart select Connect. Note that the Connection Zone Appears now. Test your page to see what you can do on the fly with Connection Zone and WebParts




Now we almost cover most of the basic features of WebParts and WebParts Pages. Hope this WebPart Tutorial series enrich your knowledge about WebParts and WebParts framework in ASP.Net 2.

Working with WebParts Page, WebPart Zones & WebParts

| Posted in

0

Introduction:

This tutorial considered to be the second part of the first tutorial Creating a Simple WebPart Page and use WebServer controls as WebParts. Here we will see how can we remove and add WebParts during run time, adding personalizable properties to your WebParts and modifying there values also in run time.

WebPart Zones:

There are 4 types of WebPart Zones. Zones is used to host (anchor or dock) WebParts. In the previous tutorial we had a look at WebPartZone. At this tutorial we will have a look at the other another two WebPart Zones, CatalogZone & EditorZone.

Modification to old project:

In the new project, have cut the XmlDataSource control -xdsRSS- and the DataList Control -dlstRss- to a newly created UserControl named UCtrlRSSReader.ascx. The same I did for SqlDataSource control -sdsTitles- and the GridView Control -gvTitles- which were saved on the UserControl UCtrlTitles.ascx.

Working with the CatalogZone:

Open the pervious project and apply the following modifications:

  1. Add another column to the table, so the table will contain 4 columns now.

  2. Drag and drop CatalogZone Control from control from the Toolbox (under the WebParts tab) into the new column cell, rename it to wpczCatalog and set its Auto format to Colorful.



  3. Drag and drop PageCatalogPart Control into the CatalogZone Control wpczCataog, rename it wpcPageCatalog.



  4. Drag and drop DeclarativeCatalogPart Control into the CatalogZone Control wpczCataog, rename it wpcDeclarativeCatalog.

  5. From DeclarativeCatalogPart Tasks smart tag, Select Edit Template.

  6. Then drag and drop UCtrlRSSReader from your solution explorer into the WebPartsTemplate area of wpcDeclarativeCatalog control, and click End Template Editing in the smart tag.



  7. Switch to Source view and add Title attribute to your UserControl you have just dropped, set its value to "RSS Reader". Be careful to edit the correct control:







  8. Drag and drop a DropDownList into your Web From but out of the table area, rename it to cmbWebPartPageMenu. Then add the following items to it.

    Normal View
    Design View
    Edit View
    Manage WebParts



  9. Set the AutoPostBack property of the DropDownList Control to true. and double click on it to implement it default event SelectedIndexChanged:

    protected void cmbWebPartPageMenu_SelectedIndexChanged(object sender, EventArgs e)
    {
    switch (cmbWebPartPageMenu.SelectedIndex)
    {
    case 0:
    wpManager.DisplayMode = WebPartManager.BrowseDisplayMode;
    break;
    case 1:
    wpManager.DisplayMode = WebPartManager.DesignDisplayMode;
    break;
    case 2:
    wpManager.DisplayMode = WebPartManager.EditDisplayMode;
    break;
    case 3:
    wpManager.DisplayMode = WebPartManager.CatalogDisplayMode;
    break;
    case 4:
    wpManager.DisplayMode = WebPartManager.ConnectDisplayMode;
    break;
    default:
    wpManager.DisplayMode = WebPartManager.BrowseDisplayMode;
    break;
    }
    }

  10. Now run your page, select Manage WebParts option and note the changes on the page.



    Click on Declarative Catalog link and notice the the deference.

    For any WebPart on the the page, click on its menu at the top right corner, and select Close. Notice the changes on the Catalog Zone. you will fine the Page Catalog is increased. Click on Page Catalog link and notice the change on the zone. You can add any WebPart listed to your page, by checking the checkbox of the WebPart, selecting the WebPart Zone and then click Add.

Hope by now you understand the deference between DeclarativeCatalogPart and PageCatalogPart. As DeclarativeCatalogPart contains WebParts that is possible to be added to the page and you defined them during design time. But they may not exists physically on the page. While PageCatalogPart contains all WebParts hosted on the Page.

Now let's work with the EditorZone Control.

Working with the EditorZone and add personalizable properties to WebParts:

  1. As we did while working with CatalogZone Control, drag and drop EditorZone Control into the 4th column just underneath the CatalogZone control, rename it to wpezEditor. Also set the Auto Format to Colorful.

  2. Drag and drop PropertyGridEditorPart & AppearanceEditorPart into the EditorZone control. rename the controls to wpPropertyGrid & wpAppearanceEditor.

  3. Open your UCtrlTitles.ascx control and switch to Code-Behind. We want to make one of the columns of the GridView inside that control to be optional for view. We will configure the Price Column for this.

  4. Declare a class level Boolean variable and name it _showPriceColumn as the following.

    private bool _showPriceColumn = false;

  5. Create a property for this variable. Mark the property with the following attributes:

    Personalizable() to be able to personalize the property for the WebPart.
    WebBrowsable() to be able to edit its value while in editing mode.
    WebDisplayName("Show Price Column") to display friendly name on the property grid wpPropertyGrid.

    [Personalizable(), WebBrowsable(), WebDisplayName("Show Price Column")]
    public bool ShowPriceColumn
    {
    get { return _showPriceColumn; }
    set { _showPriceColumn = value; }
    }

  6. Now override the OnPreRender Method of your control as the following:

    protected override void OnPreRender(EventArgs e)
    {
    base.OnPreRender(e);
    gvTitles.Columns[2].Visible = ShowPriceColumn;
    }

  7. Save your work and test the project. From the drop down list option, select Edit View. Then for your Titles or Books WebPart, select Edit from the top right corner menu or it. Notice that the Appearance and Property Grids Displayed. Also notice that the price column is not visible.



  8. Check the Show Price Column checkbox in the property grid. and click apply, Notice that the Price Column on the GridView is now visible.

Give yourself 10 min to examine the whole solution running.

Creating a Simple WebPart Page and use WebServer controls as WebParts-1

| Posted in

0

Introduction:

Portal web sites such as MY MSN and MSN Spaces, often organize their data into discrete units that support a degree of personalization. Information is organized into standalone parts [WebParts], and users can rearrange those parts to suit their individual working styles. Such personalization also lets users hide parts that contain information in which they have no interest. What's more, users can save their settings so that the site will remember their preferences the next time they visit the site. In ASP.NET 2.0, you can now build web portals that offer this kind of modularization of information and personalization using the new Web Parts Framework.

Scope of this Tutorial:

Here we will see how to add web parts to a web part page. Developing advanced WebParts from scratch is out of this tutorial scope. This tutorial also may has subsequent tutorial that explains more about Web Parts Framework.

Assumptions:

This tutorial assumes you are familiar with Data Access Controls and Data Binding Controls such as SqlDataSource and GridView. Also it requires SQL Sever 2005 Express Edition and Visual Web Developer. If you don't have SQL Server Express 2005, install ASPNETDB in your SQL Server instance using aspnet_regsql tool. and configure your application to use this instance as your personalization provider.

How to create WebParts Page:

To create a WebParts Page, you need to work with a specific ASP.Net 2.0 Controls:

  • WebPartManager Control, which manages all Web Parts controls on a WebParts Page and must be the first control that you add to the page.

  • WebPartZone Control, which contains and provides overall layout for the Web Part controls that compose the main UI of a page. This control serves as an anchor for Web Part controls. Multiple controls of this control forms the WebParts Page.

    The WebPartZone may contains one or more WebParts.

To create a WebPart Page:

  1. Create a home page for the Web Parts. Launch Visual Studio 2005 and create a new web site project.

  2. While in design view, drag and drop a WebPartManager control from the toolbox (under the WebParts tab) onto the default Web Form, rename it to wpManager.

    WebParts Controls Tab

  3. From Layout menu item, select Insert Table, insert table with 3 columns and 1 row. This is where the Web Parts on your page are to be located.

  4. Drag and drop a WebPartZone control from the Toolbox (under the WebParts tab) into each of the table's three cells. Each WebPartZone control will serve as the docking area for one or more Web Parts. A Web Part zone is an area where Web Parts are anchored. It also defines the default layout and appearance of each Web Part within that zone.

  5. Set the ID property for each WebPartZone Control to be wpzLeft, wpzMiddle and wpzRight. Then for each one set the Auto format to Professional.

    Auto Format

  6. Save your form.

You have created your WebParts Page. Now you want to add WebParts to your page, and manage them at run time so you can rearrange WebParts positions.

Next we will add 2 WebParts, one will display Information from SQL Server Database. While the other one will display data from XML file.

Adding WebParts to the WebParts Page:

  1. Drag and drop SqlDataSource control into you Web Form, rename it to sdsTitles. Configure it to retrieve data from Titles Table in Pubs Database. [you can use SQL Server 2000 or SQL Server 2005 any Edition].

    sdsTitles Code

  2. Drag and drop GridView into wpzLeft WebPartZone control, rename it to gvTitles. Configure gvTitles to user sdsTitles as a Data Source.

  3. Switch to the Source View and add title attribute to the GridVew -gvTitles- control and set its value to "Titles".



    Set Auto format for the GridView control to classic, also set the Paging and Sorting options, and set PageSize property to 5.

    GridView Settings

  4. Drag and drop XmlDataSource control to your Web Form, rename it to xdsRSS. Configure it to use the RSS.xml that is attached with the demo project, or use any other well-formed XML file you wish.

    xdsRSS Configuration

  5. Drag and drop DataList into wpzMiddle, and rename it to dlstRss. Switch to source view and configure your DataList as the following.

    dlstRss Source View

  6. Now test your page. You will be able to see the two Web Parts, minimize them or close them only. On the following steps you'll be able to create to move them and rearrange them.

  7. Drag and drop LinkBotton to your page, not into any Web Part Zone, rename it to btnDesign. and set its text property to "Design View"

  8. Double click on the button to add click event handler, then add the following code in the event handler method:

    protected void btnDesign_Click(object sender, EventArgs e)
    {
    if (btnDesign.Text == "Design View")
    {
    wpManager.DisplayMode = WebPartManager.DesignDisplayMode;
    btnDesign.Text = "Page View";
    }
    else
    {
    wpManager.DisplayMode = WebPartManager.BrowseDisplayMode;
    btnDesign.Text = "Design View";
    }

    }

  9. Now Run your application, note when you click on the button you can now rearrange you web parts on the page.

Conclusion:

Now have explored the basics of creating WebParts Page and adding WebParts to it at design/development time. This demo showed that every Control in ASP.Net 2.0 can be a web part without customization or extra code. Same for Custom User Controls; as you can put any controls we have just worked with into a user control, then drag and drop you user control into the WebPartZone and you will get your user control as WebPart.

WebParts is special kind of WebServer Controls. It has more advanced feature. Hope we will be able to discuss them in subsequent tutorials.

Select/Deselect all Checkboxes at Server side in ASP.NET using C#

| Posted in

0

Introduction:-

Some time we come across with the scenario where we need the function to select\deselect the checkboxes
from the server side code.The following code is going to describe the scenarion where we have one Panal Control which is having the multiple checkboxe

Code sample :-

//Drag and drop a panal control in asp.net web page

//Following will be the auto generated code with user defind controlName

protected System.Web.UI.WebControls.Panel PnlTimeExpence;

//Decleare one checkbox object

CheckBox chkList1;

//write a code to add dyanamic checkboxes

..
..

.. //code to add dyanamic controls(checkboxes). Check link above for adding dynamic checkboxes.

..

..

//Now we have a Panel control ready with multiple checkboxes.

//Fuction to select\Deselect checkboxes

private void SelectAllCheckBoxControls(Control parent,bool checkedVal)

{

try

{

string strLeave=string.Empty;

foreach (Control child in parent.Controls)

{

if (child.GetType().ToString().Equals("System.Web.UI.WebControls.CheckBox"))

{

CheckBox chk = (CheckBox)child;

chk.Checked=checkedVal;

}

}

}

catch(Exception exp)

{

throw new Exception("SelectAllCheckBoxControls " + exp.Message);

}

}

//Generate event on which we want to perform the select\deselect operation

//Following code is using a checkbox control to select \deselect the Event

private void chkReport_CheckedChanged(object sender, System.EventArgs e)

{

try

{

//Calling a userdefind function

SelectAllCheckBoxControls(PnlTimeExpence,chkReport.Checked);

}

catch(Exception exp)

{

throw new Exception("chkReport_CheckedChanged " + exp.Message);

}

}

Generate Dynamic Checkbox in ASP.Net using C#

| Posted in

0

Introduction

As a programmer we need to know about the static as well as dynamic controls. It's not necessary that always we will be using the static controls. Many programmers are having a mind setup like if they want the dynamic controls they have to write many lines of code but it's not like that.

Suppose we want to add dynamic control to a Panal control.So, what is the approach for that?

Following code will explain how to create the dynamic checkboxes.

Source Code:

//Drag and drop panal on the Webpage.

//After drag and drop following code will be generated automatically

protected System.Web.UI.WebControls.Panel PnlControl;

//Declare a CheckBox

CheckBox chkList1;

private void Page_Load(object sender, System.EventArgs e)

{

.

.

//Page load code goes here

.

.

}

#region dyanamic checkboxes

//Function to generate the dyanamic checkboxes

private void AddCheckboxes(string strCheckboxText)

{

try

{

if(PnlTimeExpence.HasControls())

{

return;

}

for(int intControlIndex=0;intControlIndex=5;intControlIndex++)

{

chkList1 =new CheckBox();

chkList1.Text = strCheckboxText;

chkList1.ID="Chk"+intControlIndex;

chkList1.Font.Name = "Verdana";

chkList1.Font.Size = 9;

PnlControl.Controls.Add(chkList1);

PnlControl.Controls.Add(new LiteralControl("
"));

}

}

catch(Exception exp)

{

throw new Exception(exp.Message);

}

}

#endregion

Developing a Visual WebGui gateway

| Posted in

0

Introduction

Visual WebGui basically leverages the WinForms object model giving the developer a new development experience developing rich internet applications like outlook web access. This object model by say covers 90% of what you need in order to create an outlook web access application. So how do we bridge the WinForms object model and web development? Through the concept of Gateways.

Background

Every WebGui component can declare it self as a WebGui gateway using the IGatewayControl interface, this allow controls to declare virtual URLs that are handles by the control by declaring actions. The IGatewayControl contains a method that gets an action name and should return a gateway handler. The gateway handler processes the request in the exact same way as an HTTP handler does, which actually means that you can also use HTTP handlers. This means that you can actually provide embedded ASPX pages that are hosted by the WinForms object model and can interact with that model making the interoperability between WebGui and legacy applications easy.

Other places you can use gateways:

  • Providing HTML based content to IFRAMES.
  • Providing a printable version of the current view.
  • Interacting with applets, flash, activeX and so on.
  • Using ASP.NET ready controls such as Janus grid.
  • Downloading files.

Visual WebGui is completely free to use and deploy for non-commercial purposes and is also available as an open source project in SourceForge.net. The Visual WebGui site has multiple free licenses that you can apply to in order to use it freely in your production site

This article creates a file list that can be previewed by selecting the file.

Using the code

In order to start developing Visual WebGui you need to download the SDK from the Visual WebGui download page. The installation will install a couple of assemblies to you GAC adding the Visual WebGui capabilities to your development enviroment. Installing the Visual WebGui SDK will add a two new projects to your Visual Studio (WebGui Application and WebGui Control Library). The WebGui Application project will create you a ASP.NET new project that one class named Form1.cs instead of the WebForm1.aspx file usualy created by the ASP.NET project template. Inheriting from the Gizmox.WebGUI.Forms.Form class the Form1.cs automaticly causes this file to have a WinForms like design time behavior. When you enter the design surface of the Form1.cs class you will have an aditional WebGUI toolbox available in the toolbox pane. These components can be draged to the design surface and be used exactly as WinForms components are used on a WinForms design surface. In the properties pane of any givven component you can change the component attributes including layout properties such as Dock and Anchoring which are WinForms way of layouting components and are fully supported by Visual WebGui.

Before you can run your application you need to have your form registerd in Visual WebGui web.config configuration section to a virtual page and have Visual Studio start page set to this virtual page. Visual WebGui uses a ".wgx" IIS script map extension that needs to be added to the IIS with the same definitions as the ".aspx" script map extension but without the check file exist check box as Visual WebGui uses virtual pages mapped to Gizmox.WebGUI.Forms.Form inherited classed. After setting these configurations you can start debugging your application exactly as you debug a WinForms application.

Step 1 - Creating a new WebGui Application project

Open the new project dialog and select the WebGui Application project. In the project name textbox enter WebGUIGateway and press OK.Visual WebGui will create you a new WebGui Application project that is both ASP.NET and WinFroms, as the structure is that of ASP.NET and the form classes behave like a WinForm form forms. Double clicking the Visual WebGui form1.cs page will open the design surface that is exactly the same as the WinForm design surface. The Visual Studio tool box has an added pane named WebGUI and you can find there Visual WebGui components which are identical to WinForms components. You can drag and drop components on the design surface exactly as you do in a WinForms application and the Visual WebGui designer will generate the code with in the InitializeComponent method.

Step 2 - Creating the main form

From the WebGUI toolbox pane drag a listview component on to the design surface and in the properties pane make it docked to the top. Drag a splitter and dock it to the top as well. Docking the splitter to the top will cause it to change the list view height. Drag an htmlbox and change it's docking to fill. Add the list view two columns for the file name and the file extension. Now you have the UI part of this tutorial ready.

Step 3 - Populating the list view

Go to the form properties and change to event view. Double click the Load event handler and the designer will create you an empty event handler. Add the code bellow to handler that will populate the listview with file list from a given path. Update the path to a valid path with gif images on your computer. Notice that the code generates list items and in the Tag property sets the full path of the file.

private void Form1_Load(object sender, System.EventArgs e)

{

DirectoryInfo objDir = new DirectoryInfo(@"C:\Inetpub\wwwroot\images");

foreach (FileInfo objFile in objDir.GetFiles("*.gif"))

{

ListViewItem item = listView1.Items.Add(objFile.Name);

item.SubItems.Add(objFile.Extension);

item.Tag = objFile.FullName;

}

}

Step 3 - Creating a gateway handler

A gateway handler is actually a class that inherits from IGatewayHandler, which has one method called ProcessGatewayRequest. The ProcessGatewayRequest method handles the request just as an IHTTPHanlder inherited class. In the ProcessGatewayRequest method you can actually write any thing you want into the response and in this case the handler take the path it got in the constructor and writes that file to the response. Create this class in your project.

using System;

using System.Web;

using Gizmox.WebGUI.Common.Interfaces;

namespace WebGUIGatway

{

public class FileHandler : IGatewayHandler

{

private string _path;

public FileHandler(string path)

{

_path = path;

}

#region IGatewayHandler Members

public void ProcessGatewayRequest(IContext objContext, IRegisteredComponent objComponent)

{

HttpContext.Current.Response.WriteFile(_path);

}

#endregion

}

}

Step 4 - Creating a gateway

In order to use gateways you need to have a control inherit the IGatewayControl interface which is under the namespace Gizmox.WebGUI.Common.Interfaces. A single control can expose multiple gateways. The control gateways are identified by an action code. The action code serves as a page name allowing gateways to be referenced by name. In order to reference to a gateway you need to create a GatewayReference object. GatewayReference can be constructed using a component and an action code that together will provide a unique gateway reference. So let's go ahead and make our form a gateway by implementing the IGatewayControl interface. The IGatewayControl has one method called GetGatewayHandler that has an action argument. Using the action parameter we can return different gateway handlers for different actions. So let's go and use the gateway handler we created before on an action named "OpenFile". Notice that in the path constructor we use the current selected item Tag property to get the path of the selected file.

public IGatewayHandler GetGatewayHandler(IContext objContext, string strAction)

{

IGatewayHandler handler = null;

switch (strAction)

{

case "OpenFile":

if (listView1.SelectedItem != null)

{

handler = new FileHandler((string)listView1.SelectedItem.Tag);

}

break;

}

return handler;

}

Step 5 - Using the gateway

Go back to the designer and select the list view control. From the properties of the list view go to the event section and double click the SelectedIndexChanged event. In the SelectedIndexChanged event handler let's create a GatewayReference object that can be found in the Gizmox.WebGUI.Common.Gateways namespace. Pass the constructor of the GatewayReference a reference to the form control and specify the action code of the gateway. When calling upon the ToString method of the GatewayReference class we get a relative path to the specified gateway. Use the relative path to set the htmlbox to show the current gateway. Calling the Update method on the HtmlBox will cause it to reload the control.

private void listView1_SelectedIndexChanged(object sender, System.EventArgs e)

{

GatewayReference reference = new GatewayReference(this, "OpenFile");

htmlBox1.Url = reference.ToString();

htmlBox1.Update();

}

Display hierarchal data in web form by using ASP.Net repeater

| Posted in

0

This below code shows how to display hierarchal data from multiple tables by using ASP.Net repeater control. This article shows hierarchal data from Categories, Products, Orders and Order Details tables of Northwind database.

Stored Procedure to get multiple recordset from Northwind Database :

The following stored procedure is used to get records from Categories, Products, Orders and Order Details table of Categories Id 4 and 6 only.

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
ALTER PROCEDURE GetOrderDetails
AS

-------- Get Category List -------------------
select
categoryid,
categoryname
from
categories
WHERE CategoryID IN (4,6)
order by
categoryname

-------- Get Product List ------------------------------
select
categoryid,
productid,
productname
from products
WHERE CategoryID IN (4,6)
order by productname

-------- Get Order List ---------------------------------
SELECT
OD.ProductID,
OD.OrderID,
dbo.Orders.OrderDate,
OD.Quantity,
OD.UnitPrice,
OD.Quantity*OD.UnitPrice Revenue
FROM
dbo.[Order Details] OD
INNER JOIN dbo.Orders
ON OD.OrderID = dbo.Orders.OrderID
where OD.ProductId IN (select productid from products WHERE CategoryID IN (4,6))
ORDER BY dbo.Orders.OrderDate
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

NRepeater.aspx.cs

===============

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

using System.Data.SqlClient ;

namespace NestedRepeater

{

///

/// Summary description for NRepeater.

///

public class NRepeater : System.Web.UI.Page

{

protected System.Web.UI.WebControls.Repeater rptCategory;

private DataSet _dsOrderList;

private SqlCommand _cmd;

private SqlDataAdapter _da;

private SqlConnection _con;

private string _strFilter;

private int _productId;

private string _conStr = "server=(local); uid=sa;pwd=;database=northwind";

private void Page_Load(object sender, System.EventArgs e)

{

// Put user code to initialize the page here

if (!Page.IsPostBack )

{

GetDataSet();

}

}

private void GetDataSet()

{

_con = new SqlConnection(_conStr);

_cmd = new SqlCommand();

_cmd.CommandType = CommandType.StoredProcedure ;

_cmd.CommandText = "GetOrderDetails";

_cmd.Connection = _con;

_da = new SqlDataAdapter(_cmd);

_dsOrderList = new DataSet();

_da.Fill(_dsOrderList);

/*

Dataset _dsOrderList is populated with three recordset

Table[0] : Categories

Table[1] : Products

Table[2] : Orders

*/

// Create relationship between CategoryId of Categories table and CategoryId of Products table

_dsOrderList.Relations.Add("categoryProduct",_dsOrderList.Tables[0].Columns["CategoryId"],_dsOrderList.Tables[1].Columns["CategoryId"]);

_dsOrderList.Relations["categoryProduct"].Nested = true;

// Bind main repeater i.e. rptCategory with dataset categories table

rptCategory.DataSource = _dsOrderList.Tables[0].DefaultView ;

rptCategory.DataBind();

_con.close();

}

// GetOrderDetails method get executed on ItemBound event on rptProduct repeater

protected void GetOrderDetails( object source, RepeaterItemEventArgs e)

{

//**** Get ProductId current populated row of rptProduct repeater

_productId = (int) DataBinder.Eval(e.Item.DataItem,"ProductId");

//**** set filter string to get filtered records from order table

_strFilter = "ProductId=" + _productId.ToString();

//**** get default view of filter rows of order table

_dsOrderList.Tables[2].DefaultView.RowFilter= _strFilter;

//**** get reference of nested rptOrder repeater of rptProduct repeater

Repeater rpt = (Repeater) e.Item.FindControl("rptOrder");

if(rpt != null)

{

//*** bind nested rptOrder repeater with default view

rpt.DataSource = _dsOrderList.Tables[2].DefaultView ;

rpt.DataBind();

}

}

#region Web Form Designer generated code

override protected void OnInit(EventArgs e)

{

//

// CODEGEN: This call is required by the ASP.NET Web Form Designer.

//

InitializeComponent();

base.OnInit(e);

}

///

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

///

private void InitializeComponent()

{

}

#endregion

}

}

ScreenShot:

Nested Repeater