You are on page 1of 181

1

Access Modifiers:

C# Access Modifier Meaning


Public Marks a member as accessible from an object variable as well as
any derived classes.
Private (default) Marks a method as accessible only by the class that has defined
the method. In C#, all members are private by default.
Protected Marks a method as usable by the defining class, as well as any
derived classes. Protected methods, however, are not accessible
from an object variable.
Internal Defines a method that is accessible by any type in the same
assembly, but not outside the assembly.
protected internal Defines a method whose access is limited to the current assembly
or types derived from the defining class in the current assembly.
Unmarked members are private by default in C#.

class SomeClass
{
// Accessible anywhere.
public void PublicMethod(){}
// Accessible only from SomeClass types.
private void PrivateMethod(){}
// Accessible from SomeClass and any descendent.
protected void ProtectedMethod(){}
// Accessible from within the same assembly.
internal void InternalMethod(){}
// Assembly-protected access.
protected internal void ProtectedInternalMethod(){}
// Unmarked members are private by default in C#.
void SomeMethod(){}
}

2) What is default modifier of class, function and variables? Prepare list for same.

Class Internal
Methods Private
Variables Private
Constructor Private
Interface Public
Static Method Private

3) Can we create static internal method?

Method can be declared as static internal and can be used with Class name.

4) Can Non Static class contain static functions?

Static Methods can be declared in a non static class.


2
ASP.NET Interview Questions

1. Describe the role of inetinfo.exe, aspnet_isapi.dll and aspnet_wp.exe in the page loading
process. Inetinfo.exe is theMicrosoft IIS server running, handling ASP.NET requests among other
things. When an ASP.NET request is received (usually a file with .aspx extension),the ISAPI filter
aspnet_isapi.dll takes care of it by passing the request to the actual worker process aspnet_wp.exe.

2. What’s the difference between Response.Write() andResponse.Output.Write()? The latter


one allows you to write formatted output.

3. What methods are fired during the page load? Init() - when the pageis instantiated, Load() -
when the page is loaded into server memory,PreRender() - the brief moment before the page is
displayed to the user asHTML, Unload() - when page finishes loading.

4. Where does the Web page belong in the .NET Framework class
hierarchy?System.Web.UI.Page

5. Where do you store the information about the user’s locale? System.Web.UI.Page.Culture

6. What’s the difference between Codebehind="MyCode.aspx.cs" and


Src="MyCode.aspx.cs"? CodeBehind is relevant to Visual Studio.NET only.

7. What’s a bubbled event? When you have a complex control, like DataGrid, writing an event
processing routine for each object (cell, button, row, etc.) is quite tedious. The controls can bubble
up their eventhandlers, allowing the main DataGrid event handler to take care of its constituents.

8. Suppose you want a certain ASP.NET function executed on MouseOver overa certain
button. Where do you add an event handler? It’s the Attributesproperty, the Add function inside
that property. So btnSubmit.Attributes.Add ("onMouseOver","someClientCode();")

9. What data type does the RangeValidator control support? Integer,String and Date.

10. Explain the differences between Server-side and Client-side code? Server-side code runs
on the server. Client-side code runs in the clients’ browser.

11. What type of code (server or client) is found in a Code-Behind class? Server-side code.

12. Should validation (did the user enter a real date) occur server-side or client-side? Why?
Client-side. This reduces an additional request to the server to validate the users input.

13. What does the "EnableViewState" property do? Why would I want it on or off? It enables
the viewstate on the page. It allows the page to save the users input on a form.

14. What is the difference between Server.Transfer and Response.Redirect? Why would I
choose one over the other? Server.Transfer is used to post a form to another page. Response.Redirect
is used to redirect the user to another page or site.
_____________________________________________________________________________
The Response .Redirect () method can be used to redirect the browser to specified url, pointing to
any resource and may contain query strings and causes an extra roundtrip
Server.Transfer() performs server side redirection of the page avoiding extra roundtrip.
Server.Transfer() is preferred over Response.Redirect to avoid rountrip but the limitation is the aspx
page should reside on same web server.
_____________________________________________________________________________
3
15. Can you explain the difference between an ADO.NET Dataset and an ADO Recordset?
· A DataSet can represent an entire relational database in memory, complete with tables,
relations, and views.
· A DataSet is designed to work without any continuing connection to the original data source.
· Data in a DataSet is bulk-loaded, rather than being loaded on demand.
· There's no concept of cursor types in a DataSet.
· DataSets have no current record pointer You can use For Each loops to move through the
data.
· You can store many edits in a DataSet, and write them to the original data source in a single
operation.
· Though the DataSet is universal, other objects in ADO.NET come in different versions for
different data sources.

16. Can you give an example of what might be best suited to place in the Application_Start
and Session_Start subroutines? This is where you can set the specific variables for the Application
and Session objects.

17. If I’m developing an application that must accommodate multiple security levels though
secure login and my ASP.NET web application is spanned across three web-servers (using
round-robin load balancing) what would be the best approach to maintain login-in state for the
users? Maintain the login state security through a database.

18. Can you explain what inheritance is and an example of when you might use it? When you
want to inherit (use the functionality of) another class. Base Class Employee. A Manager class could
be derived from the Employee base class.

19. Whats an assembly? Assemblies are the building blocks of the .NET framework. Overview of
assemblies from MSDN

20. Describe the difference between inline and code behind. Inline code written along side the
html in a page. Code-behind is code written in a separate file and referenced by the .aspx page.

21. Explain what a diffgram is, and a good use for one? The DiffGram is one of the two XML
formats that you can use to render DataSet object contents to XML. For reading database data to an
XML file to be sent to a Web Service.

22. Whats MSIL, and why should my developers need an appreciation of it if at all? MSIL is
the Microsoft Intermediate Language. All .NET compatible languages will get converted to MSIL.

23. Which method do you invoke on the DataAdapter control to load your generated dataset
with data? The .Fill() method

24. Can you edit data in the Repeater control? No, it just reads the information from its data
source

25. Which template must you provide, in order to display data in a Repeater control?
ItemTemplate

26. How can you provide an alternating color scheme in a Repeater control? Use the
AlternatingItemTemplate

27. What property must you set, and what method must you call in your code, in order to
bind the data from some data source to the Repeater control? You must set the DataSource
property and call the DataBind method.

28. What base class do all Web Forms inherit from? The Page class.

29. Name two properties common in every validation control? ControlToValidate property and
Text property.
4
30. What tags do you need to add within the asp:datagrid tags to bind columns manually?
Set AutoGenerateColumns Property to false on the datagrid tag

31. What tag do you use to add a hyperlink column to the DataGrid?

32. What is the transport protocol you use to call a Web service? SOAP is the preferred
protocol.

33. True or False: A Web service can only be written in .NET? False

34. What does WSDL stand for? (Web Services Description Language)

35. Where on the Internet would you look for Web services? (http://www.uddi.org)

36. Which property on a Combo Box do you set with a column name, prior to setting the
DataSource, to display data in the combo box? DataTextField property

37. Which control would you use if you needed to make sure the values in two different
controls matched? CompareValidator Control

38. True or False: To test a Web service you must create a windows application or Web
application to consume this service? False, the webservice comes with a test page and it provides
HTTP-GET method to test.

39. How many classes can a single .NET DLL contain? It can contain many classes.
- Briefly explain how code behind works and contrast that using the inline style.
- What are HTML controls, Web controls, and server controls?
- Briefly explain how the server control validation controls work.
- Briefly explain what user controls are and what server controls are and
the differences between the two.
- Briefly explain how server form post-back works (perhaps ask about view state as well).
- Can the action attribute of a server-side <form> tag be set to a value and if not how can you
possibly pass data from a form page to a subsequent page. (Extra credit: Have you heard of comdna.
:-)
- Briefly describe the role of global.asax.
- How would ASP and ASP.NET apps run at the same time on the same server?
- What are good ADO.NET object(s) to replace the ADO Recordset object.
Seems like some pretty tough questions for an interview (and certainly
questions like the ones above should not be the only type asked at an
interview) but it's a tough job market out there, a lot of people claim to
have a lot of experience with ASP.NET but have really just installed Beta 1 and maybe Beta 2 and
played around for a week, and something like the above should give a quick sense as to whether
someone has hands-on with ASP.NET or not.
- Oh, and ofcourse, what is the correct language to code ASP.NET pages with? (The only correct
answer would be C#. :-) Maybe this should be the first question.

1. Explain the code behind wors and contrast that using the inline style.
2. Different types of HTML,Web and server controls (also how Server control validation
controls work)
4. Difference between user and server controls
4. How server form post-back works (perhaps ask about view state as well).
5. Can the action attribute of a server-side <form> tag be set to a value and if not how can
you possibly pass data from a form page to a subsequent page.
6. What is the role of global.asax.
7. How would ASP and ASP.NET apps run at the same time on the same server?
8. What are good ADO.NET object(s) to replace the ADO Recordset object.
5
Answers:
3. Server controls are built-in. User controls are created by the developer to allow for the
reuse of controls that need specific functionality.

4. By default all pages in .NET post back to themselves. The view state keeps the users input
updated on the page.

5. No, You have to use Server.Transfer to pass the data to another page.

6. Store global information about the application

8. There are alot...but the base once are SqlConnection, OleDbConnection, etc...
In addition to the above some couple of basic questions, a couple of additional questions
listed below. Good luck!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Explain the differences between Server-side and Client-side code?
2. What type of code (server or client) is found in a Code-Behind
class?
3. Should validation (did the user enter a real date) occur
server-side or client-side? Why?
4. What does the "EnableViewState" property do? Why would I want it on or off?
5. What is the difference between Server.Transfer and
Response.Redirect? Why
would I choose one over the other?
6. Can you give an example of when it would be appropriate to use a
web service as opposed to a non-serviced .NET component
7. Let's say I have an existing application written using Visual
Studio 6 (VB 6, InterDev 6) and this application utilizes Windows 2000
COM+ transaction services. How would you approach migrating this
application to .NET
8. Can you explain the difference between an ADO.NET Dataset and an
ADO Recordset?
9. Can you give an example of what might be best suited to place in
the Application_Start and Session_Start subroutines?
10. If I'm developing an application that must accomodate multiple
security levels though secure login and my ASP.NET web appplication is
spanned across three web-servers (using round-robbin load balancing)
what would be the best approach to maintain login-in state for the
users?
11. What are ASP.NET Web Forms? How is this technology different than
what is available though ASP (1.0-3.0)?
12. How does VB.NET/C# achieve polymorphism?
11. Can you explain what inheritance is and an example of when you
might use it?
13. How would you implement inheritance using VB.NET/C#?
14. Whats an assembly
15. Describe the difference between inline and code behind - which is
best in a
16. loosely coupled solution
17. Explain what a diffgram is, and a good use for one
18. Where would you use an iHTTPModule, and what are the limitations
of any
19. approach you might take in implementing one
20. What are the disadvantages of viewstate/what are the benefits
21 Describe session handling in a webfarm, how does it work and what
are the > limits
22. How would you get ASP.NET running in Apache web servers - why
would you even do this?
23. Whats MSIL, and why should my developers need an appreciation of
it if at all?
6
24. In what order do the events of an ASPX page execute. As a
developer is it important to undertsand these events?
25. Which method do you invoke on the DataAdapter control to load your
generated dataset with data?
26. Can you edit data in the Repeater control?
27. Which template must you provide, in order to display data in a
Repeater control?
28. How can you provide an alternating color scheme in a Repeater
control?
29. What property must you set, and what method must you call in your
code, in order to bind the data from some data source to the Repeater
control?
30. What base class do all Web Forms inherit from?
31. What method do you use to explicitly kill a user s session?
32 How do you turn off cookies for one page in your site?
33. Which two properties are on every validation control?
34. What tags do you need to add within the asp:datagrid tags to bind
columns manually?
35. How do you create a permanent cookie?
36. What tag do you use to add a hyperlink column to the DataGrid?
37. What is the standard you use to wrap up a call to a Web service
38. Which method do you use to redirect the user to another page
without performing a round trip to the client?
39. What is the transport protocol you use to call a Web service SOAP
40. True or False: A Web service can only be written in .NET
41. What does WSDL stand for?
42. What property do you have to set to tell the grid which page to go
to when using the Pager object?
43. Where on the Internet would you look for Web services?
44. What tags do you need to add within the asp:datagrid tags to bind
columns manually.
45. Which property on a Combo Box do you set with a column name, prior to setting the
DataSource, to display data in the combo box?
46. How is a property designated as read-only?
47. Which control would you use if you needed to make sure the values
in two different controls matched?
48. True or False: To test a Web service you must create a windows
application or Web application to consume this service?
49. How many classes can a single .NET DLL contain?
~~~~~~~~~~~~~~~~~~~~
ANSWERS:
1. Server-side code runs on the server, Client-side code runs on the client.
2. Server
3. Client...so the user doesn't have to wait for the page to be posted to the server and then
returned.
4. Enables the ability to maintain the state of the page and all data within it.
5. Server.Trasfer allows you to pass variables to another page. Server.Redirect just redirects
the user to another page.
6. When there is no need for a UI to perform the required task.
8. By default Datasets are disconnected.
9. Any variables that need to be set for the application or session objects. Example: For the
path of a image directory
Application("ImagePath") = "C:\Images\"
13. VB.NET use the Implements keyword to inherit from another class or interface. C# use :
to inherit
example
Code:
VB.NET
class myClass
Inherits baseClass
7
End class

C#
class myClass : baseClass

14. An assembly is the collection of all information required by the runtime to execute your
application.
15. Inline is mixed with the html, code-behind is separated. Use code-behind.
17. An XML format. Can be used by other platforms so send and receive data to a .NET
application
23. Microsoft Intermediate Language
24. You mean the steps of the page lifetime? or that .NET is event driven?
25. Fill method
26. Yes
27. ItemTemplate
28. AlternatingItemTemplate
29. Set the datasource property and call the DataBind method
30. Page...but all .NET objects inherit form the Object Base Class.
31. Session.Contents.Remove
32. You can't (not that I am aware of...since there is no Page level directive to do this)
34. Set AutoGenerateColumns Property to false on the datagrid tag
36. <asp:HyperLinkColumn>
39. SOAP is preferred protocol
40. False
41. Web Services Description Language
42. CurrentPageIndex
43. www.uddi.org
45. DataTextField
46. Only a Get method...no, Set method
47. CompareValidator
48. False, the webservice comes with a test page and it provides HTTP-GET method to test.
49. Many

TOUGH ONE ::::

 From constructor to destructor (taking into consideration Dispose() and the concept of non-
deterministic finalization), what the are events fired as part of the ASP.NET System.Web.UI.Page
lifecycle. Why are they important? What interesting things can you do at each?
 What are ASHX files? What are HttpHandlers? Where can they be configured?
 What is needed to configure a new extension for use in ASP.NET? For example, what if I wanted
my system to serve ASPX files with a *.jsp extension?
 What events fire when binding data to a data grid? What are they good for?
 Explain how PostBacks work, on both the client-side and server-side. How do I chain my own
JavaScript into the client side without losing PostBack functionality?
 How does ViewState work and why is it either useful or evil?
 What is the OO relationship between an ASPX page and its CS/VB code behind file in ASP.NET
1.1? in 2.0?
 What happens from the point an HTTP request is received on a TCP/IP port up until the Page
fires the On_Load event?
 How does IIS communicate at runtime with ASP.NET? Where is ASP.NET at runtime in IIS5?
IIS6?
 What is an assembly binding redirect? Where are the places an administrator or developer can
affect how assembly binding policy is applied?
 Compare and contrast LoadLibrary(), CoCreateInstance(), CreateObject() and Assembly.Load().
8
Interview Questions
ASP.NET

1. Describe the role of inetinfo.exe, aspnet_isapi.dll andaspnet_wp.exe in the page


loading process. inetinfo.exe is theMicrosoft IIS server running, handling ASP.NET
requests among other things.When an ASP.NET request is received (usually a file with
.aspx extension),the ISAPI filter aspnet_isapi.dll takes care of it by passing the request
tothe actual worker process aspnet_wp.exe.
2. What’s the difference between Response.Write() andResponse.Output.Write()? The
latter one allows you to write formattedoutput. 0
3. What methods are fired during the page load? Init() - when the pageis instantiated,
Load() - when the page is loaded into server memory,PreRender() - the brief moment before
the page is displayed to the user asHTML, Unload() - when page finishes loading.
4. Where does the Web page belong in the .NET Framework class
hierarchy?System.Web.UI.Page
5. Where do you store the information about the user’s locale?
System.Web.UI.Page.Culture
6. What’s the difference between Codebehind="MyCode.aspx.cs"
andSrc="MyCode.aspx.cs"? CodeBehind is relevant to Visual Studio.NET only.
7. What’s a bubbled event? When you have a complex control, like DataGrid, writing an
event processing routine for each object (cell, button, row, etc.) is quite tedious. The
controls can bubble up their eventhandlers, allowing the main DataGrid event handler to
take care of its constituents.
8. Suppose you want a certain ASP.NET function executed on MouseOver overa certain
button. Where do you add an event handler? It’s the Attributesproperty, the Add
function inside that property. So
btnSubmit.Attributes.Add("onMouseOver","someClientCode();")
9. What data type does the RangeValidator control support? Integer,String and Date.
10. Explain the differences between Server-side and Client-side code? Server-side code
runs on the server. Client-side code runs in the clients’ browser.
11. What type of code (server or client) is found in a Code-Behind class? Server-side code.
12. Should validation (did the user enter a real date) occur server-side or client-side?
Why? Client-side. This reduces an additional request to the server to validate the users
input.
13. What does the "EnableViewState" property do? Why would I want it on or off? It
enables the viewstate on the page. It allows the page to save the users input on a form.
14. What is the difference between Server.Transfer and Response.Redirect? Why would I
choose one over the other? Server.Transfer is used to post a form to another page.
Response.Redirect is used to redirect the user to another page or site. 3
15. Can you explain the difference between an ADO.NET Dataset and an ADO Recordset?

 A DataSet can represent an entire relational database in memory, complete with


tables, relations, and views.
 A DataSet is designed to work without any continuing connection to the original
data source.
 Data in a DataSet is bulk-loaded, rather than being loaded on demand.
 There's no concept of cursor types in a DataSet.
 DataSets have no current record pointer You can use For Each loops to move
through the data.
 You can store many edits in a DataSet, and write them to the original data source
in a single operation.
 Though the DataSet is universal, other objects in ADO.NET come in different
versions for different data sources.

16. Can you give an example of what might be best suited to place in the
Application_Start and Session_Start subroutines? This is where you can set the specific
variables for the Application and Session objects.
17. If I’m developing an application that must accommodate multiple security levels
though secure login and my ASP.NET web application is spanned across three web-
9
servers (using round-robin load balancing) what would be the best approach to
maintain login-in state for the users? Maintain the login state security through a
database.
18. Can you explain what inheritance is and an example of when you might use it? When
you want to inherit (use the functionality of) another class. Base Class Employee. A
Manager class could be derived from the Employee base class.
19. Whats an assembly? Assemblies are the building blocks of the .NET framework. Overview
of assemblies from MSDN
20. Describe the difference between inline and code behind. Inline code written along side
the html in a page. Code-behind is code written in a separate file and referenced by the
.aspx page.
21. Explain what a diffgram is, and a good use for one? The DiffGram is one of the two XML
formats that you can use to render DataSet object contents to XML. For reading database
data to an XML file to be sent to a Web Service.
22. Whats MSIL, and why should my developers need an appreciation of it if at all? MSIL
is the Microsoft Intermediate Language. All .NET compatible languages will get converted to
MSIL.
23. Which method do you invoke on the DataAdapter control to load your generated
dataset with data? The .Fill() method
24. Can you edit data in the Repeater control? No, it just reads the information from its
data source
25. Which template must you provide, in order to display data in a Repeater control?
ItemTemplate
26. How can you provide an alternating color scheme in a Repeater control? Use the
AlternatingItemTemplate
27. What property must you set, and what method must you call in your code, in order to
bind the data from some data source to the Repeater control? You must set the
DataSource property and call the DataBind method.
28. What base class do all Web Forms inherit from? The Page class.
29. Name two properties common in every validation control? ControlToValidate property
and Text property.
30. What tags do you need to add within the asp:datagrid tags to bind columns manually?
Set AutoGenerateColumns Property to false on the datagrid tag
31. What tag do you use to add a hyperlink column to the DataGrid?
<asp:HyperLinkColumn>
32. What is the transport protocol you use to call a Web service? SOAP is the preferred
protocol.
33. True or False: A Web service can only be written in .NET? False
34. What does WSDL stand for? (Web Services Description Language)
35. Where on the Internet would you look for Web services? (http://www.uddi.org)
36. Which property on a Combo Box do you set with a column name, prior to setting the
DataSource, to display data in the combo box? DataTextField property
37. Which control would you use if you needed to make sure the values in two different
controls matched? CompareValidator Control
38. True or False: To test a Web service you must create a windows application or Web
application to consume this service? False, the webservice comes with a test page and it
provides HTTP-GET method to test.
39. How many classes can a single .NET DLL contain? It can contain many classes.
10
ASPLife cycle

The following are the main ten steps in the ASP.NET page life cycle.

1. Object Initialization
A page's controls (and the page itself) are first initialized in their raw form. By declaring your objects
within the constructor of your C# code-behind file, the page knows what types of objects and how
many to create. Once you have declared your objects within your constructor, you may then access
them from any sub class, method, event, or property. However, if any of your objects are controls
specified within your ASPX file, at this point the controls have no attributes or properties. It is
dangerous to access them through code, as there is no guarantee of what order the control instances
will be created (if they are created at all). The initialization event can be overridden using the OnInit
method.

Figure 1 - Controls are initialized based on their declaration.

2. Load Viewstate Data


After the Init event, controls can be referenced using their IDs only (no DOM is established yet for
relative references). At LoadViewState event, the initialized controls receive their first properties:
viewstate information that was persisted back to the server on the last submission. The page
viewstate is managed by ASP.NET and is used to persist information over a page roundtrip to the
server. Viewstate information is saved as a string of name/value pairs and contains information
such as control text or value. The viewstate is held in the value property of a hidden <input> control
that is passed from page request to page request. As you can see, this is a giant leap forward from
the old ASP 3.0 techniques of maintaining state. This event can be overridden using the
LoadViewState method and is commonly used to customize the data received by the control at the
time it is populated.

Figure 2 - When LoadViewState is fired, controls are populated with the appropriate viewstate
data.
11

3. LoadPostData Processes Postback Data


During this phase of the page creation, form data that was posted to the server (termed postback
data in ASP.NET) is processed against each control that requires it. When a page submits a form, the
framework will implement the IPostBackDataHandler interface on each control that submitted data.
The page then fires the LoadPostData event and parses through the page to find each control that
implements this interface and updates the control state with the correct postback data. ASP.NET
updates the correct control by matching the control's unique ID with the name/value pair in the
NameValueCollection. This is one reason that ASP.NET requires unique IDs for each control on any
given page. Extra steps are taken by the framework to ensure each ID is unique in situations, such
as several custom user controls existing on a single page. After the LoadPostData event triggers, the
RaisePostDataChanged event is free to execute (see below).
4. Object Load
Objects take true form during the Load event. All object are first arranged in the page DOM (called
the Control Tree in ASP.NET) and can be referenced easily through code or relative position (crawling
the DOM). Objects are then free to retrieve the client-side properties set in the HTML, such as width,
value, or visibility. During Load, coded logic, such as arithmetic, setting control properties
programmatically, and using the StringBuilder to assemble a string for output, is also executed. This
stage is where the majority of work happens. The Load event can be overridden by calling OnLoad.

Figure 3 - The OnLoad event is an ideal location to place logic.

5. Raise PostBack Change Events


As stated earlier, this occurs after all controls that implement the IPostBackDataHandler interface
have been updated with the correct postback data. During this operation, each control is flagged
with a Boolean on whether its data was actually changed or remains the same since the previous
submit. ASP.NET then sweeps through the page looking for flags indicating that any object's data
has been updated and fires RaisePostDataChanged. The RaisePostDataChanged event does not fire
until all controls are updated and after the Load event has occurred. This ensures data in another
control is not manually altered during the RaisePostDataChanged event before it is updated with
postback data.

6. Process Client-Side PostBack Event


After the server-side events fire on data that was changed due to postback updates, the object which
caused the postback is handled at the RaisePostBackEvent event. The offending object is usually a
control that posted the page back to the server due to a state change (with autopostback enabled) or
a form submit button that was clicked. There is often code that will execute in this event, as this is
an ideal location to handle event-driven logic. The RaisePostBackEvent event fires last in the series
of postback events due to the accuracy of the data that is rendered to the browser. Controls that are
12
changed during postback should not be updated after the executing function is called due to the
consistency factor. That is, data that is changed by an anticipated event should always be reflected
in the resulting page. The RaisePostBackEvent can be trapped by catching RaisePostBackEvent.

Figure 4 - The RaisePostDataChanged and RaisePostBackEvent events are defined by the


IPostBackDataHandler interface.

7. Prerender the Objects


The point at which the objects are prerendered is the last time changes to the objects can be saved
or persisted to viewstate. This makes the PreRender step a good place to make final modifications,
such as changing properties of controls or changing Control Tree structure, without having to worry
about ASP.NET making changes to objects based off of database calls or viewstate updates. After the
PreRender phase those changes to objects are locked in and can no longer be saved to the page
viewstate. The PreRender step can be overridden using OnPreRender.

8. ViewState Saved
The viewstate is saved after all changes to the page objects have occurred. Object state data is
persisted in the hidden <input> object and this is also where object state data is prepared to be
rendered to HTML. At the SaveViewState event, values can be saved to the ViewState object, but
changes to page controls are not. You can override this step by using SaveViewState.

Figure 5 - Values are set for controls in OnPreRender. During the SaveViewState event, values
are set for the ViewState object.

9. Render To HTML
The Render event commences the building of the page by assembling the HTML for output to the
browser. During the Render event, the page calls on the objects to render them into HTML. The page
13
then collects the HTML for delivery. When the Render event is overridden, the developer can write
custom HTML to the browser that nullifies all the HTML the page has created thus far. The Render
method takes an HtmlTextWriter object as a parameter and uses that to output HTML to be
streamed to the browser. Changes can still be made at this point, but they are reflected to the client
only.

10. Disposal
After the page's HTML is rendered, the objects are disposed of. During the Dispose event, you should
destroy any objects or references you have created in building the page. At this point, all processing
has occurred and it is safe to dispose of any remaining objects, including the Page object. You can
override Dispose, as well as Render by setting the appropriate selection in the object parameter

Figure 6 - The Render event will output custom HTML to the browser through the
HtmlTextWriter object.

The following are the some of the guidelines to create a good ASP.NET application.
 Disable session when not using it. This can be done at the application level in the
"machine.config" file or at a page level.
 The in-proc model of session management is the fastest of the three options. SQL Server option
has the highest performance hit.
 Minimize the amount and complexity of data stored in a session state. The larger and more
complex the data is, the cost of serializing/deserializing of the data is higher (for SQL Server
and State server options).
 Use Server.Transfer for redirecting between pages in the same application. This will avoid
unnecessary client-side redirection.
 Choose the best suited session-state provider - In-process is the fastest option.
 Avoid unnecessary round-trips to the server - Code like validating user input can be handled at
the client side itself.
 Use Page.IsPostback to avoid unnecessary processing on a round trip.
 Use server controls in appropriate circumstances. Even though are they are very easy to
implement, they are expensive because they are server resources. Sometimes, it is easier to
use simple rendering or data-binding.
 Save server control view state only when necessary.
 Buffering is on by default. Turning it off will slow down the performance. Don't code for string
buffering - Response.Write will automatically buffer any responses without the need for the
user to do it. Use multiple Response.Writes rather than create strings via concatenation,
especially if concatenating long strings.
 Don't rely on exceptions in the code. Exceptions reduce performance. Do not catch the
exception itself before handling the condition.

// Consider changing this...


try { result = 100 / num;}
catch (Exception e) { result = 0;}
14
// to this...
if (num != 0)
result = 100 / num;
else
result = 0;
 Use early binding in VB.NET and Jscript code. Enable Option Strict in the page directive to
ensure that the type-safe programming is maintained.
 Port call-intensive COM components to managed code. While doing Interop try avoiding lot of
calls. The cost of marshalling the data ranges from relatively cheap (i.e. int, bool) to more
expensive (i.e. strings). Strings, a common type of data exchanged for web applications, can be
expensive because all strings in the CLR are in Unicode, but COM or native methods may
require other types of encoding (i.e. ASCII).
 Release the COM objects or native resources as soon as the usage is over. This will allow other
requests to utilize them, as well as reducing performance issues, such as having the GC release
them at a later point.
 Use SQL server stored procedures for data access.
 Use the SQLDataReader class for a fast forward-only data cursor.
 Datagrid is a quick way of displaying data, but it slows down the application. The other
alternative, which is faster, is rendering the data for simple cases. But this is difficult to
maintain. A middle of the road solution could be a repeater control, which is light, efficient,
customizable and programmable.
 Cache data and page output whenever possible.
 Disable debug mode before deploying the application.
 For applications that rely extensively one external resource, consider enabling web gardening
on multiprocessor computers. The ASP.NET process model helps enable scalability by
distributing work to several processes, one on each CPU. If the application is using a slow
database server or calls COM objects that access external resources, web gardening could be a
solution.
 Enumerating into collections sometimes is more expensive than index access in a loop. This is
because the CLR can sometimes optimize array indexes and bounds checks away in loops, but
can't detect them in for each type of code.
 JScript .NET allows methods within methods - to implement these in the CLR required a more
expensive mechanism which can be much slower, so avoid them by moving inner methods to be
just regular methods of the page.
 Do a "pre-batch" compilation. To achieve this, request a page from the site.
 Avoid making changes to pages or assemblies that are there in the bin directory of the
application. A changed page will only recompile the page. Any change to the bin directory will
result in recompile of the entire application.
 The config file is configured to enable the widest set of features. For a performance boost it is
better to tune it to the requirements. Some key points here are:
 Encoding - Request/Response - The default is UTF-8 encoding. If the site is completely ASCII,
change the option to ASCII encoder.
 Session State - By default is ON. If session state is not maintained then the value should be
changed to OFF.
 ViewState - Default is ON. Turn it off if not being used. If ViewState is being used there are
different levels of security that need to be considered which can impact the performance of the
application.
 AutoEventWireup - Turning off AutoEventWireup means that the page will not try and match
up method names to events and hook them up (i.e. Page_Load, etc). Instead, if the application
writer wishes to receive them, they need to override the methods in the base class (i.e. override
OnLoad for the page load event instead of using a Page_Load method). By doing so, the page
will get a slight performance boost by not having to do the extra work itself, but leaving it to the
page author.
 For efficient debugging Use ASP.NET trace feature instead of Response.Write.
15

Phase What a control needs to do Method or event to override


Initialize Initialize settings needed during the Init event (OnInit method)
lifetime of the incoming Web request.
See Handling Inherited Events.
Load view state At the end of this phase, the LoadViewState method
ViewState property of a control is
automatically populated as described
in Maintaining State in a Control. A
control can override the default
implementation of the LoadViewState
method to customize state
restoration.
Process postback data Process incoming form data and LoadPostData method
update properties accordingly. See
Processing Postback Data. (if IPostBackDataHandler is
implemented)
Note Only controls
that process postback
data participate in this
phase.
Load Perform actions common to all Load event
requests, such as setting up a
database query. At this point, server (OnLoad method)
controls in the tree are created and
initialized, the state is restored, and
form controls reflect client-side data.
See Handling Inherited Events.
Send postback change Raise change events in response to RaisePostDataChangedEvent
notifications state changes between the current method
and previous postbacks. See
Processing Postback Data. (if IPostBackDataHandler is
implemented)
Note Only controls
that raise postback
change events
participate in this
phase.
Handle postback events Handle the client-side event that RaisePostBackEvent method
caused the postback and raise
appropriate events on the server. See (if IPostBackEventHandler is
Capturing Postback Events. implemented)

Note Only controls


that process postback
events participate in
this phase.
Prerender Perform any updates before the PreRender event
output is rendered. Any changes
made to the state of the control in the (OnPreRender method)
prerender phase can be saved, while
changes made in the rendering phase
are lost. See Handling Inherited
Events.
Save state The ViewState property of a control is SaveViewState method
automatically persisted to a string
object after this stage. This string
object is sent to the client and back
16
as a hidden variable. For improving
efficiency, a control can override the
SaveViewState method to modify the
ViewState property. See Maintaining
State in a Control.
Render Generate output to be rendered to the Render method
client. See Rendering an ASP.NET
Server Control.
Dispose Perform any final cleanup before the Dispose method
control is torn down. References to
expensive resources such as database
connections must be released in this
phase. See Methods in ASP.NET
Server Controls.
Unload Perform any final cleanup before the UnLoad event (On UnLoad
control is torn down. Control authors method)
generally perform cleanup in Dispose
and do not handle this event.

Note To override an EventName event, override the OnEventName method (and call
base. OnEventName).

The methods and events in the third column are inherited from System.Web.UI.Control, with the
following exceptions: LoadPostData and RaisePostDataChangedEvent are methods of the
IPostBackDataHandler interface, and RaisePostBackEvent belongs to the
IPostBackEventHandler interface. If your control participates in postback data processing you
must implement IPostBackDataHandler. If your control receives postback events you must
implement IPostBackEventHandler.
The CreateChildControls method is not listed in the table because it is called whenever the
ASP.NET page framework needs to create the controls tree and this method call is not limited to a
specific phase in a control's lifecycle. For example, CreateChildControls can be invoked when
loading a page, during data binding, or during rendering.

C__ [1] [1].NET

1. How big is the datatype int in .NET? 32 bits.


2. How big is the char? 16 bits (Unicode).
3. How do you initiate a string without escaping each backslash? Put an @ sign in front of the
double-quoted string.
4. What are valid signatures for the Main function?
 public static void Main()
 public static int Main()
 public static void Main( string[] args )
 public static int Main(string[] args )
5. Does Main() always have to be public? No.
6. How do you initialize a two-dimensional array that you don’t know the dimensions of?
 int [, ] myArray; //declaration
 myArray= new int [5, 8]; //actual initialization
7. What’s the access level of the visibility type internal? Current assembly.
8. What’s the difference between struct and class in C#? 2
 Structs cannot be inherited.
 Structs are passed by value, not by reference.
 Struct is stored on the stack, not the heap.
17
9. Explain encapsulation. The implementation is hidden, the interface is exposed.
10. What data type should you use if you want an 8-bit value that’s signed? sbyte.
11. Speaking of Boolean data types, what’s different between C# and C/C++? There’s no
conversion between 0 and false, as well as any other number and true, like in C/C++.
12. Where are the value-type variables allocated in the computer RAM? Stack.
13. Where do the reference-type variables go in the RAM? The references go on the stack, while
the objects themselves go on the heap. However, in reality things are more elaborate.
14. What is the difference between the value-type variables and reference-type variables in
terms of garbage collection? The value-type variables are not garbage-collected, they just fall
off the stack when they fall out of scope, the reference-type objects are picked up by GC when
their references go null.
15. How do you convert a string into an integer in .NET? Int32.Parse(string), Convert.ToInt32()
(3)
16. How do you box a primitive data type variable? Initialize an object with its value, pass an
object, cast it to an object
17. Why do you need to box a primitive variable? To pass it by reference or apply a method that
an object supports, but primitive doesn’t.
18. What’s the difference between Java and .NET garbage collectors? Sun left the
implementation of a specific garbage collector up to the JRE developer, so their performance
varies widely, depending on whose JRE you’re using. Microsoft standardized on their garbage
collection. 0
19. How do you enforce garbage collection in .NET? System.GC.Collect(); 3
20. Can you declare a C++ type destructor in C# like ~MyClass()? Yes, but what’s the point, since
it will call Finalize(), and Finalize() has no guarantees when the memory will be cleaned up, plus,
it introduces additional load on the garbage collector. The only time the finalizer should be
implemented, is when you’re dealing with unmanaged code. (5)
21. What’s different about namespace declaration when comparing that to package declaration
in Java? No semicolon. Package declarations also have to be the first thing within the file, can’t
be nested, and affect all classes within the file.
22. What’s the difference between const and readonly? You can initialize readonly variables to
some runtime values. Let’s say your program uses current date and time as one of the values
that won’t change. This way you declare

public readonly string DateT = new DateTime().ToString().

23. Can you create enumerated data types in C#? Yes. 5


24. What’s different about switch statements in C# as compared to C++? No fall-throughs
allowed.
25. What happens when you encounter a continue statement inside the for loop? The code for
the rest of the loop is ignored, the control is transferred back to the beginning of the loop.
26. Is goto statement supported in C#? How about Java? Gotos are supported in C#to the fullest.
In Java goto is a reserved keyword that provides absolutely no functionality. 5
27. Describe the compilation process for .NET code? Source code is compiled and run in the .NET
Framework using a two-stage process. First, source code is compiled to Microsoft intermediate
language (MSIL) code using a .NET Framework-compatible compiler, such as that for Visual
Basic .NET or Visual C#. Second, MSIL code is compiled to native code. ---(4)
28. Name any 2 of the 4 .NET authentification methods. ASP.NET, in conjunction with Microsoft
Internet Information Services (IIS), can authenticate user credentials such as names and
passwords using any of the following authentication methods:
 Windows: Basic, digest, or Integrated Windows Authentication (NTLM or Kerberos).
 Microsoft Passport authentication
 Forms authentication
 Client Certificate authentication ---
29. How do you turn off SessionState in the web.config file? In the system.web section of
web.config, you should locate the httpmodule tag and you simply disable session by doing a
remove tag with attribute name set to session.
18
<httpModules>
<remove name="Session” /> mode =off
</httpModules> 0

30. What is main difference between Global.asax and Web.Config? ASP.NET uses the global.asax
to establish any global objects that your Web application uses. The .asax extension denotes an
application file rather than .aspx for a page file. Each ASP.NET application can contain at most
one global.asax file. The file is compiled on the first page hit to your Web application. ASP.NET is
also configured so that any attempts to browse to the global.asax page directly are rejected.
However, you can specify application-wide settings in the web.config file. The web.config is an
XML-formatted text file that resides in the Web site’s root directory. Through Web.config you can
specify settings like custom 404 error pages, authentication and authorization settings for the
Web site, compilation options for the ASP.NET Web pages, if tracing should be enabled, etc. 3

1. What do you know about .NET assemblies? Assemblies are the smallest units of versioning
and deployment in the .NET application. Assemblies are also the building blocks for
programs such as Web services, Windows services, serviced components, and .NET remoting
applications. (more…)

What’s the advantage of using System.Text.StringBuilder over System.String? StringBuilder is


more efficient in the cases, where a lot of manipulation is done to the text. Strings are immutable, so
each time it’s being operated on, a new instance is created.

What is SOAP and how does it relate to XML? 4

The Simple Object Access Protocol (SOAP) uses XML to define a protocol for the exchange of
information in distributed computing environments. SOAP consists of three components: an
envelope, a set of encoding rules, and a convention for representing remote procedure calls. Unless
experience with SOAP is a direct requirement for the open position, knowing the specifics of the
protocol, or how it can be used in conjunction with HTTP, is not as important as identifying it as a
natural application of XML.

Using XSLT, how would you extract a specific attribute from an element in an XML
document?

Successful candidates should recognize this as one of the most basic applications of XSLT. If they
are not able to construct a reply similar to the example below, they should at least be able to identify
the components necessary for this operation: xsl:template to match the appropriate XML element,
xsl:value-of to select the attribute value, and the optional xsl:apply-templates to continue processing
the document. (2)

What are the core protocols/standards behind XML Web services?

XML (for message format), HTTP and others (for transport), WSDL (Web Service Definition Language,
to describe the Web services and define the contract), and UDDI (Universal Description, Discovery
and Integration, to dynamically discover and invoke Web services). (3)
19
Interview Questions C#

1. What’s the implicit name of the parameter that gets passed into the class’ set method?
Value, and its datatype depends on whatever variable we’re changing.
2. How do you inherit from a class in C#? Place a colon and then the name of the base class.
Notice that it’s double colon in C++.
3. Does C# support multiple inheritance? No, use interfaces instead. 0
4. When you inherit a protected class-level variable, who is it available to? Classes in the
same namespace.
5. Are private class-level variables inherited? Yes, but they are not accessible, so looking at it
you can honestly say that they are not inherited. But they are.
6. Describe the accessibility modifier protected internal. It’s available to derived classes and
classes within the same Assembly (and naturally from the base class it’s declared in).
7. C# provides a default constructor for me. I write a constructor that takes a string as a
parameter, but want to keep the no parameter one. How many constructors should I
write? Two. Once you write at least one constructor, C# cancels the freebie constructor, and
now you have to write one yourself, even if there’s no implementation in it.
8. What’s the top .NET class that everything is derived from? System.Object. 0
9. How’s method overriding different from overloading? When overriding, you change the
method behavior for a derived class. Overloading simply involves having a method with the
same name within the class.
10. What does the keyword virtual mean in the method definition? The method can be over-
ridden.
11. Can you declare the override method static while the original method is non-static?
No, you can’t, the signature of the virtual method must remain the same, only the keyword
virtual is changed to keyword override.
12. Can you override private virtual methods? No, moreover, you cannot access private
methods in inherited classes, have to be protected in the base class to allow any sort of
access.
13. Can you prevent your class from being inherited and becoming a base class for some
other classes? Yes, that’s what keyword sealed in the class definition is for. The developer
trying to derive from your class will get a message: cannot inherit from Sealed class
WhateverBaseClassName. It’s the same concept as final class in Java.
14. Can you allow class to be inherited, but prevent the method from being over-ridden?
Yes, just leave the class public and make the method sealed.
15. What’s an abstract class? A class that cannot be instantiated. A concept in C++ known as
pure virtual method. A class that must be inherited and have the methods over-ridden.
Essentially, it’s a blueprint for a class without any implementation.
16. When do you absolutely have to declare a class as abstract (as opposed to free-willed
educated choice or decision based on UML diagram)? When at least one of the methods in
the class is abstract. When the class itself is inherited from an abstract class, but not all
base abstract methods have been over-ridden.
17. What’s an interface class? It’s an abstract class with public abstract methods all of which
must be implemented in the inherited classes.
18. Why can’t you specify the accessibility modifier for methods inside the interface? They
all must be public. Therefore, to prevent you from getting the false impression that you have
any freedom of choice, you are not allowed to specify any accessibility, it’s public by default.
19. Can you inherit multiple interfaces? Yes, why not.
20. And if they have conflicting method names? It’s up to you to implement the method
inside your own class, so implementation is left entirely up to you. This might cause a
problem on a higher-level scale if similarly named methods from different interfaces expect
different data, but as far as compiler cares you’re okay.
21. What’s the difference between an interface and abstract class? In the interface all
methods must be abstract; in the abstract class some methods can be concrete. In the
interface no accessibility modifiers are allowed, which is ok in abstract classes.
22. How can you overload a method? Different parameter data types, different number of
parameters, different order of parameters.
20
23. If a base class has a bunch of overloaded constructors, and an inherited class has
another bunch of overloaded constructors, can you enforce a call from an inherited
constructor to an arbitrary base constructor? Yes, just place a colon, and then keyword
base (parameter list to invoke the appropriate constructor) in the overloaded constructor
definition inside the inherited class.
24. What’s the difference between System.String and System.StringBuilder classes?
System.String is immutable; System.StringBuilder was designed with the purpose of having a
mutable string where a variety of operations can be performed.
25. What’s the advantage of using System.Text.StringBuilder over System.String?
StringBuilder is more efficient in the cases, where a lot of manipulation is done to the text.
Strings are immutable, so each time it’s being operated on, a new instance is created.
26. Can you store multiple data types in System.Array? No.
27. What’s the difference between the System.Array.CopyTo() and System.Array.Clone()?
The first one performs a deep copy of the array, the second one is shallow. Clone() just
implements the ICloneable interface. It creates new instance of array holding the same
elements, but returns object you have to cast.

ArrayCopy() is static helper method. It copies elements from one array to another. The
destination array has to be already created with right dimension. You can use this method
instead for loop.

28. How can you sort the elements of the array in descending order? By calling Sort() and
then Reverse() methods.
29. What’s the .NET datatype that allows the retrieval of data by a unique key? HashTable.
30. What’s class SortedList underneath? A sorted HashTable.
31. Will finally block get executed if the exception had not occurred? Yes.
32. What’s the C# equivalent of C++ catch (…), which was a catch-all statement for any
possible exception? A catch block that catches the exception of type System.Exception. You
can also omit the parameter data type in this case and just write catch {}.
33. Can multiple catch blocks be executed? No, once the proper catch code fires off, the
control is transferred to the finally block (if there are any), and then whatever follows the
finally block.
34. Why is it a bad idea to throw your own exceptions? Well, if at that point you know that an
error has occurred, then why not write the proper code to handle that error instead of
passing a new Exception object to the catch block? Throwing your own exceptions signifies
some design flaws in the project.
35. What’s a delegate? A delegate object encapsulates a reference to a method. In C++ they were
referred to as function pointers.
36. What’s a multicast delegate? It’s a delegate that points to and eventually fires off several
methods.
37. How’s the DLL Hell problem solved in .NET? Assembly versioning allows the application to
specify not only the library it needs to run (which was available under Win32), but also the
version of the assembly.
38. What are the ways to deploy an assembly? An MSI installer, a CAB archive, and XCOPY
command.
39. What’s a satellite assembly? When you write a multilingual or multi-cultural application in
.NET, and want to distribute the core application separately from the localized modules, the
localized assemblies that modify the core application are called satellite assemblies.
40. What namespaces are necessary to create a localized application? System.Globalization,
System.Resources.
41. What’s the difference between // comments, /* */ comments and /// comments?
Single-line, multi-line and XML documentation comments.
42. How do you generate documentation from the C# file commented properly with a
command-line compiler? Compile it with a /doc switch.
43. What’s the difference between <c> and <code> XML documentation tag? Single line code
example and multiple-line code example.
44. Is XML case-sensitive? Yes, so <Student> and <student> are different elements.
21
45. What debugging tools come with the .NET SDK? CorDBG – command-line debugger,
and DbgCLR – graphic debugger. Visual Studio .NET uses the DbgCLR. To use CorDbg, you
must compile the original C# file using the /debug switch.
46. What does the This window show in the debugger? It points to the object that’s pointed to
by this reference. Object’s instance data is shown.
47. What does assert() do? In debug compilation, assert takes in a Boolean condition as a
parameter, and shows the error dialog if the condition is false. The program proceeds without
any interruption if the condition is true.
48. What’s the difference between the Debug class and Trace class? Documentation looks
the same. Use Debug class for debug builds, use Trace class for both debug and release
builds.
49. Why are there five tracing levels in System.Diagnostics.TraceSwitcher? The tracing
dumps can be quite verbose and for some applications that are constantly running you run
the risk of overloading the machine and the hard drive there. Five levels range from None to
Verbose, allowing to fine-tune the tracing activities.
50. Where is the output of TextWriterTraceListener redirected? To the Console or a text file
depending on the parameter passed to the constructor.
51. How do you debug an ASP.NET Web application? Attach the aspnet_wp.exe process to the
DbgClr debugger.
52. What are three test cases you should go through in unit testing? Positive test cases
(correct data, correct output), negative test cases (broken or missing data, proper handling),
exception test cases (exceptions are thrown and caught properly).
53. Can you change the value of a variable while debugging a C# application? Yes, if you are
debugging via Visual Studio.NET, just go to Immediate window.
54. Explain the three services model (three-tier application). Presentation (UI), business
(logic and underlying code) and data (from storage or other sources).
55. What are advantages and disadvantages of Microsoft-provided data provider classes in
ADO.NET? SQLServer.NET data provider is high-speed and robust, but requires SQL Server
license purchased from Microsoft. OLE-DB.NET is universal for accessing other sources, like
Oracle, DB2, Microsoft Access and Informix, but it’s a .NET layer on top of OLE layer, so not
the fastest thing in the world. ODBC.NET is a deprecated layer provided for backward
compatibility to ODBC engines.
56. What’s the role of the DataReader class in ADO.NET connections? It returns a read-only
dataset from the data source when the command is executed.
57. What is the wildcard character in SQL? Let’s say you want to query database with LIKE
for all employees whose name starts with La. The wildcard character is % , the proper
query with LIKE would involve ‘La% ’.
58. Explain ACID rule of thumb for transactions. Transaction must be Atomic (it is one unit of
work and does not dependent on previous and following transactions), Consistent (data is
either committed or roll back, no “in-between” case where something has been updated and
something hasn’t), Isolated (no transaction sees the intermediate results of the current
transaction), Durable (the values persist if the data had been committed even if the system
crashes right after).
59. What connections does Microsoft SQL Server support? Windows Authentication (via
Active Directory) and SQL Server authentication (via Microsoft SQL Server username and
passwords).
60. Which one is trusted and which one is untrusted? Windows Authentication is trusted
because the username and password are checked with the Active Directory, the SQL Server
authentication is untrusted, since SQL Server is the only verifier participating in the
transaction.
61. Why would you use untrusted verificaion? Web Services might use it, as well as non-
Windows applications.
62. What does the parameter Initial Catalog define inside Connection String? The database
name to connect to.
63. What’s the data provider name to connect to Access database? Microsoft.Access.
64. What does Dispose method do with the connection object? Deletes it from the memory.
65. What is a pre-requisite for connection pooling? Multiple processes must agree that they
will share the same connection, where every parameter is the same, including the security
settings.
22

Caching Overview

Caching is a technique widely used in computing to increase performance by keeping frequently


accessed or expensive data in memory. In the context of a Web application, caching is used to
retain pages or data across HTTP requests and reuse them without the expense of recreating
them.
ASP.NET has three kinds of caching that can be used by Web applications:

 Output caching, which caches the dynamic response generated by a request.


 Fragment caching, which caches portions of a response generated by a request.
 Data caching, which caches arbitrary objects programmatically. To support this, ASP.NET
provides a full-featured cache engine that allows programmers to easily retain data
across requests.

Output caching is useful when the contents of an entire page can be cached. On a heavily
accessed site, caching frequently accessed pages for even a minute at a time can result in
substantial throughput gains. While a page is cached by the output cache, subsequent requests
for that page are served from the output page without executing the code that created it.
Sometimes it is not practical to cache an entire page - perhaps portions of the page must be
created or customized for each request. In this case, it is often worthwhile to identify objects or
data that are expensive to construct and are eligible for caching. Once these items are
identified, they can be created once and then cached for some period of time. Additionally,
fragment caching can be used to cache regions of a page's output.
Choosing the time to cache an item can be an interesting decision. For some items, the data
might be refreshed at regular intervals or the data is valid for a certain amount of time. In that
case, the cache items can be given an expiration policy that causes them to be removed from
the cache when they have expired. Code that accesses the cache item simply checks for the
absence of the item and recreates it, if necessary.
The ASP.NET cache supports file and cache key dependencies, allowing developers to make a
cache item dependent on an external file or another cache item. This technique can be used to
invalidate items when their underlying data source changes.

Introduction
In classic ASP, one of the techniques developers commonly relied on to speed up processing was the
use of caching. One could, fairly easily, build their own caching system using Application variables,
as highlighted in the FAQ, How can I use Application-level variables to cache information? There
were also third-party options, like XCache. The main benefits of caching are performance-related:
operations like accessing database information can be one of the most expensive operations of an
ASP page's life cycle. If the database information is fairly static, this database-information can be
cached.
When information is cached, it stays cached either indefinitely, until some relative time, or until
some absolute time. Most commonly, information is cached for a relative time frame. That is, our
database information may be fairly static, updated just a few times a week. Therefore, we might want
to invalidate the cache every other day, meaning every other day the cached content is rebuilt from
the database.
While caching in classic ASP was a bit of a chore, it is quite easy in ASP.NET. There are a number of
classes in the .NET Framework designed to aid with caching information. In this article, I will
explain how .NET supports caching and explain in detail how to properly incorporate each supported
method into Web-based applications.
Caching Options in ASP.NET
ASP.NET supports three types of caching for Web-based applications:

 Page Level Caching (called Output Caching)


23
 Page Fragment Caching (often called Partial-Page Output Caching)
 Programmatic or Data Caching

We'll look at each of these options, including how, and when, to use each option to increase your
site's performance!
Output Caching

Page level, or output caching, caches the HTML output of dynamic requests to ASP.NET Web pages.
The way ASP.NET implements this (roughly) is through an Output Cache engine. Each time an
incoming ASP.NET page request comes in, this engine checks to see if the page being requested has
a cached output entry. If it does, this cached HTML is sent as a response; otherwise, the page is
dynamically rendered, it's output is stored in the Output Cache engine.
Output Caching is particularly useful when you have very static pages. For example, the articles
here on 4GuysFromRolla.com are very static. The only dynamic content is the banners, the dynamic
selection being performed on a separate ad server. Hence, the articles on 4Guys would be prime
candidates for Output Caching.
Output caching is easy to implement. By simply using the @OuputCache page directive, ASP.NET
Web pages can take advantage of this powerful technique. The syntax looks like this:
<% @OutputCache Duration="60" VaryByParam="none" % >

The Duration parameter specifies how long, in seconds, the HTML output of the Web page should be
held in the cache. When the duration expires, the cache becomes invalid and, with the next visit, the
cached content is flushed, the ASP.NET Web page's HTML dynamically generated, and the cache
repopulated with this HTML. The VaryByParam parameter is used to indicate whether any GET
(QueryString) or POST (via a form submit with method="POST") parameters should be used in
varying what gets cached. In other words, multiple versions of a page can be cached if the output
used to generate the page is different for different values passed in via either a GET or POST.
The VaryByParam is a useful setting that can be used to cache different "views" of a dynamic page
whose content is generated by GET or POST values. For example, you may have an ASP.NET Web
page that reads in a Part number from the QueryString and displays information about a particular
widget whose part number matches the QueryString Part number. Imagine for a moment that
Output Caching ignored the QueryString parameters altogether (which you can do by setting
VaryByParam="none"). If the first user visited the page with QueryString
/ProductInfo.aspx?PartNo=4, she would see information out widget #4. The HTML for this page
would be cached. The next user now visits and wished to see information on widget #8, a la
/ProductInfo.aspx?PartNo=8. If VaryByParam is set to VaryByParam="none", the Output Caching
engine will assume that the requests to the two pages are synonymous, and return the cached HTML
for widget #4 to the person wishing to see widget #8! To solve for this problem, you can specify that
the Output Caching engine should vary its caches based on the PartNo parameter by either
specifying it explicitly, like VaryByParam="PartNo", or by saying to vary on all GET/POST
parameters, like: VaryByParam="*".
Partial-Page Output Caching

More often than not, it is impractical to cache entire pages. For example, you may have some
content on your page that is fairly static, such as a listing of current inventory, but you may have
other information, such as the user's shopping cart, or the current stock price of the company, that
you wish to not be cached at all. Since Output Caching caches the HTML of the entire ASP.NET Web
page, clearly Output Caching cannot be used for these scenarios: enter Partial-Page Output Caching.
Partial-Page Output Caching, or page fragment caching, allows specific regions of pages to be
cached. ASP.NET provides a way to take advantage of this powerful technique, requiring that the
part(s) of the page you wish to have cached appear in a User Control. One way to specify that the
contents of a User Control should be cached is to supply an OutputCache directive at the top of the
User Control. That's it! The content inside the User Control will now be cached for the specified
period, while the ASP.NET Web page that contains the User Control will continue to serve dynamic
24
content. (Note that for this you should not place an OutputCache directive in the ASP.NET Web
page that contains the User Control - just inside of the User Control.)
Now that we've tackled Output Caching and Fragment Caching, there is still one more caching
technique worth discussing: Data Caching. In Part 2 we'll examine what, exactly, Data Caching is
and how you can use it to improve the performance of your ASP.NET Web pages. We'll also examine
a really cool, real-world caching demo!
In Part 1 we looked at how to use Output Caching and Fragement Caching of an ASP.NET Web page.
These two techniques cached either the full HTML output of an ASP.NET Web page, or a portion of
the HTML output of an ASP.NET Web page (by caching the HTML output of a User Control). In this
part, we'll examine Data Caching, which is an in-memory cache used for caching objects.
Data Catching
Sometimes, more control over what gets cached is desired. ASP.NET provides this power and
flexibility by providing a cache engine. Programmatic or data caching takes advantage of the .NET
Runtime cache engine to store any data or object between responses. That is, you can store objects
into a cache, similar to the storing of objects in Application scope in classic ASP. (As with classic
ASP, do not store open database connections in the cache!)
Realize that this data cache is kept in memory and "lives" as long as the host application does. In
other words, when the ASP.NET application using data caching is restarted, the cache is destroyed
and recreated. Data Caching is almost as easy to use as Output Caching or Fragment caching: you
simply interact with it as you would any simple dictionary object. To store a value in the cache, use
syntax like this:

Cache["foo"] = bar; // C#
Cache("foo") = bar ' VB.NET

To retrieve a value, simply reverse the syntax like this:

bar = Cache["foo"]; // C#
bar = Cache("foo") ' VB.NET

Note that after you retrieve a cache value in the above manner you should first verify that the cache
value is not null prior to doing something with the data. Since Data Caching uses an in-memory
cache, there are times when cache elements may need to be evicted. That is, if there is not enough
memory and you attempt to insert something new into the cache, something else has gotta go! The
Data Cache engine does all of this scavenging for your behind the scenes, of course. However, don't
forget that you should always check to ensure that the cache value is there before using it. This is
fairly simply to do - just check to ensure that the value isn't null/Nothing. If it is, then you need to
dynamically retrieve the object and restore it into the cache.
For example, if we were storing a string myString in the cache whose value was set from some
method named SetStringToSomething(), and we wanted to read the value of myString from the
cache, we'd want to:

1. Read the myString from the cache: str = Cache("myString")


2. Ensure that str wasn't null/Nothing. If it was, we'd want to get the value of str from
SetStringToSomething(), and then put it in the cache, like so:

'Try to read the cache entry MyString into str


str = Cache("myString")

'Check if str is Nothing


If str is Nothing then
'If it is, populate str from SetStringToSomething()
str = SetStringToSomething()

'Now insert str into the cache entry myString


Cache("myString") = str
25
End If
Besides using the dictionary-like key/value assignment, as shown in the example above, you can
also use the Insert or Add method to add items to the cache. Both of these methods are overloaded
to accommodate a variety of situations. The Add and the Insert methods operate exactly the same
except the Add method returns a reference to the object being inserted to the cache. Because of the
similarity of the two methods, I will concentrate on the Insert method. Note that the Insert method
allows you to simply add items to the cache using a key and value notation as well. For example to
simply add an instance of the object bar to the cache named foo, use syntax like this:
Cache.Insert("foo", bar); // C#
Cache.Insert("foo", bar) ' VB.NET
(Note that this is synonymous to using the Cache("foo") = bar syntax we looked at earlier.)
Note that with inserting items into the Data Cache using the Cache(key) = value method or the
Cache.Insert(key, value) we have no control over when (if ever) the items are evicted from the cache.
However, there are times when we'd like to have control over when items leave the cache. For
example, perhaps we want to have an inserted item in the cache to only live for n seconds, as with
Output Caching. Or perhaps we'd like to have it exit the cache n seconds after it's last accessed.
With Data Caching, you can optionally specify when the cache should have a member evicted.
Additionally, you can have an item evicted from the cache when a file changes. Such an eviction
dependency is called a file dependency, and has many real-world applications, especially when
working with XML files. For example, if you want to pull data out of an XML file, but you don't want
to constantly go to disk to read the data, you can tell the ASP.NET caching engine to expire the
cached XML file whenever the XML file on disk is changed. To do this, use the following syntax:
Cache.Insert("foo", bar, new CacheDependancy(Server.MapPath("BarData.xml")))
By using this syntax, the cache engine takes care of removing the object bar from the cache when
BarData.xml file is changed. Very cool! There are also means to have the inserted cache value expire
based on an interval, or at an absolute time, as discussed before. For more information on these
methods, consult the documentation for the Cache.Insert method.
A Cached XML File Example

Hopefully by now you'll agree that one of the most interesting and useful uses of the Cache.Insert
method involves using the version of the method that takes advantage of the CacheDependancy
parameter. By using this parameter, developers can create web pages that contain "semi-static"
data. In other words, the rendering of the pages is based on configuration-like data which can be
stored in an XML file (or anywhere really, I just like to use XML for this type of data). But I digress.
The point is, why go back to disk or, worse yet, a SQL Server just to retrieve data that only changes
periodically when I can have it done automatically.
To illustrate this point, I've created a simple example. In this example, an XML file is used to house
data that is used to create a simple navigation control. Each <Destination> element contains a
<LinkText> and a <NavigateURL> tag to house the appropriate data. Below is a section of this XML
file:

<Destinations>
<Destination>
<LinkText>
Bazquirk
</LinkText>
<NavigateURL>
Bazquik.aspx
</NavigateURL>
</Destination>
<Destination>
<LinkText>Blah</LinkText>
<NavigateURL>Blah.aspx</NavigateURL>
</Destination>
....
In a User Control a DataList control is used to bind the XML data using a HyperLink control. The
Text property is set to the values contained in the <LinkText> tags. The HyperLink control's
NavigateUrl property is set to the values contained in the <NavigateURL> tags. A Label control is
26
used in the code behind class to output the time the cache is updated. (All of the code, and the
output, can be seen at this live demo!)
A simple method, BindDestinations, does the work of binding the XML data to the DataList control.
This method is called everytime the Page_Load event is fired. A DataSet object is created and then
filled with the XML data by using the DataSet's ReadXML method.
In the BindDestinations method, an attempt is made to pull the data out of the Cache object. If
nothing is found, as is the case when the XML file is changed, the data is re-read from the XML file
and re-inserted into the Cache object. The time this occurs is also displayed via the lblTime Label
control. Finally, the data is bound to the DataList control and displayed. In this manner, the data of
the page is cached until it needs to be refreshed (i.e., the XML file data is changed). Neat!
Conclusion
The .NET caching services will prove to be one of the most powerful ways to squeeze performance out
of new Web-based applications. Whether using Output Caching, Fragment Caching, or the Cache
object directly, your web applications will see dramatic improvements in throughput and scalability
through the technique of caching expensive dynamic data computations.

Caching-XML-Trace
Introduction
Data caching was introduced with Internet Information Server (IIS) in order to optimize the transfer
of Web pages and speed up the user’s access to these pages. ASP 2.x did not have any native caching
ability and simply made use of the caching provided by IIS.Third-party utilities could also be used to
increase the caching abilities of ASP 2.x and provide a greater level of control over the IIS cache.
Caching is now available natively within ASP.NET and has three new faces: utput, data, and
fragment caching. Each of these methods provides new and powerful ethods of optimizing the
utilization of system resources and increasing pplication performance. utput caching is more like the
old method of caching provided by IIS; a ingle page is stored within memory for a small period of
time, for any reason hat the programmer sees fit.While this model is troublesome in some instances,
it can be helpful to the end-user at times.This allows for faster access to pages hat contain some
dynamic content without having to regenerate the entire page. ragment caching is an innovation to
output caching; it enables the programmer to determine which parts of a page should be cached for
future reference.This is done by breaking the code into separate user controls and then caching the
control.This new feature greatly expands on our caching options.Data caching enables the
programmer to have full control over the caching at the object level.You can define which objects and
which areas are to be cached and for what length of time, as you see fit.This detailed level of control
enables you to save any object to memory that you wish, in order to speed up access to that object.
In this chapter, we are going to go over the three methods of caching that are available in
ASP.NET.We will also discuss how and why to use each method and in what situations each method
should be used.The options and parameters for each method will be discussed and illustrated. By
using this information, you can greatly increase the performance of your application.This objective is
key in creating an application that fits well with the needs of your users.

Caching Overview
Caching is a technique used in various aspects of computing to increase performance by decreasing
access times for obtaining data.This is accomplished by retaining frequently accessed data within
memory.This technique is used by many operating systems to cut down on the number of times that
a hard drive must be accessed or a network connection utilized, by storing the needed data in the
system’s memory. It is also used by some databases to store data retrieved from queries that may be
needed again later.As it pertains to a Web application, data is retained from across multiple HTTP
requests, and can then be reused without incurring additional access times that would normally be
necessary to recreate the data.
ASP.NET makes available three different types of caching, which, when used properly, can greatly
increase the overall performance of your application.These types are as follows:
_ Output Caching
_ Fragment Caching
_ Data Caching
We will go into detail in this chapter on each of these caching types, but they all are based off of the
basic concept of saving all or a portion of the data generated by your application, with the purpose of
presenting the same data again at a later time. Output caching basically caches the entire content of
an output Web page. This can be very useful when the content of your pages changes very little.
27
Programmers familiar with ASP 2.x should be familiar with this concept, as it was the only
available caching method for ASP.This method provides the greatest performance increase, but can
only be used when nothing on the output page is expected to change within the valid timeframe of
the cache. Fragment caching, which is new in ASP.NET, allows for the caching of portions
of your output page.This is an excellent improvement in caching technique, and is best used when
your application’s output page has content that changes constantly in addition to content that
changes very little.While this method does not provide as much of a performance increase as output
caching, it does increase performance for applications that would formerly have been unable to use
any caching at all due to the strict requirements of output caching. Data caching, also new in
ASP.NET, provides the ability to cache individual objects. Placing objects into the cache in this
manner is similar to adding items to a dictionary. By using a simple dictionary-style interface, this
method makes for an easy-to-use temporary data storage area while conserving server resources by
releasing memory as cached objects expire.

A major consideration in planning your caching strategy is the appropriate utilization of server
resources.There is a trade-off when it comes to the use of any kind of caching, in that for every item
cached, less memory is available for other uses.While output caching provides the greatest
performance increase, it also utilizes more memory than caching a few objects using data caching.
On the other hand, due to the overhead required to store multiple objects by using data caching, it
may be more logical to cache a portion of the output page by using fragment caching. Suggested
uses are listed in Table 6.1; however, the best caching method for your specific application is
dependant upon your output.
www.syngress.com
Table 6.1 Suggested Uses of Caching Types
Situation Suggested Caching Type
1.The generated page generally stays the same, but there are several tables shown within the output
that change regularly.
2.The generated page constantly changes, but there are a few objects that don’t change very often.
3.The generated page changes every few hours as information is loaded into a database through
automated processes.

1.Use Fragment Caching in this situation. Cache the portions of the page that remain somewhat
static, while dynamically generating the table contents. Also consider using Data Caching for storing
some individual objects.
2.Use Data Caching for the objects.
3.Use Output Caching and set the duration to match the frequency of the data changes.

Components of an XML Document


In this section, we will introduce the major components of an XML document.
An XML document contains a variety of constructs. Some of the frequently used
ones are as follows:
_ Declaration Each XML document may have the optional entry <?xml version=“1.0”?>. This
standard entry is used to identify the document as an XML document conforming to the W3C (World
Wide Web Consortium) recommendation for version 1.0.
_ Comment An XML document may contain html-style comments like
<!--Catalog data -->.
_ Schema or Document Type Definition (DTD) In certain situations, a schema or DTD may
precede the XML document. A schema or DTD contains the rules about the elements of the
document. For example, we may specify a rule like “A product element must have a ProductName,
but a ListPrice element is optional.”We will discuss schemas later in the chapter. _ Elements An
XML document is mostly composed of elements.An element has a start-tag and end-tag. In between
the start-tag and end-tag, we include the content of the element.An element may contain a piece of
character data, or it may contain other elements. For example, in the Catalog1.xml, the Product
element contains three other elements: ProductId,ProductName, and ListPrice. On the other hand, the
first ProductName element contains a piece of character data like Shimano Calcutta.
_ Root Element In an XML document, one single main element must contain all other elements
inside it.This specific element is often called the root element. In our example, the root element is the
Catalog element. The XML document may contain many Product elements, but there must be only
one instance of the Catalog element. _ Attributes Okay, we agree that we didn’t tell you the whole
story in our first example. So far, we have said that an element may contain other elements, or it
28
may contain data, or both. Besides these, an element may also contain zero or more so-called
attributes. An attribute is just an additional way to attach a piece of data to an element. An attribute
is always placed inside the start-tag of an element, and we specify its value using the “name=value”
pair protocol. Let us revise our Catalog1.xml and include some attributes to the Product element.
Here, we will assume that a Product element will have two attributes named Type and SupplierId.As
shown in Figure 8.5, we will simply add the Type=“Spinning Reel” and SupplierId=“5” attributes in
the first product element. Similarly, we will also add the attributes to the second product element.

Table 9.2 Sections in a Trace Page


Sections Description
Request Details Describes information pertaining to the request (e.g., SessionID, Encoding, and time
of request).
Trace Information Contains detailed information about the application currently running. Trace
information is displayed in this section. Control Tree Displays information about controls used in a
page and the size of the Viewstate hidden field. Cookies Collection Displays the cookie set by the
page and its value. Headers Collection Displays HTTP header information like content length and
user agent. Forms Collection Displays the name of controls in a page and its value. Server Variables
Displays the environment variables on the server side. Notice that our Trace message is written
under the “Trace Information” section. The Trace class contains the following members (Table 9.3
and Table 9.4).
Table 9.3 Properties in the Trace Class
Property Description
IsEnabled Indicates whether tracing is enabled for the current request.
TraceMode Sets the trace mode: sortByCategory or sortByTime.
Methods in the Trace Class
Methods() Description
Warn Writes the trace information in red.
Write Writes the trace information.

Solutions Fast Track


Handling Errors
@ There are four main categories of programming errors: syntax, compilation, runtime, and logic

errors.

@ Visual Studio .NET IDE provides help for detecting syntax errors.
Runtime errors can be handled using structured and unstructured error
handling mechanisms.
@ Structured handling using the Try-Catch-Finally statement is the
recommended mode for handling runtime errors in .NET.
Page Tracing
@ The Trace class provides tracing capability.
@ Turning tracing on and off is easy.
@ Trace information can be grouped into multiple categories for easier
viewing and it can be written into log files, viewable using the Event
Viewer.
@ Tracing can be done at the page level or at the application level.
www.syngress.com
29
Debugging ASP.NET • Chapter 9 439
Using Visual Studio .NET Debugging Tools
@ Programmers can use the Visual Studio .NET IDE to set breakpoints in
their application.
@ Breakpoints allow you to examine variables and trace the execution flow
of your application.
@ The Object Browser and Class Viewer provide quick reference to the
various class libraries.
Q: Is the Try-Catch-Finally block available in C# as well?
A:Yes, the Try-Catch-Finally block is available in both VB.NET and C#.
Q: Can I use both structured and unstructured error handling within a function/ subroutine?
A: No, you cannot use both error handling mechanisms at the same time. It is recommended you
use structured error handling in .NET.
Q: When I try to run my ASP.NET application in VS.NET, I encounter this error message “Error while
trying to run project: Unable to start debugging on the Web server.The project is not configured to be
debugged.”Why does this occur?
A: This is caused by the setting of the debug attribute within the <compilation> element. During
development stage, set the value of the debug attribute to “true.” Remember, however, to set this
attribute to “false” when you are ready to deploy your application.
www.syngress.com
Frequently Asked Questions
The following Frequently Asked Questions, answered by the authors of this book, are designed to
both measure your understanding of the concepts presented in this chapter and to assist you with
real-life implementation of these concepts. To have your questions about this chapter answered by
the author, browse to www.syngress.com/solutions and click on the “Ask the Author” form.
440 Chapter 9 • Debugging ASP.NET
Q: I noticed during tracing that the Session ID for my application changes when I refresh my page or
when I do a postback.Why is this happening?
A: For performance reasons, the .NET Framework does not maintain state between the Web server
and the Web browser automatically, hence the Session ID is always different between submissions.
However, when the Session object is used or when the Session_OnStart() event is added to the
global.asax file, the Session ID would be maintained between postbacks.

Frequently Asked Questions(Web Services)

Q:Why replace COM objects with Web Services?


A:Web Services have a platform neutral interface.This enables Web Services to be easily utilized by
multiple clients on different platforms developed with different programming languages. Note that
existing COM components can be wrapped by Web Services.
Q: Can I create access to Web Services from a standard ASP page?
A:Yes, you can; however, you might want to look into Microsoft’s SOAP toolkit.
Q: How do I know I need Web Services?
A: If you have data that is needed by various customers (different departments, different levels of
management, vendors, industry partners, consumers and so on) and getting to that data is hindered
or prevented by issues involving platform, programming language, legacy hardware or other types of
incompatibility, developing Web Services can help.
Q: What area of development are Web Services best for?
A: I believe that Web Services development like COM development will remain in the hands of the
middle tier programmer.Traditionally this was accomplished with C++ and VB programmers,
however simple data access type components may be developed by intermediate and advanced ASP
developers. While this might still be the case,ASP.NET developers need a firmer grasp of
programming with a strongly typed compiled language then their ASP predecessors.This makes the
ASP.NET developer more of a middle tier programmer and less of a front-end Web developer. Since
building and deploying Web classes and Web Services are relatively easy with VS.NET as compared
to traditional COM development. I think the proportion of components built by the ASP developer
(using ASP.NET) will be larger than it has been in the past.

Q: Is it possible to try out Web Services using only my local computer?


30
A:Yes, it is. Using the WSDL.exe command line tool, you can point to any Web server.This is even
easier with the VS.NET UI. Simply right-click Web references, then select any Web service from the
UDDI directory or your local machine, or simply type the URL of a disco file on any server.You can
easily generate a WSDL proxy and use it as long as you are connected to the Internet.
Q: I’m currently in the process of migrating.What considerations should I take with my existing COM
components?
A: Here are a few things to consider: _ Who is the customer? If the customer is only within the
intranet and there are no external customers in the foreseeable future, an existing DCOM
infrastructure needn’t be changed. _ What type of clients do I have? If the client is a desktop
application, switching to Web Services would require updating the client, which may include
updating the OS, and possibly the hardware so that the client has enough memory to host the .NET
Framework.
_ Will I need to support Mobile devices in the near future? Using the .NET Mobile Framework to access
Web Services is as simple as it is with .NET. Updating the existing clients to .NET will make adding
future clients simple and cost-effective.

Choosing Between User Controls and Custom Controls

ASP.NET provides two models of creating Web controls – user controls and custom controls. This
article assumes basic knowledge of the two models and will not provide detailed information on
writing controls. Instead, this article will present the reasons why one should choose one model over
the other.

User Controls

User controls are authored in the same fashion as a standard Web Form. This makes user controls
relatively easy to create, especially when aided by a visual designer such as Visual Studio .NET.
Hence, given the same WYSIWYG and declarative environment as an ASP.NET page, user controls
can be created with or without a code-behind file, and can handle their own events independent of
the parent page. Design-time support for user controls, however, is limited. User controls are
represented only by a dull placeholder and properties cannot be set via the Properties window. Also,
user controls cannot be added to the Toolbox; sharing of user controls is achieved through placing
the necessary user control files in each Web application directory.

Custom Controls

Unlike user controls which are authored in the same fashion as a Web Form, custom controls are
compiled and distributed in binary format. Control authors must create their own classes which
subclass from System.Web.UI.Control either directly or indirectly by subclassing another control.
Custom controls are created without the aid of a designer and require the author to overcome a
much steeper learning curve. On the other hand, custom controls provide strong designer-time
support. Once compiled, custom controls can be added to the Toolbox and be used the same fashion
as the other controls that ship with the .NET SDK such as the TextBox and Button controls.
Furthermore, custom controls can expose properties which can easily be set by page developers
using the Properties window of the visual designer. Finally, custom controls allow authors to extend
or modify the functionality provided by existing controls.

Performance

With regards to performance, neither has a distinct advantage over the other. Both derive from
System.Web.UI.Control and both are compiled into assemblies. Hence, performance is not a factor to
consider when choosing between user and custom controls.

Conclusion

In conclusion, the single most important factor is how the control will be used – will the control be
application specific or generic and redistributable? If the control is application specific and contains
a lot of static layout, such as a site header and footer, a user control would make sense. If the
31
control is generic, redistributable, and contains dynamic layout, such as the server controls that
ship with the .NET SDK, then a custom control would be more suitable.

Summary

Ease of Authoring – User controls win hands down

Design-Time Support – Custom controls can be added to the toolbox, can expose simple or complex
properties, and can be bound to a data source

Deployment – Custom controls are compiled into binary format and are easily deployed across
applications

Layout – User controls suite static layout while custom controls are better suited for complex layouts

Performance – Equal. Consider the other factors.

collectionBase

Introduction
System.Collections namespace has several collection type classes like Stack, Queue, Dictionary,
Collectionbase,Arraylist etc; each one is out there to meet specific development requirements. In the
snippet we will not get into the nuts and bolts of all the collection type but we will restrict ourselves
to CollectionBase type.

Built-in functionality
The CollectionBase class has implementations for the Clear method and the Count property, and a
List property, which it uses for the internal storage and organization. Other methods, such as Add
and Remove, as well as the Item property, require implementation. This sample uses two classes:
Author and Authors. Authors inherit from System.Collections.CollectionBase in order to create a
type-safe collection to manage multiple Author instances.

Author Class
------------
using System;
namespace collection
{
public class Author
{
private Int16 vid;
private string vname;
private string vtitle;

public Author(Int16 id,string name,string title )


{
this.ID=id;
this.Name=name;
this.Title=title;
}

public Int16 ID
{
get{return vid;}
set{vid=value;}
}
32
public string Name
{
get{return vname;}
set{vname=value;}
}

public string Title


{
get{return vtitle;}
set{vtitle=value;}
}

Authors Class
-------------
public class Authors:System.Collections.CollectionBase
{
public Authors()
{
}
//Add author to collection
public void Add(Author oAuthor)
{
List.Add(oAuthor);
}

public Author Item(int Index)


{
// explicitly cast to the Author type
return (Author) List[Index];
}
}}

How To Use?

private void Test()


{
//Create instance of collection
Authors oCol=new Authors();

//Add authors to collection


oCol.Add(new Author(1,"David","CollectionBase class"));
oCol.Add(new Author(2,"Gentry","Imaging sysyems"));
oCol.Add(new Author(3,"Peter",".net Framework"));

Debug.WriteLine("ID " +" Name " + " Title ");


//Print results
foreach(Author obj in oCol)
{Debug.WriteLine(obj.ID + " " +obj.Name+" " +obj.Title);}
}

Results
This is a proof that author objects have been added to the collection.

ID Name Title
1 David CollectionBase class
2 Gentry Imaging sysyems
3 Peter .net Framework
33

COMInteroperability

The .NET platform is a major shift from the earlier COM technology, which dominated the Microsoft
world for many years. Although new development may be carried out using .NET, there will be a
need to reuse some of the functionality existing in the form of COM components. In this article, I
examine some COM and .NET interoperability techniques.

COM to .NET: A shift in technology

Though a COM component and a .NET assembly share the same .dll extension, things are not the
same internally. A .NET assembly does not need information about it to be stored in the registry, but
instead holds the type information in the form of metadata. This metadata is present within the
assembly itself. Further, a .NET assembly is not based on the IUnknown interface, which is an
interface exposed by all COM objects.

The code that exists in the form of COM is known as unmanaged code, because the execution of this
code is not managed by the common language runtime (CLR). Code written with the .NET
Framework is managed by the CLR and is hence known as managed code.

It is impractical to rewrite every piece of code in .NET, because a lot of functionality exists in COM
form. Moreover, more code exists in COM today than .NET, because .NET is a relatively new
platform. From this fact arises the need for interoperating between COM and .NET. The .NET
Framework has dedicated a namespace for this purpose. The System.Runtime.InteropServices
namespace provides classes that can be used for accessing COM objects from .NET. We will begin by
calling COM objects from .NET—a common necessity.

Calling COM objects from .NET

The code within a COM object is not executed by the CLR. The mechanism followed to expose a COM
object to .NET is as follows: The COM object is encapsulated within a wrapper class, and this
exposes the COM object as a .NET assembly to the CLR. This wrapper is known as the runtime
callable wrapper (RCW). This process is illustrated in Figure A.

Figure A

Runtime callable wrapper (RCW)


This wrapper class (RCW) acts as a bridge between the unmanaged and managed code, and all
operations are routed through this class. That's enough theory; let’s take a quick look at how this
can be done. The entire process of generating an RCW is automatically handled by Visual
Studio.NET.

Interoperability using Visual Studio.NET


Let’s assume we need to utilize Microsoft Excel in our application. We can do so by accessing the
Project menu and References and choosing Microsoft Excel Object Library from the COM tab, as
shown in Figure B.
34

Choosing the Microsoft Excel Object Library

As soon as we do so, Visual Studio.NET automatically generates an RCW. The naming convention
followed is Interop.COMObject.dll. In this case, the RCW is called Interop.Excel.dll, which is
referenced in the .NET application; we can instantiate and use Excel objects in code. The same is
true for any custom COM component authored by you. The only requirement is that the COM
component must be registered.

You can also use ActiveX Controls from .NET. To do so, right-click on the Toolbox and select
Customize Toolbox. From the COM Components tab, select (for example) Microsoft ListView Control
and check the checkbox beside it (see Figure C). The Listview control will be added to the Toolbox.
35
Figure C

Selecting the Microsoft ListView Control

As soon as you place the Listview control on the form, Visual Studio.NET generates the RCW for the
ActiveX Control. The naming convention followed is AxInterop.ActiveXControl.dll, so in this case it is
called AxInterop.MSComctlLib.dll.

Interoperability without Visual Studio.NET


Suppose you are not using Visual Studio.NET. Another way of achieving the same result is to use
the .Net Framework tool called the Type Library Importer (tlbimp.exe). This tool can be used to
convert type definitions in a COM library into a .NET assembly.
For example, if you have a COM DLL named MyCOMComponent.dll, you can build an RCW for it as
follows:
Tlbimp MyCOMComponent.dll /out:MyRCW.dll
In the case of ActiveX Controls, you can use the .NET Framework tool called the ActiveX Importer to
convert the type definitions in an ActiveX Control into a Windows Forms Control. It can be used from
the command line as follows:
Aximp MyOCX.ocx

Wrap it up
If you are wondering how Visual Studio.NET or the command-line tools generate these wrappers,
here is the key. The .NET Framework Class Library has a class called TypeLibConverter
(System.Runtime.IneropServices.TypeLibConverter), which exposes a method called
ConvertTypeLibToAssembly that can be used to write your own tool; this tool generates an RCW. The
same is true for the ActiveX controls—the AxImporter Class
(System.Windows.Forms.Design.AxImporter) can be used to generate RCWs for ActiveX controls.

Memory management
One of the main architectural differences between .NET and COM is memory management. The CLR
provides automatic memory management by means of a garbage collector that manages the allocation
and release of memory. This is done periodically, so an object is not immediately destroyed when it
goes out of scope or when it is set to Nothing (Visual Basic.NET, the same as null in C#).
36

When an RCW goes out of scope or is set to Nothing, the object is not destroyed immediately, and
the corresponding COM object will also reside in memory—which might not be desirable. In such
situations, steps should be taken to clean up the memory. You can do so by calling the garbage
collector, by calling the System.GC.Collect method, or—the preferred way—by calling the
Marshal.ReleaseComObject method on the RCW.
Apart from providing backward compatibility, the .NET framework also provides forward
compatibility, which means that it is possible to expose a .NET assembly so that it can be consumed
from COM. We will now shift our focus to this aspect of utilizing .NET assemblies from COM.

Calling .NET assemblies from COM


Let us now see how we can utilize .NET assemblies from COM (see Figure A).

Figure A

Utilizing .NET assemblies from COM

Similar to the process of calling COM Objects from .NET, here we have a wrapper class over a .NET
Assembly, which can be accessed from a COM-based application. This wrapper class is known as
the “COM Callable Wrapper” (CCW). Let’s see how we can do this using Visual Studio.NET.
Start Visual Studio.NET and start a new project of type Class Library. Call it DotnetForCOM (for
example). Add a default constructor to the class and some public methods, which you want available
in COM. Once you have this ready, right-click on the project in the Solution Explorer and select
Properties to bring up the project property pages. Here, choose Configuration properties and select
the Build option. You will be presented with the screen displayed in Figure B.
Figure B
37
Working with property pages

Check the checkbox Register For COM Interop (in Figure B). Now, when you build this project, the
.NET assembly is automatically registered for COM Interop. You will now be able to use this
assembly from COM, for example from Visual Basic 6.0. If you start a new Visual Basic 6 project and
choose the Project Menu and References, this .NET assembly is available to reference from COM (see
Figure C).
Figure C

Visual Basic project references

Once this is done, you can access the functionality provided by the .NET assembly from Visual Basic
6.
Working outside Visual Studio.NET
Let us now see what we need to do if we are not using Visual Studio.NET. There are certain
requirements for a .NET assembly to be exposed to COM.
Provide a default constructor
Firstly, .NET assembly must provide a default constructor. This is because COM Clients do not
support parameterized constructors available in .NET, so make sure you provide a default
constructor to the class. You can have constructors with parameters, as well, along with the default
constructor, but the default constructor needs to be present to instantiate the .NET assembly from
COM client.
Generating type libraries
Generate the type library for the .NET assembly, and make entries in the System Registry. There are
two ways to achieve this:
Use the Type Library Exporter tool provided with the .NET Framework SDK to generate the type
library for the .NET assembly. Then register the type library using the Assembly Registration tool.
Tlbexp test.dll /out:test.tlb Regasm test.dll
Directly generate the type library, and register it using Regasm.
Regasm test.dll /tlb:test.tlb
The .NET Assembly must have a Strong Name and must reside in the Global Assembly Cache.
For this purpose you will need to generate a key for the Assembly using the Strong Name tool
(Sn.exe). Once this is done, you can add the assembly to the Global Assembly Cache (GAC) using
the Global Assembly Cache Tool (Gacutil.exe). You can add an assembly to the GAC using:
gacutil –I SampleAssembly.dll

Once this has been done, you will be able to add a reference to the .NET assembly from COM and
38
use it. The COM Callable Wrapper (CCW) is generated at the time when a call is given to the .NET
Assembly from COM; it acts as a bridge between the managed and unmanaged boundaries.

Concept
Web garden:
An application pool that uses more than one worker process is called a Web garden. The worker
processes in a Web garden share the requests that arrive for that particular application pool. If a
worker process fails, another worker process can continue to process requests.

This feature of IIS 6.0 is available only when IIS is running in worker process isolation mode.
In IIS 6.0 worker process isolation mode, application pools enhance Web site or application
reliability by isolating applications and the worker processes that service those applications. For
even greater reliability, you can configure an application pool to be supported by multiple worker
processes. An application pool that uses more than one worker process is called a Web garden. The
worker processes in a Web garden share the requests that arrive for that particular application pool.
If a worker process fails, another worker process can continue to process requests.
Note
Web gardens are different from Web farms. A Web garden is configured on a single server by
specifying multiple worker processes for an application pool. Web farms use multiple servers for a
Web site.
Creating a Web garden for an application pool can also enhance performance in the following
situations:

Robust processing of requests: When a worker process in an application pool is tied up (for
example, when a script engine stops responding), other worker processes can accept and process
requests for the application pool.

Reduced contention for resources: When a Web garden reaches a steady state, each new TCP/IP
connection is assigned, according to a round-robin scheme, to a worker process in the Web
garden. This helps smooth out workloads and reduce contention for resources that are bound to a
worker process.

Procedures
Important You must be a member of the Administrators group on the local computer to perform
the following procedure or procedures. As a security best practice, log on to your computer by using
an account that is not in the Administrators group, and then use the runas command to run IIS
Manager as an administrator. At a command prompt, type runas /user:Administrative_AccountName
"mmc %systemroot%\system32\inetsrv\iis.msc".

To configure a Web garden by using IIS Manager

1. In IIS Manager, expand the local computer, expand Application Pools, right-click the
application pool, and then click Properties.

2. Click the Performance tab, and under Web garden, in the Maximum number of worker
processes box, type the number of worker processes that you want to assign to the application
pool. (You must type a number greater than 1 for the application pool to become a Web garden.

3. Click OK.

Optionally, you can configure a Web garden by setting the metabase property MaxProcesses. The
MaxProcesses property determines the maximum number of worker processes that an application
39
pool allows to service its requests. A value of zero indicates an unmanaged application pool that is
not served by a worker process.
The default value for the MaxProcesses property is 1, which is the default number of worker
processes that service an application pool. To configure an application pool so that it is a Web
garden, set the MaxProcesses property to a value greater than 1.
Important You must be a member of the Administrators group on the local computer to run
scripts and executables. As a security best practice, log on to your computer by using an account
that is not in the Administrators group, and then use the runas command to run your script or
executable as an administrator. At a command prompt, type runas /profile
/user:MyComputer\Administrator cmd to open a command window with administrator rights and
then type cscript.exeScriptName (include the script's full path and any known parameters).

To configure a Web garden by using Adsutil.vbs

1. In the Run dialog box, type cmd, and then click OK.

2. At the command prompt, type:


cscript %SystemDrive%\Inetpub\AdminScripts\adsutil.vbs set
W3SVC/AppPools/ApplicationPoolName/MaxProcesses n
Replace n with the number of worker processes that you want to service the application pool.

Custom Control Overview

Embedding user controls in a Windows form is just like adding a simple button or text box that are
already provided with .NET. These basic controls were written essentially like you code your own
controls. Typically the controls you design are to be used in multiple forms or to modularize your
code. These reasons help reduce the amount of code you have to type as well as make it easier for
you to change your implementation. There should almost never be any reason to duplicate code
because it leaves a lot of room for bugs. So, implementing functionality specific to your control in
the control's source code is a good idea. This reduces code duplication as well as modularize your
code, which is a good programming guideline.

Custom controls are a key theme in .NET development. They can help your programming style by
improving encapsulation, simplifying a programming model, and making user interface more
"pluggable" (i.e., making it easier to swap out one control and replace it with a completely different
one without rewriting your form code). Of course, custom controls can have other benefits, including
the ability to transform a generic window into a state-of-the-art modern interface.

Generally, developers tackle custom control development for one of three reasons:

To create controls that abstract away unimportant details and are tailored
for a specific type of data. You saw this model in Chapter 6 with custom
ListView and TreeView examples.

To create controls that provide entirely new functionality, or just combine


existing UI elements in a unique way.

To create controls with a distinct original look, or ones that mimic popular
controls in professional applications (like Microsoft's Outlook bar) that
aren't available to the masses.
40
In .NET, creating a custom control is as easy as creating an ordinary class. You simply inherit
from the best possible ancestor and add the specific features you need. Best of all, you can create a
custom control class as part of an existing project, and then decide later to place it in a separate
assembly that can be shared with other programmers.

Types of Custom Controls

Developers often make a distinction between three or four types of controls:

User controls are the simplest type of control. They inherit from the
System.Windows.Forms.UserControl class, and follow a model of composition.
Usually, user controls combine more than one control in a logical
unit (like a group of text boxes for entering address information).

Inherited controls are generally more powerful and flexible. With an inherited
control, you choose the existing .NET control that is closest to what you
want to provide. Then, you derive a custom class that overrides or adds
properties and methods. The examples you've looked at so far in this book,
including the custom TreeViews and ListViews, have all been inherited
controls.

Owner-drawn controls generally use GDI+ drawing routines to generate


their interfaces from scratch. Because of this, they tend to inherit from a
base class like System.Windows.Forms.Control. Owner-drawn controls
require the most work and provide the most customizable user interface.

Extender providers, which aren't necessarily controls at all. These components


add features to other controls on a form, and provide a remarkable way to
implement
extensible user interface.

Communication between User Controls and subscribing Applications

Because the basic .NET controls are contained within our user control, events are not fired for the
contained applications. Our user control is treated like any other and must implement it's own
properties (besides those inherited from System.Windows.Forms.Control) and events.

Publising and Subscribing Events

The Event model in C# finds its roots in the event programming model that is popular in
asynchronous programming. The basic foundation behind this programming model is the idea of
"publisher and subscribers." In this model, you have publishers who will do some logic and publish
an "event." Publishers will then send out their event only to subscribers who have subscribed to
receive the specific event.

In C#, any object can publish a set of events to which other applications can subscribe. When the
publishing class raises an event, all the subscribed applications are notified. The following figure
shows this mechanism.
41

Events and Delegates

At the heart of Events in C# are Delegates. When an object generates an events, it must send the
event out. The way that events are dispatched is through the use of delegates. Let's look how
Events are declared in C#.

[attributes] [modifier] event type member-name;

Modifier is any allowable scope modifier.


Type must be a delegate.
Member-name is the Name of the Event with which you will refer to the event in your
code.

The important thing to note here is the delegate type that events should use. In the strictest sense,
the delegate can be any legal delegate. But there is a convention that you should follow and is one
that Window Forms uses. By Convention, the delegate should accept two parameters:

1. The object that generated the event


2. The parameters for the specific event

An example of an event / delegate is as follows:

public delegate void SubmitClickedHandler(object sender, EventArgs e);


public event SubmitClickedHandler SubmitClicked;

SubmitClickedHandler is the name of the delegate, sender is self explanatory. EventArgs is defined
under the System namespace and is a very plain class. SubmitClicked is the name of the event,
which is published to the Subscriber.

Submit Button User Control

Create the Submit Button User Control

The control we will create will contain a text box for your name and a button that will fire an event.
To begin, open Visual Studio .NET and begin a new C# Windows Control Library. You may name it
whatever you like, for this sample the project name will be SubmitButton.
42

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Akadia
{
namespace SubmitButton
{
// User Control which contain a text box for your
// name and a button that will fire an event.
public class SubmitButtonControl : System.Windows.Forms.UserControl
{
private System.Windows.Forms.TextBox txtName;
private System.Windows.Forms.Label lblName;
private System.Windows.Forms.Button btnSubmit;
private System.ComponentModel.Container components = null;

// Declare delegate for submit button clicked.


//
// Most action events (like the Click event) in Windows Forms
// use the EventHandler delegate and the EventArgs arguments.
// We will define our own delegate that does not specify parameters.
// Mostly, we really don't care what the conditions of the
// click event for the Submit button were, we just care that
// the Submit button was clicked.
public delegate void SubmitClickedHandler();

// Constructor
public SubmitButtonControl()
{
// Create visual controls
InitializeComponent();
}

// Clean up any resources being used.


protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
.....
43
.....

// Declare the event, which is associated with our


// delegate SubmitClickedHandler(). Add some attributes
// for the Visual C# control property.
[Category("Action")]
[Description("Fires when the Submit button is clicked.")]
public event SubmitClickedHandler SubmitClicked;

// Add a protected method called OnSubmitClicked().


// You may use this in child classes instead of adding
// event handlers.
protected virtual void OnSubmitClicked()
{
// If an event has no subscribers registerd, it will
// evaluate to null. The test checks that the value is not
// null, ensuring that there are subsribers before
// calling the event itself.
if (SubmitClicked != null)
{
SubmitClicked(); // Notify Subscribers
}
}

// Handler for Submit Button. Do some validation before


// calling the event.
private void btnSubmit_Click(object sender, System.EventArgs e)
{
if (txtName.Text.Length == 0)
{
MessageBox.Show("Please enter your name.");
}
else
{
OnSubmitClicked();
}
}

// Read / Write Property for the User Name. This Property


// will be visible in the containing application.
[Category("Appearance")]
[Description("Gets or sets the name in the text box")]
public string UserName
{
get { return txtName.Text; }
set { txtName.Text = value; }
}
}
}
}

Using the Submit User Control in a Windows Application

Using the control in a Windows form is trivial. It's just like adding any other control like a button or
a DataGrid. First, create a new Windows Application project named: TestApp. Add a reference to the
Submit Button User Control DLL named: SubmitButton.dll. Now you are ready to customize the
Toolbox: Right-Click the Toolbox, .NET Framework Components, Browse, select the SubmitButton.dll.
44

The Submit Button User Control is now added to the Toolbox and can be inserted in Windows Form
as any other control. Now we want to handle the SubmitClicked event for the user control. This will
simply close the form. The control itself will take care of validation and the event won't be fired
unless the text is valid. Click on the lightning-looking button (for events) with the control selected
and you'll see the event, SubmitClicked, listed under the "Action" category. Click on it once and you'll
see the description we added previously. Now double-click it and VS.NET will add an event handler
SubmitClicked() which displays the name from the user control and close the form when the event is
fired.

using System;
using System.Drawing;
using System.Collections;
45
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestApp
{
// Test Application for the Submit Button User Control
public class TestApp : System.Windows.Forms.Form
{
private Akadia.SubmitButton.SubmitButtonControl submitButtonControl;
private System.ComponentModel.Container components = null;

....
.....

[STAThread]
static void Main()
{
Application.Run(new TestApp());
}

// Handle the SubmitClicked Event


private void SubmitClicked()
{
MessageBox.Show(String.Format("Hello, {0}!",
submitButtonControl.UserName));
this.Close();
}
}
}

Login Validation User Control

Create the Login Validation User Control

The following sample shows how to implement a Login user control. When the user clicks the Login
button, the control will validate the data entered by the user. If the user has left either the User
name or the Password text boxes empty, the loginError validation control will display an error icon
against the offending control. The Password will then be checked by a "secret algorithm", if the
Password is valid, the user control will raise an event called LoginSuccess; otherwise it will fire a
different event called LoginFailed.

In this sample we use the predefined System.EventHandler delegate. This delegate is useful if you
want to define an event that has no additional data. The event will be passed an empty
System.EventArgs parameter instead. This is the delegate used by many of the Windows Forms.
46

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Akadia
{
namespace LoginControl
{
// Implementation of a Login User Control
public class LoginControl : System.Windows.Forms.UserControl
{
private System.Windows.Forms.Label lblUserName;
private System.Windows.Forms.Label lblPassword;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.TextBox txtPassword;
private System.Windows.Forms.Button btnLogin;
private System.Windows.Forms.ErrorProvider erpLoginError;
private System.Windows.Forms.StatusBar stbMessage;
private System.ComponentModel.Container components = null;

// Here we use the predefined System.EventHandler delegate.


// This delegate is useful if you want to define an event
// that has no additional data. The event will be passed an
// empty System.EcentArgs parameter instead. This is the
// delegate used by many of the Windows Forms.
public delegate void EventHandler(Object sender, EventArgs e);
public event EventHandler LoginSuccess;
public event EventHandler LoginFailed;

// Constructor
public LoginControl()
{
InitializeComponent();
}
47
....
....

// This is the very simple Login Check Validation


// The Password mus be ... "secret" .....
private bool LoginCheck(string pName, string pPassword)
{
return pPassword.Equals("secret");
}

// Validate Login, in any case call the LoginSuccess or


// LoginFailed event, which will notify the Application's
// Event Handlers.
private void loginButtonClicked(object sender, System.EventArgs e)
{
// User Name Validation
if (txtUserName.Text.Length == 0)
{
erpLoginError.SetError(txtUserName,"Please enter a user name");
stbMessage.Text = "Please enter a user name";
return;
}
else
{
erpLoginError.SetError(txtUserName,"");
stbMessage.Text = "";
}

// Password Validation
if (txtPassword.Text.Length == 0)
{
erpLoginError.SetError(txtPassword,"Please enter a password");
stbMessage.Text = "Please enter a password";
return;
}
else
{
erpLoginError.SetError(txtPassword,"");
stbMessage.Text = "";
}

// Check Password
if (LoginCheck(txtUserName.Text, txtPassword.Text))
{
// If there any Subscribers for the LoginSuccess
// Event, notify them ...
if (LoginSuccess != null)
{
LoginSuccess(this, new System.EventArgs());
}
}
else
{
// If there any Subscribers for the LoginFailed
// Event, notify them ...
if (LoginFailed != null)
{
LoginFailed(this, new System.EventArgs());
}
}
48
}

// Read-Write Property for User Name Label


public string LabelName
{
get
{
return lblUserName.Text;
}
set
{
lblUserName.Text = value;
}
}

// Read-Write Property for User Name Password


public string LabelPassword
{
get
{
return lblPassword.Text;
}
set
{
lblPassword.Text = value;
}
}

// Read-Write Property for Login Button Text


public string LoginButtonText
{
get
{
return btnLogin.Text;
}
set
{
btnLogin.Text = value;
}
}

// Read-Only Property for User Name


[Browsable(false)]
public string UserName
{
set
{
txtUserName.Text = value;
}
}

// Read-Only Property for Password


[Browsable(false)]
public string Password
{
set
{
txtPassword.Text = value;
}
}
49

}
}
}

Using the Login Validation User Control in a Windows Application

Create a new Windows Application project named: TestApp. Add a reference to the Login Validation
User Control DLL named: LoginControl.dll. Now you are ready to customize the Toolbox: Right-Click
the Toolbox, .NET Framework Components, Browse, select the LoginControl.dll.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestApp
{
// Test Application for the Login Validation User Control
public class TestApp : System.Windows.Forms.Form
{
private Akadia.LoginControl.LoginControl loginControl;
private System.ComponentModel.Container components = null;

....
....

[STAThread]
static void Main()
{
Application.Run(new TestApp());
}

// This Event is fired by the Login Validation User Control


private void LoginFailed(object sender, System.EventArgs e)
{
MessageBox.Show("Login falied ....", "Login Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
50
// This Event is fired by the Login Validation User Control
private void LoginSuccess(object sender, System.EventArgs e)
{
MessageBox.Show("Login success ....", "Login Validation",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}

Format Mask Control

Create the Format Mask Control

An inherited control example is one for a custom masked text box. A masked text box is one that
automatically formats the user's input into the correct format. For example, it may add dashes or
brackets to make sure it looks like a phone number. This task is notoriously difficult. One useful
tool is Microsoft's masked edit text box, which is provided as an ActiveX control with previous
versions of Visual Studio.

The example of a masked text box is important because it demonstrates how features (rather than
data) might be added to an existing control by subclassing. The example is still quite limited-
notably, it restricts deletions and the
use of the arrow keys. Tracking the cursor position, which is required to allow inline masked edits,
results in a good deal of tedious code that only obscures the point.

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Akadia
{
namespace FormatMask
{
// Extended User Control to implement an Edit Mask Text Box
public class EditMask : System.Windows.Forms.TextBox
{
// Fields
private string _mask;

// Properties
public string Mask
{
get { return _mask; }
51
set
{
_mask = value;
this.Text = "";
}
}

// To use the masked control, the application programmer chooses


// a mask and applies it to the Mask property of the control.
// The number sign (#) represents any number, and the period (.)
// represents any letter. All other characters in the mask
// are treated as fixed characters, and are inserted automatically
// when needed. For example, in the phone number mask (###) ###-####
// the first bracket is inserted automatically when the user types
// the first number.
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (Mask != "")
{
// Suppress the typed character.
e.Handled = true;

string newText = this.Text;

// Loop through the mask, adding fixed characters as needed.


// If the next allowed character matches what the user has
// typed in (a number or letter), that is added to the end.
bool finished = false;
for (int i = this.SelectionStart; i < _mask.Length; i++)
{
switch (_mask[i].ToString())
{
case "#" :
// Allow the keypress as long as it is a number.
if (Char.IsDigit(e.KeyChar))
{
newText += e.KeyChar.ToString();
finished = true;
break;
}
else
{
// Invalid entry; exit and don't change the text.
return;
}
case "." :
// Allow the keypress as long as it is a letter.
if (Char.IsLetter(e.KeyChar))
{
newText += e.KeyChar.ToString();
finished = true;
break;
}
else
{
// Invalid entry; exit and don't change the text.
return;
}
default :
// Insert the mask character.
52
newText += _mask[i];
break;
}
if (finished)
{ break; }
}

// Update the text.


this.Text = newText;
this.SelectionStart = this.Text.Length;
}
// base.OnKeyPress(e);
}

// Stop special characters.


protected override void OnKeyDown(KeyEventArgs e)
{
e.Handled = true;
}
}
}
}

Using the Edit Mask User Control in a Windows Application

Create a new Windows Application project named: TestApp. Add a reference to the Edit Mask User
Control DLL named: FormatMask.dll. Now you are ready to customize the Toolbox: Right-Click the
Toolbox, .NET Framework Components, Browse, select the FormatMask.dll.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestApp
{
// Test Application for the Edit mask User Control
public class TestApp : System.Windows.Forms.Form
{
private Akadia.FormatMask.EditMask editMask;
private System.Windows.Forms.Label lblText;
private System.ComponentModel.Container components = null;

public TestApp()
{
InitializeComponent();
}
......
private void InitializeComponent()
{
....
this.editMask.Location = new System.Drawing.Point(93, 63);
this.editMask.Mask = "[###]-(##)-#####";
this.editMask.Name = "editMask";
this.editMask.TabIndex = 0;
....
}
53

static void Main()


{
Application.Run(new TestApp());
}
}
}

Toggle Button User Control

Create the Toggle Button User Control

The Toggle Button User Control is an inherited control. When the user clicks a toggle Button, the
Text and BackColor properties should be set according to the Checked state of the button. The
natural place to do this is the Click event. However, keep in mind that you only want to extend the
default Click event supplied with the CheckBox class rather than replacing is. In the .NET
Framework documentation, you will be notice that controls typically have a protected OnXXX
method that raises each event (where XXX is the name of the event) - for example the Click
event is raised by the OnClick method. The Control call these methods when an event occurs. If you
want to extend the Click event, the Trick is therefore to override the OnClick method.

If the Appearance value is set to Appearance.Normal, then the check box has a typical appearance.
If the value is set to Button, the check box appears like a toggle button, which may be toggled to an
up or down state.

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace Akadia
{
namespace ToggleButton
{
// The ToggleButton class is inherited from the
// System.Windows.Forms.CheckBox Class
public class ToggleButton : System.Windows.Forms.CheckBox
{
// Fields
private string _checkedText;
54
private string _uncheckedText;
private Color _checkedColor;
private Color _uncheckedColor;

// Constructor
public ToggleButton()
{
// If Appearance value is set to Appearance.Normal,
// the check box has a typical appearance.
// If the value is set to Button, the check box appears
// like a toggle button, which may be toggled to
// an up or down state.
this.Appearance = Appearance.Button;

// Set Default toggled Text


this._checkedText = "Checked";
this._uncheckedText = "Unchecked";

// Set Default toggled Color


this._checkedColor = Color.Gray;
this._uncheckedColor = this.BackColor;
}

// Public Properties, can be accessed in Property Panel


public string CheckedText
{
get { return this._checkedText; }
set { this._checkedText = value; }
}

public string UncheckedText


{
get { return this._uncheckedText; }
set { this._uncheckedText = value; }
}

public Color CheckedColor


{
get { return this._checkedColor; }
set { this._checkedColor = value; }
}

public Color UncheckedColor


{
get { return this._uncheckedColor; }
set { this._uncheckedColor = value; }
}

// When the user clicks a toggle Button, the Text and


// BackColor properties should be set according to the Checked
// state of the button. The natural place to do this is
// the Click event. However, keep in mind that you only
// want to extend the default Click event supplied with
// the CheckBox class rather than replacing is. In the .NET
// Framework documentation, you will be notice that controls
// typically have a protected OnXXX method that raises each
// event (where XXX is the name of the event) - for example
// the Click event is raised by the OnClick method. The Control
// call these methods when an event occurs. If you want to
// extend the Click event, the Trick is therefore to override
55
// the OnClick method.
protected override void OnClick(EventArgs e)
{
base.OnClick(e); // Call the CheckBox Baseclass

// Set Text and Color according to the


// current state
if (this.Checked)
{
this.Text = this._checkedText;
this.BackColor = this._checkedColor;
}
else
{
this.Text = this._uncheckedText;
this.BackColor = this._uncheckedColor;
}
}
}
}
}

Using the Toggle Button User Control in a Windows Application

Create a new Windows Application project named: TestApp. Add a reference to the Toggle Button
User Control DLL named: ToggleButton.dll. Now you are ready to customize the Toolbox: Right-Click
the Toolbox, .NET Framework Components, Browse, select the ToggleButton.dll.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestApp
{
// Test Application for the toggled CheckBox und Button
public class TestApp : System.Windows.Forms.Form
{
private Akadia.ToggleButton.ToggleButton btnToggle1;
private Akadia.ToggleButton.ToggleButton btnToggle2;
private Akadia.ToggleButton.ToggleButton btnToggle3;
private System.Windows.Forms.Label lblText1;
private System.Windows.Forms.Label lblText2;
private Akadia.ToggleButton.ToggleButton btnToggle4;
private System.ComponentModel.Container components = null;

public TestApp()
{
InitializeComponent();

// Set Appearance to CheckBox


btnToggle1.Appearance = Appearance.Normal;
btnToggle2.Appearance = Appearance.Normal;
}
......
private void InitializeComponent()
{
56
this.btnToggle1 = new Akadia.ToggleButton.ToggleButton();
this.btnToggle2 = new Akadia.ToggleButton.ToggleButton();
this.btnToggle3 = new Akadia.ToggleButton.ToggleButton();
.....
}

static void Main()


{
Application.Run(new TestApp());
}
}
}

Custom control vs User Control

Overview

In this month's column, I'll discuss the following topics:


• What are user controls?
• What are custom controls?
• What are the basic differences between user controls and custom controls?
I'll also introduce a few of the advanced topics that concern custom controls, such as state
management and the rendering of custom controls.

What are user controls?

User controls are custom, reusable controls, and they use the same techniques that are employed
by HTML and Web server controls. They offer an easy way to partition and reuse common user
interfaces across ASP.NET Web applications. They use the same Web Forms programming model on
which a Web Forms page works. For more details about the Web Forms programming model, visit
the following Microsoft Developer Network (MSDN) Web sites:
Introduction to Web Forms pages
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbconIntroductionToWebForms.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbconIntroductionToWebForms.asp)

Web Forms code model


http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbconwebformscodemodel.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbconwebformscodemodel.asp)

How to create a user control

The syntax you use to create a user control is similar to the syntax you use to create a Web
Forms page (.aspx). The only difference is that a user control does not include the <html>, <body>,
and <form> elements since a Web Forms page hosts the user control. To create a user control, follow
these steps:
Open a text or HTML editor, and create a server-side code block exposing all the properties,
methods, and events.
1.
<script language="C#" runat="server">
57
public void button1_Click(object sender, EventArgs e)

label1.Text = "Hello World!!!";

</script>

Create a user interface for the user control.

<asp:Label id="label1" runat="server"/>


2.
<br><br>

<asp:button id="button1" text="Hit" OnClick="button1_Click" runat="server" />

How to use a user control in a Web Forms page

Create a new Web Forms page (.aspx) in Microsoft Visual Studio .NET 2002, Microsoft Visual
1. Studio .NET 2003, Microsoft Visual Studio 2005, or any text editor.
Declare the @ Register directive. For example, use the following code.

2. <% @ Register TagPrefix="UC" TagName="TestControl" Src="test.ascx" %>

Note Assume that the user control and the Web Forms page are in the same location.
To use the user control in the Web Forms page, use the following code after the @ Register
directive.

<html>

<body>

<form runat="server">
3.
<UC:TestControl id="Test1" runat="server"/>

</form>

</body>

</html>

How to create an instance of a user control programmatically in the code behind file of a Web
Forms page

The previous example instantiated a user control declaratively in a Web Forms page using the @
Register directive. However, you can instantiate a user control dynamically and add it to the page.
Here are the steps for doing that:

1. Create a new Web Forms page in Visual Studio.


58
2. Navigate to the code behind file generated for this Web Forms page.
In the Page_Load event of the Page class, write the following code.

// Load the control by calling LoadControl on the page class.

Control c1 = LoadControl("test.ascx");

// Add the loaded control in the page controls collection.

Page.Controls.Add(c1);

Note You can add a user control dynamically at certain events of the page life cycle.

For more information, visit the following Web sites:


3.
Adding controls to a Web Forms page programmatically
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbtskAddingControlsToWebFormsPageProgrammatically.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/vbcon/html/vbtskAddingControlsToWebFormsPageProgrammatically.asp)

Control execution lifecycle


http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconcontrolexecutionlifecycle.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconcontrolexecutionlifecycle.asp)

Dynamic Web controls, postbacks, and view state, by Scott Mitchell


http://aspnet.4guysfromrolla.com/articles/092904-1.aspx
(http://aspnet.4guysfromrolla.com/articles/092904-1.aspx)

How a user control is processed

When a page with a user control is requested, the following occurs:


The page parser parses the .ascx file specified in the Src attribute in the @ Register directive and

generates a class that derives from the System.Web.UI.UserControl class.
• The parser then dynamically compiles the class into an assembly.
If you are using Visual Studio, then at design time only, Visual Studio creates a code behind file for

the user control, and the file is precompiled by the designer itself.
Finally, the class for the user control, which is generated through the process of dynamic code
• generation and compilation, includes the code for the code behind file (.ascx.cs) as well as the code
written inside the .ascx file.

What are custom controls?

Custom controls are compiled code components that execute on the server, expose the object
model, and render markup text, such as HTML or XML, as a normal Web Form or user control does.

How to choose the base class for your custom control

To write a custom control, you should directly or indirectly derive the new class from the
System.Web.UI.Control class or from the System.Web.UI.WebControls.WebControl class:
You should derive from System.Web.UI.Control if you want the control to render nonvisual

elements. For example, <meta> and <head> are examples of nonvisual rendering.
• You should derive from System.Web.UI.WebControls.WebControl if you want the control to
59
render HTML that generates a visual interface on the client computer.
If you want to change the functionality of existing controls, such as a button or label, you can
directly derive the new class with these existing classes and can change their default behavior.

In brief, the Control class provides the basic functionality by which you can place it in the control
tree for a Page class. The WebControl class adds the functionality to the base Control class for
displaying visual content on the client computer. For example, you can use the WebControl class to
control the look and styles through properties like font, color, and height.

How to create and use a simple custom control that extends from System.Web.UI.Control
using Visual Studio

1. Start Visual Studio.


2. Create a class library project, and give it a name, for example, CustomServerControlsLib.
3. Add a source file to the project, for example, SimpleServerControl.cs.
4. Include the reference of the System.Web namespace in the references section.
Check whether the following namespaces are included in the SimpleServerControl.cs file.

System

System.Collections

System.ComponentModel

System.Data
5.
System.Web

System.Web.SessionState

System.Web.UI

System.Web.UI.WebControls

Inherit the SimpleServerControls class with the Control base class.


6.
public class SimpleServerControl : Control

Override the Render method to write the output to the output stream.

protected override void Render(HtmlTextWriter writer)

7. writer.Write("Hello World from custom control");

Note The HtmlTextWriter class has the functionality of writing HTML to a text stream. The
Write method of the HtmlTextWriter class outputs the specified text to the HTTP response
stream and is the same as the Response.Write method.
8. Compile the class library project. It will generate the DLL output.
9. Open an existing or create a new ASP.NET Web application project.
10. Add a Web Forms page where the custom control can be used.
60
11. Add a reference to the class library in the references section of the ASP.NET project.
Register the custom control on the Web Forms page.

12. <% @ Register TagPrefix="CC " Namespace=" CustomServerControlsLib "


Assembly="CustomServerControlsLib " % >

To instantiate or use the custom control on the Web Forms page, add the following line of code
in the <form> tags.

<form id="Form1" method="post" runat="server">

<CC:SimpleServerControl id="ctlSimpleControl" runat="server">


13.
</CC:SimpleServerControl >

</form>

Note In this code, SimpleServerControl is the control class name inside the class library.
14. Run the Web Forms page, and you will see the output from the custom control.
If you are not using Visual Studio, you need to perform the following steps:
1. Open any text editor.
2. Create a file named SimpleServerControl.cs, and write the code as given in steps 1 through 14.
In the PATH variable, add the following path:
3.
c:\windows (winnt)\Microsoft.Net\Framework\v1.1.4322
4. Start a command prompt, and go to the location where SimpleServerControl.cs is present.
Run the following command:
csc /t:library /out: CustomServerControlsLib. SimpleServerControl.dll /r:System.dll
/r:System.Web.dll SimpleServerControl.cs
For more information about the C# compiler (csc.exe), visit the following MSDN Web site:
5.
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cscomp/html/vcgrfbuildingfromcommandline.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cscomp/html/vcgrfbuildingfromcommandline.asp)
To run the custom control on the Web Forms page, do the following:
a. Create a directory under the wwwroot folder.
Start Microsoft Internet Information Services (IIS) Manager, and mark the new directory as the
b.
virtual root directory.
6. c. Create a Bin folder under the new directory.
d. Copy the custom control DLL into the Bin folder.
Place the sample Web Forms page that you created in the previous steps inside the new
e.
directory.
f. Run the sample page from IIS Manager.
Now that you have built a simple custom control, let's look at how to expose properties and apply
design-time attributes on that custom control.

How to expose properties on the custom control

I will build on the previous example and introduce one or more properties that can be configured
while using the custom control on the Web Forms page.

The following example shows how to define a property that will display a message from the control a
certain number of times, as specified in the property of the control:
1. Open SimpleServerControl.cs in a text editor.
2. Add a property in the SimpleServerControl class.
61

public class SimpleServerControl : Control

private int noOfTimes;

public int NoOfTimes

get { return this.noOfTimes; }

set { this.noOfTimes = value; }

protected override void Render (HtmlTextWriter writer)

for (int i=0; i< NoOfTimes; i++)

write.Write("Hello World.."+"<BR>");

3. Compile the custom control.


To use the custom control on the Web Forms page, add the new property to the control
declaration.
4.
<CC:SimpleServerControl id="ctlSimpleControl" NoOfTimes="5"
runat="server"></CC:SimpleServerControl>

Running the page will display the message "Hello world" from the custom control as many times
5.
as specified in the property of the control.

How to apply design-time attributes on the custom control

Why design-time attributes are needed

The custom control that you built in the previous example works as expected. However, if you
want to use that control in Visual Studio, you may want the NoOfTimes property to be
automatically highlighted in the Properties window whenever the custom control is selected at design
time.

To make this happen, you need to provide the metadata information to Visual Studio, which you can
do by using a feature in Visual Studio called attributes. Attributes can define a class, a method, a
property, or a field. When Visual Studio loads the custom control's class, it checks for any attributes
defined at the class, method, property, or field level and changes the behavior of the custom control
at design time accordingly.
62

To find more information about attributes, visit the following MSDN Web site:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/csref/html/vclrfintroductiontoattributes.asp
(http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/csref/html/vclrfintroductiontoattributes.asp)
Let's build a sample that uses commonly used attributes:
1. Open SimpleServerControl.cs in a text editor.
Introduce some basic attributes at the class level, for example, DefaultProperty, ToolboxData,
and TagPrefixAttrbute. We'll build our sample on these three attributes.

// Specify the default property for the control.

DefaultProperty("DefaultProperty"),

// Specify the tag that is written to the aspx page when the

// control is dragged from the Toolbox to the Design view.

// However this tag is optional since the designer automatically

// generates the default tag if it is not specified.

ToolboxData("<{0}:ControlWithAttributes runat=\"server\">" +

"</{0}:ControlWithAttributes>")

]
2.
public class ControlWithAttributes : Control

{ private string _defaultProperty;

public string DefaultProperty

{ get { return "This is a default property value"; }

set { this._defaultProperty = value; }

protected override void Render(HtmlTextWriter writer)

{ writer.Write("Default Property --> <B>" +

DefaultProperty + "</B>");

There is one more tag called TagPrefixAttrbute. It is an assembly-level attribute that provides a
prefix to a tag when you drag the control from the Toolbox to the designer. Otherwise, the
3. designer generates a prefix such as "cc1" by default. TagPrefixAttrbute is not directly applied to
the control class. To apply TagPrefixAttrbute, open AssemblyInfo.cs, include the following line of
code, and then rebuild the project.
63

[assembly:TagPrefix("ServerControlsLib ", "MyControl")]

Note If you want to build the source using the command line, you need to create the
AssemblyInfo.cs file, place the file in the directory that contains all the source files, and run the
following command to build the control:
> csc /t:library /out: ServerControlsLib.dll /r:System.dll /r :System.Web.dll *.cs

What are the basic differences between user controls and custom controls?

Now that you have a basic idea of what user controls and custom controls are and how to create
them, let's take a quick look at the differences between the two.

Factors User control Custom control


Designed for single-application
scenarios
Designed so that it can be used by more than one
application
Deployed in the source form (.ascx)
along with the source code of the
Deployed either in the application's Bin directory
Deployment application
or in the global assembly cache
If the same control needs to be used
Distributed easily and without problems
in more than one application, it
associated with redundancy and maintenance
introduces redundancy and
maintenance problems
Creation is similar to the way Web
Forms pages are created; well-suited Writing involves lots of code because there is no
Creation
for rapid application development designer support
(RAD)
A much better choice when you need More suited for when an application requires
static content within a fixed layout, dynamic content to be displayed; can be reused
Content
for example, when you make headers across an application, for example, for a data
and footers bound table control with dynamic rows
Writing doesn't require much Writing from scratch requires a good
application designing because they understanding of the control's life cycle and the
Design
are authored at design time and order in which events execute, which is normally
mostly contain static data taken care of in user controls

Delegets

Introduction
A delegate is an object that can refer to a method. Thus, when you create a delegate, you are creating an object
that can hold a reference to a method. Furthermore, the method can be called through this reference. Thus, a
delegate can invoke the method to which it refers (It’s Like a function pointer in c/c++).

Paragraph Heading 1
Even though a method is not an object, it still has a physical location in memory. This address is the entry
point of the method and is the address called when the method is invoked. The address of a method can be
assigned to a delegate. Once a delegate refers to a method, the method can be called through that delegate.
Furthermore, the same delegate can be used to call a different method by simply changing the method to which
the delegate refers. The principal advantage of a delegate is that it allows you to specify a call to a method, but
the method actually invoked is determined at runtime, not at compile time.
64
A delegate is declared using the keyword delegate. The general form of a delegate declaration is shown here:

delegate ret-type name(parameter-list);

Here, ret-type is the type of value returned by the methods that the delegate will be calling. The name of the
delegate is specified by name. The parameters required by the methods called through the delegate are specified
in the parameter-list. Once declared, a delegate can call only methods whose return type and parameter list
match those specified by the delegate.

As mentioned, the key point about delegates is that a delegate can be used to call any method that agrees with
its signature. This makes it possible to determine which method to invoke at runtime. Furthermore, the method
invoked can be an instance method associated with an object, or a static method associated with a class. All
that matters is that the signature of the method agrees with that of the delegate.

To see delegates in action, let’s begin with the simple example shown here:
[]CODE]
// A simple delegate example.
using System;

// Declare a delegate.
delegate string strMod(string str);

class DelegateTest
{
// Replaces spaces with hyphens.
static string replaceSpaces(string a)
{
Console.WriteLine("Replaces spaces with hyphens.");
return a.Replace(' ', '-');
}

// Remove spaces.
static string removeSpaces(string a)
{
string temp = "";
int i;
Console.WriteLine("Removing spaces.");
for(i=0; i < a.Length; i++)
if(a[i] != ' ') temp += a[i];
return temp;
}

// Reverse a string.
static string reverse(string a)
{
string temp = "";
int i, j;
Console.WriteLine("Reversing string.");
for(j=0, i=a.Length-1; i >= 0; i--, j++)
temp += a[i];
return temp;
}

public static void Main()


{
// Construct delegates.
strMod strOp = new strMod(replaceSpaces);
string str;

// Call methods through delegates.


str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();

strOp = new strMod(removeSpaces);


str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
65
Console.WriteLine();

strOp = new strMod(reverse);


str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
}
[]/CODE]}

Multicasting

One of the most exciting features of a delegate is its support for multicasting. In simple terms, multicasting is
the ability to create a chain of methods that will be automatically called when a delegate is invoked. Such a
chain is very easy to create. Simply instantiate a delegate, and then use the += operator to add methods to the
chain. To remove a method, use – =. (You can also use the +, –, and = operators separately to add and subtract
delegates, but += and – = are more convenient.) The only restriction is that the delegate being multicast must
have a void return type.

Example
[]CODE]
// Demonstrate multicasting.
using System;
// Declare a delegate.
delegate void strMod(ref string str);

class StringOps
{
// Replaces spaces with hyphens.
static void replaceSpaces(ref string a)
{
Console.WriteLine("Replaces spaces with hyphens.");
a = a.Replace(' ', '-');
}
// Remove spaces.
static void removeSpaces(ref string a)
{
string temp = "";
int i;
Console.WriteLine("Removing spaces.");
for(i=0; i < a.Length; i++)
if(a[i] != ' ') temp += a[i];
a = temp;
}

// Reverse a string.
static void reverse(ref string a)
{
string temp = "";
int i, j;
Console.WriteLine("Reversing string.");
for(j=0, i=a.Length-1; i >= 0; i--, j++)
temp += a[i];
a = temp;
}

public static void Main()


{
// Construct delegates.
strMod strOp;
strMod replaceSp = new strMod(replaceSpaces);
strMod removeSp = new strMod(removeSpaces);
strMod reverseStr = new strMod(reverse);
string str = "This is a test";

// set up multicast
strOp = replaceSp;
strOp += reverseStr;
66

// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();

// remove replace and add remove


strOp -= replaceSp;
strOp += removeSp;
str = "This is a test."; // reset string

// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
}
[/CODE]}

In general, delegates are useful for two main reasons.


First, delegates support events. Second, delegates give your program a way to execute a method at runtime
without having to know precisely what that method is at compile time. This ability is quite useful when you
want to create a framework that allows components to be plugged in. For example, imagine a drawing program
(a bit like the standard Windows Paint accessory). Using a delegate, you could allow the user to plug in special
color filters or image analyzers. Furthermore, the user could create a sequence of these filters or analyzers.
Such a scheme would be easily handled using a delegate.

Destructor,Finalize and IDisposable Interface

Destructors
Destructors are used to destruct instances of classes.
Remarks
 Destructors cannot be defined in structs. They are only used with classes.
 A class can only have one destructor.
 Destructors cannot be inherited or overloaded.
 Destructors cannot be called. They are invoked automatically.
 A destructor does not take modifiers or have parameters.
For example, the following is a declaration of a destructor for the class Car:
class Car { ~ Car() // destructor { // cleanup statements... } }
The destructor implicitly calls Finalize on the object's base class. Therefore, the preceding destructor
code is implicitly translated to:
protected override void Finalize() { try { // cleanup statements... } finally { base.Finalize(); } }
This means the Finalize method is called recursively for all of the instances in the inheritance chain,
from the most-derived to the least-derived.
Note
Empty destructors should not be used. When a class contains a destructor, an entry is created in
the Finalize queue. When the destructor is called, the garbage collector is invoked to process the
queue. If the destructor is empty, this simply results in a needless loss of performance.
The programmer has no control over when the destructor is called because this is determined by the
garbage collector. The garbage collector checks for objects that are no longer being used by the
application. If it considers an object eligible for destruction, it calls the destructor (if any) and
reclaims the memory used to store the object. Destructors are also called when the program exits.
67
It is possible to force garbage collection by calling Collect but in most cases, this should be
avoided because it may result in performance issues.
68
Using Destructor to release resources

Explicit Release of Resources


If your application is using an expensive external resource, it is also recommended that you provide
a way to explicitly release the resource before the garbage collector frees the object. You do this by
implementing a Dispose method from the IDisposable interface that performs the necessary cleanup
for the object. This can considerably improve the performance of the application. Even with this
explicit control over resources, the destructor becomes a safeguard to clean up resources if the call
to the Dispose method failed.
Example
The following example creates three classes that make a chain of inheritance. The class First is the
base class, Second is derived from First, and Third is derived from Second. All three have
destructors. In Main(), an instance of the most-derived class is created. When the program runs,
notice that the destructors for the three classes are called automatically, and in order, from the
most-derived to the least-derived.
class First { ~First() { System.Console.WriteLine("First's destructor is called"); } } class Second: First {
~Second() { System.Console.WriteLine("Second's destructor is called"); } } class Third: Second {
~Third() { System.Console.WriteLine("Third's destructor is called"); } } class TestDestructors { static
void Main() { Third t = new Third(); } }
Output
Third's destructor is called
Second's destructor is called
First's destructor is called
Object.Finalize Method
Allows an object to attempt to free resources and perform other cleanup operations before the Object
is reclaimed by garbage collection.
Remarks
Finalize is protected and, therefore, is accessible only through this class or a derived class.
This method is automatically called after an object becomes inaccessible, unless the object has been
exempted from finalization by a call to SuppressFinalize. During shutdown of an application domain,
Finalize is automatically called on objects that are not exempt from finalization, even those that are
still accessible. Finalize is automatically called only once on a given instance, unless the object is
re-registered using a mechanism such as ReRegisterForFinalize and GC.SuppressFinalize has not
been subsequently called.
Every implementation of Finalize in a derived type must call its base type's implementation of
Finalize. This is the only case in which application code is allowed to call Finalize.
Finalize operations have the following limitations:
 The exact time when the finalizer executes during garbage collection is undefined. Resources
are not guaranteed to be released at any specific time, unless calling a Close method or a
Dispose method.
 The finalizers of two objects are not guaranteed to run in any specific order, even if one object
refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object
B might have already finalized when the finalizer of Object A starts.
 The thread on which the finalizer is run is unspecified.
The Finalize method might not run to completion or might not run at all in the following exceptional
circumstances:
69
 Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can
never obtain and so on). Because the runtime attempts to run finalizers to completion, other
finalizers might not be called if a finalizer blocks indefinitely.
 The process terminates without giving the runtime a chance to clean up. In this case, the
runtime's first notification of process termination is a DLL_PROCESS_DETACH notification.
The runtime continues to Finalize objects during shutdown only while the number of finalizable
objects continues to decrease.
If Finalize or an override of Finalize throws an exception, and the runtime is not hosted by an
application that overrides the default policy, the runtime terminates the process and no active try-
finally blocks or finalizers are executed. This behavior ensures process integrity if the finalizer
cannot free or destroy resources.
Notes to Implementers: Object.Finalize does nothing by default. It must be overridden by a
derived class only if necessary, because reclamation during garbage collection tends to take much
longer if a Finalize operation must be run. If an Object holds references to any resources, Finalize
must be overridden by a derived class in order to free these resources before the Object is discarded
during garbage collection. A type must implement Finalize when it uses unmanaged resources such
as file handles or database connections that must be released when the managed object that uses
them is reclaimed. See the IDisposable interface for a complementary and more controllable means
of disposing resources. Finalize can take any action, including resurrecting an object (that is,
making the object accessible again) after it has been cleaned up during garbage collection. However,
the object can only be resurrected once; Finalize cannot be called on resurrected objects during
garbage collection.
Destructors are the C# mechanism for performing cleanup operations. Destructors provide
appropriate safeguards, such as automatically calling the base type's destructor. In C# code,
Object.Finalize cannot be called or overridden.
IDisposable Interface
Defines a method to release allocated unmanaged resources.
C#
[ComVisibleAttribute(true)] public interface IDisposable
Remarks
The garbage collector automatically releases the memory allocated to a managed object when that
object is no longer used, however, it is not possible to predict when garbage collection will occur.
Furthermore, the garbage collector has no knowledge of unmanaged resources such as window
handles, or open files and streams.
Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction
with the garbage collector. The consumer of an object can call this method when the object is no
longer needed.
Calling the IDisposable Interface
When calling a class that implements the IDisposable interface, use the try-finally pattern to make
sure that unmanaged resources are disposed of even if an exception interrupts your application.
Note that you can use the using statement (Using in Visual Basic) instead of the try-finally pattern.
Example
C#
using System; using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
70
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed. // If disposing equals false, the method has been called by the // runtime from
inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource. [System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
71
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}

Developing Multilingual Applications

The need for applications that span different cultures increased the demand for the
creation of multilingual applications. The necessity for these applications originated due to
the use of multiple languages across the globe and the different emerging cultures within a
locale. Depending on the languages in a locale, the application needs to display the user’s
locale-specific information in the locale-specific language. This is often referred as
localization. Locale-specific settings include formatting of date, time, calendar
specifications, and so on.

The .NET framework provides support for multilingual applications by creating resource
files. These resource files allow you to specify the locale-specific settings. For each locale,
you can create one resource file and specify the settings for that locale in the resource file.
These resource files are then compiled into satellite assemblies and can be accessed in
the applications by the classes provided by .NET framework.

The .NET framework allows you to create resource files in three different formats namely
text file (.txt) format, .resx format and .resources format. After the creation of these files,
you need to create the satellite assembly. Satellite Assembly can be created in two
methods. One method is to use the AL.exe (Assembly Linker) utility and the other method
is to use the VS.NET utility.

You can create the text format of the resource files, if the resource information is a string
data. If the resources need to contain any embedded objects, then you need to create .resx
file or .resources file. These two file formats can hold object(s) and string data. The text file
format can be created using a text editor such as Notepad. The information will be
specified in the form of key-value pairs.
The .resx file can be created by using the VS.NET IDE. To create a .resx file:
1. In the Project Menu, select Add New Item to display the Add New Item dialog box.
2. Select the Assembly Resource File option from the dialog box. This will add a new .resx
file to your project.
72
You can specify the name and value of the resource information in the created .resx file.
You can also create a resource file to specify a particular locale. There are certain naming
conventions to be followed while creating such files. They should adhere to the syntax
specified below:
< baseFileName >.< locale >.txt
< baseFileName >.< locale >.resx.
For example, when you create a resource file for the locale “kn-IN”, the resource file name
takes the form:

MyResource.kn-IN.txt – in case of the text file


MyResource.kn-IN.resx – in case of the .resx file

When the created resource file is compiled with ResGen.exe (Resource Generation File)
utility, the output will be a CLR binary .resources file. This file can be embedded into a
runtime executable or compiled into a satellite assembly.
Once the .resources file is created, you need to create the satellite assembly. Satellite
assemblies are compiled DLL’s which contains only resource data. These assemblies are
useful to load the data dynamically depending upon the current culture of your
application. These are two methods to create the assembly.

One method is to use the AL.exe utility provided by the .NET SDK. The utility has the
following switches:

/t: Represents the type of the output file


/culture: Represents the name of the locale for which the assembly is being created
/embed: Represents the name of the resource file that needs to be embedded into
the assembly
/out: Represents the name of the output assembly generated
For example, if

the type of output file is a dll file,


the locale is ta-IN,
the name of the resource file is MyResource.ta-IN.resources and
the name of the output assembly is Myresource.resources.dll

then, AL.exe is invoked as,


AL /t: lib /culture: ta-IN /embed: MyResource.ta-IN.resources /out:
Myresource.resources.dll

The assembly thus created is a satellite assembly.

The alternate method of creating a satellite assembly is by using the VS.NET IDE. You can
add a new resource file from the Add New Item submenu of the Project menu. After the
resource information is stored, you need to set the Build option of the resource file to
“Embedded Resource” in the Property window of the file. When the project is compiled,
VS.NET automatically embeds the resource file into the assembly being generated.

Once the required resource files and satellite assemblies are created, the information from
the resource files has to be retrieved to apply it to the GUI application. When a new form is
created, you need to enable the Localization property of the form from its Property window.
73
After enabling the Localization property, any controls that are added to the form will follow
the same localization property. You can choose the language supported by the form using
the Language property of the form. For each language chosen, a resource file will be
created. You can store the resource information in those files.

Retrieving data from the resource files and satellite assemblies can be performed with the
help of the ResourceManager class defined in the System.Resources namespace.

In order to retrieve data from the resource file, you need to create a .resx file by selecting
Add New Item sub-menu of the Project menu. You then specify the file name as
MyResources.ta-IN.resx and specify the key and value for the assembly. For example, you
can create a resource file with the key and value as follows:
Key : f1 ; Value : Sun Flower
Key : f2 ; Value : Lilly.
After saving the file, you have to create the .resources file from the .resx file using the
resgen.exe utility. You have to embed the resource file into an assembly using the al.exe
utility. You then have to write code to read data from the resource files.
The following code shows how to retrieve data from the resource files using the
ResourceManager class:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Resources.

namespace Resource
{
partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)


{
ResourceManager rm = new
ResourceManager("Resource.MyResource",
typeof(Form2).Assembly);
System.Threading.Thread.CurrentThread.CurrentUICulture = new
System.Globalization.CultureInfo("ta-IN");
label1.Text = rm.GetString("f2");
}
}
74
In the above code, Resource.MyResource refers to namespace.resource file name. The
GetString method of the ResourceManager class reads the value from the resource file and
applies it to the Label control.

The following figure displays the output of executing the above code:

The following code shows how to retrieve data from the satellite assemblies using the
ResourceManager class:

System.Resources.ResourceManager rm = new
System.Resources.ResourceManager(Resource.Form2_ta_IN);
System.Resources.ResourceManager x;
System.Globalization.CultureInfo ci = new CultureInfo("ta-IN");
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
x = new ResourceManager("myresource.ta-IN",
[Assembly].GetExecutingAssembly.GetSatelliteAssembly(ci));
Label1.Text=x.GetString("f1");

In the above code, you retrieve the value of the satellite assembly with respect to the
culture specified by the ci variable.

Thus, the resource files created manually or by the VS.NET runtime allows you to store the
locale specific settings for a particular form. When a form is localized to more than one
culture, the application developed becomes a multilingual application.

The Microsoft .NET Framework was designed keeping in mind the international markets and the
necessity of globalization or internationalization of the software applications designed on top of the
.NET Framework. The .NET Framework provides a powerful support for localization through the
System.Globalization, System.Resources and System.Threading namespaces. This article discusses
the concepts of Globalization and Localization and how we can implement a multilingual application
in .NET.

What is Localization and Globalization?


[ Back To Top ]

Localization is the process of adapting a software application for a specific locale. It is defined as the
process of creating and configuring an application for supporting a specific language or locale.
Globalization is defined as the process of identifying the specific portion of the application that
needs to be different for different languages and how to isolate them from the application's core.
Therefore, it is the process of identifying the localizable resources of the application.
75
The Microsoft .NET library provides support for globalization and localization using the following
namespaces.
System.Globalization
System.Resources
System.Text
System.Threading
The System.Globalization namespace provides support for developing multilingual applications in
Microsoft .NET by allowing the developers to define culture specific information. The sections that
follow discuss cultures and how to work with them in .NET. The System.Resources namespace
provides support to create, store and manage various culture-specific resources used in an
application. It contains a class called ResourceManager that allows access to resources either from
the main assembly or those that are present in Satellite Assemblies. We will discuss both
ResourceManager and Satellite Assemblies in more detail later in this article. The System.Text
namespace provides support for representing various character encodings like ASCII, Unicode, UTF-
7 and UTF-8. The System.Threading namespace contains classes and interfaces that provide
support for multithreaded programming.

Culture
[ Back To Top ]

The term Culture denotes a combination of a geographical location and the language spoken in it. A
Culture can be represented in any of the ways shown below.
en-US
en-GB
The former refers to English language that is spoken in the US while the latter implies that which is
spoken in Great Britain.

Working with Culture Information


[ Back To Top ]

Microsoft .NET provides support for working with culture specific information using the CultureInfo
class in the System.Globalization namespace. Culture information can be set both at the page level
as well as at the application level.
To set the Culture information at the page levels use the following in the Page directive of the
ASP.NET page.
Listing 1
<% @ Page language="C#" Culture="fr-FR"%>
This statement in listing 1 would ensure that the culture information is applicable only for this
particular page in the application.
To set the Culture information at the application level, use the following in the Globalization section
of the web.config file.
Listing 2
<configuration>
<system.web>
<globalization
culture="en-GB"
/>
</system.web>
</configuration>
This specification as shown in listing 2 in the web.config file would ensure that the culture
information is applicable throughout the application.

Resource Files
76
[ Back To Top ]

A resource file consists of non-executable data that is required by the application and is deployed
along with it. Bitmaps, icons, cursors, etc. are typical examples of resource files. Microsoft .NET
provides support for multilingual applications using resource files. The resource files used to create
a multilingual application contain the culture dependent resources for the application. A resource
file can be used to specify the locale-specific settings. Note that to support each locale in the
application, there should be one resource file created. These resource files are then compiled into
satellite assemblies and accessed by the application. Resource files can be either text files or resx
files in .NET.
The basic advantages of using resource files are given below.
Support for Globalization with isolation of the resource content from the application
Reusability and the provision for change of the resource content without the need to change
the application's code
It should be noted that each resource file has support for a specific culture. Hence, if we need to
have support for "n" cultures, we need to have "n" different resource files.
Creating Resource Files
First create a resource file using the VS.NET IDE and save using either a .txt or a .resx extension.
The resource file should be created using the intended culture if it is to be used for Globalization or
Localization purposes.
When creating resource files for specific locales, the following naming convention should be followed.
<base file name>.<locale>.txt
or
<base file name>.<locale>.resx
Therefore the resource file targetted at en-GB locale should be named as TestResource.en-GB.txt or
TestResource.en-GB.resx. Note that the resource file name TestResource.en-GB.resx contains the
name of the resource that it is intended at.
The ResourceWriter class in the System.Resources namespace is used to create a resource
programmatically. The sample code below creates a resource file called Test.Resources in the root
directory of the C drive.
Listing 3
using System;
using System.Resources;
class CreateResources
{
public static void Main(string[]args)
{
ResourceWriter rw = new ResourceWriter("C:\\Test.resources");
rw.AddResource("CopyRight", "CopyRight Message in English");
rw.Close();
}
}
The ResourceWriter class can also be used to store any other serializable object in the resource file.
Reading Resource Files
The content of the resource files can be read in the application using the ResourceManager class
defined in the System.Resources namespace. The ResourceManager class looks up culture-specific
resources and provides convenient access to culture-specific resources at runtime. According to
MSDN, "The Resource Manager class looks up culture-specific resources, provides resource fallback
when a localized resource does not exist, and supports resource serialization."
Listing 4
ResourceManager resourceManager = new
ResourceManager("Internationalization.en-GB"+culture, Assembly.GetExecutingAssembly());
77
CultureInfo cultureInfo = new CultureInfo(culture);
string message = resourceManager.GetString("ID",cultureInfo);
Compiling Resource Files
Refer to the section above. Note that we had created a resource file named TestResource.en-
GB.resx. Now let us compile the resource using the ResGen utility shipped with the Microsoft .NET
Framework to create a compiled resource that would have a .resources extension.
Listing 5
resgen Internationalization.en-GB.resx Internationalization.en-GB.resources
When used, the above command line tool would compile the .resx file to a compiled binary
.resources file for the en-GB locale.

Working with Embedded Resource Files


[ Back To Top ]

An embedded resource is one that is embedded inside the application's code. Thus, when the
application is compiled, this resource gets stored in the assembly that is generated after the
compilation of the application's code. Let us create a text resource file called TextFile.txt and make
the same an embedded resource by selecting the properties of the same file and then setting the
Build Action in the item properties to "Embedded Resource." This means the resource will be
embedded directly into the current assembly along with the code. Further, let the resource file that
has just been created contain a text message.
The following code snippet shows how we can retrieve the content of the resource as a string from
the current executing assembly.
Listing 6
public string GetResourceFromAssembly(string resourceName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
TextReader txtReader = new
StreamReader(assembly.GetManifestResourceStream(resourceName));
string str = txtReader.ReadToEnd();
txtReader.Close();
return str;
}
The above method accepts the fully qualified path to the resource as a parameter and returns the
resource as a string from the current executing assembly. Invoke the above method as shown
below.
Listing 7
Response.Write(GetResourceFromAssembly("Test.TextFile.txt"));
The GetResourceFromAssembly method would return the resource value from the specified resource
file.
It is also possible to list all the embedded resources in the assembly as shown in the section below.
The following method shows how we can display the names of all the embedded resources in the
current executing assembly.
Listing 8
public string GetResourceNamesFromAssembly()
{
Assembly assembly = Assembly.GetExecutingAssembly();
string [] resourceNames = assembly.GetManifestResourceNames();
StringBuilder stringBuilder = new StringBuilder();
foreach(string str in resourceNames)
{
stringBuilder.Append(str);
stringBuilder.Append("<BR>");
}
return stringBuilder.ToString();
}
78
The above method would return all the resource names from the current executing assembly. Invoke
the above method as shown in the listing below.
Listing 9
Response.Write(GetResourceNamesFromAssembly());
Satellite Assemblies
[ Back To Top ]

An assembly is essentially a portable executable or library file containing partially compiled code for
use in deployment, security and versioning in Microsoft .NET's managed environment. The
assembly is compiled into the machine language instructions by the CLR.
Satellite Assemblies are special assemblies that only contain resources and are associated with the
main assembly. Satellite assemblies are used to store compiled localized application resources.
They contain only resource data and no other code. Satellite assemblies are used to load the data
dynamically depending upon the culture of the application. They can be created using the AL utility
tool provided with Microsoft .NET SDK. With satellite assemblies, resources are embedded in a
binary format within a DLL. This makes the resources not very visible to the user and ensures
faster access. These assemblies can be deployed even after deployment of the application.
Refer to the earlier sections where we had already created a resource file that was intended for UK
English culture. We had then compiled the same to create a compiled resource file using the resgen
utility. Now we can use the AL utility shipped with the Microsoft .NET SDK to create a satellite
assembly from a compiled resource file as shown below.
Listing 10
al /t:lib /culture:en-GB /embed: Internationalization.en-GB.resources
/out: Internationalization.resources.dll
The output file Internationalization.en-GB.resources is a satellite assembly file that is created for the
en-GB locale from the compiled resource file. The .NET Framework Developer's Guide, MSDN,
states, "Ideally, you should package the resources for the default or neutral assembly with the main
assembly and create a separate satellite assembly for each language that your application supports."

Implementing Multilingual Applications


[ Back To Top ]

A Multilingual application is one that provides support for multiple languages. This section
discusses how we can implement a multilingual application in .NET using the concepts explained
earlier. The steps for implementing a multilingual application in .NET can be summarized as the
following.
Create a resource file for each locale.
Save the resource files with a .resx extension.
Compile the resource files using resgen utility of .NET SDK to create a compiled binary
resource file.
Create satellite assembly using al utility of .NET SDK.
Create folders for storing the satellite assembly and store the satellite assembly there.
Read resources from the satellite assembly in the application's source code.
First, we have to create culture specific resources in resource files. Then we can store the culture
specific data in the resource file and save the same with a .resx extension. Note that the culture
name should be provided in the resource file name to follow the resource file naming convention. We
can use Visual Studio .NET to create a resource for a particular culture. Resource files have been
explained in more detail earlier. Let us assume that a file Internationalization.en-GB.resx be created
for en-GB culture and compiled (as shown in listing 4) to create the Internationalization.en-
GB.resources file. This file is the complied resources file. This compiled resource file can be used to
create a satellite assembly. This satellite assembly can then be used by the application. Refer to
code listing 9. The file Internationalization.resources.dll is a satellite assembly. This satellite
assembly should now be placed in a sub folder inside the application's main folder and the name of
79
this sub folder should be the same as the name of the culture that the satellite assembly is targeted
for. This satellite assembly can now be used to display locale specific information in the application.

The CultureInfo class


[ Back To Top ]

The CultureInfo class of the .NET Framework SDK provides access to the properties of a locale. An
instance of the CultureInfo class can be created by passing the culture name as a string parameter.
The following code can be used to create a CultureInfo instance for French spoken in France.
Listing 11
CultureInfo c = new CultureInfo("en-FR");
The following code can be used to create a CultureInfo instance for UK English locale.
Listing 12
CultureInfo c = new CultureInfo("en-GB");
Configuring Localization in our Application
[ Back To Top ]

In order to ensure that we do not require changing the application source code each time we require
to have support for a newer culture in the application, we can ensure even loose coupling by setting
the culture name in the web.config file. This ensures that the application's culture settings are
configurable. This information can be read by the application at run time and the appropriate
culture settings set accordingly.
The <appSettings> element of the web.config file can be used to specify the culture name as shown
below.
Listing 13
<appSettings>
<add key = "Culture" value = "fr-FR">
</add>
</appSettings>

Or
Listing 14
<appSettings>
<add key = "Culture" value = "en-GB">
</add>
</appSettings>
Note that fr-FR refers to French language that is spoken in France while en-GB refers to English
language that is spoken in Great Britain.
The culture type that is specified in the web.config file can be read by using
System.ConfigurationSettings.AppSettings in the source code. Note that
System.Configuration.ConfigurationSettings.AppSettings is a class in the System.Configuration
namespace in the system.dll assembly. The source code is provided below.
Listing 15
string culture =
System.Configuration.ConfigurationSettings.AppSettings["Culture"].ToString();
ResourceManager resourceManager = new
ResourceManager(typeof(TestForm).Namespace.ToString()+"."+culture,
Assembly.GetExecutingAssembly());
CultureInfo cultureInfo = new CultureInfo(culture);
string message = resourceManager.GetString("ID",cultureInfo);
Response.Write(message);
In the code listing shown above, an instance of the ResourceManager class is created by passing the
resource and the assembly in which the resource is embedded as parameters. Here the culture and
a reference of the current executing assembly are passed to it as parameters. Then an object of the
CultureInfo class is created and the culture name passed to the parameterized constructor of the
80
class. The ResourceManager class enables access to the resources for a particular culture using the
GetObject and GetString methods. Now we have to call the GetString method on the
ResourceManager instance and pass the ID string as key and the instance of the CultureInfo class
as parameters. The resource value is returned as string and the same can now be used as needed in
the application. For the sake of simplicity, I have displayed the message using Response.Write
method. This concept can be used to set the text of a particular control in a specific language by
reading the locale specific text from the resource. The current locale is specified in the web.config
file.
As an example, to set the copyright on a label control in the web from use the code provided below.
Listing 16
lblCopyright.Text = resourceManager.GetString("Copyright",culture);
Here the copyright message would be displayed in the label control based on the current culture that
is set using the web.config file as explained earlier.
Note that either the satellite assembly or the application's assembly should have the resources for all
the cultures to be supported by the application.

DOT NET QUESTIONS & ANSW

Some of the questions are


1. Explain the code behind wors and contrast that using the inline style.
2. Different types of HTML,Web and server controls (also how Server control validation controls
work)
4. Difference btn user and server controls
4. How server form post-back works (perhaps ask about view state as well).
5. Can the action attribute of a server-side <form> tag be set to a value and if not how can you
possibly pass data from a form page to a subsequent page.
6. What is the role of global.asax.
7. How would ASP and ASP.NET apps run at the same time on the same server?
8. What are good ADO.NET object(s) to replace the ADO Recordset object.

In addition to the above some couple of basic questions, a couple of additional questions listed
below. Good luck!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Explain the differences between Server-side and Client-side code?
2. What type of code (server or client) is found in a Code-Behind
class?
3. Should validation (did the user enter a real date) occur
server-side or client-side? Why?
4. What does the "EnableViewState" property do? Why would I want it on or off?
5. What is the difference between Server.Transfer and
Response.Redirect? Why
would I choose one over the other?
6. Can you give an example of when it would be appropriate to use a
web service as opposed to a non-serviced .NET component
7. Let's say I have an existing application written using Visual
Studio 6 (VB 6, InterDev 6) and this application utilizes Windows 2000
COM+ transaction services. How would you approach migrating this
application to .NET
8. Can you explain the difference between an ADO.NET Dataset and an
ADO Recordset?
9. Can you give an example of what might be best suited to place in
the Application_Start and Session_Start subroutines?
10. If I'm developing an application that must accomodate multiple
security levels though secure login and my ASP.NET web appplication is
spanned across three web-servers (using round-robbin load balancing)
81
what would be the best approach to maintain login-in state for the
users?
11. What are ASP.NET Web Forms? How is this technology different than
what is available though ASP (1.0-3.0)?
12. How does VB.NET/C# achieve polymorphism?
11. Can you explain what inheritance is and an example of when you
might use it?
13. How would you implement inheritance using VB.NET/C#?
14. Whats an assembly
15. Describe the difference between inline and code behind - which is
best in a
16. loosely coupled solution
17. Explain what a diffgram is, and a good use for one
18. Where would you use an iHTTPModule, and what are the limitations
of any
19. approach you might take in implementing one
20. What are the disadvantages of viewstate/what are the benefits
21 Describe session handling in a webfarm, how does it work and what
are the > limits
22. How would you get ASP.NET running in Apache web servers - why
would you even do this?
23. Whats MSIL, and why should my developers need an appreciation of
it if at all?
24. In what order do the events of an ASPX page execute. As a
developer is it important to undertsand these events?
25. Which method do you invoke on the DataAdapter control to load your
generated dataset with data?
26. Can you edit data in the Repeater control?
27. Which template must you provide, in order to display data in a
Repeater control?
28. How can you provide an alternating color scheme in a Repeater
control?
29. What property must you set, and what method must you call in your
code, in order to bind the data from some data source to the Repeater
control?
30. What base class do all Web Forms inherit from?
31. What method do you use to explicitly kill a user s session?
32 How do you turn off cookies for one page in your site?
33. Which two properties are on every validation control?
34. What tags do you need to add within the asp:datagrid tags to bind
columns manually?
35. How do you create a permanent cookie?
36. What tag do you use to add a hyperlink column to the DataGrid?
37. What is the standard you use to wrap up a call to a Web service
38. Which method do you use to redirect the user to another page
without performing a round trip to the client?
39. What is the transport protocol you use to call a Web service SOAP
40. True or False: A Web service can only be written in .NET
41. What does WSDL stand for?
42. What property do you have to set to tell the grid which page to go
to when using the Pager object?
43. Where on the Internet would you look for Web services?
44. What tags do you need to add within the asp:datagrid tags to bind
columns manually.
45. Which property on a Combo Box do you set with a column name, prior to setting the
DataSource, to display data in the combo box?
46. How is a property designated as read-only?
47. Which control would you use if you needed to make sure the values
in two different controls matched?
48. True or False: To test a Web service you must create a windows
82
application or Web application to consume this service?
49. How many classes can a single .NET DLL contain?

ANSWEAR

Alot of these answers are way to detailed to be explained in a couple of sentences...your better off
researching them.
I will answer the ones that can be answered pretty plainly.

3. Server controls are built-in. User controls are created by the developer to allow for the reuse of
controls that need specific functionality.

4. By default all pages in .NET post back to themselves. The view state keeps the users input
updated on the page.

5. No, You have to use Server.Transfer to pass the data to another page.

6. Store global information about the application

8. There are alot...but the base once are SqlConnection, OleDbConnection, etc...
----------------------------------------------------------------------------------

1. Server-side code runs on the server, Client-side code runs on the client.

2. Server

3. Client...so the user doesn't have to wait for the page to be posted to the server and then returned.

4. Enables the ability to maintain the state of the page and all data within it.

5. Server.Trasfer allows you to pass variables to another page. Server.Redirect just redirects the user
to another page.

6. When there is no need for a UI to perform the required task.

8. By default Datasets are disconnected.

9. Any variables that need to be set for the application or session objects. Example: For the path of a
image directory
Application("ImagePath") = "C:\Images\"

13. VB.NET use the Implements keyword to inherit from another class or interface. C# use : to
inherit
example
Code:
VB.NET

class myClass
Inherits baseClass

End class

C#
class myClass : baseClass
14. An assembly is the collection of all information required by the runtime to execute your
application.

15. Inline is mixed with the html, code-behind is separated. Use code-behind.
83

17. An XML format. Can be used by other platforms so send and receive data to a .NET application

23. Microsoft Intermediate Language

24. You mean the steps of the page lifetime? or that .NET is event driven?

25. Fill method

26. Yes

27. ItemTemplate

28. AlternatingItemTemplate

29. Set the datasource property and call the DataBind method

30. Page...but all .NET objects inherit form the Object Base Class.

31. Session.Contents.Remove

32. You can't (not that I am aware of...since there is no Page level directive to do this)

34. Set AutoGenerateColumns Property to false on the datagrid tag

36. <asp:HyperLinkColumn>

39. SOAP is preferred protocol

40. False

41. Web Services Description Language

42. CurrentPageIndex

43. www.uddi.org

45. DataTextField

46. Only a Get method...no, Set method

47. CompareValidator

48. False, the webservice comes with a test page and it provides HTTP-GET method to test.

49. Many
84
FAQNET .NET and the Microsoft .NET Framework.

Q1-What is .NET?
Simply put, Microsoft® .NET is Microsoft's strategy for delivering software as a service. For complete
information, read this whitepaper on the topic.
An excerpt from that paper briefly describes the key points of .NET:
1. Microsoft .NET platform
Includes .NET infrastructure and tools to build and operate a new generation of services, .NET
user experience to enable rich clients, .NET building block services and .NET device software to
enable a new generation of smart Internet devices.
2. Microsoft .NET products and services
Includes Microsoft® Windows.NET (with a core integrated set of building block services),
MSN.NET, personal subscription services, Microsoft® Office.NET, Microsoft® Visual
Studio.NET, and Microsoft® bCentral™ for .NET.
3. Third-party .NET services
A vast range of partners and developers will have the opportunity to produce corporate and
vertical services built on the .NET platform.
This FAQ targets the .NET Framework, which is a piece of the .NET platform's infrastructure. See the
next question to learn more about the .NET Framework.

Q2-What is the .NET Framework?


The .NET Framework is an environment for building, deploying, and running Web Services and other
applications. It consists of three main parts: the Common Language Runtime, the Framework classes,
and ASP.NET.

Q3-Does the .NET Framework only apply to people building Web sites?
The .NET Framework enables you to create great Web applications. However, it can also help you build
the same applications you build today. If you write any Windows software (using ATL/COM, MFC,
Microsoft® Visual Basic®, or even standard Microsoft® Win32®), .NET offers many advantages to the
way you currently build applications. Of course, if you do develop Web sites, then the .NET Framework
has a lot to interest you—starting with ASP.NET.

Q4-Where can I get the .NET Framework SDK?


The Beta 1 of the .NET Framework SDK is now available for public download at MSDN Online
Downloads. Because of its size, we offer this beta as a single download (106 MB), an 11-part download,
or you can order the CD from Microsoft Developer Store:
1. United States/Canada
2. International
Q5-On what platforms will the .NET Framework run?
The Beta 1 version will run on Microsoft® Windows® 2000, Windows 95/98/ME, and Windows NT®
4.0.
There is also a version of the .NET Framework called the .NET Compact Framework. It is designed to
bring some of the capabilities of the .NET Framework to devices such as cell phones and enhanced
televisions. The .NET Compact Framework will run on Windows CE and other embedded operating
systems.

Q6-What programming languages will the .NET Framework support?


The .NET Framework is language neutral; virtually any language can target the .NET Framework.
Currently, you can build .NET programs in a number of languages, including C++, Microsoft® Visual
Basic.NET, _JScript®, and Microsoft's newest language—C#. A large number of third-party languages
will also be available for building .NET Framework applications. These languages include COBOL,
Eiffel, Perl, Python, Smalltalk, and others.

Q7-What is the relationship between the .NET Framework and COM+ Services?
The .NET Framework gives you full access to COM+ services, while also making it easier to build
serviced components.
.NET Framework components can be added to a COM+ application. There they can take advantage of
automatic component services such as transactions, object pooling, queued components, events, and
so on.
85

Q8-What is the relationship between the .NET Framework and DCOM?


DCOM is the COM infrastructure for cross-process communication. The .NET Framework supports a
number of pluggable channels and formatters for cross-process communication. When making
transitions between managed and unmanaged code, the .NET Framework uses the COM
infrastructure, specifically, DCOM. All scenarios using COM+ services use managed-to-unmanaged
transitions, and thus use DCOM by default. The .NET Framework also supports SOAP, the Simple
Object Access Protocol, for cross-process communication where interoperability is critical.

Q9-Is the .NET Framework just a new name for Windows DNA?
No. Windows DNA is architecture for building tightly-coupled, distributed Web applications. As the
needs of distributed applications changed to require more loosely-coupled principles, Microsoft evolved
the architecture to .NET. The .NET Framework is a part of the .NET architecture.

Runtime Technical Questions


Terminology
Q10-What is the Common Language Runtime (CLR)?
The Common Language Runtime is the execution engine for .NET Framework applications.
It provides a number of services, including the following:
1. Code management (loading and execution)
2. Application memory isolation
3. Verification of type safety
4. Conversion of IL to native code
5. Access to metadata (enhanced type information)
6. Managing memory for managed objects
7. Enforcement of code access security
8. Exception handling, including cross-language exceptions
9. Interoperation between managed code, COM objects, and pre-existing DLLs (unmanaged code
and data)
10. Automation of object layout
11. Support for developer services (profiling, debugging, and so on)

Q11-What is the common type system (CTS)?


The common type system is a rich type system, built into the Common Language Runtime, that
supports the types and operations found in most programming languages. The common type system
supports the complete implementation of a wide range of programming languages.

Q12-What is the Common Language Specification (CLS)?


The Common Language Specification is a set of constructs and constraints that serves as a guide for
library writers and compiler writers. It allows libraries to be fully usable from any language supporting
the CLS, and for those languages to integrate with each other. The Common Language Specification is
a subset of the common type system. The Common Language Specification is also important to
application developers who are writing code that will be used by other developers. When developers
design publicly accessible APIs following the rules of the CLS, those APIs are easily used from all other
programming languages that target the Common Language Runtime.

Q13-What is the Microsoft Intermediate Language (MSIL)?


MSIL is the CPU-independent instruction set into which .NET Framework programs are compiled. It
contains instructions for loading, storing, initializing, and calling methods on objects.
Combined with metadata and the common type system, MSIL allows for true cross-language
integration.
Prior to execution, MSIL is converted to machine code. It is not interpreted.

Q14-What is managed code and managed data?


Managed code is code that is written to target the services of the Common Language Runtime (see
What is the Common Language Runtime?). In order to target these services, the code must provide a
minimum level of information (metadata) to the runtime. All C#, Visual Basic.NET, and _JScript.NET
code is managed by default. Visual Studio.NET C++ code is not managed by default, but the compiler
can produce managed code by specifying a command-line switch (/CLR).
Closely related to managed code is managed data—data that is allocated and de-allocated by the
86
Common Language Runtime's garbage collector. C#, Visual Basic, and _JScript.NET data is managed
by default. C# data can, however, be marked as unmanaged through the use of special keywords.
Visual Studio.NET C++ data is unmanaged by default (even when using the /CLR switch), but when
using Managed Extensions for C++, a class can be marked as managed by using the __gc keyword. As
the name suggests, this means that the memory for instances of the class is managed by the garbage
collector. In addition, the class becomes a full participating member of the .NET Framework
community, with the benefits and restrictions that brings. An example of a benefit is proper
interoperability with classes written in other languages (for example, a managed C++ class can inherit
from a Visual Basic class). An example of a restriction is that a managed class can only inherit from
one base class.

Assemblies

Q15-What is an assembly?
An assembly is the primary building block of a .NET Framework application. It is a collection of
functionality that is built, versioned, and deployed as a single implementation unit (as one or more
files). All managed types and resources are marked either as accessible only within their
implementation unit, or as accessible by code outside that unit.
Assemblies are self-describing by means of their manifest, which is an integral part of every assembly.
The manifest:
1. Establishes the assembly identity (in the form of a text name), version, culture, and digital
signature (if the assembly is to be shared across applications).
2. Defines what files (by name and file hash) make up the assembly implementation.
3. Specifies the types and resources that make up the assembly, including which are exported
from the assembly.
4. Itemizes the compile-time dependencies on other assemblies.
5. Specifies the set of permissions required for the assembly to run properly.
This information is used at run time to resolve references, enforce version binding policy, and validate
the integrity of loaded assemblies. The runtime can determine and locate the assembly for any running
object, since every type is loaded in the context of an assembly. Assemblies are also the unit at which
code access security permissions are applied. The identity evidence for each assembly is considered
separately when determining what permissions to grant the code it contains.
The self-describing nature of assemblies also helps makes zero-impact install and XCOPY deployment
feasible.

Q16-What are private assemblies and shared assemblies?


A private assembly is used only by a single application, and is stored in that application's install
directory (or a subdirectory therein). A shared assembly is one that can be referenced by more than
one application. In order to share an assembly, the assembly must be explicitly built for this purpose
by giving it a cryptographically strong name (referred to as a shared name). By contrast, a private
assembly name need only be unique within the application that uses it.
By making a distinction between private and shared assemblies, we introduce the notion of sharing as
an explicit decision. Simply by deploying private assemblies to an application directory, you can
guarantee that that application will run only with the bits it was built and deployed with. References
to private assemblies will only be resolved locally to the private application directory.
There are several reasons you may elect to build and use shared assemblies, such as the ability to
express version policy. The fact that shared assemblies have a cryptographically strong name means
that only the author of the assembly has the key to produce a new version of that assembly. Thus, if
you make a policy statement that says you want to accept a new version of an assembly, you can have
some confidence that version updates will be controlled and verified by the author. Otherwise, you
don’t have to accept them.
For locally installed applications, a shared assembly is typically explicitly installed into the global
assembly cache (a local cache of assemblies maintained by the .NET Framework). Key to the version
management features of the .NET Framework is that downloaded code does not affect the execution of
locally installed applications. Downloaded code is put in a special download cache and is not globally
available on the machine even if some of the downloaded components are built as shared assemblies.
The classes that ship with the .NET Framework are all built as shared assemblies.

Q17-If I want to build a shared assembly, does that require the overhead of signing and
managing key pairs?
87
Building a shared assembly does involve working with cryptographic keys. Only the public key is
strictly needed when the assembly is being built. Compilers targeting the .NET Framework provide
command line options (or use custom attributes) for supplying the public key when building the
assembly. It is common to keep a copy of a common public key in a source database and point build
scripts to this key. Before the assembly is shipped, the assembly must be fully signed with the
corresponding private key. This is done using an SDK tool called SN.exe (Strong Name).
Strong name signing does not involve certificates like Authenticode does. There are no third party
organizations involved, no fees to pay, and no certificate chains. In addition, the overhead for verifying
a strong name is much less than it is for Authenticode. However, strong names do not make any
statements about trusting a particular publisher. Strong names allow you to ensure that the contents
of a given assembly haven't been tampered with, and that the assembly loaded on your behalf at run
time comes from the same publisher as the one you developed against. But it makes no statement
about whether you can trust the identity of that publisher.

Q18-What is the difference between a namespace and an assembly name?


A namespace is a logical naming scheme for types in which a simple type name, such as MyType, is
preceded with a dot-separated hierarchical name. Such a naming scheme is completely under the
control of the developer. For example, types MyCompany.FileAccess.A and MyCompany.FileAccess.B
might be logically expected to have functionality related to file access. The .NET Framework uses a
hierarchical naming scheme for grouping types into logical categories of related functionality, such as
the ASP.NET application framework, or remoting functionality. Design tools can make use of
namespaces to make it easier for developers to browse and reference types in their code. The concept
of a namespace is not related to that of an assembly. A single assembly may contain types whose
hierarchical names have different namespace roots, and a logical namespace root may span multiple
assemblies. In the .NET Framework, a namespace is a logical design-time naming convenience,
whereas an assembly establishes the name scope for types at run time.

Application Deployment and Isolation

Q19-What options are available to deploy my .NET applications?


The .NET Framework simplifies deployment by making zero-impact install and XCOPY deployment of
applications feasible. Because all requests are resolved first to the private application directory, simply
copying an application’s directory files to disk is all that is needed to run the application. No
registration is required.
This scenario is particularly compelling for Web applications, Web Services, and self-contained
desktop applications. However, there are scenarios where XCOPY is not sufficient as a distribution
mechanism. An example is when the application has little private code and relies on the availability of
shared assemblies, or when the application is not locally installed (but rather downloaded on demand).
For these cases, the .NET Framework provides extensive code download services and integration with
the Windows Installer. The code download support provided by the .NET Framework offers several
advantages over current platforms, including incremental download, code access security (no more
Authenticode dialogs), and application isolation (code downloaded on behalf of one application doesn't
affect other applications). The Windows Installer is another powerful deployment mechanism available
to .NET applications. All of the features of Windows Installer, including publishing, advertisement, and
application repair will be available to .NET applications in Windows Installer 1.5.

Q20-I've written an assembly that I want to use in more than one application. Where do I deploy
it?
Assemblies that are to be used by multiple applications (for example, shared assemblies) are deployed
to the global assembly cache. In the prerelease and Beta builds, use the /i option to the Alink SDK
tool to install an assembly into the cache:
al /i:myDll.dll
A future version of the Windows Installer will be able to install assemblies into the global assembly
cache.

Q21-How can I see what assemblies are installed in the global assembly cache?
The .NET Framework ships with a Windows shell extension for viewing the assembly cache. Navigating
to % windir% \assembly with the Windows Explorer activates the viewer.

Q22-What is an application domain?


88
An application domain (often AppDomain) is a virtual process that serves to isolate an application. All
objects created within the same application scope (in other words, anywhere along the sequence of
object activations beginning with the application entry point) are created within the same application
domain. Multiple application domains can exist in a single operating system process, making them a
lightweight means of application isolation.
An OS process provides isolation by having a distinct memory address space. While this is effective, it
is also expensive, and does not scale to the numbers required for large web servers. The Common
Language Runtime, on the other hand, enforces application isolation by managing the memory use of
code running within the application domain. This ensures that it does not access memory outside the
boundaries of the domain. It is important to note that only type-safe code can be managed in this way
(the runtime cannot guarantee isolation when unsafe code is loaded in an application domain).

Garbage Collection

Q23-What is garbage collection?


Garbage collection is a mechanism that allows the computer to detect when an object can no longer be
accessed. It then automatically releases the memory used by that object (as well as calling a clean-up
routine, called a "finalizer," which is written by the user). Some garbage collectors, like the one used by
.NET, compact memory and therefore decrease your program's working set.

Q24-How does non-deterministic garbage collection affect my code?


For most programmers, having a garbage collector (and using garbage collected objects) means that
you never have to worry about deallocating memory, or reference counting objects, even if you use
sophisticated data structures. It does require some changes in coding style, however, if you typically
deallocate system resources (file handles, locks, and so forth) in the same block of code that releases
the memory for an object. With a garbage collected object you should provide a method that releases
the system resources deterministically (that is, under your program control) and let the garbage
collector release the memory when it compacts the working set.

Q25-Can I avoid using the garbage collected heap?


All languages that target the runtime allow you to allocate class objects from the garbage-collected
heap. This brings benefits in terms of fast allocation, and avoids the need for programmers to work out
when they should explicitly 'free' each object.
The CLR also provides what are called ValueTypes -- these are like classes, except that ValueType
objects are allocated on the runtime stack (rather than the heap), and therefore reclaimed
automatically when your code exits the procedure in which they are defined. This is how "structs" in
C# operate.
Managed Extensions to C++ lets you choose where class objects are allocated. If declared as managed
Classes, with the __gc keyword, then they are allocated from the garbage-collected heap. If they don't
include the __gc keyword, they behave like regular C++ objects, allocated from the C++ heap, and freed
explicitly with the "free" method.
For additional information about Garbage Collection see:
1. Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework
2. Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework

Remoting

Q26-How do in-process and cross-process communication work in the Common Language


Runtime?
There are two aspects to in-process communication: between contexts within a single application
domain, or across application domains. Between contexts in the same application domain, proxies are
used as an interception mechanism. No marshaling/serialization is involved. When crossing
application domains, we do marshaling/serialization using the runtime binary protocol.
Cross-process communication uses a pluggable channel and formatter protocol, each suited to a
specific purpose.
1. If the developer specifies an endpoint using the tool soapsuds.exe to generate a metadata
proxy, HTTP channel with SOAP formatter is the default.
2. If a developer is doing explicit remoting in the managed world, it is necessary to be explicit
about what channel and formatter to use. This may be expressed administratively, through
configuration files, or with API calls to load specific channels. Options are:
89
HTTP channel w/ SOAP formatter (HTTP works well on the Internet, or anytime traffic must travel
through firewalls)
TCP channel w/ binary formatter (TCP is a higher performance option for local-area networks (LANs))
SMTP channel w/ SOAP formatter (only makes sense cross-machine)
When making transitions between managed and unmanaged code, the COM infrastructure
(specifically, DCOM) is used for remoting. In interim releases of the CLR, this applies also to serviced
components (components that use COM+ services). Upon final release, it should be possible to
configure any remotable component.
Distributed garbage collection of objects is managed by a system called "leased based lifetime." Each
object has a lease time, and when that time expires, the object is disconnected from the remoting
infrastructure of the CLR. Objects have a default renew time—the lease is renewed when a successful
call is made from the client to the object. The client can also explicitly renew the lease.

Interoperability

Q27-Can I use COM objects from a .NET Framework program?


Yes. Any COM component you have deployed today can be used from managed code, and in common
cases the adaptation is totally automatic.
Specifically, COM components are accessed from the .NET Framework by use of a runtime callable
wrapper (RCW). This wrapper turns the COM interfaces exposed by the COM component into .NET
Framework-compatible interfaces. For OLE automation interfaces, the RCW can be generated
automatically from a type library. For non-OLE automation interfaces, a developer may write a custom
RCW and manually map the types exposed by the COM interface to .NET Framework-compatible
types.

Q28-Can .NET Framework components be used from a COM program?


Yes. Managed types you build today can be made accessible from COM, and in the common case the
configuration is totally automatic. There are certain new features of the managed development
environment that are not accessible from COM. For example, static methods and parameterized
constructors cannot be used from COM. In general, it is a good idea to decide in advance who the
intended user of a given type will be. If the type is to be used from COM, you may be restricted to
using those features that are COM accessible.
Depending on the language used to write the managed type, it may or may not be visible by default.
Specifically, .NET Framework components are accessed from COM by using a COM callable wrapper
(CCW). This is similar to an RCW (see previous question), but works in the opposite direction. Again, if
the .NET Framework development tools cannot automatically generate the wrapper, or if the automatic
behavior is not what you want, a custom CCW can be developed.

Q29-Can I use the Win32 API from a .NET Framework program?


Yes. Using P/Invoke, .NET Framework programs can access native code libraries by means of static
DLL entry points.
Here is an example of C# calling the Win32 MessageBox function:
using System;
using System.Runtime.InteropServices;
class MainApp
{
[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);
public static void Main()
{
MessageBox( 0, "Hello, this is PInvoke in operation!", ".NET", 0 );
}
}

Security

Q30-What do I have to do to make my code work with the security system?


Usually, not a thing—most applications will run safely and will not be exploitable by malicious
attacks. By simply using the standard class libraries to access resources (like files) or perform
protected operations (such as a reflection on private members of a type), security will be enforced by
90
these libraries. The one simple thing application developers may want to do is include a permission
request (a form of declarative security) to limit the permissions their code may receive (to only those it
requires). This also ensures that if the code is allowed to run, it will do so with all the permissions it
needs.
Only developers writing new base class libraries that expose new kinds of resources need to work
directly with the security system. Instead of all code being a potential security risk, code access
security constrains this to a very small bit of code that explicitly overrides the security system.

Q31-Why does my code get a security exception when I run it from a network shared drive?
Default security policy gives only a restricted set of permissions to code that comes from the local
intranet zone. This zone is defined by the Internet Explorer security settings, and should be configured
to match the local network within an enterprise. Since files named by UNC or by a mapped drive (such
as with the NET USE command) are being sent over this local network, they too are in the local
intranet zone.
The default is set for the worst case of an unsecured intranet. If your intranet is more secure you can
modify security policy (with the CASPol tool) to grant more permissions to the local intranet, or to
portions of it (such as specific machine share names).

Q32-How do I make it so that code runs when the security system is stopping it?
Security exceptions occur when code attempts to perform actions for which it has not been granted
permission. Permissions are granted based on what is known about code; especially its location. For
example, code run from the Internet is given fewer permissions than that run from the local machine
because experience has proven that it is generally less reliable. So, to allow code to run that is failing
due to security exceptions, you must increase the permissions granted to it. One simple way to do so
is to move the code to a more trusted location (such as the local file system). But this won't work in all
cases (web applications are a good example, and intranet applications on a corporate network are
another). So, instead of changing the code's location, you can also change security policy to grant
more permissions to that location. This is done using either the code access security policy utility
(caspol.exe) or the graphical administration tool (available in Beta 2 and beyond). If you are the code's
developer or publisher, you may also digitally sign it and then modify security policy to grant more
permissions to code bearing that signature. When taking any of these actions, however, remember that
code is given fewer permissions because it is not from an identifiably trustworthy source—before you
move code to your local machine or change security policy, you should be sure that you trust the code
to not perform malicious or damaging actions.

Q33-How do I administer security for my machine? For an enterprise?


Currently, the CASPol command line tool is the only way to administer security. Security policy
consists of two levels: machine, and by-user. There are plans to provide a full-featured administration
tool, as well as support for enterprise policy administration, as part of the first version of the .NET
Framework.

Q34-How does evidence-based security work with Windows 2000 security?


Evidence-based security (which authorizes code) works together with Windows 2000 security (which is
based on log on identity). For example, to access a file, managed code must have both the code access
security file permission and must also be running under a log on identity that has NTFS file access
rights. The managed libraries that are included with the .NET Framework also provide classes for role-
based security. These allow the application to work with Windows log on identities and user groups.
91
.NET Remoting Interview Questions

1. What’s a Windows process? It’s an application that’s running and had been allocated memory.
2. What’s typical about a Windows process in regards to memory allocation? Each process is
allocated its own block of available RAM space, no process can access another process’ code or data.
If the process crashes, it dies alone without taking the entire OS or a bunch of other applications
down.
3. Why do you call it a process? What’s different between process and application in .NET,
not common computer usage, terminology? A process is an instance of a running application. An
application is an executable on the hard drive or network. There can be numerous processes
launched of the same application (5 copies of Word running), but 1 process can run just 1
application.
4. What distributed process frameworks outside .NET do you know? Distributed Computing
Environment/Remote Procedure Calls (DEC/RPC), Microsoft Distributed Component Object Model
(DCOM), Common Object Request Broker Architecture (CORBA), and Java Remote Method
Invocation (RMI).
5. What are possible implementations of distributed applications in .NET? .NET Remoting and
ASP.NET Web Services. If we talk about the Framework Class Library, noteworthy classes are in
System.Runtime.Remoting and System.Web.Services.
6. When would you use .NET Remoting and when Web services? Use remoting for more efficient
exchange of information when you control both ends of the application. Use Web services for open-
protocol-based information exchange when you are just a client or a server with the other end
belonging to someone else.
7. What’s a proxy of the server object in .NET Remoting? It’s a fake copy of the server object that
resides on the client side and behaves as if it was the server. It handles the communication between
real server object and the client object. This process is also known as marshaling.
8. What are remotable objects in .NET Remoting? Remotable objects are the objects that can be
marshaled across the application domains. You can marshal by value, where a deep copy of the
object is created and then passed to the receiver. You can also marshal by reference, where just a
reference to an existing object is passed.
9. What are channels in .NET Remoting? Channels represent the objects that transfer the other
serialized objects from one application domain to another and from one computer to another, as well
as one process to another on the same box. A channel must exist before an object can be
transferred.
10. What security measures exist for .NET Remoting in System.Runtime.Remoting? None.
Security should be taken care of at the application level. Cryptography and other security techniques
can be applied at application or server level.
11. What is a formatter? A formatter is an object that is responsible for encoding and serializing
data into messages on one end, and deserializing and decoding messages into data on the other end.
12. Choosing between HTTP and TCP for protocols and Binary and SOAP for formatters, what
are the trade-offs? Binary over TCP is the most effiecient, SOAP over HTTP is the most
interoperable.
13. What’s SingleCall activation mode used for? If the server object is instantiated for responding
to just one single request, the request should be made in SingleCall mode.
14. What’s Singleton activation mode? A single object is instantiated regardless of the number of
clients accessing it. Lifetime of this object is determined by lifetime lease.
15. How do you define the lease of the object? By implementing ILease interface when writing the
class code.
16. Can you configure a .NET Remoting object via XML file? Yes, via machine.config and
application level .config file (or web.config in ASP.NET). Application-level XML settings take
precedence over machine.config.
17. How can you automatically generate interface for the remotable object in .NET with
Microsoft tools? Use the Soapsuds tool.
92
ASP.NET DataGrid questions

1. What is datagrid?
The DataGrid Web server control is a powerful tool for displaying information from a data source. It
is easy to use; you can display editable data in a professional-looking grid by setting only a few
properties. At the same time, the grid has a sophisticated object model that provides you with great
flexibility in how you display the data.
2. What’s the difference between the System.Web.UI.WebControls.DataGrid and and
System.Windows.Forms.DataGrid?
The Web UI control does not inherently support master-detail data structures. As with other Web
server controls, it does not support two-way data binding. If you want to update data, you must
write code to do this yourself. You can only edit one row at a time. It does not inherently support
sorting, although it raises events you can handle in order to sort the grid contents. You can bind the
Web Forms DataGrid to any object that supports the IEnumerable interface. The Web Forms
DataGrid control supports paging. It is easy to customize the appearance and layout of the Web
Forms DataGrid control as compared to the Windows Forms one.
3. How do you customize the column content inside the datagrid?
If you want to customize the content of a column, make the column a template column. Template
columns work like item templates in the DataList or Repeater control, except that you are defining
the layout of a column rather than a row.
4. How do you apply specific formatting to the data inside the cells?
You cannot specify formatting for columns generated when the grid’s AutoGenerateColumns
property is set to true, only for bound or template columns. To format, set the column’s
DataFormatString property to a string-formatting expression suitable for the data type of the data
you are formatting.
5. How do you hide the columns?
One way to have columns appear dynamically is to create them at design time, and then to hide or
show them as needed. You can do this by setting a column’s Visible property.
6. How do you display an editable drop-down list?
Displaying a drop-down list requires a template column in the grid. Typically, the ItemTemplate
contains a control such as a data-bound Label control to show the current value of a field in the
record. You then add a drop-down list to the EditItemTemplate. In Visual Studio, you can add a
template column in the Property builder for the grid, and then use standard template editing to
remove the default TextBox control from the EditItemTemplate and drag a DropDownList control into
it instead. Alternatively, you can add the template column in HTML view. After you have created the
template column with the drop-down list in it, there are two tasks. The first is to populate the list.
The second is to preselect the appropriate item in the list — for example, if a book’s genre is set to
“fiction,” when the drop-down list displays, you often want “fiction” to be preselected.
7. How do you check whether the row data has been changed?
The definitive way to determine whether a row has been dirtied is to handle the changed event for
the controls in a row. For example, if your grid row contains a TextBox control, you can respond to
the control’s TextChanged event. Similarly, for check boxes, you can respond to a CheckedChanged
event. In the handler for these events, you maintain a list of the rows to be updated. Generally, the
best strategy is to track the primary keys of the affected rows. For example, you can maintain an
ArrayList object that contains the primary keys of the rows to update.
This is just a brief on dealing with ASP.NET DataGrid control. The full version of the document and
the sample code is available on MSDN.
93
ASP.NET questions, part 2

1. Whats an assembly?
Assemblies are the building blocks of .NET Framework applications; they form the fundamental unit
of deployment, version control, reuse, activation scoping, and security permissions. An assembly is a
collection of types and resources that are built to work together and form a logical unit of
functionality. An assembly provides the common language runtime with the information it needs to
be aware of type implementations. To the runtime, a type does not exist outside the context of an
assembly.
2. Describe the difference between inline and code behind - which is best in a loosely coupled
solution?
ASP.NET supports two modes of page development: Page logic code that is written inside <script
runat=server> blocks within an .aspx file and dynamically compiled the first time the page is
requested on the server. Page logic code that is written within an external class that is compiled
prior to deployment on a server and linked "behind" the .aspx file at run time.
3. Explain what a diffgram is, and a good use for one?
A DiffGram is an XML format that is used to identify current and original versions of data elements.
The DataSet uses the DiffGram format to load and persist its contents, and to serialize its contents
for transport across a network connection. When a DataSet is written as a DiffGram, it populates the
DiffGram with all the necessary information to accurately recreate the contents, though not the
schema, of the DataSet, including column values from both the Original and Current row versions,
row error information, and row order.
4. Where would you use an iHTTPModule, and what are the limitations of anyapproach you
might take in implementing one?
One of ASP.NET’s most useful features is the extensibility of the HTTP pipeline, the path that data
takes between client and server. You can use them to extend your ASP.NET applications by adding
pre- and post-processing to each HTTP request coming into your application. For example, if you
wanted custom authentication facilities for your application, the best technique would be to
intercept the request when it comes in and process the request in a custom HTTP module.
9. In what order do the events of an ASPX page execute. As a developer is it important to
undertsand these events?
Every Page object (which your .aspx page is) has nine events, most of which you will not have to
worry about in your day to day dealings with ASP.NET. The three that you will deal with the most
are: Page_Init, Page_Load, Page_PreRender.
10.Which method do you invoke on the DataAdapter control to load your generated dataset
with data?
System.Data.Common.DataAdapter.Fill(System.Data.DataSet); If my DataAdapter is
sqlDataAdapter and my DataSet is dsUsers then it is called this way:
sqlDataAdapter.Fill(dsUsers);
11. Which template must you provide, in order to display data in a Repeater control?
ItemTemplate
12. How can you provide an alternating color scheme in a Repeater control?
AlternatingItemTemplate Like the ItemTemplate element, but rendered for every other
row (alternating items) in the Repeater control. You can specify a different appearance
for the AlternatingItemTemplate element by setting its style properties.
13. What property must you set, and what method must you call in your code, in order to bind
the data from some data source to the Repeater control?
You must set the DataMember property which Gets or sets the specific table in the DataSource to
bind to the control and the DataBind method to bind data from a source to a server control. This
method is commonly used after retrieving a data set through a database query.
14. What base class do all Web Forms inherit from?
System.Web.UI.Page
15. What method do you use to explicitly kill a user’s session?
The Abandon method destroys all the objects stored in a Session object and releases their resources.
If you do not call the Abandon method explicitly, the server destroys these objects when the session
times out.
Syntax: Session.Abandon
94
16. How do you turn off cookies for one page in your site?
Use the Cookie.Discard Property which Gets or sets the discard flag set by the server. When true,
this
property instructs the client application not to save the Cookie on the user’s hard disk when a
session ends.
17. Which two properties are on every validation control? ControlToValidate & ErrorMessage
properties
18. What tags do you need to add within the asp:datagrid tags to bind columns manually?
19. How do you create a permanent cookie? Setting the Expires property to MinValue means that
the Cookie never expires.

22. Which method do you use to redirect the user to another page without performing a round
trip to the client?
Server.transfer()
23. What is the transport protocol you use to call a Web service? SOAP. Transport Protocols: It
is essential for the acceptance of Web Services that they are based on established Internet
infrastructure. This in fact imposes the usage of of the HTTP, SMTP and FTP protocols based on the
TCP/IP family of transports. Messaging Protocol: The format of messages exchanged between Web
Services clients and Web Services should be vendor neutral and should not carry details about the
technology used to implement the service. Also, the message format should allow for extensions and
different bindings to specific transport protocols. SOAP and ebXML Transport are specifications
which fulfill these requirements. We expect that the W3C XML Protocol Working Group defines a
successor standard.
24. True or False: A Web service can only be written in .NET.
False.
25. What does WSDL stand for?
Web Services Description Language
26. What property do you have to set to tell the grid which page to go to when using the Pager
object?
27. Where on the Internet would you look for Web services?
UDDI repositaries like uddi.microsoft.com, IBM UDDI node, UDDI Registries in Google Directory,
enthusiast sites like XMethods.net.
28. What tags do you need to add within the asp:datagrid tags to bind columns manually?
Column tag and an ASP:databound tag.
29. Which property on a Combo Box do you set with a column name, prior to setting the
DataSource, to display data in the combo box?
30. How is a property designated as read-only? In VB.NET:
Public ReadOnly Property PropertyName As ReturnType
Get ‘Your Property Implementation goes in here
End Get
End Property
in C#
public returntype PropertyName
{
get{
//property implementation goes here
}
// Do not write the set implementation
}
31. Which control would you use if you needed to make sure the values in two different
controls matched? Use the CompareValidator control to compare the values
of 2 different controls.
32. True or False: To test a Web service you must create a windows application or Web
application to consume this service? False.
33. How many classes can a single .NET DLL contain? Unlimited.
95
.NET and COM interop questions

1. Describe the advantages of writing a managed code application instead of unmanaged one.
What’s involved in certain piece of code being managed? The advantages include automatic
garbage collection, memory management, support for versioning and security. These advantages are
provided through .NET FCL and CLR, while with the unmanaged code similar capabilities had to be
implemented through third-party libraries or as a part of the application itself.
2. Are COM objects managed or unmanaged? Since COM objects were written before .NET,
apparently they are unmanaged.
3. So can a COM object talk to a .NET object? Yes, through Runtime Callable Wrapper (RCW) or
PInvoke.
4. How do you generate an RCW from a COM object? Use the Type Library Import utility shipped
with SDK. tlbimp COMobject.dll /out:.NETobject.dll or reference the COM library from Visual Studio
in your project.
5. I can’t import the COM object that I have on my machine. Did you write that object? You can
only import your own objects. If you need to use a COM component from another developer, you
should obtain a Primary Interop Assembly (PIA) from whoever authored the original object.
6. How do you call unmanaged methods from your .NET code through PInvoke? Supply a
DllImport attribute. Declare the methods in your .NET code as static extern. Do not implement the
methods as they are implemented in your unmanaged code, you’re just providing declarations for
method signatures.
7. Can you retrieve complex data types like structs from the PInvoke calls? Yes, just make
sure you re-declare that struct, so that managed code knows what to do with it.
8. I want to expose my .NET objects to COM objects. Is that possible? Yes, but few things
should be considered first. Classes should implement interfaces explicitly. Managed types must be
public. Methods, properties, fields, and events that are exposed to COM must be public. Types must
have a public default constructor with no arguments to be activated from COM. Types cannot be
abstract.
9. Can you inherit a COM class in a .NET application? The .NET Framework extends the COM
model for reusability by adding implementation inheritance. Managed types can derive directly or
indirectly from a COM coclass; more specifically, they can derive from the runtime callable wrapper
generated by the runtime. The derived type can expose all the method and properties of the COM
object as well as methods and properties implemented in managed code. The resulting object is
partly implemented in managed code and partly implemented in unmanaged code.
10. Suppose I call a COM object from a .NET applicaiton, but COM object throws an error.
What happens on the .NET end? COM methods report errors by returning HRESULTs; .NET
methods report them by throwing exceptions. The runtime handles the transition between the two.
Each exception class in the .NET Framework maps to an HRESULT.
96
Garbage Collection

Implementing proper resource management for your applications can be a difficult, tedious task. It
can distract your concentration from the real problems that you're trying to solve. Wouldn't it be
wonderful if some mechanism existed that simplified the mind-numbing task of memory
management for the developer? Fortunately, in .NET there is: garbage collection (GC).
Let's back up a minute. Every program uses resources of one sort or another—memory buffers,
screen space, network connections, database resources, and so on. In fact, in an object-oriented
environment, every type identifies some resource available for your program's use. To use any of
these resources requires that memory be allocated to represent the type. The steps required to
access a resource are as follows:

1. Allocate memory for the type that represents the resource.


2. Initialize the memory to set the initial state of the resource and to make the resource usable.

3. Use the resource by accessing the instance members of the type (repeat as necessary).

4. Tear down the state of the resource to clean up.


5. Free the memory.
This seemingly simple paradigm has been one of the major sources of programming errors. After
all, how many times have you forgotten to free memory when it is no longer needed or attempted to
use memory after you've already freed it?
These two bugs are worse than most other application bugs because what the consequences will be
and when those consequences will occur are typically unpredictable. For other bugs, when you see
your application misbehaving, you just fix it. But these two bugs cause resource leaks (memory
consumption) and object corruption (destabilization), making your application perform in
unpredictable ways at unpredictable times. In fact, there are many tools (such as the Task Manager,
the System Monitor ActiveX® Control, CompuWare's BoundsChecker, and Rational's Purify) that are
specifically designed to help developers locate these types of bugs.
As I examine GC, you'll notice that it completely absolves the developer from tracking memory
usage and knowing when to free memory. However, the garbage collector doesn't know anything
about the resource represented by the type in memory. This means that a garbage collector can't
know how to perform step four—tearing down the state of a resource. To get a resource to clean up
properly, the developer must write code that knows how to properly clean up a resource. In the .NET
Framework, the developer writes this code in a Close, Dispose, or Finalize method, which I'll describe
later. However, as you'll see later, the garbage collector can determine when to call this method
automatically.
Also, many types represent resources that do not require any cleanup. For example, a Rectangle
resource can be completely cleaned up simply by destroying the left, right, width, and height fields
maintained in the type's memory. On the other hand, a type that represents a file resource or a
network connection resource will require the execution of some explicit clean up code when the
resource is to be destroyed. I will explain how to accomplish all of this properly. For now, let's
examine how memory is allocated and how resources are initialized.

Resource Allocation
The Microsoft® .NET common language runtime requires that all resources be allocated from the
managed heap. This is similar to a C-runtime heap except that you never free objects from the
managed heap—objects are automatically freed when they are no longer needed by the application.
This, of course, raises the question: how does the managed heap know when an object is no longer
in use by the application? I will address this question shortly.
There are several GC algorithms in use today. Each algorithm is fine-tuned for a particular
environment in order to provide the best performance. This article concentrates on the GC algorithm
that is used by the common language runtime. Let's start with the basic concepts.
When a process is initialized, the runtime reserves a contiguous region of address space that
initially has no storage allocated for it. This address space region is the managed heap. The heap
also maintains a pointer, which I'll call the NextObjPtr. This pointer indicates where the next object
is to be allocated within the heap. Initially, the NextObjPtr is set to the base address of the reserved
97
address space region.
An application creates an object using the new operator. This operator first makes sure that the
bytes required by the new object fit in the reserved region (committing storage if necessary). If the
object fits, then NextObjPtr points to the object in the heap, this object's constructor is called, and
the new operator returns the address of the object.

Figure 1 Managed Heap

At this point, NextObjPtr is incremented past the object so that it points to where the next object
will be placed in the heap. Figure 1 shows a managed heap consisting of three objects: A, B, and C.
The next object to be allocated will be placed where NextObjPtr points (immediately after object C).
Now let's look at how the C-runtime heap allocates memory. In a C-runtime heap, allocating
memory for an object requires walking though a linked list of data structures. Once a large enough
block is found, that block has to be split, and pointers in the linked list nodes must be modified to
keep everything intact. For the managed heap, allocating an object simply means adding a value to a
pointer—this is blazingly fast by comparison. In fact, allocating an object from the managed heap is
nearly as fast as allocating memory from a thread's stack!
So far, it sounds like the managed heap is far superior to the C-runtime heap due to its speed and
simplicity of implementation. Of course, the managed heap gains these advantages because it makes
one really big assumption: address space and storage are infinite. This assumption is (without a
doubt) ridiculous, and there must be a mechanism employed by the managed heap that allows the
heap to make this assumption. This mechanism is called the garbage collector. Let's see how it
works.
When an application calls the new operator to create an object, there may not be enough address
space left in the region to allocate to the object. The heap detects this by adding the size of the new
object to NextObjPtr. If NextObjPtr is beyond the end of the address space region, then the heap is
full and a collection must be performed.
In reality, a collection occurs when generation 0 is completely full. Briefly, a generation is a
mechanism implemented by the garbage collector in order to improve performance. The idea is that
newly created objects are part of a young generation, and objects created early in the application's
lifecycle are in an old generation. Separating objects into generations can allow the garbage collector
to collect specific generations instead of collecting all objects in the managed heap. Generations will
be discussed in more detail in Part 2 of this article.

The Garbage Collection Algorithm


The garbage collector checks to see if there are any objects in the heap that are no longer being
used by the application. If such objects exist, then the memory used by these objects can be
reclaimed. (If no more memory is available for the heap, then the new operator throws an
OutOfMemoryException.) How does the garbage collector know if the application is using an object
or not? As you might imagine, this isn't a simple question to answer.
Every application has a set of roots. Roots identify storage locations, which refer to objects on the
managed heap or to objects that are set to null. For example, all the global and static object pointers
in an application are considered part of the application's roots. In addition, any local
variable/parameter object pointers on a thread's stack are considered part of the application's roots.
Finally, any CPU registers containing pointers to objects in the managed heap are also considered
part of the application's roots. The list of active roots is maintained by the just-in-time (JIT) compiler
and common language runtime, and is made accessible to the garbage collector's algorithm.
When the garbage collector starts running, it makes the assumption that all objects in the heap are
garbage. In other words, it assumes that none of the application's roots refer to any objects in the
heap. Now, the garbage collector starts walking the roots and building a graph of all objects
reachable from the roots. For example, the garbage collector may locate a global variable that points
to an object in the heap.
98
Figure 2 shows a heap with several allocated objects where the application's roots refer directly
to objects A, C, D, and F. All of these objects become part of the graph. When adding object D, the
collector notices that this object refers to object H, and object H is also added to the graph. The
collector continues to walk through all reachable objects recursively.

Figure 2 Allocated Objects in Heap

Once this part of the graph is complete, the garbage collector checks the next root and walks the
objects again. As the garbage collector walks from object to object, if it attempts to add an object to
the graph that it previously added, then the garbage collector can stop walking down that path. This
serves two purposes. First, it helps performance significantly since it doesn't walk through a set of
objects more than once. Second, it prevents infinite loops should you have any circular linked lists of
objects.
Once all the roots have been checked, the garbage collector's graph contains the set of all objects
that are somehow reachable from the application's roots; any objects that are not in the graph are
not accessible by the application, and are therefore considered garbage. The garbage collector now
walks through the heap linearly, looking for contiguous blocks of garbage objects (now considered
free space). The garbage collector then shifts the non-garbage objects down in memory (using the
standard memcpy function that you've known for years), removing all of the gaps in the heap. Of
course, moving the objects in memory invalidates all pointers to the objects. So the garbage collector
must modify the application's roots so that the pointers point to the objects' new locations. In
addition, if any object contains a pointer to another object, the garbage collector is responsible for
correcting these pointers as well. Figure 3 shows the managed heap after a collection.

Figure 3 Managed Heap after Collection

After all the garbage has been identified, all the non-garbage has been compacted, and all the non-
garbage pointers have been fixed-up, the NextObjPtr is positioned just after the last non-garbage
object. At this point, the new operation is tried again and the resource requested by the application
is successfully created.
As you can see, a GC generates a significant performance hit, and this is the major downside of
using a managed heap. However, keep in mind that GCs only occur when the heap is full and, until
then, the managed heap is significantly faster than a C-runtime heap. The runtime's garbage
collector also offers some optimizations that greatly improve the performance of garbage collection.
99
I'll discuss these optimizations in Part 2 of this article when I talk about generations.
There are a few important things to note at this point. You no longer have to implement any code
that manages the lifetime of any resources that your application uses. And notice how the two bugs I
discussed at the beginning of this article no longer exist. First, it is not possible to leak resources,
since any resource not accessible from your application's roots can be collected at some point.
Second, it is not possible to access a resource that is freed, since the resource won't be freed if it is
reachable. If it's not reachable, then your application has no way to access it. The code in Figure 4
demonstrates how resources are allocated and managed.
If GC is so great, you might be wondering why it isn't in ANSI C++. The reason is that a garbage
collector must be able to identify an application's roots and must also be able to find all object
pointers. The problem with C++ is that it allows casting a pointer from one type to another, and
there's no way to know what a pointer refers to. In the common language runtime, the managed
heap always knows the actual type of an object, and the metadata information is used to determine
which members of an object refer to other objects.

Finalization
The garbage collector offers an additional feature that you may want to take advantage of:
finalization. Finalization allows a resource to gracefully clean up after itself when it is being
collected. By using finalization, a resource representing a file or network connection is able to clean
itself up properly when the garbage collector decides to free the resource's memory.
Here is an oversimplification of what happens: when the garbage collector detects that an object is
garbage, the garbage collector calls the object's Finalize method (if it exists) and then the object's
memory is reclaimed. For example, let's say you have the following type (in C#):
public class BaseObj {
public BaseObj() {
}

protected override void Finalize() {


// Perform resource cleanup code here...
// Example: Close file/Close network connection
Console.WriteLine("In Finalize.");
}
}
Now you can create an instance of this object by calling:
BaseObj bo = new BaseObj();
Some time in the future, the garbage collector will determine that this object is garbage. When that
happens, the garbage collector will see that the type has a Finalize method and will call the method,
causing "In Finalize" to appear in the console window and reclaiming the memory block used by this
object.
Many developers who are used to programming in C++ draw an immediate correlation between a
destructor and the Finalize method. However, let me warn you right now: object finalization and
destructors have very different semantics and it is best to forget everything you know about
destructors when thinking about finalization. Managed objects never have destructors—period.
When designing a type it is best to avoid using a Finalize method. There are several reasons for
this:

 Finalizable objects get promoted to older generations, which increases memory pressure and
prevents the object's memory from being collected when the garbage collector determines the
object is garbage. In addition, all objects referred to directly or indirectly by this object get
promoted as well. Generations and promotions will be discussed in Part 2 of this article.
 Finalizable objects take longer to allocate.
 Forcing the garbage collector to execute a Finalize method can significantly hurt
performance. Remember, each object is finalized. So if I have an array of 10,000 objects, each
object must have its Finalize method called.
 Finalizable objects may refer to other (non-finalizable) objects, prolonging their lifetime
unnecessarily. In fact, you might want to consider breaking a type into two different types: a
lightweight type with a Finalize method that doesn't refer to any other objects, and a separate
type without a Finalize method that does refer to other objects.
100
 You have no control over when the Finalize method will execute. The object may hold on
to resources until the next time the garbage collector runs.
 When an application terminates, some objects are still reachable and will not have their
Finalize method called. This can happen if background threads are using the objects or if objects
are created during application shutdown or AppDomain unloading. In addition, by default,
Finalize methods are not called for unreachable objects when an application exits so that the
application may terminate quickly. Of course, all operating system resources will be reclaimed,
but any objects in the managed heap are not able to clean up gracefully. You can change this
default behavior by calling the System.GC type's RequestFinalizeOnShutdown method. However,
you should use this method with care since calling it means that your type is controlling a policy
for the entire application.
 The runtime doesn't make any guarantees as to the order in which Finalize methods are
called. For example, let's say there is an object that contains a pointer to an inner object. The
garbage collector has detected that both objects are garbage. Furthermore, say that the inner
object's Finalize method gets called first. Now, the outer object's Finalize method is allowed to
access the inner object and call methods on it, but the inner object has been finalized and the
results may be unpredictable. For this reason, it is strongly recommended that Finalize methods
not access any inner, member objects.
If you determine that your type must implement a Finalize method, then make sure the code
executes as quickly as possible. Avoid all actions that would block the Finalize method, including
any thread synchronization operations. Also, if you let any exceptions escape the Finalize method,
the system just assumes that the Finalize method returned and continues calling other objects'
Finalize methods.
When the compiler generates code for a constructor, the compiler automatically inserts a call to the
base type's constructor. Likewise, when a C++ compiler generates code for a destructor, the compiler
automatically inserts a call to the base type's destructor. However, as I've said before, Finalize
methods are different from destructors. The compiler has no special knowledge about a Finalize
method, so the compiler does not automatically generate code to call a base type's Finalize method.
If you want this behavior—and frequently you do—then you must explicitly call the base type's
Finalize method from your type's Finalize method:
public class BaseObj {
public BaseObj() {
}

protected override void Finalize() {


Console.WriteLine("In Finalize.");
base.Finalize(); // Call base type's Finalize
}
}
Note that you'll usually call the base type's Finalize method as the last statement in the derived
type's Finalize method. This keeps the base object alive as long as possible. Since calling a base type
Finalize method is common, C# has a syntax that simplifies your work. In C#, the following code
class MyObject {
~MyObject() {
•••
}
}
causes the compiler to generate this code:
class MyObject {
protected override void Finalize() {
•••
base.Finalize();
}
}
Note that this C# syntax looks identical to the C++ language's syntax for defining a destructor. But
remember, C# doesn't support destructors. Don't let the identical syntax fool you.

Finalization Internals
101
On the surface, finalization seems pretty straightforward: you create an object and when the
object is collected, the object's Finalize method is called. But there is more to finalization than this.
When an application creates a new object, the new operator allocates the memory from the heap. If
the object's type contains a Finalize method, then a pointer to the object is placed on the finalization
queue. The finalization queue is an internal data structure controlled by the garbage collector. Each
entry in the queue points to an object that should have its Finalize method called before the object's
memory can be reclaimed.
Figure 5 shows a heap containing several objects. Some of these objects are reachable from the
application's roots, and some are not. When objects C, E, F, I, and J were created, the system
detected that these objects had Finalize methods and pointers to these objects were added to the
finalization queue.

Figure 5 A Heap with Many Objects

When a GC occurs, objects B, E, G, H, I, and J are determined to be garbage. The garbage collector
scans the finalization queue looking for pointers to these objects. When a pointer is found, the
pointer is removed from the finalization queue and appended to the freachable queue (pronounced
"F-reachable"). The freachable queue is another internal data structure controlled by the garbage
collector. Each pointer in the freachable queue identifies an object that is ready to have its Finalize
method called.
After the collection, the managed heap looks like Figure 6. Here, you see that the memory
occupied by objects B, G, and H has been reclaimed because these objects did not have a Finalize
method that needed to be called. However, the memory occupied by objects E, I, and J could not be
reclaimed because their Finalize method has not been called yet.

Figure 6 Managed Heap after Garbage Collection

There is a special runtime thread dedicated to calling Finalize methods. When the freachable queue
is empty (which is usually the case), this thread sleeps. But when entries appear, this thread wakes,
removes each entry from the queue, and calls each object's Finalize method. Because of this, you
should not execute any code in a Finalize method that makes any assumption about the thread
that's executing the code. For example, avoid accessing thread local storage in the Finalize method.
102
The interaction of the finalization queue and the freachable queue is quite fascinating. First, let
me tell you how the freachable queue got its name. The f is obvious and stands for finalization; every
entry in the freachable queue should have its Finalize method called. The "reachable" part of the
name means that the objects are reachable. To put it another way, the freachable queue is
considered to be a root just like global and static variables are roots. Therefore, if an object is on the
freachable queue, then the object is reachable and is not garbage.
In short, when an object is not reachable, the garbage collector considers the object garbage. Then,
when the garbage collector moves an object's entry from the finalization queue to the freachable
queue, the object is no longer considered garbage and its memory is not reclaimed. At this point, the
garbage collector has finished identifying garbage. Some of the objects identified as garbage have
been reclassified as not garbage. The garbage collector compacts the reclaimable memory and the
special runtime thread empties the freachable queue, executing each object's Finalize method.

Figure 7 Managed Heap after Second Garbage Collection

The next time the garbage collector is invoked, it sees that the finalized objects are truly garbage,
since the application's roots don't point to it and the freachable queue no longer points to it. Now the
memory for the object is simply reclaimed. The important thing to understand here is that two GCs
are required to reclaim memory used by objects that require finalization. In reality, more than two
collections may be necessary since the objects could get promoted to an older generation. Figure 7
shows what the managed heap looks like after the second GC.

Resurrection
The whole concept of finalization is fascinating. However, there is more to it than what I've
described so far. You'll notice in the previous section that when an application is no longer accessing
a live object, the garbage collector considers the object to be dead. However, if the object requires
finalization, the object is considered live again until it is actually finalized, and then it is
permanently dead. In other words, an object requiring finalization dies, lives, and then dies again.
This is a very interesting phenomenon called resurrection. Resurrection, as its name implies, allows
an object to come back from the dead.
I've already described a form of resurrection. When the garbage collector places a reference to the
object on the freachable queue, the object is reachable from a root and has come back to life.
Eventually, the object's Finalize method is called, no roots point to the object, and the object is dead
forever after. But what if an object's Finalize method executed code that placed a pointer to the
object in a global or static variable?
public class BaseObj {

protected override void Finalize() {


Application.ObjHolder = this;
}
}

class Application {
static public Object ObjHolder; // Defaults to null
•••
}
103
In this case, when the object's Finalize method executes, a pointer to the object is placed in a
root and the object is reachable from the application's code. This object is now resurrected and the
garbage collector will not consider the object to be garbage. The application is free to use the object,
but it is very important to note that the object has been finalized and that using the object may
cause unpredictable results. Also note: if BaseObj contained members that pointed to other objects
(either directly or indirectly), all objects would be resurrected, since they are all reachable from the
application's roots. However, be aware that some of these other objects may also have been finalized.
In fact, when designing your own object types, objects of your type can get finalized and
resurrected totally out of your control. Implement your code so that you handle this gracefully. For
many types, this means keeping a Boolean flag indicating whether the object has been finalized or
not. Then, if methods are called on your finalized object, you might consider throwing an exception.
The exact technique to use depends on your type.
Now, if some other piece of code sets Application.ObjHolder to null, the object is unreachable.
Eventually the garbage collector will consider the object to be garbage and will reclaim the object's
storage. Note that the object's Finalize method will not be called because no pointer to the object
exists on the finalization queue.
There are very few good uses of resurrection, and you really should avoid it if possible. However,
when people do use resurrection, they usually want the object to clean itself up gracefully every time
the object dies. To make this possible, the GC type offers a method called ReRegisterForFinalize,
which takes a single parameter: the pointer to an object.
public class BaseObj {

protected override void Finalize() {


Application.ObjHolder = this;
GC.ReRegisterForFinalize(this);
}
}
When this object's Finalize method is called, it resurrects itself by making a root point to the
object. The Finalize method then calls ReRegisterForFinalize, which appends the address of the
specified object (this) to the end of the finalization queue. When the garbage collector detects that
this object is unreachable again, it will queue the object's pointer on the freachable queue and the
Finalize method will get called again. This specific example shows how to create an object that
constantly resurrects itself and never dies, which is usually not desirable. It is far more common to
conditionally set a root to reference the object inside the Finalize method.
Make sure that you call ReRegisterForFinalize no more than once per resurrection, or the object
will have its Finalize method called multiple times. This happens because each call to
ReRegisterForFinalize appends a new entry to the end of the finalization queue. When an object is
determined to be garbage, all of these entries move from the finalization queue to the freachable
queue, calling the object's Finalize method multiple times.

Forcing an Object to Clean Up


If you can, you should try to define objects that do not require any clean up. Unfortunately, for many
objects, this is simply not possible. So for these objects, you must implement a Finalize method as
part of the type's definition. However, it is also recommended that you add an additional method to
the type that allows a user of the type to explicitly clean up the object when they want. By
convention, this method should be called Close or Dispose.
In general, you use Close if the object can be reopened or reused after it has been closed. You also
use Close if the object is generally considered to be closed, such as a file. On the other hand, you
would use Dispose if the object should no longer be used at all after it has been disposed. For
example, to delete a System.Drawing.Brush object, you call its Dispose method. Once disposed, the
Brush object cannot be used, and calling methods to manipulate the object may cause exceptions to
be thrown. If you need to work with another Brush, you must construct a new Brush object.
Now, let's look at what the Close/Dispose method is supposed to do. The System.IO.FileStream
type allows the user to open a file for reading and writing. To improve performance, the type's
implementation makes use of a memory buffer. Only when the buffer fills does the type flush the
contents of the buffer to the file. Let's say that you create a new FileStream object and write just a
few bytes of information to it. If these bytes don't fill the buffer, then the buffer is not written to disk.
The FileStream type does implement a Finalize method, and when the FileStream object is collected
the Finalize method flushes any remaining data from memory to disk and then closes the file.
But this approach may not be good enough for the user of the FileStream type. Let's say that the
104
first FileStream object has not been collected yet, but the application wants to create a new
FileStream object using the same disk file. In this scenario, the second FileStream object will fail to
open the file if the first FileStream object had the file open for exclusive access. The user of the
FileStream object must have some way to force the final memory flush to disk and to close the file.
If you examine the FileStream type's documentation, you'll see that it has a method called Close.
When called, this method flushes the remaining data in memory to the disk and closes the file. Now
the user of a FileStream object has control of the object's behavior.
But an interesting problem arises now: what should the FileStream's Finalize method do when the
FileStream object is collected? Obviously, the answer is nothing. In fact, there is no reason for the
FileStream's Finalize method to execute at all if the application has explicitly called the Close
method. You know that Finalize methods are discouraged, and in this scenario you're going to have
the system call a Finalize method that should do nothing. It seems like there ought to be a way to
suppress the system's calling of the object's Finalize method. Fortunately, there is. The System.GC
type contains a static method, SuppressFinalize, that takes a single parameter, the address of an
object.
Figure 8 shows FileStream's type implementation. When you call SuppressFinalize, it turns on a
bit flag associated with the object. When this flag is on, the runtime knows not to move this object's
pointer to the freachable queue, preventing the object's Finalize method from being called.
Let's examine another related issue. It is very common to use a StreamWriter object with a
FileStream object.
FileStream fs = new FileStream("C:\\SomeFile.txt",
FileMode.Open, FileAccess.Write, FileShare.Read);
StreamWriter sw = new StreamWriter(fs);
sw.Write ("Hi there");

// The call to Close below is what you should do


sw.Close();
// NOTE: StreamWriter.Close closes the FileStream. The FileStream
// should not be explicitly closed in this scenario
Notice that the StreamWriter's constructor takes a FileStream object as a parameter. Internally, the
StreamWriter object saves the FileStream's pointer. Both of these objects have internal data buffers
that should be flushed to the file when you're finished accessing the file. Calling the StreamWriter's
Close method writes the final data to the FileStream and internally calls the FileStream's Close
method, which writes the final data to the disk file and closes the file. Since StreamWriter's Close
method closes the FileStream object associated with it, you should not call fs.Close yourself.
What do you think would happen if you removed the two calls to Close? Well, the garbage collector
would correctly detect that the objects are garbage and the objects would get finalized. But, the
garbage collector doesn't guarantee the order in which the Finalize methods are called. So if the
FileStream gets finalized first, it closes the file. Then when the StreamWriter gets finalized, it would
attempt to write data to the closed file, raising an exception. Of course, if the StreamWriter got
finalized first, then the data would be safely written to the file.
How did Microsoft solve this problem? Making the garbage collector finalize objects in a specific
order is impossible because objects could contain pointers to each other and there is no way for the
garbage collector to correctly guess the order to finalize these objects. So, here is Microsoft's
solution: the StreamWriter type doesn't implement a Finalize method at all. Of course, this means
that forgetting to explicitly close the StreamWriter object guarantees data loss. Microsoft expects
that developers will see this consistent loss of data and will fix the code by inserting an explicit call
to Close.
As stated earlier, the SuppressFinalize method simply sets a bit flag indicating that the object's
Finalize method should not be called. However, this flag is reset when the runtime determines that
it's time to call a Finalize method. This means that calls to ReRegisterForFinalize cannot be balanced
by calls to SuppressFinalize. The code in Figure 9 demonstrates exactly what I mean.
ReRegisterForFinalize and SuppressFinalize are implemented the way they are for performance
reasons. As long as each call to SuppressFinalize has an intervening call to ReRegisterForFinalize,
everything works. It is up to you to ensure that you do not call ReRegisterForFinalize or
SuppressFinalize multiple times consecutively, or multiple calls to an object's Finalize method can
occur.

Conclusion
The motivation for garbage-collected environments is to simplify memory management for the
105
developer. The first part of this overview looked at some general GC concepts and internals. In
Part 2, I will conclude this discussion. First, I will explore a feature called WeakReferences, which
you can use to reduce the memory pressure placed on the managed heap by large objects. Then I'll
examine a mechanism that allows you to artificially extend the lifetime of a managed object. Finally,
I'll wrap up by discussing various aspects of the garbage collector's performance. I'll discuss
generations, multithreaded collections, and the performance counters that the common language
runtime exposes, which allow you to monitor the garbage collector's real-time behavior

SUMMARY The first part of this two-part article explained how the garbage collection algorithm
works, how resources can clean up properly when the garbage collector decides to free a resource's
memory, and how to force an object to clean up when it is freed. The conclusion of this series
explains strong and weak object references that help to manage memory for large objects, as well as
object generations and how they improve performance. In addition, the use of methods and
properties for controlling garbage collection, resources for monitoring collection performance, and
garbage collection for multithreaded applications are covered.

ast month, I described the motivation for garbage-collected environments: to simplify memory
management for the developer. I also discussed the general algorithm used by the common
language runtime (CLR) and some of the internal workings of this algorithm. In addition, I
explained how the developer must still explicitly handle resource management and cleanup by
implementing Finalize, Close, and/or Dispose methods. This month, I will conclude my discussion of
the CLR garbage collector.
I'll start by exploring a feature called weak references, which you can use to reduce the memory
pressure placed on the managed heap by large objects. Then, I'll discuss how the garbage collector
uses generations as a performance enhancement. Finally, I'll wrap up by discussing a few other
performance enhancements offered by the garbage collector, such as multithreaded collections and
performance counters exposed by the CLR that allow you to monitor the garbage collector's real-time
behavior.

Weak References
When a root points to an object, the object cannot be collected because the application's code can
reach the object. When a root points to an object, it's called a strong reference to the object.
However, the garbage collector also supports weak references. Weak references allow the garbage
collector to collect the object, but they also allow the application to access the object. How can this
be? It all comes down to timing.
If only weak references to an object exist and the garbage collector runs, the object is collected and
when the application later attempts to access the object, the access will fail. On the other hand, to
access a weakly referenced object, the application must obtain a strong reference to the object. If the
application obtains this strong reference before the garbage collector collects the object, then the
garbage collector can't collect the object because a strong reference to the object exists. I know this
all sounds somewhat confusing, so let's clear it up by examining the code in Figure 1.
Why might you use weak references? Well, there are some data structures that are created easily,
but require a lot of memory. For example, you might have an application that needs to know all the
directories and files on the user's hard drive. You can easily build a tree that reflects this
information and as your application runs, you'll refer to the tree in memory instead of actually
accessing the user's hard disk. This procedure greatly improves the performance of your application.
The problem is that the tree could be extremely large, requiring quite a bit of memory. If the user
starts accessing a different part of your application, the tree may no longer be necessary and is
wasting valuable memory. You could delete the tree, but if the user switches back to the first part of
your application, you'll need to reconstruct the tree again. Weak references allow you to handle this
scenario quite easily and efficiently.
When the user switches away from the first part of the application, you can create a weak reference
to the tree and destroy all strong references. If the memory load is low for the other part of the
application, then the garbage collector will not reclaim the tree's objects. When the user switches
back to the first part of the application, the application attempts to obtain a strong reference for the
tree. If successful, the application doesn't have to traverse the user's hard drive again.
The WeakReference type offers two constructors:
WeakReference(Object target);
WeakReference(Object target, Boolean trackResurrection);
106
The target parameter identifies the object that the WeakReference object should track. The
trackResurrection parameter indicates whether the WeakReference object should track the object
after it has had its Finalize method called. Usually, false is passed for the trackResurrection
parameter and the first constructor creates a WeakReference that does not track resurrection. (For
an explanation of resurrection, see part 1 of this article at Garbage Collection: Automatic Memory
Management in the Microsoft .NET Framework.)
For convenience, a weak reference that does not track resurrection is called a short weak reference,
while a weak reference that does track resurrection is called a long weak reference. If an object's type
doesn't offer a Finalize method, then short and long weak references behave identically. It is strongly
recommended that you avoid using long weak references. Long weak references allow you to
resurrect an object after it has been finalized and the state of the object is unpredictable.
Once you've created a weak reference to an object, you usually set the strong reference to the
object to null. If any strong reference remains, the garbage collector will be unable to collect the
object.
To use the object again, you must turn the weak reference into a strong reference. You accomplish
this simply by calling the WeakReference object's Target property and assigning the result to one of
your application's roots. If the Target property returns null, then the object was collected. If the
property does not return null, then the root is a strong reference to the object and the code may
manipulate the object. As long as the strong reference exists, the object cannot be collected.

Weak Reference Internals


From the previous discussion, it should be obvious that WeakReference objects do not behave like
other object types. Normally, if your application has a root that refers to an object and that object
refers to another object, then both objects are reachable and the garbage collector cannot reclaim
the memory in use by either object. However, if your application has a root that refers to a
WeakReference object, then the object referred to by the WeakReference object is not considered
reachable and may be collected.
To fully understand how weak references work, let's look inside the managed heap again. The
managed heap contains two internal data structures whose sole purpose is to manage weak
references: the short weak reference table and the long weak reference table. These two tables simply
contain pointers to objects allocated within the managed heap.
Initially, both tables are empty. When you create a WeakReference object, an object is not allocated
from the managed heap. Instead, an empty slot in one of the weak reference tables is located; short
weak references use the short weak reference table and long weak references use the long weak
reference table.
Once an empty slot is found, the value in the slot is set to the address of the object you wish to
track—the object's pointer is passed to the WeakReference's constructor. The value returned from
the new operator is the address of the slot in the WeakReference table. Obviously, the two weak
reference tables are not considered part of an application's roots or the garbage collector would not
be able to reclaim the objects pointed to by the tables.
Now, here's what happens when a garbage collection (GC) runs:

1. The garbage collector builds a graph of all the reachable objects. Part 1 of this article
discussed how this works.
2. The garbage collector scans the short weak reference table. If a pointer in the table refers to
an object that is not part of the graph, then the pointer identifies an unreachable object and the
slot in the short weak reference table is set to null.
3. The garbage collector scans the finalization queue. If a pointer in the queue refers to an
object that is not part of the graph, then the pointer identifies an unreachable object and the
pointer is moved from the finalization queue to the freachable queue. At this point, the object is
added to the graph since the object is now considered reachable.

4. The garbage collector scans the long weak reference table. If a pointer in the table refers to an
object that is not part of the graph (which now contains the objects pointed to by entries in the
freachable queue), then the pointer identifies an unreachable object and the slot is set to null.
5. The garbage collector compacts the memory, squeezing out the holes left by the unreachable
objects.
107
Once you understand the logic of the garbage collection process, it's easy to understand how weak
references work. Accessing the WeakReference's Target property causes the system to return the
value in the appropriate weak reference table's slot. If null is in the slot, the object was collected.
A short weak reference doesn't track resurrection. This means that the garbage collector sets the
pointer to null in the short weak reference table as soon as it has determined that the object is
unreachable. If the object has a Finalize method, the method has not been called yet so the object
still exists. If the application accesses the WeakReference object's Target property, then null will be
returned even though the object actually still exists.
A long weak reference tracks resurrection. This means that the garbage collector sets the pointer to
null in the long weak reference table when the object's storage is reclaimable. If the object has a
Finalize method, the Finalize method has been called and the object was not resurrected.

Generations
When I first started working in a garbage-collected environment, I had many concerns about
performance. After all, I've been a C/C++ programmer for more than 15 years and I understand the
overhead of allocating and freeing memory blocks from a heap. Sure, each version of Windows® and
each version of the C runtime has tweaked the internals of the heap algorithms in order to improve
performance.
Well, like the developers of Windows and the C runtime, the GC developers are tweaking the
garbage collector to improve its performance. One feature of the garbage collector that exists purely
to improve performance is called generations. A generational garbage collector (also known as an
ephemeral garbage collector) makes the following assumptions:

 The newer an object is, the shorter its lifetime will be.
 The older an object is, the longer its lifetime will be.
 Newer objects tend to have strong relationships to each other and are frequently accessed
around the same time.
 Compacting a portion of the heap is faster than compacting the whole heap.
Of course, many studies have demonstrated that these assumptions are valid for a very large set of
existing applications. So, let's discuss how these assumptions have influenced the implementation of
the garbage collector.
When initialized, the managed heap contains no objects. Objects added to the heap are said to be
in generation 0, as you can see in Figure 2. Stated simply, objects in generation 0 are young objects
that have never been examined by the garbage collector.

Figure 2 Generation 0

Now, if more objects are added to the heap, the heap fills and a garbage collection must occur.
When the garbage collector analyzes the heap, it builds the graph of garbage (shown here in purple)
and non-garbage objects. Any objects that survive the collection are compacted into the left-most
108
portion of the heap. These objects have survived a collection, are older, and are now considered to be
in generation 1 (see Figure 3).

Figure 3 Generations 0 and 1

As even more objects are added to the heap, these new, young objects are placed in generation 0. If
generation 0 fills again, a GC is performed. This time, all objects in generation 1 that survive are
compacted and considered to be in generation 2 (see Figure 4). All survivors in generation 0 are now
compacted and considered to be in generation 1. Generation 0 currently contains no objects, but all
new objects will go into generation 0.

Figure 4 Generations 0, 1, and 2

Currently, generation 2 is the highest generation supported by the runtime's garbage collector.
When future collections occur, any surviving objects currently in generation 2 simply stay in
generation 2.

Generational GC Performance Optimizations


As I stated earlier, generational garbage collecting improves performance. When the heap fills and a
collection occurs, the garbage collector can choose to examine only the objects in generation 0 and
ignore the objects in any greater generations. After all, the newer an object is, the shorter its lifetime
is expected to be. So, collecting and compacting generation 0 objects is likely to reclaim a significant
amount of space from the heap and be faster than if the collector had examined the objects in all
generations.
This is the simplest optimization that can be obtained from generational GC. A generational
collector can offer more optimizations by not traversing every object in the managed heap. If a root or
object refers to an object in an old generation, the garbage collector can ignore any of the older
109
objects' inner references, decreasing the time required to build the graph of reachable objects. Of
course, it is possible that an old object refers to a new object. So that these objects are examined,
the collector can take advantage of the system's write-watch support (provided by the Win32®
GetWriteWatch function in Kernel32.dll). This support lets the collector know which old objects (if
any) have been written to since the last collection. These specific old objects can have their
references checked to see if they refer to any new objects.
If collecting generation 0 doesn't provide the necessary amount of storage, then the collector can
attempt to collect the objects from generations 1 and 0. If all else fails, then the collector can collect
the objects from all generations—2, 1, and 0. The exact algorithm used by the collector to determine
which generations to collect is one of those areas that Microsoft will be tweaking forever.
Most heaps (like the C runtime heap) allocate objects wherever they find free space. Therefore, if I
create several objects consecutively, it is quite possible that these objects will be separated by
megabytes of address space. However, in the managed heap, allocating several objects consecutively
ensures that the objects are contiguous in memory.
One of the assumptions stated earlier was that newer objects tend to have strong relationships to
each other and are frequently accessed around the same time. Since new objects are allocated
contiguously in memory, you gain performance from locality of reference. More specifically, it is
highly likely that all the objects can reside in the CPU's cache. Your application will access these
objects with phenomenal speed since the CPU will be able to perform most of its manipulations
without having cache misses which forces RAM access.
Microsoft's performance tests show that managed heap allocations are faster than standard
allocations performed by the Win32 HeapAlloc function. These tests also show that it takes less than
1 millisecond on a 200Mhz Pentium to perform a full GC of generation 0. It is Microsoft's goal to
make GCs take no more time than an ordinary page fault.

Direct Control with System.GC


The System.GC type allows your application some direct control over the garbage collector. For
starters, you can query the maximum generation supported by the managed heap by reading the
GC.MaxGeneration property. Currently, the GC.MaxGeneration property always returns 2.
It is also possible to force the garbage collector to perform a collection by calling one of the two
methods shown here:
void GC.Collect(Int32 Generation)
void GC.Collect()
The first method allows you to specify which generation to collect. You may pass any integer from 0
to GC.MaxGeneration, inclusive. Passing 0 causes generation 0 to be collected; passing 1 causes
generation 1 and 0 to be collected; and passing 2 causes generation 2, 1, and 0 to be collected. The
version of the Collect method that takes no parameters forces a full collection of all generations and
is equivalent to calling:
GC.Collect(GC.MaxGeneration);
Under most circumstances, you should avoid calling any of the Collect methods; it is best to just
let the garbage collector run on its own accord. However, since your application knows more about
its behavior than the runtime does, you could help matters by explicitly forcing some collections. For
example, it might make sense for your application to force a full collection of all generations after the
user saves his data file. I imagine Internet browsers performing a full collection when pages are
unloaded. You might also want to force a collection when your application is performing other
lengthy operations; this hides the fact that the collection is taking processing time and prevents a
collection from occurring when the user is interacting with your application.
The GC type also offers a WaitForPendingFinalizers method. This method simply suspends the
calling thread until the thread processing the freachable queue has emptied the queue, calling each
object's Finalize method. In most applications, it is unlikely that you will ever have to call this
method.
Lastly, the garbage collector offers two methods that allow you to determine which generation an
object is currently in:
Int32 GetGeneration(Object obj)
Int32 GetGeneration(WeakReference wr)
The first version of GetGeneration takes an object reference as a parameter, and the second version
takes a WeakReference reference as a parameter. Of course, the value returned will be somewhere
between 0 and GC.MaxGeneration, inclusive.
The code in Figure 5 will help you understand how generations work. It also demonstrates the use
110
of the garbage collection methods just discussed.

Performance for Multithreaded Applications


In the previous section, I explained the GC algorithm and optimizations. However, there was a big
assumption made during that discussion: only one thread is running. In the real world, it is quite
likely that multiple threads will be accessing the managed heap or at least manipulating objects
allocated within the managed heap. When one thread sparks a collection, other threads must not
access any objects (including object references on its own stack) since the collector is likely to move
these objects, changing their memory locations.
So, when the garbage collector wants to start a collection, all threads executing managed code
must be suspended. The runtime has a few different mechanisms that it uses to safely suspend
threads so that a collection may be done. The reason there are multiple mechanisms is to keep
threads running as long as possible and to reduce overhead as much as possible. I don't want to go
into all the details here, but suffice it to say that Microsoft has done a lot of work to reduce the
overhead involved with performing a collection. Microsoft will continue to modify these mechanisms
over time to help ensure efficient garbage collections.
The following paragraphs describe a few of the mechanisms that the garbage collector employs
when applications have multiple threads:
Fully Interruptible Code When a collection starts, the collector suspends all application threads.
The collector then determines where a thread got suspended and using tables produced by the just-
in-time (JIT) compiler, the collector can tell where in a method the thread stopped, what object
references the code is currently accessing, and where those references are held (in a variable, CPU
register, and so on).
Hijacking The collector can modify a thread's stack so that the return address points to a special
function. When the currently executing method returns, this special function will execute,
suspending the thread. Stealing the thread's execution path this way is referred to as hijacking the
thread. When the collection is complete, the thread will resume and return to the method that
originally called it.
Safe Points As the JIT compiler compiles a method, it can insert calls to a special function that
checks if a GC is pending. If so, the thread is suspended, the GC runs to completion, and the thread
is then resumed. The position where the compiler inserts these method calls is called a GC safe
point.
Note that thread hijacking allows threads that are executing unmanaged code to continue
execution while a garbage collection is occurring. This is not a problem since unmanaged code is not
accessing objects on the managed heap unless the objects are pinned and don't contain object
references. A pinned object is one that the garbage collector is not allowed to move in memory. If a
thread that is currently executing unmanaged code returns to managed code, the thread is hijacked
and is suspended until the GC completes.
In addition to the mechanisms I just mentioned, the garbage collector offers some additional
improvements that enhance the performance of object allocations and collections when applications
have multiple threads.
Synchronization-free Allocations On a multiprocessor system, generation 0 of the managed heap
is split into multiple memory arenas using one arena per thread. This allows multiple threads to
make allocations simultaneously so that exclusive access to the heap is not required.
Scalable Collections On a multiprocessor system running the server version of the execution engine
(MSCorSvr.dll), the managed heap is split into several sections, one per CPU. When a collection is
initiated, the collector has one thread per CPU; all threads collect their own sections simultaneously.
The workstation version of the execution engine (MSCorWks.dll) doesn't support this feature.

Garbage-collecting Large Objects


There is one more performance improvement that you might want to be aware of. Large objects
(those that are 20,000 bytes or larger) are allocated from a special large object heap. Objects in this
heap are finalized and freed just like the small objects I've been talking about. However, large objects
are never compacted because shifting 20,000-byte blocks of memory down in the heap would waste
too much CPU time.
Note that all of these mechanisms are transparent to your application code. To you, the developer,
it looks like there is just one managed heap; these mechanisms exist simply to improve application
performance.
111
Monitoring Garbage Collections
The runtime team at Microsoft has created a set of performance counters that provide a lot of real-
time statistics about the runtime's operations. You can view these statistics via the Windows 2000
System Monitor ActiveX® control. The easiest way to access the System Monitor control is to run
PerfMon.exe and select the + toolbar button, causing the Add Counters dialog box to appear (see
Figure 6).

Figure 6 Adding Performance Counters

To monitor the runtime's garbage collector, select the COM+ Memory Performance object. Then,
you can select a specific application from the instance list box. Finally, select the set of counters that
you're interested in monitoring and press the Add button followed by the Close button. At this point,
the System Monitor will graph the selected real-time statistics. Figure 7 describes the function of
each counter.

Conclusion
So that's just about the full story on garbage collection. Last month I provided the background on
how resources are allocated, how automatic garbage collection works, how to use the finalization
feature to allow an object to clean up after itself, and how the resurrection feature can restore access
to objects. This month I explained how weak and strong references to objects are implemented, how
classifying objects in generations results in performance benefits, and how you can manually control
garbage collection with System.GC. I also covered the mechanisms the garbage collector uses in
multithreaded applications to improve performance, what happens with objects that are larger than
20,000 bytes, and finally, how you can use the Windows 2000 System Monitor to track garbage
collection performance. With this information in hand, you should be able to simplify memory
management and boost performance in your applications.
112
Memory Management

Resource Allocation
The Microsoft .NET common language runtime requires that all resources be allocated from the
managed heap. Objects are automatically freed when they are no longer needed by the application.

When a process is initialized, the runtime reserves a contiguous region of address space that initially
has no storage allocated for it. This address space region is the managed heap. The heap also
maintains a pointer. This pointer indicates where the next object is to be allocated within the heap.
Initially, the pointer is set to the base address of the reserved address space region.

An application creates an object using the new operator. This operator first makes sure that the bytes
required by the new object fit in the reserved region (committing storage if necessary). If the object fits,
then pointer points to the object in the heap, this object's constructor is called, and the new operator
returns the address of the object.

Above fig shows a managed heap consisting of three objects: A, B, and C. The next object to be
allocated will be placed where NextObjPtr points (immediately after object C).

When an application calls the new operator to create an object, there may not be enough address
space left in the region to allocate to the object. The heap detects this by adding the size of the new
object to NextObjPtr. If NextObjPtr is beyond the end of the address space region, then the heap is
full and a collection must be performed.

In reality, a collection occurs when generation 0 is completely full. Briefly, a generation is a


mechanism implemented by the garbage collector in order to improve performance. The idea is that
newly created objects are part of a young generation, and objects created early in the application's
lifecycle are in an old generation. Separating objects into generations can allow the garbage collector
to collect specific generations instead of collecting all objects in the managed heap.
The Garbage Collection Algorithm
The garbage collector checks to see if there are any objects in the heap that are no longer being used
by the application. If such objects exist, then the memory used by these objects can be reclaimed. (If
no more memory is available for the heap, then the new operator throws an
OutOfMemoryException.)

Every application has a set of roots. Roots identify storage locations, which refer to objects on the
managed heap or to objects that are set to null. For example, all the global and static object pointers
in an application are considered part of the application's roots. In addition, any local
variable/parameter object pointers on a thread's stack are considered part of the application's roots.
Finally, any CPU registers containing pointers to objects in the managed heap are also considered
part of the application's roots. The list of active roots is maintained by the just-in-time (JIT) compiler
and common language runtime, and is made accessible to the garbage collector's algorithm.

When the garbage collector starts running, it makes the assumption that all objects in the heap are
113
garbage. In other words, it assumes that none of the application's roots refer to any objects in the
heap. Now, the garbage collector starts walking the roots and building a graph of all objects
reachable from the roots. For example, the garbage collector may locate a global variable that points
to an object in the heap.

Following fig shows a heap with several allocated objects where the application's roots refer directly
to objects A, C, D, and F. All of these objects become part of the graph. When adding object D, the
collector notices that this object refers to object H, and object H is also added to the graph. The
collector continues to walk through all reachable objects recursively.

Once this part of the graph is complete, the garbage collector checks the next root and walks the
objects again. As the garbage collector walks from object to object, if it attempts to add an object to
the graph that it previously added, then the garbage collector can stop walking down that path. This
serves two purposes. First, it helps performance significantly since it doesn't walk through a set of
objects more than once. Second, it prevents infinite loops should you have any circular linked lists of
objects.

Once all the roots have been checked, the garbage collector's graph contains the set of all objects
that are somehow reachable from the application's roots; any objects that are not in the graph are
not accessible by the application, and are therefore considered garbage.

The garbage collector now walks through the heap linearly, looking for contiguous blocks of garbage
objects (now considered free space). The garbage collector then shifts the non-garbage objects down
in memory (using the standard memcpy function), removing all of the gaps in the heap. Of course,
moving the objects in memory invalidates all pointers to the objects. So the garbage collector must
modify the application's roots so that the pointers point to the objects' new locations. In addition, if
any object contains a pointer to another object, the garbage collector is responsible for correcting
these pointers as well.

Following fig shows the managed heap after a collection.

After all the garbage has been identified, all the non-garbage has been compacted, and all the non-
garbage pointers have been fixed-up, the NextObjPtr is positioned just after the last non-garbage
object. At this point, the new operation is tried again and the resource requested by the application
is successfully created.

GC generates a significant performance hit, and this is the major downside of using a managed
heap. However, keep in mind that GCs only occur when the heap is full and, until then, the
managed heap is significantly faster than a C-runtime heap. The runtime's garbage collector also
114
offers some optimizations using Generations that greatly improve the performance of garbage
collection.

You no longer have to implement any code that manages the lifetime of any resources that your
application uses. Now it is not possible to leak resources, since any resource not accessible from
your application's roots can be collected at some point. Also it is not possible to access a resource
that is freed, since the resource won't be freed if it is reachable. If it's not reachable, then your
application has no way to access it.

Following code demonstrates how resources are allocated and managed:


class Application
{
public static int Main(String[] args)
{
// ArrayList object created in heap, myArray is now in root
ArrayList myArray = new ArrayList();

// Create 10000 objects in the heap


for (int x = 0; x < 10000; x++)
{
myArray.Add(new Object()); // Object object created in heap
}

// Right now, myArray is a root (on the thread's stack). So,


// myArray is reachable and the 10000 objects it points to are also reachable.
Console.WriteLine(myArray.Count);

// After the last reference to myArray in the code, myArray is not a root.
// Note that the method doesn't have to return, the JIT compiler knows
// to make myArray not a root after the last reference to it in the code.

// Since myArray is not a root, all 10001 objects are not reachable
// and are considered garbage. However, the objects are not
// collected until a GC is performed.
}
}

If GC is so great, you might be wondering why it isn't in ANSI C++. The reason is that a garbage
collector must be able to identify an application's roots and must also be able to find all object
pointers. The problem with C++ is that it allows casting a pointer from one type to another, and
there's no way to know what a pointer refers to. In the common language runtime, the managed
heap always knows the actual type of an object, and the metadata information is used to determine
which members of an object refer to other objects.
Generations
One feature of the garbage collector that exists purely to improve performance is called generations.
A generational garbage collector (also known as an ephemeral garbage collector) makes the following
assumptions:

 The newer an object is, the shorter its lifetime will be.
 The older an object is, the longer its lifetime will be.
 Newer objects tend to have strong relationships to each other and are frequently accessed
around the same time.
 Compacting a portion of the heap is faster than compacting the whole heap.

When initialized, the managed heap contains no objects. Objects added to the heap are said to be in
generation 0, as you can see in following fig. Stated simply, objects in generation 0 are young objects
that have never been examined by the garbage collector.
115

Now, if more objects are added to the heap, the heap fills and a garbage collection must occur. When
the garbage collector analyzes the heap, it builds the graph of garbage (shown here in Green) and
non-garbage objects. Any objects that survive the collection are compacted into the left-most portion
of the heap. These objects have survived a collection, are older, and are now considered to be in
generation 1.
116

As even more objects are added to the heap, these new, young objects are placed in generation 0. If
generation 0 fills again, a GC is performed. This time, all objects in generation 1 that survive are
compacted and considered to be in generation 2 (see following fig). All survivors in generation 0 are
now compacted and considered to be in generation 1. Generation 0 currently contains no objects,
but all new objects will go into generation 0.
117
Currently, generation 2 is the highest generation supported by the runtime's garbage collector.
When future collections occur, any surviving objects currently in generation 2 simply stay in
generation 2.

Generational GC Performance Optimizations


Generational garbage collecting improves performance. When the heap fills and a collection occurs,
the garbage collector can choose to examine only the objects in generation 0 and ignore the objects
in any greater generations. After all, the newer an object is, the shorter its lifetime is expected to be.
So, collecting and compacting generation 0 objects is likely to reclaim a significant amount of space
from the heap and be faster than if the collector had examined the objects in all generations.

A generational collector can offer more optimizations by not traversing every object in the managed
heap. If a root or object refers to an object in an old generation, the garbage collector can ignore any
of the older objects' inner references, decreasing the time required to build the graph of reachable
objects. Of course, it is possible that an old object refers to a new object. So that these objects are
examined, the collector can take advantage of the system's write-watch support (provided by the
Win32® GetWriteWatch function in Kernel32.dll). This support lets the collector know which old
objects (if any) have been written to since the last collection. These specific old objects can have their
references checked to see if they refer to any new objects.

If collecting generation 0 doesn't provide the necessary amount of storage, then the collector can
attempt to collect the objects from generations 1 and 0. If all else fails, then the collector can collect
the objects from all generations—2, 1, and 0.

One of the assumptions stated earlier was that newer objects tend to have strong relationships to
each other and are frequently accessed around the same time. Since new objects are allocated
contiguously in memory, you gain performance from locality of reference. More specifically, it is
highly likely that all the objects can reside in the CPU's cache. Your application will access these
objects with phenomenal speed since the CPU will be able to perform most of its manipulations
without having cache misses which forces RAM access.

Microsoft's performance tests show that managed heap allocations are faster than standard
allocations performed by the Win32 HeapAlloc function. These tests also show that it takes less than
1 millisecond on a 200 MHz Pentium to perform a full GC of generation 0. It is Microsoft's goal to
make GCs take no more time than an ordinary page fault.

Disadvantages of Win32 heap:

 Most heaps (like the C runtime heap) allocate objects wherever they find free space.
Therefore, if I create several objects consecutively, it is quite possible that these objects will
be separated by megabytes of address space. However, in the managed heap, allocating
several objects consecutively ensures that the objects are contiguous in memory.
 When memory is allocated from a Win32 heap, the heap must be examined to find a block of
memory that can satisfy the request. This is not required in managed heap, since here
objects are contiguous in memory.
 In Win32 heap, data structures that the heap maintains must be updated. The managed
heap, on the other hand, only needs to increment the heap pointer.

Finalization
The garbage collector offers an additional feature that you may want to take advantage of:
finalization. Finalization allows a resource to gracefully clean up after itself when it is being
collected. By using finalization, a resource representing a file or network connection is able to clean
itself up properly when the garbage collector decides to free the resource's memory.

When the garbage collector detects that an object is garbage, the garbage collector calls the object's
Finalize method (if it exists) and then the object's memory is reclaimed. For example, let's say you
have the following type (in C#):
public class BaseObj {
public BaseObj()
118
{
}

protected override void Finalize()


{
// Perform resource cleanup code here...
// Example: Close file/Close network connection
Console.WriteLine("In Finalize.");
}
}

Now you can create an instance of this object by calling:


BaseObj bo = new BaseObj();

Some time in the future, the garbage collector will determine that this object is garbage. When that
happens, the garbage collector will see that the type has a Finalize method and will call the method,
causing "In Finalize" to appear in the console window and reclaiming the memory block used by this
object.

Many developers who are used to programming in C++ draw an immediate correlation between a
destructor and the Finalize method. However, object finalization and destructors have very different
semantics and it is best to forget everything you know about destructors when thinking about
finalization. Managed objects never have destructors.

When designing a type it is best to avoid using a Finalize method. There are several reasons for this:

 Finalizable objects get promoted to older generations, which increases memory pressure and
prevents the object's memory from being collected when the garbage collector determines the
object is garbage. In addition, all objects referred to directly or indirectly by this object get
promoted as well.
 Finalizable objects take longer to allocate.
 Forcing the garbage collector to execute a Finalize method can significantly hurt
performance. Remember, each object is finalized. So if I have an array of 10,000 objects, each
object must have its Finalize method called.
 Finalizable objects may refer to other (non-finalizable) objects, prolonging their lifetime
unnecessarily. In fact, you might want to consider breaking a type into two different types: a
lightweight type with a Finalize method that doesn't refer to any other objects, and a separate
type without a Finalize method that does refer to other objects.
 You have no control over when the Finalize method will execute. The object may hold on to
resources until the next time the garbage collector runs.
 When an application terminates, some objects are still reachable and will not have their
Finalize method called. This can happen if background threads are using the objects or if
objects are created during application shutdown or AppDomain unloading. In addition, by
default, Finalize methods are not called for unreachable objects when an application exits so
that the application may terminate quickly. Of course, all operating system resources will be
reclaimed, but any objects in the managed heap are not able to clean up gracefully. You can
change this default behavior by calling the System.GC type's RequestFinalizeOnShutdown
method. However, you should use this method with care since calling it means that your type
is controlling a policy for the entire application.
 The runtime doesn't make any guarantees as to the order in which Finalize methods are
called. For example, let's say there is an object that contains a pointer to an inner object. The
garbage collector has detected that both objects are garbage. Furthermore, say that the inner
object's Finalize method gets called first. Now, the outer object's Finalize method is allowed to
access the inner object and call methods on it, but the inner object has been finalized and
the results may be unpredictable. For this reason, it is strongly recommended that Finalize
methods not access any inner, member objects.

If you determine that your type must implement a Finalize method, then make sure the code
executes as quickly as possible. Avoid all actions that would block the Finalize method, including
119
any thread synchronization operations. Also, if you let any exceptions escape the Finalize
method, the system just assumes that the Finalize method returned and continues calling other
objects' Finalize methods.
When the compiler generates code for a constructor, the compiler automatically inserts a call to the
base type's constructor. Likewise, when a C++ compiler generates code for a destructor, the compiler
automatically inserts a call to the base type's destructor. Finalize methods are different from
destructors. The compiler has no special knowledge about a Finalize method, so the compiler does
not automatically generate code to call a base type's Finalize method. If you want this behavior—and
frequently you do—then you must explicitly call the base type's Finalize method from your type's
Finalize method:

public class BaseObj


{
public BaseObj()
{
}

protected override void Finalize()


{
Console.WriteLine("In Finalize.");
base.Finalize(); // Call base type's Finalize
}
}
Note that you'll usually call the base type's Finalize method as the last statement in the derived
type's Finalize method. This keeps the base object alive as long as possible. Since calling a base type
Finalize method is common, C# has a syntax that simplifies your work. In C#, the following code:
class MyObject
{
~MyObject()
{
•••
}
}

causes the compiler to generate this code:

class MyObject {
protected override void Finalize() {
•••
base.Finalize();
}
}
Note that this C# syntax looks identical to the C++ language's syntax for defining a destructor. But
remember, C# doesn't support destructors. Don't let the identical syntax fool you.
Finalization Internals
When an application creates a new object, the new operator allocates the memory from the heap. If
the object's type contains a Finalize method, then a pointer to the object is placed on the finalization
queue. The finalization queue is an internal data structure controlled by the garbage collector. Each
entry in the queue points to an object that should have its Finalize method called before the object's
memory can be reclaimed.
Following fig shows a heap containing several objects. Some of these objects are reachable from the
application's roots, and some are not. When objects C, E, F, I, and J were created, the system
detected that these objects had Finalize methods and pointers to these objects were added to the
finalization queue.
120

When a GC occurs, objects B, E, G, H, I, and J are determined to be garbage. The garbage collector
scans the finalization queue looking for pointers to these objects. When a pointer is found, the
pointer is removed from the finalization queue and appended to the freachable queue (pronounced
"F-reachable"). The freachable queue is another internal data structure controlled by the garbage
collector. Each pointer in the freachable queue identifies an object that is ready to have its Finalize
method called.
After the collection, the managed heap looks like following fig. Here, you see that the memory
occupied by objects B, G, and H has been reclaimed because these objects did not have a Finalize
method that needed to be called. However, the memory occupied by objects E, I, and J could not be
reclaimed because their Finalize method has not been called yet.
121

There is a special runtime thread dedicated to calling Finalize methods. When the freachable queue
is empty (which is usually the case), this thread sleeps. But when entries appear, this thread wakes,
removes each entry from the queue, and calls each object's Finalize method. Because of this, you
should not execute any code in a Finalize method that makes any assumption about the thread
that's executing the code. For example, avoid accessing thread local storage in the Finalize method.
The interaction of the finalization queue and the freachable queue is quite fascinating. First, let me
tell you how the freachable queue got its name. The f is obvious and stands for finalization; every
entry in the freachable queue should have its Finalize method called. The "reachable" part of the
name means that the objects are reachable. To put it another way, the freachable queue is
considered to be a root just like global and static variables are roots. Therefore, if an object is on the
freachable queue, then the object is reachable and is not garbage.
In short, when an object is not reachable, the garbage collector considers the object garbage. Then,
when the garbage collector moves an object's entry from the finalization queue to the freachable
queue, the object is no longer considered garbage and its memory is not reclaimed. At this point, the
garbage collector has finished identifying garbage. Some of the objects identified as garbage have
been reclassified as not garbage. The garbage collector compacts the reclaimable memory and the
special runtime thread empties the freachable queue, executing each object's Finalize method.
122

The next time the garbage collector is invoked, it sees that the finalized objects are truly garbage,
since the application's roots don't point to it and the freachable queue no longer points to it. Now the
memory for the object is simply reclaimed. The important thing to understand here is that two GCs
are required to reclaim memory used by objects that require finalization. In reality, more than two
collections may be necessary since the objects could get promoted to an older generation. Above fig
shows what the managed heap looks like after the second GC.
Dispose Method
Use this method to close or release unmanaged resources such as files, streams, and handles held
by an instance of the class that implements this interface. This method is, by convention, used for
all tasks associated with freeing resources held by an object, or preparing an object for reuse.

When implementing this method, objects must seek to ensure that all held resources are freed by
propagating the call through the containment hierarchy. For example, if an object A allocates an
object B, and object B allocates an object C, then A's Dispose implementation must call Dispose on
B, which must in turn call Dispose on C. Objects must also call the Dispose method of their base
class if the base class implements IDisposable.

If an object's Dispose method is called more than once, the object must ignore all calls after the first
one. The object must not throw an exception if its Dispose method is called multiple times. Dispose
can throw an exception if an error occurs because a resource has already been freed and Dispose
had not been called previously.

Because the Dispose method must be called explicitly, objects that implement IDisposable must also
implement a finalizer to handle freeing resources when Dispose is not called. By default, the garbage
collector will automatically call an object's finalizer prior to reclaiming its memory. However, once
the Dispose method has been called, it is typically unnecessary for the garbage collector to call the
disposed object's finalizer. To prevent automatic finalization, Dispose implementations can call the
GC.SuppressFinalize method.

Direct Control with System.GC


The System.GC type allows your application some direct control over the garbage collector. You can
query the maximum generation supported by the managed heap by reading the GC.MaxGeneration
property. Currently, the GC.MaxGeneration property always returns 2.

It is also possible to force the garbage collector to perform a collection by calling one of the two
methods shown here:
123

void GC.Collect(Int32 Generation)


void GC.Collect()

The first method allows you to specify which generation to collect. You may pass any integer from 0
to GC.MaxGeneration, inclusive. Passing 0 causes generation 0 to be collected; passing 1 cause
generation 1 and 0 to be collected; and passing 2 causes generation 2, 1, and 0 to be collected. The
version of the Collect method that takes no parameters forces a full collection of all generations and
is equivalent to calling:

GC.Collect(GC.MaxGeneration);

Under most circumstances, you should avoid calling any of the Collect methods; it is best to just let
the garbage collector run on its own accord. However, since your application knows more about its
behavior than the runtime does, you could help matters by explicitly forcing some collections. For
example, it might make sense for your application to force a full collection of all generations after the
user saves his data file. I imagine Internet browsers performing a full collection when pages are
unloaded. You might also want to force a collection when your application is performing other
lengthy operations; this hides the fact that the collection is taking processing time and prevents a
collection from occurring when the user is interacting with your application.

The GC type also offers a WaitForPendingFinalizers method. This method simply suspends the
calling thread until the thread processing the freachable queue has emptied the queue, calling each
object's Finalize method. In most applications, it is unlikely that you will ever have to call this
method.

Lastly, the garbage collector offers two methods that allow you to determine which generation an
object is currently in:

Int32 GetGeneration(Object obj)


Int32 GetGeneration(WeakReference wr)

The first version of GetGeneration takes an object reference as a parameter, and the second version
takes a WeakReference reference as a parameter. Of course, the value returned will be somewhere
between 0 and GC.MaxGeneration, inclusive.

Multi File Assembly

This section provides a complete example that illustrates the steps required to create a multifile
assembly.

Step 1 — Compiling Files with Namespaces Referenced by Other Files


This example starts with some simple code for the Stringer file. Stringer has a namespace called
myStringer with a class called Stringer. The Stringer class contains a method called StringerMethod
that writes a single line to the console.

[C#]
// Assembly building example in the .NET Framework SDK.
using System;
namespace myStringer
{
public class Stringer
{
public void StringerMethod()
{
System.Console.WriteLine("This is a line from StringerMethod.");
}
124
}
}
Use the following command to compile this code:
[C#]
csc /t:module Stringer.cs
Specifying the module parameter with the /t: compiler option indicates that the file should be
compiled as a module rather than as an assembly. The compiler produces a module called
Stringer.netmodule, which can be added to an assembly.

Step 2 — Compiling Modules with References to Other Modules


This step uses the /addmodule compiler option. In this example, a code module called Client has an
entry point Main method that references a method in the Stringer.dll module created in Step 1.
The following example shows the code for Client.
[C#]
using System;
using myStringer; //The namespace created in Stringer.netmodule.
class MainClientApp
{
// Static method Main is the entry point method.
public static void Main()
{
Stringer myStringInstance = new Stringer();
Console.WriteLine("Client code executes");
//myStringComp.Stringer();
myStringInstance.StringerMethod();
}
}
Use the following command to compile this code:
[C#]
csc /addmodule:Stringer.netmodule /t:module Client.cs
Specify the /t:module option because this module will be added to an assembly in a future step.
Specify the /addmodule option because the code in Client references a namespace created by the
code in Stringer.netmodule. The compiler produces a module called Client.netmodule that contains a
reference to another module, Stringer.netmodule.
Note The C# and Visual Basic compilers support directly creating multifile assemblies using
the following two different syntaxes.

 Two compilations create a two-file assembly:


 [Visual Basic]
 vbc /t:module Stringer.vb
 vbc Client.vb /addmodule:Stringer.netmodule
 [C#]
 csc /t:module Stringer.cs
csc Client.cs /addmodule:Stringer.netmodule

 One compilation creates a two-file assembly:


 [Visual Basic]
 vbc /out:Stringer.netmodule Stringer.vb /out:Client.exe Client.vb
125
 [C#]
csc /out:Client.exe Client.cs /out:Stringer.netmodule Stringer.cs

Step 3 — Creating a Multifile Assembly Using the Assembly Linker


You can use the Assembly Linker (Al.exe) to create an assembly from a collection of compiled code
modules.

To create a multifile assembly using the Assembly Linker

 At the command prompt, type the following command:


al <module name> <module name> ... /main:<method name> /out:<file name>
/target:<assembly file type>
In this command, the module name arguments specify the name of each module to include in
the assembly. The /main: option specifies the method name that is the assembly's entry point.
The /out: option specifies the name of the output file, which contains assembly metadata. The
/target: option specifies that the assembly is a console application executable (.exe) file, a
Windows executable (.win) file, or a library (.lib) file.
In the following example, Al.exe creates an assembly that is a console application executable called
myAssembly.exe. The application consists of two modules called Client.netmodule and
Stringer.netmodule, and the executable file called myAssembly.exe, which contains only assembly
metadata . The entry point of the assembly is the Main method in the class MainClientApp, which is
located in Client.dll.
al Client.netmodule Stringer.netmodule /main:MainClientApp.Main /out:myAssembly.exe
/target:exe
You can use the MSIL Disassembler (Ildasm.exe) to examine the contents of an assembly, or
determine whether a file is an assembly or a module.

NET Remoting Versus Web Services

With the advent of .NET and the .NET Framework, Microsoft introduced a set of new technologies in
the form of Web services and .NET remoting. .NET remoting and ASP.NET Web services are powerful
technologies that provide a suitable framework for developing distributed applications. It is
important to understand how both technologies work and then choose the one that is right for your
application.
The Web services technology enables cross-platform integration by using HTTP, XML and SOAP for
communication thereby enabling true business-to-business application integrations across firewalls.
Because Web services rely on industry standards to expose application functionality on the Internet,
they are independent of programming language, platform and device.
Remoting is .a technology that allows programs and software components to interact across
application domains, processes, and machine boundaries. This enables your applications to take
advantage of remote resources in a networked environment.
Both Web services and remoting support developing distributed applications and application
integration, but you need to consider how they differ before choosing one implementation over the
other. In this article, I will show the differences between these two technologies. I will present
samples for each type of implementation and identify when to use which technology.
126

DCOM
If you are a real Microsoft platform developer then you have done some
work on COM and interface based components. When it comes to
distributing your program logic, you are almost tied to Distributed COM
(DCOM).
DCOM is a very proprietary RPC-based communication protocol for COM-
based distributed component architectures. Even though DCOM allows us
to create scalable and reliable architectures in the Intranet environment,
there are a lot of problems with DCOM when you try to integrate with
different platforms and technologies in an Internet environment.

A Look at .NET Remoting


.NET Remoting uses a flexible and extremely extensible architecture. Remoting uses the .NET
concept of an Application Domain (AppDomain) to determine its activity. An AppDomain is an
abstract construct for ensuring isolation of data and code, but not having to rely on operating
system specific concepts such as processes or threads. A process can contain multiple AppDomains
but one AppDomain can only exist in exactly one process. If a call from program logic crosses an
AppDomain boundary then .NET Remoting will come into place. An object is considered local if it
resides in the same AppDomain as the caller. If the object is not in the same appdomain as the
caller, then it is considered remote.
In .NET remoting, the remote object is implemented in a class that derives from
System.MarshalByRefObject. The MarshalByRefObject class provides the core foundation for
enabling remote access of objects across application domains. A remote object is confined to the
application domain where it is created. In .NET remoting, a client doesn't call the methods directly;
instead a proxy object is used to invoke methods on the remote object. Every public method that we
define in the remote object class is available to be called from clients.

When a client calls the remote method, the proxy receives the call, encodes the message using an
appropriate formatter, then sends the call over the channel to the server process. A listening channel
on the server appdomain picks up the request and forwards it to the server remoting system, which
locates and invokes the methods on the requested object. Once the execution is completed, the
process is reversed and the results are returned back to the client.
127
Out of the box, the remoting framework comes with two formatters: the binary and SOAP
formatters. The binary formatter is extremely fast, and encodes method calls in a proprietary, binary
format. The SOAP formatter is slower, but it allows developers to encode the remote messages in a
SOAP format. If neither formatter fits your needs, developers are free to write their own and plug it in
as a replacement.

Different Types of Remote Objects


The remoting infrastructure allows you to create two distinct types of remote objects.

1. Client-activated objects - A client-activated object is a server-side object whose creation and


destruction is controlled by the client application. An instance of the remote object is created
when the client calls the new operator on the server object. This instance lives as long as the
client needs it, and lives across one to many method calls. The object will be subject to
garbage collection once it's determined that no other clients need it.

2. Server-activated objects - A server-activated object's lifetime is managed by the remote


server, not the client that instantiates the object. This differs from the client-activated object,
where the client governs when the object will be marked for finalization. It is important to
understand that the server-activated objects are not created when a client calls New or
Activator.GetObject. They are rather created when the client actually invokes a method on
the proxy. There are two types of server activated objects. They are:
o Single call . Single-call objects handle one, and only one, request coming from a
client. When the client calls a method on a single call object, the object constructs
itself, performs whatever action the method calls for, and the object is then subject to
garbage collection. No state is held between calls, and each call (no matter what client
it came from) is called on a new object instance.

o Singleton - The difference in a singleton and single call lies in lifetime management.
While single-call objects are stateless in nature, singletons are stateful objects,
meaning that they can be used to retain state across multiple method calls. A singleton
object instance serves multiple clients, allowing those clients to share data among themselves.

A Look At ASP.NET Web Services


With the arrival of .NET, creating an ASP.NET Web service is a breezy experience with the .NET
framework taking away all the complexities in creating and consuming Web services. To create a
Web service, all you need to do is create a Web service class that derives from the
System.Web.Services.WebService class and decorate the methods (that you want to expose as Web
services) with the WebMethod attribute. Once this is done, these methods can be invoked by
sending HTTP requests using SOAP.
Consuming a Web service is very straightforward too. You can very easily create a proxy class for
your Web service using either wsdl.exe utility or the Add Web Reference option in VS.NET. The
Web service proxy hides all the network and marshaling plumbing from the application code, so
using the Web service looks just like using any other local object.
128

As you can see from the above diagram, the client proxy receives the request from the client,
serializes the request into a SOAP request which is then forwarded to the remote Web service. The
remote Web service receives the SOAP request, executes the method, and sends the results in the
form of a SOAP response to the client proxy, which deserializes the message and forwards the actual
results to the client.

ASP.NET Web Services Vs .NET Remoting


Now that we have understood the basic concepts of .NET remoting and Web services, let us identify
the differences between these two technologies. For this, I present different factors such as
performance, state management, etc and then identify which technology to use in what situations.

Performance
In terms of performance, the .NET remoting plumbing provides the fastest communication when you
use the TCP channel and the binary formatter. In the case of Web services, the primary issue is
performance. The verbosity of XML can cause SOAP serialization to be many times slower than a
binary formatter. Additionally, string manipulation is very slow when compared to processing the
individual bits of a binary stream. All data transported across the wire is formatted into a SOAP
packet. However if your Web service performs computation intensive operations, you might want to
consider using caching to increase the performance of your Web service on the server side. This will
increase the scalability of the Web service, which in turn can contribute to the increase in
performance of the Web service consumers. A remoting component, using the TCP channel and the
binary formatter, provides the greatest performance of any remoting scenario, primarily because the
binary formatter is able to serialize and deserialize data much faster.
If you use .NET remoting with a SOAP formatter, you will find that the performance provided by
ASP.NET Web services is better than the performance provided by NET remoting endpoints that used
the SOAP formatter with either the HTTP or the TCP channel. However the .NET remoting provides
clear performance advantages over ASP.NET Web services only when you use TCP channels with
binary communication.

State Management
Web services are a stateless programming model, which means each incoming request is handled
independently. In addition, each time a client invokes an ASP.NET Web service, a new object is
created to service the request. The object is destroyed after the method call completes. To maintain
129
state between requests, you can either use the same techniques used by ASP.NET pages, i.e., the
Session and Application objects, or you can implement your own custom solution. However it is
important to remember that maintaining state can be costly with Web services as they use extensive
memory resources.
.NET remoting supports a range of state management options that you can choose from. As
mentioned before, SingleCall objects are stateless, Singleton objects can share state for all clients,
and client-activated objects maintain state on a per-client basis. Having three types of remote
objects (as opposed to one with Web services) during the design phase helps us create more efficient,
scalable applications. If you don't need to maintain state, use single-call objects; if you need to
maintain state in a small section of code, use single call and singletons together. The ability to mix
and match the various object types facilitates creation of solid architectural designs.

Security
.NET remoting plumbing does not provide out of the box support for securing cross-process
invocations. However a .NET remoting object hosted in IIS, can leverage all the same security
features provided by IIS. If you are using the TCP channel or the HTTP channel hosted in a container
other than IIS, you have to implement authentication, authorization and privacy mechanisms
yourself.
Since ASP.NET Web services are hosted, by default, in IIS, they benefit from all the security features
of IIS such as support for secure communication over the wire using SSL, authentication and
authorization services.

Reliability
.NET remoting gives you the flexibility to host remote objects in any type of application including a
Windows Form, a managed Windows Service, a console application or the ASP.NET worker process.
If you host your remote objects in a windows service, or a console application, you need to make
sure that you provide features such as fault tolerance within your hosting application so that the
reliability of the remote object is not compromised. However if you do host remote objects in IIS, then
you can take advantage of the fact that the ASP.NET worker process is both auto-starting and
thread-safe. In the case of ASP.NET Web services, reliability is not a consideration as they are always
hosted in IIS, making it easy for them to take advantage of the capabilities provided by IIS.

Extensibility
Both the ASP.NET Web services and the .NET remoting infrastructures are extensible. You can filter
inbound and outbound messages, control aspects of type marshaling and metadata generation. .NET
remoting takes extensibility to the next level allowing you to implement your own formatters and
channels.
Since ASP.NET Web services rely on the System.Xml.Serialization.XmlSerializer class to marshal
data to and from SOAP messages at runtime, we can very easily customize the marshaling by adding
a set of custom attributes that can be used to control the serialization process. As a result, you have
very fine-grained control over the shape of the XML being generated when an object is serialized.

Ease of programming and deployment


In this section, we will consider a simple remoting object and an ASP.NET Web service to understand
the complexities involved in creating and consuming them. We will start off by creating a simple
remote object.

Creating a remote object


Creating a remoting object is a simple process. To create a remote object, you need to inherit from
MarshalByRefObject class. The following code shows a remotable class.
using System;
namespace RemoteClassLib
{
public class MyRemoteObject : System.MarshalByRefObject
130
{
public MyRemoteObject()
{
Console.WriteLine("Constructor called");
}

public string Hello(string name)


{
Console.WriteLine("Hello Called");
return "Hello " + name;
}
}
}
The above code is very simple and straightforward. We start off by defining a class that inherits from
MarshalByRefObject. After that we add code to the constructor of the class to write out a message
to the console. Then we have a method named Hello that basically takes a string argument and
appends that with the string and returns the concatenated value back to the caller. Once the remote
object is created, the next step is to create a host application that hosts the remote object. For the
purposes of this article, we will create a console application that reads the details of the remote
object from its configuration file.
using System;
using System.Runtime.Remoting;

namespace RemoteClassLibServer
{
class RemoteServer
{
[STAThread]
static void Main(string[] args)
{
RemotingConfiguration.Configure(
"RemoteClassLibServer.exe.config");
Console.WriteLine("Press return to Exit");
Console.ReadLine();
}
}
}
In the main method, we just read the configuration settings from the configuration file using the
RemotingConfiguration.Configure method and wait for the client applications to connect to it.
The configuration file used by the above hosting application looks like the following. In the
configuration file, we specify that we want to expose the remote object using the TCP channel by
using the channel element.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application name="RemoteClassLibServer">
<service>
<wellknown mode="SingleCall"
type="RemoteClassLib.MyRemoteObject,RemoteClassLib"
objectUri="MyRemoteObject">
</wellknown>
</service>
<channels>
<channel ref="tcp server" port="9000"/>
</channels>
</application>
</system.runtime.remoting>
131
</configuration>
Once the hosting application is started, then client applications can start creating instances of the
remote object and invoke its methods. In the next section, we will understand the processes involved
in creating an ASP.NET Web service.

Creating an ASP.NET Web Service


As mentioned before, creating an ASP.NET Web service is pretty easy in VS.NET. Select the ASP.NET
Web Service template using Visual Studio.NET New Project dialog box. Enter the name of the
project and click OK to create the project. Once the project is created, modify the default
service1.asmx file to look like the following.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;

namespace XmlWebServicesExample
{

public class Service1 : System.Web.Services.WebService


{
public Service1()
{
}

[WebMethod (EnableSession=true)]
public string HelloWorld()
{
return "Hello World";
}
}
}
As you can see from the above, the Web service class named Service1 is derived from
System.Web.Services.WebService. Inheriting from the WebService class is optional and it is used
to gain access to common ASP.NET objects like Application, Session, User, and Context. Then we
also add a method named HelloWorld that basically returns a simple string back to the callers of the
Web service. In the WebMethod attribute of the HelloWorld method, we also specify that we want to
enable session state for our ASP.NET Web service by setting the EnableSession attribute to true.

Creating the consumer for the ASP.NET Web Service


You can consume the Web service by using the Add Web Reference option in VS.NET to create a
proxy for the Web service. When you create a Web reference, the VS.NET IDE creates a proxy for you
based on the WSDL file published by the Web service. Once the proxy is generated, you can treat the
proxy class methods as if they are the actual Web service methods. At runtime, when the proxy class
methods are invoked, they will connect to the actual Web service, invoke the Web service method,
retrieve the results returned by the Web service and hand it back to the consumers. The following
screenshot shows how to use the Add Web Reference option to create a proxy for the Web service.
132

So far, we have seen the steps involved in creating a .NET remoting object and an ASP.NET Web
service. As can be seen from the above code, ASP.NET Web services are very easy-to-create.
Consuming ASP.NET Web service is also a very simple process due to the excellent Web service
support provided by Visual Studio.NET. With .NET remoting, you need to create the remote object
first and then write a hosting application (assuming that you are not using IIS) to expose that remote
object. You also need to make sure that the information about the remote object is retrieved from the
configuration file to allow for extensibility in the future. If you all these factors into consideration,
you will agree that .NET remoting objects are complex to develop and deploy.

Type Fidelity
ASP.NET Web services favor the XML schema type system, and provide a simple programming model
with broad cross-platform reach. .NET remoting favors the runtime type system, and provides a
more complex programming model with much more limited reach. This essential difference is the
primary factor in determining which technology to use.

Putting it all together


So far, we have looked at the differences between these two technologies. Let us summarize the
difference in a table.

ASP.NET Web Services .NET Remoting


Can be accessed over any protocol
Protocol Can be accessed only over HTTP
(including TCP, HTTP, SMTP and so on)
Provide support for both stateful and
State Web services work in a stateless
stateless environments through Singleton
Management environment
and SingleCall objects
Web services support only the
Using binary communication, .NET
datatypes defined in the XSD type
Type System Remoting can provide support for rich type
system, limiting the number of objects
system
that can be serialized.
Web services support interoperability .NET remoting requires the client be built
Interoperability across platforms, and are ideal for using .NET, enforcing homogenous
heterogeneous environments. environment.
133
Can also take advantage of IIS for fault
Highly reliable due to the fact that isolation. If IIS is not used, application
Reliability
Web services are always hosted in IIS needs to provide plumbing for ensuring the
reliability of the application.
Provides extensibility by allowing us to
Very extensible by allowing us to customize
intercept the SOAP messages during
Extensibility the different components of the .NET
the serialization and deserialization
remoting framework.
stages.
Ease-of-
Easy-to-create and deploy. Complex to program.
Programming

Though both the .NET Remoting infrastructure and ASP.NET Web services can enable cross-process
communication, each is designed to benefit a different target audience. ASP.NET Web services
provide a simple programming model and a wide reach. .NET Remoting provides a more complex
programming model and has a much narrower reach.
As explained before, the clear performance advantage provided by TCPChannel-remoting should
make you think about using this channel whenever you can afford to do so. If you can create direct
TCP connections from your clients to your server and if you need to support only the .NET platform,
you should go for this channel. If you are going to go cross-platform or you have the requirement of
supporting SOAP via HTTP, you should definitely go for ASP.NET Web services.

Combination of .NET Remoting and ASP.NET Web Services in Action

So far, we have understood how the .NET remoting and ASP.NET Web services technologies differ in
implementation. We have also had a detailed look at different factors to understand what technology
to choose in what situation. Even though these two technologies are meant for different purposes,
there are times where you will be able to use the combination of these technologies in your
application. For example, in an application scenario where you are trying to address the needs of
both internet and intranet clients, you might consider using both .NET remoting and Web services
as shown in the above diagram. For the intranet .NET clients, you can use .NET remoting to enable
cross appdomain communication. For the internet clients, you can expose the same functionality as
Web services, allowing client applications running in different platforms to take advantage of the
Web service.
134
Conclusion
Both the .NET remoting and ASP.NET Web services are powerful technologies that provide a suitable
framework for developing distributed applications. It is important to understand how both
technologies work and then choose the one that is right for your application. For applications that
require interoperability and must function over public networks, Web services are probably the best
bet. For those that require communications with other .NET components and where performance is
a key priority, .NET Remoting is the best choice. In short, use Web services when you need to send
and receive data from different computing platforms, use .NET Remoting when sending and receiving
data between .NET applications. In some architectural scenarios, you might also be able to use.NET
Remoting in conjunction with ASP.NET Web services and take advantage of the best of both worlds.

OOPS Concept

1) Access Modifiers:

C# Access Modifier Meaning


Public Marks a member as accessible from an object variable as well
as any derived classes.
Private (default) Marks a method as accessible only by the class that has
defined the method. In C#, all members are private by default.
Protected Marks a method as usable by the defining class, as well as any
derived classes. Protected methods, however, are not
accessible from an object variable.
Internal Defines a method that is accessible by any type in the same
assembly, but not outside the assembly.
protected internal Defines a method whose access is limited to the current
assembly or types derived from the defining class in the
current assembly.
Unmarked members are private by default in C#.

class SomeClass
{
// Accessible anywhere.
public void PublicMethod(){}
// Accessible only from SomeClass types.
private void PrivateMethod(){}
// Accessible from SomeClass and any descendent.
protected void ProtectedMethod(){}
// Accessible from within the same assembly.
internal void InternalMethod(){}
// Assembly-protected access.
protected internal void ProtectedInternalMethod(){}
// Unmarked members are private by default in C#.
void SomeMethod(){}
}

2) What is default modifier of class, function and variables? Prepare list for same.

Class Internal
Methods Private
Variables Private
Constructor Private
Interface Public
Static Method Private
135

3) Can we create static internal method?

Method can be declared as static internal and can be used with Class name.

4) Can Non Static class contain static functions?

Static Methods can be declared in a non static class.

Q1 In C# How do you call a member of a base class from within a derived

class?

1. There is no way to call like thar

2. using the key word 'MyBase'

3. using the key word 'base'

4. using the key word 'this'

Ans: base

Q2 Which of the following operations can you NOT perform on an ADO.NET

DataSet?

1. A DataSet can be synchronised with the database.

2. A DataSet can be converted to XML.

3. A DataSet can be synchronised with a RecordSet.

4. You can infer the schema from a DataSet.

Ans: A DataSet can be synchronised with a RecordSet

Q3 Which of these statements correctly declares a two-dimensional array

in C#?

1. int[,] myArray;

2. int[][] myArray;

3. int[2] myArray;

4. System.Array[2] myArray;

Ans: int[,] myArray;

Q4 What is a delegate?

1. A strongly typed function pointer.

2. A light weight thread or process that can call a single method.

3. A reference to an object in a different process.


136
4. An inter-process message channel.

Ans: A strongly typed function pointer

Q5 In C#, a technique used to stream data is known as...

1. wading.

2. serialization.

3. crunching.

4. marshalling.

Ans: serialization

Q6 What is the output of following C# code?

public interface Inter

{ void MyFun();

int MyProp { get; set; }

public class AClass:Inter

{ int aField;

public AClass( ){ }

public static void Main()

{ AClass aClass = new AClass();

Console.Write(aClass.MyProp);

aClass.MyFun();

void Inter.MyFun( )

{ Console.WriteLine(" MyFun()");

public int MyProp

{ get { return aField; }

set { aField = value; }}}

1. Exception

2. Syntax Error( aField is not intialised ).

3. MyFun()
137
4. Syntax Error( 'AClass' does not contain a definition for 'MyFun' ).

5. 0 MyFun()

Ans: Syntax Error( 'AClass' does not contain a definition for 'MyFun' ).

Q6. A static constructor can have parameters.True or False.

1. True

2. False

Ans: False

Q7. Does C# support multiple-inheritance?

1. No, use interfaces instead

2. yes, use interfaces instead

3. both one and two

4. none of the above

Ans: No, use interfaces instead

Q8. What happens when you include a Throw statement in the catch block?

1. Compilation Error

2. Current Exception is re-thrown

3. Runtime Error

4. Execution is abandoned

Ans: Current Exception is re-thrown

Q9. We can't use Indexers with structures.

1. True

2. False

3. Don't Know

Ans: False

Q10. classes can implement interfaces where as the structures can't.

1. True

2. False

3. Don't Know

Ans: False

Q11. What Should be done to avoid a class Inheritence in C#?


138
1. use "NonInhertable" keyword before class/method name

2. use "sealed" keyword before class/method name

3. use "abstract" keyword before class/method name

4. There is no provision in c#

5. None of the above

Ans: use "sealed" keyword before class/method name

Q12. Can Static Methods can be overridable?

1. Yes

2. No

3. It Depends on how we declare them

4. It depends on sccessspecifiers

Ans: No

Q13. When Static Constructors invokes

1. When we create the object of the class

2. When we create a Class

3. It is called before the first instance is created

4. All the above

Ans: It is called before the first instance is created.

Q14. What is the accessibility modifier for methods inside the interface?

1. Private by default

2. Public by default

3. protected

4. Friend

Ans: Public by default

Q15. Can you override private virtual methods?

1. Yes

2. No

3. Either 1 0r 2

4. None

Ans: No
139
Q16. Is it possible to have different access modifiers on the get/set

methods of a property?

Yes

No

Ans: No. The access modifier on a property applies to both its get and set accessors. What you need
to do if you want them to be different is make the property read- only (by only providing a get
accessor) and create a private/internal set method that is separate from the property

Q17. What is diffrence between Interface and abstract class.

1. Both are same.

2. unlike abstracts class interface class have no implementation.

3. interface require inheritance

Ans: unlike abstracts class interface class have no implementation.

Q19. What is the printout of the following?

What is the printout of the following?

byte b1=1;

byte b2=255;

byte total=b1+b2;

Console.WriteLine (total);

1. We will get a runtime error

2. We will get a compilation error

3. 256

4. 1

Ans: We will get a compilation error.

Q20 What is the error in the following code

Public Interface ITest1()

{ void MySub(){ }

Public Interface ITest2()

{ void MySub(){}

}
140
Public Class MyTest: ITest1, ITest2

{ Public void MySub() :ITest1.MySub

Public Sub MySub1() :ITest2.MySub

}Public Class Test:MyTest, ITest2

1. Compile Time Error - Itest2.MySub is not implemented in Class Test

2. Compile Time Error - ITest2 is already implemented by base class

3. Compile Time Error - MySub cannot be implemented as both ITest1 and ITest2 have the
same method name

4. Runtime Error

Ans : Compile Time Error - ITest2 is already implemented by base class

Plain Text Attachment [ Download File | Save to Yahoo! Briefcase ]

Q1. How to implement Multiple Inheritance in C# ?


1. Using Interface
2. Using Abstract Class
3. Using Delegates
4. Using Events
5. Using All
6. Using Interface & Delegates only
Ans: Using Interface

Q2. What is the size of Session ID?


1. 32-bit long string
2. 32-bit long double
3. 32-bit long char
4. 32-bit long integers
Ans: 32-bit long integers

Q3. Which of the following forms of caching involves the storing of


Arbitrary objects across multiple requests?
141
1. Page output caching
2. Fragment caching
3. Page data caching
4. None of the above
Ans: Page data caching

Q4. If browsers do not support client-side cookies, what state


Maintenance approach can be used?
1. Client-side
2. Server-side
3. Cookieless
4. None of the above
Ans: 3 Cookieless

Q5 Which language can support SOAP?


1. VB
2. JAVA
3. COBOL
4. ALL OF ABOVE aNS: 4 ALL OF ABOVE

Q6. How many ways are there in asp.net for managing persistent user state ?
1. Nine
2. four
3. five
4. seven
Ans: Nine

Q7 What is finalise method and what are the role of it?


1. Release object memory
2. Release memory
3. it calls when page is closed
4. All of the above
Ans: Release object memory

Q8 it is NOT possible for any class method in the System namespace to be used directly
without first creating an object from the class. Is it true?
1. True
2. False
Ans: False

Q9 If Date is interpreted as 0 (numeric) Sql server Inter Prets as


1. 1754 dec31
2. 1854Mar 17
3. 1900 jan1
4. 1854 dec31
5. 1857 dec31
Ans: 1900 jan1
142
Q10 Which property is used to specify whether a tree node label is displayed in the form of
a hyperlink when the mouse pointer moves over it?
1. TopNode
2. SelectedNode
3. HotTracking
4. Nodes
Ans: HotTracking

Q11 The only control(s)s that are avialble in HTML and not in WebControl(s) is
1. FileField
2. Input Hidden
3. Group controls like Flow Layout, Grid Layout
4. None
Ans: FileField & Input Hidden

Q13 What is the total no. of events in Global.asax file in Asp.NET?


1. 20
2. 25
3. 19
4. 32
Ans: 19

Q14 which of the following OleDbConnection properties is used to obtain the database to
which an OleDbConnection object is connected?
1. Provider
2. DataSource
3. Database
4. UserID
5. Database Provider

Ans: Database

Q15 What data type does the RangeValidator control support?


1. Integer
2. Date
3. Boolean
4. String
5. all of the above
6. 1 and 2
7. 1,2 and 4
Ans: 1,2 and 4

Q16 Which of the following in not a session stste mode?


1. Inproc
2. Outproc
3. StateServer
4. SqlServer
5. OracleServer
Ans OutProc
143

Q17 What is the default executionTimeout of an aspx page?


1. 30s
2. 60s
3. 90s
4. 120s
Ans: 90s

Q18 Which of the following are authentication methods?


1. Web, windows, passport
2. Web, forms, none
3. Windows, Passport, Forms, None
4. None of the above
Ans: Windows, Passport, Forms, None

Q19 What is the default authendication mode in aps.net web application?


1. Windows
2. Passport
3. Form
4. Client Certificate
5. Cookies
ANs: Windows

Q20 what is the difference between Server.Transfer and response.Redirect?


1. No difference
2. Server.Transfer needs a Round Trip, Response.Rediect not
3. Response.Rediect needs Rountrip to bowser Server.Transfer does not need a Round Trip,
4. Server.Transfer can transfer user between two applications
Ans: Response.Rediect needs Rountrip to bowser Server.Transfer does not need a Round Trip,

Remoting

What is .NET Remoting?


.NET Remoting is an enabler for application communication. It is a generic system for different
applications to use to communicate with one another. .NET objects are exposed to remote processes,
thus allowing interprocess communication. The applications can be located on the same computer,
different computers on the same network, or even computers across separate networks.

.NET Remoting versus Distributed COM


In the past interprocess communication between applications was handled through Distributed
COM, or DCOM. DCOM works well and the performance is adequate when applications exist on
computers of similar type on the same network. However, DCOM has its drawbacks in the Internet
connected world. DCOM relies on a proprietary binary protocol that not all object models support,
which hinders interoperability across platforms. In addition, have you tried to get DCOM to work
through a firewall? DCOM wants to communicate over a range of ports that are typically blocked by
firewalls. There are a ways to get it to work, but they either decrease the effectiveness of the firewall
(why bother to even have the firewall if you open up a ton of ports on it), or require you to get a
firewall that allows support for binary traffic over port 80.
.NET Remoting eliminates the difficulties of DCOM by supporting different transport protocol
formats and communication protocols. This allows .NET Remoting to be adaptable to the network
environment in which it is being used.
144
.NET Remoting versus Web Services
Unless you have been living in a cave, or are way behind in your reading, you have probably read
something about Web services. When you read the description of .NET Remoting it may remind you
a lot of what you're read about Web services. That is because Web services fall under the umbrella of
.NET Remoting, but have a simplified programming model and are intended for a wide target
audience.
Web services involve allowing applications to exchange messages in a way that is platform, object
model, and programming language independent. Web services are stateless and know nothing about
the client that is making the request. The clients communicate by transferring messages back and
forth in a specific format known as the Simple Object Access Protocol, or SOAP. (Want to get some
funny looks in the hallway? Stand around in the hallway near the marketing department with your
colleagues and discuss the benefits of using SOAP).
The following list outlines some of the major differences between .NET Remoting and Web services
that will help you to decide when to use one or the other:

 ASP.NET based Web services can only be accessed over HTTP. .NET Remoting can be used
across any protocol.
 Web services work in a stateless environment where each request results in a new object
created to service the request. .NET Remoting supports state management options and can
correlate multiple calls from the same client and support callbacks.
 Web services serialize objects through XML contained in the SOAP messages and can thus
only handle items that can be fully expressed in XML. .NET Remoting relies on the existence
of the common language runtime assemblies that contain information about data types. This
limits the information that must be passed about an object and allows objects to be passed
by value or by reference.
 Web services support interoperability across platforms and are good for heterogeneous
environments. .NET Remoting requires the clients be built using .NET, or another framework
that supports .NET Remoting, which means a homogeneous environment.

Channels
Remote objects are accessed through Channels. Channels physically transport the messages to and
from remote objects. There are two existing channels TcpChannel and HttpChannel. Their names
give away the protocols that they use. In addition, the TcpChannel or HttpChannel can be extended,
or a new channel created if you determine the existing channels do not meet your needs.

Create a Remotable Object


A remotable object is nothing more than an object that inherits from MarshalByRefObject. The
following sample demonstrates a simple class to expose the omnipresent hello world. This object
exposes a single method HelloWorld that will return a string. The only values that can be returned
from methods are the classes in the .NET Framework that are serializable such as string and
DataSet. In addition, if you need to return a user-defined object then the object needs to be marked
as serializable.
Create a new C# class library project. Add a class called SampleObject and put in the following code.
Add a reference to System.Runtime.Remoting in the project, otherwise the TcpChannel will not be
found. Compile the class to make sure you have everything correct.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace CodeGuru.Remoting
{
/// <remarks>
/// Sample object to demonstrate the use of .NET Remoting.
/// </remarks>
public class SampleObject : MarshalByRefObject
{
/// <summary>
145
/// Constructor
/// </summary>
public SampleObject()
{
}

/// <summary>
/// Return a hello message
/// </summary>
/// <returns>Hello world message</returns>
public string HelloWorld()
{
return "Hello World!";
}
}
}

Create a Server To Expose the Remotable Object


We need to create a server object that will act as a listener to accept remote object requests. For this
example we will use the TCP/IP channel. We first create an instance of the channel and then register
it for use by clients at a specific port. The service can be registered as
WellKnownObjectMode.SingleCall, which results in a new instance of the object for each client, or as
WellKnownObjectMode.Singleton, which results in one instance of the object used for all clients.
It is not necessary to create the server listener if you are planning to use IIS. For obvious reasons,
IIS only supports the use of the HttpChannel. Create a virtual directory for your application and
then put code to register your service in the Application_Start event.
For our example, we'll go ahead and create a server listener in case you don't have IIS. Since the
service needs to be bound to an available port, for our example I chose 8080, which is a port that I
know to be unused on my computer. You may need to choose a different port depending upon what
ports you have available. To see a list of the used ports on your computer open a command prompt
and issue the command "netstat --a". It may produce a long listing so make sure the command
prompt buffer sizes are set to allow scrolling. Compile the class to make sure you have everything
correct.
Create a new C# console application project. Add a class called SampleServer and paste in the
following code. Add a reference to System.Runtime.Remoting in the project, otherwise the
TcpChannel will not be found. In addition, add a reference to the project containing the
SampleObject, otherwise the code will not compile because it won't know how to find a reference to
SampleObject.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace CodeGuru.Remoting
{
/// <remarks>
/// Sample server to demonstrate the use of .NET Remoting.
/// </remarks>
public class SampleServer
{
public static int Main(string [] args)
{
// Create an instance of a channel
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);

// Register as an available service with the name HelloWorld


RemotingConfiguration.RegisterWellKnownServiceType(
typeof(SampleObject),
"HelloWorld",
146
WellKnownObjectMode.SingleCall );

System.Console.WriteLine("Press the enter key to exit...");


System.Console.ReadLine();
return 0;
}

}
}

Create a Client To Use the Remotable Object


Now that we have our remotable object and a server object to listen for requests, let's create a client
to use it. Our client will be very simple. It will connect to the server, create an instance of the object
using the server, and then execute the HelloWorld method.
Create a new C# console application project. Add a class called SampleClient and paste in the
following code. Add a reference to System.Runtime.Remoting in the project, otherwise the
TcpChannel will not be found. In addition, add a reference to the project containing the
SampleObject, otherwise the code will not compile because it won't know how to find a reference to
SampleObject. Compile the class to make sure you have everything correct.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace CodeGuru.Remoting
{
/// <remarks>
/// Sample client to demonstrate the use of .NET Remoting.
/// </remarks>
public class SampleClient
{
public static int Main(string [] args)
{
// Create a channel for communicating w/ the remote object
// Notice no port is specified on the client
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan);

// Create an instance of the remote object


SampleObject obj = (SampleObject) Activator.GetObject(
typeof(CodeGuru.Remoting.SampleObject),
"tcp://localhost:8080/HelloWorld" );

// Use the object


if( obj.Equals(null) )
{
System.Console.WriteLine("Error: unable to locate server");
}
else
{
Console.WriteLine(obj.HelloWorld());
}
return 0;
}
}
}
147
Test the Remoting Sample
Once you have created the projects and successfully compiled each of them you are ready to try it
out. Assuming you chose a free TCP/IP port for the service, start the server executable. After the
server successfully starts it will result in a console window being displayed with the message "Press
the enter key to exit". The server is listening so you are now ready to run the client. Executing the
client should result in "Hello World!" being displayed in a separate console window. The client
window will then close while the server remains open and available.
If you have multiple computers available to you on a network you could execute the server on one
machine and the client on another just to prove to yourself that it really is remoting. In order to run
on separate machines you would need to change the reference to localhost in the sample client to
point to the appropriate location.

Summary
.NET Remoting is a powerful way to enable interprocess communication. It is more complicated to
program against than Web services. You need to decide for yourself whether your standard
architecture is to use .NET Remoting or Web services.

The following list provides an overview of the key elements of the architecture:

 A remote object is an object that’s running on the server. The client doesn’t call methods on this
object directly, but uses a proxy instead. With .NET it’s easy to distinguish remote objects from
local objects; every class that derived from MarshalByRefObject never leaves its application
domain. The client can call methods of the remote object via a proxy.
 A channel is used for communication between the client and the server. There are client and
server parts of the channel .NET Framework 1.1 offers two channel type that communicate via
TCP or HTTP. You can also create a custom channel that communicates by using a different
protocol.
 Messages are sent into a channel. Messages are created for communication between the client
and the server. These messages hold the information about the remote object, the method name
called, and all of the arguments.
 The formatter defines how messages are transferred into the channel. With .NET Framework 1.1,
we have SOAP binary formatters. The SOAP formatter can be used to communicate with Web
services that are not based on .NET Framework. Binary formatters are much faster and can be
used efficiently in an intranet environment of course; you also have the possibility to create a
custom formatter.
 A formatter provider is used to associate a formatter with a channel. By creating a channel, you
can specify what formatter provider to use, and this in turn defines the formatter that is used to
transfer the data into the channel.
 The client calls method on a proxy instead of the remote object. There are two types of proxies:
the transparent proxy and real proxy. To the client, the transparent proxy looks likes the remote
object. On the transparent proxy, the client can call the methods implemented by the remote
objects. In a turn, the transparent proxy calls the Invoke() method on the real proxy. The Invoke()
method uses the message sink to pass to the channel.
 Messages sink, or sink for short, is an interceptor object. Interceptors are used on both the client
and server. A sink is associated with the channel. The real proxy uses the message sink to pass
the message into the channel. Depending on where the sink is used, is known as envoy sink, a
server context sink, an object context sink, and so on.
 The client can use an activator to create a remote object on the server or to get a proxy of a
server-activated object.
 Remotingcongiguration is a utility class to configure remote servers and clients. This class can
be used either to read configuration files, or to configure remote objects dynamically.
 Channelservices is a utility class to register channels and then to dispatch messages to them.
148
State Management in ASP.NET

Web form pages are HTTP-Based, they are stateless, which means they don’t know whether the
requests are all from the same client, and pages are destroyed and recreated with each round trip to
the server, therefore information will be lost, therefore state management is really an issue in
developing web applications

Mainly there are two different ways to manage web page’s state: Client-side and Server-side.

1. Client-side state management:


There is no information maintained on the server between round trips. Information will be stored in
the page or on the client’s computer.

A. Cookies.
A cookie is a small amount of data stored either in a text file on the client's file system or in-memory
in the client browser session. Cookies are mainly used for tracking data settings. Let’s take an
example: say we want to customize a welcome web page, when the user request the default web
page, the application first to detect if the user has login before, we can retrieve the user information
from cookies:
if (Request.Cookies[“username”]!=null)
lbMessage.text=”Dear “+Request.Cookies[“username”].Value+”, Welcome shopping here!”;
else
lbMessage.text=”Welcome shopping here!”;

If you want to store client’s information, you can use the following code:
Response.Cookies[“username’].Value=username;
So next time when the user request the web page, you can easily recognize the user again.

B. Hidden Field
A hidden field does not render visibly in the browser, but you can set its properties just as you can
with a standard control. When a page is submitted to the server, the content of a hidden field is sent
in the HTTP Form collection along with the values of other controls. A hidden field acts as a
repository for any page-specific information that you would like to store directly in the page. Hidden
field stores a single variable in its value property and must be explicitly added it to the page.
ASP.NET provides the HtmlInputHidden control that offers hidden field functionality.
protected System.Web.UI.HtmlControls.HtmlInputHidden Hidden1;
//to assign a value to Hidden field
Hidden1.Value=”this is a test”;
//to retrieve a value
string str=Hidden1.Value;

Note: Keep in mind, in order to use hidden field, you have to use HTTP-Post method to post web
page. Although its name is ‘Hidden’, its value is not hidden; you can see its value through ‘view
source’ function.

C. View State
Each control on a Web Forms page, including the page itself, has a ViewState property; it is a built-
in struture for automatic retention of page and control state, which means you don’t need to do
anything about getting back the data of controls after posting page to the server.

Here, which is useful to us is the ViewState property; we can use it to save information between
round trips to the server.
//to save information
ViewState.Add(“shape”,”circle”);
//to retrieve information
string shapes=ViewState[“shape”];

D. Query Strings
Query strings provide a simple but limited way of maintaining some state information. You can
easily pass information from one page to another, But most browsers and client devices impose a
149
255-character limit on the length of the URL. In addition, the query values are exposed to the
Internet via the URL so in some cases security may be an issue.
A URL with query strings may look like this:
http://www.examples.com/list.aspx?categoryid=1&productid=101

When list.aspx is being requested, the category and product information can be obtained by using
the following codes:
string categoryid, productid;
categoryid=Request.Params[“categoryid”];
productid=Request.Params[“productid”];

Note: you can only use HTTP-Get method to post the web page, or you will never get the value from
query strings.

2. Server-side state management:


Information will be stored on the server, it has higher security but it can use more web server
resources.

A. Application object
The Application object provides a mechanism for storing data that is accessible to all code running
within the Web application, the ideal data to insert into application state variables is data that is
shared by multiple sessions and does not change often. And just because it is visible to the entire
application, you need to used Lock and UnLock pair to avoid having conflit value.

Application.Lock();
Application[“mydata”] =”mydata”;
Application.UnLock();

B. Session object
Session object can be used for storing session-specific information that needs to be maintained
between server round trips and between requests for pages. Session object is per-client basis, which
means different clients generate different session object.The ideal data to store in session-state
variables is short-lived, sensitive data that is specific to an individual session.

Each active ASP.NET session is identified and tracked using a 120-bit SessionID string containing
URL-legal ASCII characters. SessionID values are generated using an algorithm that guarantees
uniqueness so that sessions do not collide, and SessionID’s randomness makes it harder to guess
the session ID of an existing session.SessionIDs are communicated across client-server requests
either by an HTTP cookie or a modified URL, depending on how you set the application's
configuration settings.

Every web application must have a configuration file named web.config, it is a XML-Based file, there
is a section name ‘sessionState’, and the following is an example:

‘cookieless’ option can be ‘true’ or ‘false’. When it is ‘false’(default value), ASP.NET will use HTTP
cookie to identify users. When it is ‘true’, ASP.NET will randomly generate a unique number and put
it just right ahead of the requested file, this number is used to identify users, you can see it on the
address bar of IE:
http://localhost/Management/(2yzakzez3eqxut45ukyzq3qp)/Default.aspx

//to store information


Session[“myname”]=”Mike”;
//to retrieve information
myname=Session[“myname”];

C. Database
Database enables you to store large amount of information pertaining to state in your Web
application. Sometimes users continually query the database by using the unique ID, you can save it
in the database for use across multiple request for the pages in your site.
150
Summary
Choosing among the options will depand upon your application, you have to think about the
following before making any choose:

1. How much information do you need to store?


2. Does the client accept persistent or in-memory cookies?
3. Do you want to store the information on the client or server?

4. Is the information sensitive?


5. What kind of performance experience are you expecting from your pages?

Cookies- You need to store small amounts of information on the client and security is not an issue.
Viewstate- You needs to store small amounts of information for a page that will post back to itself.
Use of the ViewState property does supply semi-secure functionality.
Hidden fields- You need to store small amounts of information for a page that will post back to itself
or another page, and security is not an issue. Note You can use a hidden field only on pages that
are submitted to the server.
Querystring- You are transferring small amounts of information from one page to another and
security is not an issue. Note You can use query strings only if you are requesting the same page,
or another page via a link.
Application state object- You are storing infrequently changed, application-scope information that is
used by many users and security is not an issue. Do not store large quantities of information in an
application state object.
Session state object - You are storing short-lived information that is specific to an individual session,
and security is an issue. Do not store large quantities of information in a session state object. Be
aware that a session state object will be created and maintained for the lifetime of every session in
your application. In applications hosting many users, this can occupy significant server resources
and affect scalability.
Database support- You are storing large amounts of information, managing transactions, or the
information must survive application and session restarts. Data mining is a concern, and security is
an issue.

Static Constructor

Notes for Static Constructors:

1. There can be only one static constructor in the class.


2. The static constructor should be without parameters.
3. It can only access the static members of the class.
4. There should be no access modifier in static constructor definition.
5. A static constructor does not take access modifiers or have parameters.
6. A static constructor is called automatically to initialize the class before the first instance is
created or any static members are referenced.
7. A static constructor cannot be called directly.
8. The user has no control on when the static constructor is executed in the program.
9. A typical use of static constructors is when the class is using a log file and the constructor is
used to write entries to this file.
10. Static constructors are also useful when creating wrapper classes for unmanaged code, when
the constructor can call the LoadLibrary method

Ok fine, all the above points are fine, but why is it like that? Let us go step by step here.
Firstly, the call to the static method is made by the CLR and not by the object, so we do not need to
have the access modifier to it.
Secondly, it is going to be called by CLR, who can pass the parameters to it, if required. So we
cannot have parameterized static constructor.
151
Thirdly, non-static members in the class are specific to the object instance. So static constructor,
if allowed to work on non-static members, will reflect the changes in all the object instances, which
is impractical. So static constructor can access only static members of the class.
Fourthly, overloading needs the two methods to be different in terms of methods definition, which
you cannot do with Static Constructors, so you can have at the most one static constructor in the
class.

Example

public class Bus


{

// Static constructor:

static Bus()
{
System.Console.WriteLine("The static constructor invoked.");
}

public static void Drive()


{
System.Console.WriteLine("The Drive method invoked.");
}
}

class TestBus
{
static void Main()
{
Bus.Drive();
}
}

Copy Constructor

class Person
{
private string name;
private int age;
// Copy constructor.
public Person(Person previousPerson)
{
name = previousPerson.name;
age = previousPerson.age;
}

// Instance constructor.
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
// Get accessor.
public string Details
{
get
{
return name + " is " + age.ToString();
152
}
}
}

class TestPerson
{
static void Main()
{
// Create a new person object.
Person person1 = new Person("George", 40);
// Create another new object, copying person1.
Person person2 = new Person(person1);
System.Console.WriteLine(person2.Details);
}
}

using System;
using System.Collections.Generic;

namespace Model
{
/// <summary>
///
///
/// </summary>
[Serializable]
public class SearchType
{
// The available search types
private const string SEARCH_BY_ID = null;
private const string SEARCH_BY_CODE = null;

private readonly string _id;


/// <summary>
/// The id used to represent this search type
/// </summary>
public string Id
{
get { return _id; }
}

private readonly string _description;


/// <summary>
/// A description of the Search Type
/// </summary>
public string Description
{
get { return _description; }
}
/// <summary>
/// An instance of a Search type representing SearchType only with No
/// </summary>
public static readonly SearchType SearchById = new SearchType (SEARCH_BY_ID, "
Reference");
/// <summary>
/// An instance of a Search type representing SearchType only with Agency Code
/// </summary>
public static readonly SearchType SearchByCode = new SearchType(SEARCH_BY_ CODE, "
Code");
153
/// <summary>
/// overriding toString() method
/// </summary>
/// <returns>A description of the Search Type</returns>
public override string ToString()
{
return Description;
}
/// <summary>
/// Private parameterize constructor to initialized object
/// </summary>
/// <param name="id">string</param>
/// <param name="description">string</param>
private SearchType(string id, string description)
{
_id = id;
_description = description;
}
}
}

Static Constructor in C# and their Usages


Static constructor is used to initialize static data members as soon as the class is referenced first time, whereas an instance
constructor is used to create an instance of that class with keyword.

C# supports two types of constructor, a class constructor (static constructor) and an instance
constructor (non-static constructor).
Static constructor is used to initialize static data members as soon as the class is referenced first
time, whereas an instance constructor is used to create an instance of that class with <new>
keyword. A static constructor does not take access modifiers or have parameters and can't access
any non-static data member of a class.
Since static constructor is a class constructor, they are guaranteed to be called as soon as we refer
to that class or by creating an instance of that class.
You may say, why not initialize static data members where we declare them in the code. Like this:
private static int id = 10;
private static string name = "jack";
Usages:
Static data members can certainly be initialized at the time of their declaration but there are times
when value of one static member may depend upon the value of another static member. In such
cases we definitely need some mechanism to handle conditional initialization of static members. To
handle such situation, C# provides static constructor.
Examples:
//File Name : Test.cs
using System;
namespace Constructor
{
class Test
{
//Declaration and initialization of static data member
private static int id = 5;
public static int Id
154
{
get
{
return id;
}
}
public static void print()
{
Console.WriteLine("Test.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id
Test.print();
}
}
}

In the above example, static data member <id> is declared and initialized in same line. So if you
compile and run this program your output would look similar to this :
Test.id = 5
Lets create one more class similar to class Test but this time the value of its static data member
would depend on the value of static data member <id> of class Test.id.
//File Name: Test1.cs
using System;
namespace Constructor
{
class Test1
{
private static int id ;
//Static constructor, value of data member id is set conditionally here.
//This type of initialization is not possible at the time of declaration.
static Test1()
{
if( Test.Id < 10 )
{
id = 20;
}
else
{
id = 100;
}
Console.WriteLine("Static<Class> Constructor for Class Test1 Called..");
}
public static void print()
{
Console.WriteLine("Test1.id = " + id);
}
static void Main(string[] args)
{
//Print the value of id
Test1.print();
}
}
}

As you can see in the above static constructor, static data member <id> is initialized conditionally.
155
This type of initialization is not possible at the time of declaration. This is where static
constructor comes in picture. So if you compile and run this program your output would look similar
to this:
Static<Class> Constructor for Class Test1 Called..
id = 20
Since <id> in class Test was initialized with a value of 5, therefore <id> in class Test1 got initialized
to a value of 20.
Some important point regarding static constructor from C# Language Specification and C#
Programmer's Reference:
1) The static constructor for a class executes before any instance of the class is created.
2) The static constructor for a class executes before any of the static members for the class are
referenced.
3) The static constructor for a class executes after the static field initializers (if any) for the class.
4) The static constructor for a class executes at most one time during a single program instantiation
5) A static constructor does not take access modifiers or have parameters.
6) A static constructor is called automatically to initialize the class before the first instance is created
or any static members are referenced.
7) A static constructor cannot be called directly.
8) The user has no control on when the static constructor is executed in the program.
9) A typical use of static constructors is when the class is using a log file and the constructor is used
to write entries to this file.

Structs in C#

This article introduces you to the differences between classes and structs in C#, and explains how to
use structs correctly.

Why we need Structs?


The basic reason is the ability to create types with value semantics, which, if properly used, leads to
better performance in a managed environment.

.NET supports the notion of value types and reference types. Instances of reference types get
allocated in the managed heap and are garbage collected when there are no outstanding references
to them. Instances of value types, on the other hand, are allocated in the stack, and hence allocated
memory is reclaimed as soon as their scope ends. All C# primitive data types, except for
System.String, are value types.
In C#, structs are value types, classes are reference types. There are two ways you can create value
types, in C#, using the enum keyword and the struct keyword. Using a value type instead of a
reference type will result in fewer objects on the managed heap, which results in lesser load on the
garbage collector (GC), less frequent GC cycles, and consequently better performance. However,
value types have their downsides too. Passing around a big struct is definitely costlier than passing a
reference, that's one obvious problem. The other problem is the overhead associated with
boxing/unboxing. Apart from performance, there are times when you simply need types to have
value semantics, which would be very difficult to implement if reference types are all you have.
Differences between Class & Struct:

1. Struct and Inheritance


structs derive from System.ValueType whereas classes derive from System.Object or one of
its descendants. Of course, System.ValueType again derives from System.Object, but that's
beside the point. structs cannot derive from any other class/struct, nor can they be derived
from. However, a struct can implement any number of interfaces. Although, that when you
156
treat the struct as an interface, it gets implicitly boxed, as interfaces operate only on
reference types. E.g.

struct Foo : IFoo


{
int x;
}
and then:
IFoo iFoo = new Foo();
an instance of Foo is created and boxed. All interface method calls then execute only on the
boxed instance.
2. Constructors:
Although the CLR allows it, C# does not allow structs to have a default parameterless
constructor. The reason is that, for a value type, compilers by default neither generate a
default constructor, nor do they generate a call to the default constructor. So, even if you
happened to define a default constructor, it will not be called and that will only confuse you.
To avoid such problems, the C# compiler disallows definition of a default constructor by the
user. And because it doesn't generate a default constructor, you can't initialize fields when
defining them, like:
struct MyWrongFoo
{
int x = 1;
}
The compiler puts all this initialization code into the constructor (every constructor), and
because there's no default constructor, you can't do the initialization.
3. Destructors:
You cannot define destructors for structs. The compiler straightaway flags it as an error. Of
course, structs can implement IDisposable (it being an interface), so you can always use the
dispose pattern (with the extra boxing overhead).
When to use Structs?
 You want your type to look and feel like a primitive type.
 You create a lot of instances, use them briefly, and then drop them. For e.g., within a loop.
 The instances you create are not passed around a lot.
 You don't want to derive from other types or let others derive from your type.
 You want others to operate on a copy of your data (basically pass by value semantics).

When not to use Structs?


 The size of the struct (the sum of the sizes of its members) gets large. The reason is that
beyond a particular size, the overhead involved in passing it around gets prohibitive.
Microsoft recommends that the size of a struct should ideally be below 16 bytes, but it really
is up to you. In case your struct has reference types as members, make sure you don't
include the size of instances of reference types, just the size of the references.
 You create instances, put them in a collection, iterate and modify elements in the collection.
This will result in a lot of boxing/unboxing as FCL Collections operate on System.Object.
Every addition will involve a boxing operation, and every modification will involve an
unboxing followed by a boxing operation.
157
Typed DataSet:

Along with late bound access to values through weakly typed variables, the DataSet provides access
to data through a strongly typed metaphor. Tables and columns that are part of the DataSet can be
accessed using user-friendly names and strongly typed variables.

A typed DataSet is a class that derives from a DataSet. As such, it inherits all the methods, events,
and properties of a DataSet. Additionally, a typed DataSet provides strongly typed methods, events,
and properties. This means you can access tables and columns by name, instead of using collection-
based methods. Aside from the improved readability of the code, a typed DataSet also allows the
Visual Studio .NET code editor to automatically complete lines as you type.

Additionally, the strongly typed DataSet provides access to values as the correct type at compile
time. With a strongly typed DataSet, type mismatch errors are caught when the code is compiled
rather than at run time.

Strongly Typed DataSet

Given an XML Schema that complies with the XML Schema definition language (XSD)
standard, you can generate a strongly typed DataSet using the XSD.exe tool provided with the
.NET Framework SDK.
The following code shows the syntax for generating a DataSet using this tool.

xsd.exe /d /l:CS XSDSchemaFileName.xsd /n:XSDSchema.Namespace


In this syntax, the /d directive tells the tool to generate a DataSet, and the /l: tells the tool what
language to use (for example, C# or Visual Basic .NET). The optional /n: directive tells the tool to
also generate a namespace for the DataSet called XSDSchema.Namespace. The output of the
command is XSDSchemaFileName.cs, which can be compiled and used in an ADO.NET application.
The generated code can be compiled as a library or a module.

The following code shows the syntax for compiling the generated code as a library using the C#
compiler (csc.exe).

csc.exe /t:library XSDSchemaFileName.cs /r:System.dll /r:System.Data.dll


The /t: directive tells the tool to compile to a library, and the /r: directives specify dependent
libraries required to compile. The output of the command is XSDSchemaFileName.dll, which can be
passed to the compiler when compiling an ADO.NET application with the /r: directive.

The following code shows the syntax for accessing the namespace passed to XSD.exe in an ADO.NET
application.

[Visual Basic]
Imports XSDSchema.Namespace
[C#]
using XSDSchema.Namespace;
The following code example uses a typed DataSet named CustomerDataSet to load a list of
customers from the Northwind database. Once the data is loaded using the Fill method, the example
loops through each customer in the Customers table using the typed CustomersRow (DataRow)
object. This provides direct access to the CustomerID column, as opposed to accessing it through
the DataColumnCollection.

[Visual Basic]
Dim custDS As CustomerDataSet= New CustomerDataSet()
Dim custCMD As SqlDataAdapter New SqlDataAdapter("SELECT * FROM Customers", _
"Data Source=localhost;Integrated Security=SSPI;Initial
Catalog=northwind")
158
custCMD.Fill(custDS, "Customers")

Dim custRow As CustomerDataSet.CustomersRow


For Each custRow In custDS.Customers
Console.WriteLine(custRow.CustomerID)
Next
[C#]
CustomerDataSet custDS = new CustomerDataSet();
SqlDataAdapter custCMD = new SqlDataAdapter("SELECT * FROM Customers",
"Data Source=localhost;Integrated Security=SSPI;Initial
Catalog=northwind");

custCMD.Fill(custDS, "Customers");

foreach(CustomerDataSet.CustomersRow custRow in custDS.Customers)


Console.WriteLine(custRow.CustomerID);
Following is the XML Schema used for the example.

<?xml version="1.0" encoding="utf-8"?>


<xs:schema id="CustomerDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="CustomerDataSet" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
159

Webservises
ASP.NET AJAX provides the power of asynchronous JavaScript and XML to your web sites. AJAX
makes web pages more responsive and interactive by reducing page refreshes or postbacks. It
harnesses the power of client-side JavaScript and the XML HTTP object to provide these features.
Although AJAX is essentially a client-side technique, most of its real-world deployments call for
server-side processing. Most commonly, the data manipulated by your web site will reside in some
RDBMS on the server. To make AJAX really useful, you need an easy and robust way to deal with
this server-side data. Fortunately, ASP.NET AJAX provides a sound infrastructure for doing just
that. AJAX communication happens between your browser and the server over the Internet.
Naturally, web services can play a significant role in data transport and overall communication
between the client and the server. This article shows how ASP.NET AJAX can consume ASP.NET web
services.

Software Requirements
All the examples in this article are developed using the RC build of ASP.NET AJAX that you can
download from ajax.asp.net. Moreover, you need to have SQL Server 2005 (Express Edition will do)
with the Northwind database installed. The examples use Visual Studio 2005 as the IDE.

Example Scenario
The example develops a web form that acts as a data entry page for an Employees table of the
Northwind database. Using ASP.NET AJAX features, this data entry page will consume a web service
that allows you to SELECT, INSERT, UPDATE, and DELETE employees.

Creating the Web Service


To begin with, create a new web site using Visual Studio 2005. Notice that installing ASP.NET AJAX
adds project templates to the New Web Site dialog, including the "ASP.NET AJAX Enabled Web Site"
template (see Figure 1).

Click here for a larger image.


Figure 1: The New Web Site Dialog with Added Templates
A web site created using the "ASP.NET AJAX Enabled Web Site" template is different from a normal
web site in the following ways:

 It has a web.config file with a lot of ASP.NET AJAX-specific configuration information.


 It refers System.Web.Extensions assembly.
160
Of course, you can modify a normal web site to make it AJAX enabled, but this template
simplifies your job.
Now that you have created a new web site, add a new web service to it and name it
EmployeeService.asmx. The EmployeeService will contain five web methods (see Table 1).

Method Name Description


GetEmployees() Returns a list of employees from the Employees table. The list is returned in the
form of an array of Employee objects.
GetEmployee() Accepts an EmployeeID and returns its details as an Employee object.
Insert() Adds a new employee to the Employees table.
Update() Updates an existing employee from the Employees table.
Delete() Deletes an existing employee from the Employees table.

Table 1. Web Methods in EmployeeService


The GetEmployees() and GetEmployee() methods return data in the form of Employee object(s).
Therefore, you first need to create a class called Employee. Right-click the App_Code folder of your
web site and choose "Add New Item...". Add a new class called Employee. The following is the
complete code that makes the Employee class:
public class Employee
{
private int intEmployeeID;
private string strFirstName;
private string strLastName;
public int EmployeeID
{
get
{
return intEmployeeID;
}
set
{
intEmployeeID = value;
}
}
public string FirstName
{
get
{
return strFirstName;
}
set
{
strFirstName = value;
}
}
public string LastName
{
get
{
return strLastName;
}
set
{
strLastName = value;
}
161
}
}
The Employee class declares three provate variables for storing employee ID, first name, and last
name, respectively. The three variables are wrapped inside three public properties: EmployeeID,
FirstName, and LastName.
Open the web.config file and add a <connectionStrings> section as follows:
<connectionStrings>
<add name="connstr" connectionString=
"data source=.\sqlexpress;
initial catalog=northwind;
integrated security=true"/>
</connectionStrings>
This stores a database connection string that points to the Northwind database. Make sure to
change SQL Server name/IP and authentication details to match your environment.
Now, open EmployeeService.cs and add the following code:
private string strConn =
"";
public EmployeeService()
{
strConn = ConfigurationManager.ConnectionStrings["connstr"].
ConnectionString;
}
The code uses the ConfigurationManager class to read the connection string from the config file and
stores it in a class-level variable called strConn. This variable is used further by all the other web
methods.
Now, add the GetEmployees web method as follows:
[WebMethod]
public Employee[] GetEmployees()
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select employeeid,firstname,
lastname from employees";
SqlDataReader reader = cmd.ExecuteReader();
List<Employee> list = new List<Employee>();
while (reader.Read())
{
Employee emp = new Employee();
emp.EmployeeID = reader.GetInt32(0);
emp.FirstName = reader.GetString(1);
emp.LastName = reader.GetString(2);
list.Add(emp);
}
reader.Close();
cnn.Close();
return list.ToArray();
}
The code creates new SqlConnection and SqlCommand objects. It then executes a SELECT query
and fetches EmployeeID, FirstName, and LastName columns from the Employees table. The results
are retrieved as SqlDataReader instances. Then, a generic-based List of Employee objects is created.
A while loop iterates through the SqlDataReader. With each iteration, a new Employee object is
162
created and its EmployeeID, FirstName, and LastName properties are set. The Employee object
then is added to the List. After the while loop completes, SqlDataReader and SqlConnection are
closed. The return type of the GetEmployees() web method is an array of Employee objects. Hence,
the generic List is converted into Employee array using the ToArray() method of the List class.
Next, add a web method called GetEmployee() as follows:
[WebMethod]
public Employee GetEmployee(int pEmployeeId)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "select employeeid,firstname,lastname
from employees where employeeid=@id";
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(id);
SqlDataReader reader = cmd.ExecuteReader();
Employee emp = new Employee();
while (reader.Read())
{
emp.EmployeeID = reader.GetInt32(0);
emp.FirstName = reader.GetString(1);
emp.LastName = reader.GetString(2);
}
reader.Close();
cnn.Close();
return emp;
}
The GetEmployee() web method accepts an employee ID that is to be returned. The code is very
similar to the previous code but this time it fetches only one employee. Note that you used
SqlParameter to represent the passed EmployeeID.
Now you can add the Insert(), Update(), and Delete() web methods as follows:
[WebMethod]
public int Insert(string pFirstName, string pLastName)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "insert into employees(firstname,lastname)
values (@fname,@lname)";
SqlParameter fname = new SqlParameter("@fname", pFirstName);
SqlParameter lname = new SqlParameter("@lname", pLastName);
cmd.Parameters.Add(fname);
cmd.Parameters.Add(lname);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
[WebMethod]
public int Update(int pEmployeeId,string pFirstName, string pLastName)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "update employees set firstname=@fname,
163
lastname=@lname where employeeid=@id";
SqlParameter fname = new SqlParameter("@fname", pFirstName);
SqlParameter lname = new SqlParameter("@lname", pLastName);
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(fname);
cmd.Parameters.Add(lname);
cmd.Parameters.Add(id);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
[WebMethod]
public int Delete(int pEmployeeId)
{
SqlConnection cnn = new SqlConnection(strConn);
cnn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandText = "delete from employees where employeeid=@id";
SqlParameter id = new SqlParameter("@id", pEmployeeId);
cmd.Parameters.Add(id);
int i = cmd.ExecuteNonQuery();
cnn.Close();
return i;
}
The Insert() web method accepts the first name and last name of the employee to be added. It then
creates an instance each of SqlConnection and SqlCommand and executes the INSERT statement
using the ExecuteNonQuery() method of the SqlCommand object. Similarly, the Update() web method
accepts the employee ID to be updated, along with new values for first name and last name, and
fires an UPDATE statement. Finally, the Delete() web method accepts an employee ID that is to be
deleted and fires a DELETE statement.
This completes your web service. To this point, you have not done anything specific to AJAX
functionality. Now, it's time to do just that. Modify your web service class definition as follows:
using System.Web.Script.Services;
...
...
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class EmployeeService : System.Web.Services.WebService
{
...
...
Notice the lines marked in bold. You have imported a namespace System.Web.Script.Services, which
comes from the System.Web.Extensions assembly. The [ScriptService] attribute you'll use later is
supplied by this namespace. The [ScriptService] attribute enables the web service to be called from
the client-side JavaScript (i.e., ASP.NET AJAX).
That's it! You are now ready to consume your web service from ASP.NET AJAX.

How to Consume the Web Service


In this section, you will create a web form that acts as a data entry page for the Employees table by
consuming the web service you just created. To begin, add a new web form called
EmployeeServiceClient.aspx to the web site. Open the toolbox by selecting the View > Toolbox menu
option. On the toolbox, locate a node titled AJAX Extensions (see Figure 2).
164

Figure 2: The New Web Site Dialog with Added Templates


The AJAX Extensions node displays all the ASP.NET AJAX components that you can use on a web
form. Drag and drop a ScriptManager component on the web form. Every web form making use of
ASP.NET AJAX needs one ScriptManager component. Open the properties window for the
ScriptManager. Locate its Services property and open the Service Reference collection editor as
shown in Figure 3.

Click here for a larger image.


Figure 3: The Service Reference Collection Editor
Click the Add button at the bottom of the dialog and set the Path property to the virtual path of the
web service (in other words, EmployeeService.asmx). This will generate the following markup in the
web form file:
<asp:ScriptManager ID="ScriptManager1" runat="server" >
<Services>
<asp:ServiceReference Path="EmployeeService.asmx" />
</Services>
</asp:ScriptManager>
For each web service that you want to consume, you need one <asp:ServiceReference> element
inside the <asp:ScriptManager> section. The <asp:ServiceReference> tag registers a web service to
use in the current web form.
Now, design the web form as shown in Figure 4.
165

Figure 4: Design the Web Form


The web form consists of a dropdown (<SELECT>) that lists all the existing employee IDs. Once you
select a specific ID, details of that employee are displayed in the two textboxes. You then can update
them. To add an employee, you simply need to enter the first name and last name and click the
Insert button. Similarly, you can delete an employee by selecting employee ID in the dropdown and
clicking the Delete button. A success or failure message is displayed once the INSERT, UPDATE, or
DELETE operation is over. The following is the complete markup of the web form:
<table>
<tr>
<td colspan="2">
<asp:Label ID="Label4" runat="server" Font-Size="X-Large"
Text="Employee Management">
</asp:Label></td>
</tr>
<tr>
<td style="width: 100px">
<asp:Label ID="Label1" runat="server"
Text="Employee ID :"></asp:Label></td>
<td style="width: 100px">
<select id="Select1" >
</select>
</td>
</tr>
<tr>
<td style="width: 100px">
<asp:Label ID="Label2" runat="server"
Text="First Name :"></asp:Label></td>
<td style="width: 100px">
<input id="Text1" type="text" /></td>
</tr>
<tr>
<td style="width: 100px">
<asp:Label ID="Label3" runat="server"
Text="Last Name :"></asp:Label></td>
<td style="width: 100px">
<input id="Text2" type="text" /></td>
</tr>
<tr>
<td align="center" colspan="2">
<input id="Button3" type="button" value="Insert" />
<input id="Button4" type="button" value="Update" />
<input id="Button5" type="button" value="Delete" />
</td>
</tr>
166
<tr>
<td align="center" colspan="2">
<span id="lblMsg" style="font-weight: bold;
color: red;"></span>
</td>
</tr>
</table>
Notice one important thing: You did not use ASP.NET server controls such as DropDownList,
TextBox, and Button. Instead, you used traditional HTML controls such as <SELECT> and <INPUT>.
This is because you want to call your web service from client-side JavaScript and not from server-
side code. Also, notice the <SPAN> tag at the bottom. It will be used for displaying success or failure
messages.
Next, add a <script> section inside the <head> HTML element. Add a function called
CallWebMethod() as shown below:
function CallWebMethod(methodType)
{
switch(methodType)
{
case "select":
EmployeeService.GetEmployees(FillEmployeeList,ErrorHandler,
TimeOutHandler);
break;
case "selectone":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
EmployeeService.GetEmployee(empid,DisplayEmployeeDetails,
ErrorHandler,TimeOutHandler);
break;
case "insert":
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
EmployeeService.Insert(text1.value,text2.value,
InsertEmployee,ErrorHandler,
TimeOutHandler);
break;
case "update":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
var emp=new Employee();
emp.EmployeeID=empid;
emp.FirstName=text1.value;
emp.LastName=text2.value;
EmployeeService.Update(empid,text1.value,text2.value,
UpdateEmployee,ErrorHandler,
TimeOutHandler);
break;
case "delete":
var select=document.getElementById("Select1");
var empid=select.options[select.selectedIndex].value;
EmployeeService.Delete(empid,DeleteEmployee,ErrorHandler,
TimeOutHandler);
break;
}
}
167
The CallWebMethod() function is a central function that makes calls to the web service. The
function accepts a string parameter indicating the method to be called and then calls that method. It
contains a switch statement that checks off the method to be called. Each case block calls one web
method. Notice how the web method has been called. The ASP.NET AJAX framework automatically
creates a JavaScript proxy class for the web service. The proxy class has the same name as the web
service. So, the EmployeeService in the above code is not the actual web service class but a
JavaScript proxy class. The proxy contains all the web methods of the original web service. In
addition to the original web method parameters, each method can have three extra parameters.
The first extra parameter is a JavaScript function that should be called when the web method call is
successfully completed. Remember that any AJAX communication between client and server is
asynchronous. Hence, this function is necessary to capture the return value of the web method. The
second parameter is a JavaScript function that is called in the event of error. Finally, the third extra
parameter is a JavaScript function that is called if a timeout occurs during the web method call.
In the first case ("select"), you simply call the GetEmployees() method. In the second case
("selectone"), you call the GetEmployee() method. The employee ID is picked up from the dropdown
using traditional JavaScript code. Similarly, the third, fourth, and fifth case blocks call the Insert(),
Update(), and Delete() methods, respectively.
The above code uses five JavaScript functions that are called when the respective web method calls
are successful: FillEmployeeList(), DisplayEmployeeDetails(), InsertEmployee(), UpdateEmployee(),
and DeleteEmployee(). Each of these functions accepts a single parameter that represents the return
value of the corresponding web method:
function FillEmployeeList(result)
{
var select=document.getElementById("Select1");
for(var i=0;i<result.length;i++)
{
var option=new Option(result[i].EmployeeID,
result[i].EmployeeID);
select.options.add(option);
}
}
function DisplayEmployeeDetails(result)
{
var text1=document.getElementById("Text1");
var text2=document.getElementById("Text2");
text1.innerText=result.FirstName;
text2.innerText=result.LastName;
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="";
}
function InsertEmployee(result)
{
if(result>0)
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee added successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while adding new employee!";
}
}
function UpdateEmployee(result)
{
if(result>0)
{
168
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee updated successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while updating the employee!";
}
}
function DeleteEmployee(result)
{
if(result>0)
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Employee deleted successfully!";
}
else
{
var lblMsg=document.getElementById("lblMsg");
lblMsg.innerText="Error occurred while deleting employee!";
}
}
The FillEmployeeList() function receives an array of Employee objects as a parameter. Recollect that
your GetEmployees() web method returns an array of Employee objects. It then iterates through the
array. With each iteration, a new OPTION element is created and added to the dropdown (in other
words, <SELECT>). The DisplayEmployeeDetails() function receives an Employee object containing
details about an employee. It simply displays those details in the two textboxes. The
InsertEmployee(), UpdateEmployee(), and DeleteEmployee() functions receive an integer indicating
the number of records affected by the INSERT, UPDATE, and DELETE operations, respectively. A
result greater than zero indicates success and they display a success message in the <SPAN> tag.
Otherwise, they display an error message. When your page is displayed for the first time, you need to
populate the dropdown list with the existing employee IDs. This is done by calling the
CallWebMethod() method in a special function named pageLoad():
function pageLoad()
{
CallWebMethod("select");
}
The pageLoad() function gets called automatically when the web page is loaded in the client browser.
Finally, the error handler and timeout handler functions look like this:
function ErrorHandler(result)
{
var msg=result.get_exceptionType() + "\r\n";
msg += result.get_message() + "\r\n";
msg += result.get_stackTrace();
alert(msg);
}
function TimeOutHandler(result)
{
alert("Timeout :" + result);
}
The TimeOutHandler() function is called whenever a web method times out. It simply shows an alert
to the user. The ErrorHandler() function is called whenever there is any error. The result parameter
received by this method provides three methods: get_exceptionType(), get_message(), and
get_stackTrace(). These three methods return the type of exception, detailed error message, and
stack trace, respectively. The ErrorHandler() function simply displays an alert to the end user.
169
Testing the Web Page
Now that you have developed the web service and the client application, it's time to test them. Run
the web form and try inserting, updating, or deleting employees. Figure 5 shows the web form after
updating an employee.

Figure 5: Web Form After Updating an Employee


To test the error handler function, deliberately initialize the connection string to an empty string and
run the web page again. This time, you should see an alert as shown in Figure 6.

Click here for a larger image.


Figure 6: ConnectionString Property Alert

Calling External Web Services


In this example, the EmployeeService was part of your web site. Sometimes, you may need to call
web services that are not hosted by your domain at all. ASP.NET AJAX internally relies on the XML
HTTP object, which for security reasons cannot communicate outside the originating web site. That
means the above technique won't work for external web services. Unfortunately, ASP.NET AJAX does
not have a direct solution to this issue (at least in the RC version). However, Microsoft has released a
"bridge" technology that is still in CTP stages. You can use the bridge to call a wrapper class residing
in your web site, which in turn calls the actual web service. In the current RC version, you can
create a wrapper web service in your web site, which in turn calls the original web service. From the
170
client application, you then can call your wrapper web service and achieve the communication.
The following is an outline of the necessary steps:

1. Add a web reference to the external web service in your web site.
2. Create a new web service in your web site.
3. In the newly created web service, provide wrapper web methods that call the external web
methods via web reference.
4. Call this newly added web service from the client application as described in this article.

Infrastructure for Calling ASP.NET Web Services


ASP.NET AJAX provides a complete infrastructure for calling ASP.NET web services from client-side
JavaScript. You can easily integrate server data with the user-responsive web pages using AJAX. All
you need to do is mark your web service with the [ScriptService] attribute. The ASP.NET AJAX
framework generates a JavaScript proxy for your web service. The proxy then is used to call the web
methods.

Generics
What Are Generics?
When we look at the term "generic", unrelated to the programming world, it simply means
something that is not tied to any sort of brand name. For example, if we purchase some generic
dish soap, soap that has no brand name on it, we know that we are buying dish soap and expect it
to help us clean our dishes, but we really don't know what exact brand (if any) will be inside the
bottle itself. We can treat it as dish soap even though we don't really have any idea of its exact
contents.

Think of Generics in this manner. We can refer to a class, where we don't force it to be related to any
specific Type, but we can still perform work with it in a Type-Safe manner. A perfect example of
where we would need Generics is in dealing with collections of items (integers, strings, Orders etc.).
We can create a generic collection than can handle any Type in a generic and Type-Safe manner. For
example, we can have a single array class that we can use to store a list of Users or even a list of
Products, and when we actually use it, we will be able to access the items in the collection directly as
a list of Users or Products, and not as objects (with boxing/unboxing, casting).

"Generic" Collections as we see them today

Currently, if we want to handle our Types in a generic manner, we always need to cast them to a
System.Object, and we lose any benefit of a rich-typed development experience. For example, I'm
sure most of us are familiar with the System.Collection.ArrayList class in Framework v1 and v1.1. If
you have used it at all, you will notice a few things about it:

1. It requires that you store everything in it as an object

public virtual int Add(object value);


public virtual object this[int index] {get; set;}

2. You need to cast up in order to get your object back to its actual Type

3. Performance is really lacking, especially when iterating with foreach()

4. It performs no type safety for you (no exceptions are thrown even if you add objects of different
types to a single list)

System.Collections.ArrayList list = new System.Collections.ArrayList();


list.Add("a string");
list.Add(45); //no exception thrown
171
list.Add(new System.Collections.ArrayList()); //no exception

foreach(string s in list) { //exception will be thrown!


System.Console.WriteLine(s);
}

For some situations we may feel the need to implement IEnumerable and IEnumerator in order to
create a custom collection of our given Type, that is, a Type-safe collection for our needs. If you had
a User object, you could create another class (which implements IEnumerable and IEnumerator, or
just IList) that allows you to only add and access User objects, even though most implementations
will still store them as objects. It is a lot of work implementing these two interfaces, and you can
imagine the work needed to create this additional collection class every time you wanted a Type-safe
collection.

The third and final way of creating a collection of items is by simply creating an array of that type,
for example:

string[] mystrings = new string[]{"a", "b", "c"};

This will guarantee Type safety, but is not very reusable nor very friendly to work with. Adding a new
item to this collection would mean needing to create a temporary array and copy the elements into
this new temporary array, resizing the old array, copying the data back into it, and then adding the
new item to the end of that collection. In my humble opinion, this is too much work that tends to be
very error prone.

What we need is a way to create a Type-safe collection of items that we can use for any type
imaginable. This template, or generic class, should be able to perform all of the existing duties that
we need for our collections: adding, removing, inserting, etc. The ideal situation is for us to be able
to create this generic collection functionality once and never have to do it again. You must also
consider other types of collections that we commonly work with and their functionality, such as a
Stack (First in, Last out) or a Queue (First In, First out), etc. It would be nice to be able to create
different types of generic collections that behave in standard ways.

In the next I will show you how to create your first Generic Type.

Creating Our First Generic Type

In this section we will create a very simple generic class and demonstrate how it can be used as a
container for a variety of other Types. Below is a simple example of what a generic class could look
like:

public class Col<T> {


T t;
public T Val{get{return t;}set{t=value;}}
}

There are a few things to notice. The class name "Col<T>" is our first indication that this Type is
generic, specifically the brackets containing the Type placeholder. This Type placeholder "T" is used
to show that if we need to refer to the actual Type that is going to be used when we write this class,
we will represent it as "T". Notice on the next line the variable declaration "T t;" creates a member
variable with the type of T, or the generic Type which we will specify later during construction of the
class (it will actually get inserted by the Common Language Runtime (CLR) automatically for us). The
final item in the class is the public property. Again, notice that we are using the Type placeholder "T"
to represent that generic type for the type of that property. Also notice that we can freely use the
private variable "t" within the class.
172
In order to use this class to hold any Type, we simply need to create a new instance of our new
Type, providing the name of the Type within the "<>" brackets and then use that class in a Type-safe
manner. For example:

public class ColMain {


public static void Main() {
//create a string version of our generic class
Col<string> mystring = new Col<string>();
//set the value
mystring.Val = "hello";

//output that value


System.Console.WriteLine(mystring.Val);
//output the value's type
System.Console.WriteLine(mystring.Val.GetType());

//create another instance of our generic class, using a different type


Col<int> myint = new Col<int>();
//load the value
myint.Val = 5;
//output the value
System.Console.WriteLine(myint.Val);
//output the value's type
System.Console.WriteLine(myint.Val.GetType());

}
}

When we compile the two classes above and then run them, we will see the following output:

hello
System.String
5
System.Int32

Even though we used the same class to actually hold our string and int, it keeps their original type
intact. That is, we are not going to and from a System.Object type just to hold them.

Generic Collections

The .NET team has provided us with a number of generic collections to work with in the the latest
version of the .NET Framework. List, Stack, and Queue are all going to be implemented for us. Let's
see an example on how to use the provided Generic List class.

For this example we want to be able to hold a collection of a Type that we create, which we used to
represent a User in our system. Here is the definition for that class:

namespace Rob {
public class User {
protected string name;
protected int age;
public string Name{get{return name;}set{name=value;}}
public int Age{get{return age;}set{age=value;}}
}
}

Now that we have our User defined, let's create an instance of the .NET Framework Generic version
of a simple List:
173
System.Collections.Generic.List<Rob.User> users
= new System.Collections.Generic.List<Rob.User>();

Notice the new "Generic" namespace within the System.Collections namespace. This is where we will
find all the new classes for our use. The "List" class within that namespace is synonymous with the
typical System.Collections.ArrayList class, which I'm sure most of us are very familiar with by now.
Please note that although they are similar there are several important differences.

So now that we have a Type-safe list of our User class, let's see how we can use this class. What we
will do is simply loop 5 times and create a new User and add that User to our users collection above:

for(int x=0;x<5;x++) {
Rob.User user = new Rob.User();
user.Name="Rob" + x;
user.Age=x;
users.Add(user);
}

This should seem straight forward to you by now. In the next step we will iterate over that same
collection and output each item to the console:

foreach(Rob.User user in users) {


System.Console.WriteLine(
System.String.Format("{0}:{1}", user.Name, user.Age)
);
}

This is slightly different that what we are used to. What you should notice right off the bat is that we
do not have to worry about the Type being "Rob.User". This is because our generic collection is
working in a Type-safe manner; it will always be what we expect.

Another way to output the same list would be to use a simple for() loop instead, and in this case we
do not have to cast the object out of the collection in order to use it properly:

for(int x=0;x<users.Count;x++) {
System.Console.WriteLine(
System.String.Format("{0}:{1}", users[x].Name, users[x].Age)
);
}

No more silly casting or boxing involved. Here is the complete listing of the source plus the output of
the result of executing the console application:

User.cs

namespace Rob {
public class User {
protected string name;
protected int age;
public string Name{get{return name;}set{name=value;}}
public int Age{get{return age;}set{age=value;}}
}
}

Main.cs

public class M {
public static void Main(string[] args) {
174
System.Collections.Generic.List<Rob.User> users = new
System.Collections.Generic.List<Rob.User>();
for(int x=0;x<5;x++) {
Rob.User user = new Rob.User();
user.Name="Rob" + x;
user.Age=x;
users.Add(user);
}

foreach(Rob.User user in users) {


System.Console.WriteLine(System.String.Format("{0}:{1}", user.Name, user.Age));
}
System.Console.WriteLine("press enter");
System.Console.ReadLine();

for(int x=0;x<users.Count;x++) {
System.Console.WriteLine(System.String.Format("{0}:{1}", users[x].Name, users[x].Age));
}

}
}

Output

Rob0:0
Rob1:1
Rob2:2
Rob3:3
Rob4:4
press enter

Rob0:0
Rob1:1
Rob2:2
Rob3:3
Rob4:4

More on Generics

More Generics features in the latest release of the .NET Framework include Generic Methods and
Constraints. A generic method is very straight forward. Consider this example:

public static T[] CreateArray<T>(int size) {


return new T[size];
}

This static method simply creates a method of the given Type "T" and of the given "size" and returns
it to the caller. An example of calling this method would be:

string[] myString = CreateArray<string>(5);

This will new up an instance of our string array, with an initial size of 5. You should take time to
investigate the new version of the framework. You will be surprised at all the little helpful features
like this.

Lastly, we should take a quick look at constraints. A constraint is setup to limit the Types which the
Generic can accept. Let's say for example we had a generic type:
175

public class Dictionary<K, V> where K : IComparable {}

Notice the "where" clause on this class definition. It is forcing the K Type to be of Type IComparable.
If K does NOT implement IComparable, you will get a Compiler error. Another type of constraint is a
constructor constraint:

public class Something<V> where V: new() {}

In this example V must have at least the default constructor available, if not the Compiler will throw
an error.

Conclusion

This article has introduced you to the new and exciting world of Generics. I hope you learned
something with this article, and are beginning to prepare yourself for the latest release of the .NET
Framework.

-------------------------------------------------------
----------------------------------------

When and How to Use Dispose and Finalize in C#

Although the .NET framework frees managed memory and resources transparently, it's not as
adept at freeing unmanaged resources; you have to help it out by implementing the Dispose and
Finalize patterns in your code.

hen the .NET framework instantiates an object, it allocates memory for that object on the managed
heap. The object remains on the heap until it's no longer referenced by any active code, at which
point the memory it's using is "garbage," ready for memory deallocation by the .NET Garbage Collector
(GC). Before the GC deallocates the memory, the framework calls the object's Finalize() method, but
developers are responsible for calling the Dispose() method.

The two methods are not equivalent. Even though both methods perform object cleanup, there are
distinct differences between them. To design efficient .NET applications, it's essential that you have a
proper understanding of both how the .NET framework cleans up objects and when and how to use the
Finalize and Dispose methods. This article discusses both methods and provides code examples and tips
on how and when to use them.

System Requirements
To implement the techniques discussed in the article, the minimum requirements are:

 .NET framework version 1.1 or higher


 Operating System: Windows XP/2000 or higher

An Insight into the Dispose and Finalize Methods


The .NET garbage collector manages the memory of managed objects (native .NET objects) but it does
not manage, nor is it directly able to clean up unmanaged resources. Managed resources are those that
are cleaned up implicitly by the garbage collector. You do not have to write code to release such
resources explicitly. In contrast, you must clean up unmanaged resources (file handles, database
collections, etc.) explicitly in your code.

There are situations when you might need to allocate memory for unmanaged resources from managed
code. As an example, suppose you have to open a database connection from within a class. The
database connection instance is an unmanaged resource encapsulated within this class and should be
released as soon as you are done with it. In such cases, you'll need to free the memory occupied by the
176
unmanaged resources explicitly, because the GC doesn't free them implicitly.

Briefly, the GC works as shown below:

 It searches for managed objects that are referenced in managed code.


 It then attempts to finalize those objects that are not referenced in the code.
 Lastly, it frees the unreferenced objects and reclaims the memory occupied by them.

The GC maintains lists of managed objects arranged in "generations." A generation is a measure of the
relative lifetime of the objects in memory. The generation number indicates to which generation an
object belongs. Recently created objects are stored in lower generations compared to those created
earlier in the application's life cycle. Longer-lived objects get promoted to higher generations. Because
applications tend to create many short-lived objects compared to relatively few long-lived objects, the GC
runs much more frequently to clean up objects in the lower generations than in the higher ones.

Keep this information about the .NET garbage collector in mind as you read the remainder of the article.
I'll walk you through the Finalize method first, and then discuss the Dispose method.

Finalizers—Implicit Resource Cleanup


Finalization is the process by which the GC allows objects to clean up any unmanaged resources that
they're holding, before the actually destroying the instance. An implementation of the Finalize method is
called a "finalizer." Finalizers should free only external resources held directly by the object itself. The
GC attempts to call finalizers on objects when it finds that the object is no longer in use—when no other
object is holding a valid reference to it. In other words, finalizers are methods that the GC calls on
"seemingly dead objects" before it reclaims memory for that object.

The GC calls an object's finalizer automatically, typically once per instance—although that's not always
the case (see the Author's Note below for more information). The framework calls finalizers on a
secondary thread handled by the GC. You should never rely on finalizers to clean up managed
resources. A class that has no finalizer implemented but is holding references to unmanaged objects can
cause memory leaks, because the resources might become orphaned if a class instance is destroyed
before releasing the unmanaged objects.

Author's Note: Although the GC usually calls an object's finalizer only once, you can change that
by writing code to re-register the instance using the ReRegisterForFinalize method and not
subsequently calling the GC.SuppressFinalize method on the instance.

You must implement finalizers very carefully; it's a complex operation that can carry considerable
performance overhead. The performance overhead stems from the fact that finalizable objects are
enlisted and removed from the finalization queues, which are internal data structures containing
pointers to instances of classes that implement a finalizer method. When pointers to these objects are
placed in this data structure, the object is said to be enlisted in the Finalization Queue. Note that the
GC periodically scans this data structure to locate these pointers. When it finds one, it removes the
pointer from the queue and appends the pointer at the end of another queue called the freachable
queue.

Further, finalizable objects tend to get promoted to the higher generations and hence stay in memory for
a relatively longer period of time. Note that the GC works more frequently in the lower generations than
in the higher ones.

The time and order of execution of finalizers cannot be predicted or pre-determined. This is why you'll
hear that the nature of finalization is "non-deterministic." Further, due to the non-deterministic nature
of finalization the framework does not and cannot guarantee that the Finalize method will ever be called
on an instance. Hence, you cannot rely upon this method to free up any un-managed resources (such as
a file handle or a database connection instance) that would otherwise not be garbage collected by the
177
GC.

Note that you cannot call or override the Finalize method. It is generated implicitly if you have a
destructor for the class. This is shown in the following piece of C# code:—

class Test
{

// Some Code

~Test
{
//Necessary cleanup code
}
}

In the preceding code, the ~Test syntax declares an explicit destructor in C#, letting you write explicit
cleanup code that will run during the finalize operation.

The framework implicitly translates the explicit destructor to create a call to Finalize:

protected override void Finalize()


{
try
{
//Necessary cleanup code
}
finally
{
base.Finalize();
}
}

Note that the generated code above calls the base.Finalize method.

You should note the following points should when implementing finalizers:

 Finalizers should always be protected, not public or private so that the method cannot be called
from the application's code directly and at the same time, it can make a call to the base.Finalize
method
 Finalizers should release unmanaged resources only.
 The framework does not guarantee that a finalizer will execute at all on any given instance.
 Never allocate memory in finalizers or call virtual methods from finalizers.
 Avoid synchronization and raising unhandled exceptions in the finalizers.
 The execution order of finalizers is non-deterministic—in other words, you can't rely on another
object still being available within your finalizer.
 Do not define finalizers on value types.
 Don't create empty destructors. In other words, you should never explicitly define a destructor
unless your class needs to clean up unmanaged resources—and if you do define one, it should
do some work. If, later, you no longer need to clean up unmanaged resources in the destructor,
remove it altogether.

To close out this section, Finalize() is a non-explicit way to clean up resources. Because you can't control
when (or even if) the GC calls Finalize, you should treat destructors only as a fallback mechanism for
releasing unmanaged resources. Instead, the approved way to release unmanaged resources is to make
your class inherit from the IDisposable interface and implement the Dispose() method.

The Dispose Method—Explicit Resource Cleanup


178
Unlike Finalize, developers should call Dispose explicitly to free unmanaged resources. In fact, you
should call the Dispose method explicitly on any object that implements it to free any unmanaged
resources for which the object may be holding references. The Dispose method generally doesn't free
managed memory—typically, it's used for early reclamation of only the unmanaged resources to which a
class is holding references. In other words, this method can release the unmanaged resources in a
deterministic fashion.

However, Dispose doesn't remove the object itself from memory. The object will be removed when the
garbage collector finds it convenient. It should be noted that the developer implementing the Dispose
method must call GC.SuppressFinalize(this) to prevent the finalizer from running.

Note that an object should implement IDisposable and the Dispose method not only when it must
explicitly free unmanaged resources, but also when it instantiates managed classes which in turn use
such unmanaged resources. Implementing IDisposable is a good choice when you want your code, not
the GC, to decide when to clean up resources. Further, note that the Dispose method should not be
called concurrently from two or more different threads as it might lead to unpredictable results if other
threads still have access to unmanaged resources belonging to the instance.

The IDisposable interface consists of only one Dispose method with no arguments.

public interface IDisposable


{
void Dispose();
}
The following code illustrates how to implement the Dispose method on a class that implements the
IDisposable interface:

class Test : IDisposable


{
private bool isDisposed = false;

~Test()
{
Dispose(false);
}

protected void Dispose(bool disposing)


{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class

isDisposed = true;
}

public void Dispose()


{
Dispose(true);
GC.SuppressFinalize(this);
}
}

In the preceding code, when the Boolean variable disposed equals true, the object can free both
managed and unmanaged resources; but if the value equals false, the call has been initiated from within
the finalizer (~Test) in which case the object should release only the unmanaged resources that the
instance has reference to.
179
The Dispose/Finalize Pattern
Microsoft recommends that you implement both Dispose and Finalize when working with unmanaged
resources. The correct sequence then would be for a developer to call Dispose. The Finalize
implementation would run and the resources would still be released when the object is garbage collected
even if a developer neglected to call the Dispose method explicitly. Francesco Balena writes in his blog
"the Dispose/Finalize pattern should be used only when your type invokes unmanaged code that
allocates unmanaged resources (including unmanaged memory) and returns a handle that you must use
eventually to release the resource. Both dispose and finalize must chain up to their parent objects by
calling their parent's respective methods after they have disposed or finalized their own members".

Simply put, cleanup the unmanaged resources in the Finalize method and the managed ones in the
Dispose method, when the Dispose/Finalize pattern has been used in your code.

As an example, consider a class that holds a database connection instance. A developer can call Dispose
on an instance of this class to release the memory resource held by the database connection object.
After it is freed, the Finalize method can be called when the class instance needs to be released from the
memory. According to MSDN, "Finalize provides a backup to prevent resources from permanently
leaking if the programmer fails to call Dispose". Please refer to the following link:

Suppressing Finalization
After the Dispose method has been called on an object, you should suppress calls to the Finalize method
by invoking the GC.SuppressFinalize method as a measure of performance optimization. Note that you
should never change the order of calls in the finalization context (first Dispose(true) and then
GC.SupressFinalize) to ensure that the latter gets called if and only if the Dispose method has completed
its operation successfully.

The following code illustrates how to implement both the Dispose and Finalize pattern for a class.

public class Base: IDisposable


{
private bool isDisposed = false;

public void Dispose()


{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!isDisposed)
{
if (disposing)
{
// Code to dispose the managed resources
// held by the class
}
}
// Code to dispose the unmanaged resources
// held by the class
isDisposed = true;
base.Dispose(disposing);
}
~Base()
{
Dispose (false);
}
}
You should not reimplement IDisposable for a class that inherits from a base class in which IDispose
has already been implemented. The following code snippet may help you understand this concept:
180
public class Base: IDisposable
{
private bool isDisposed = false;

public void Dispose()


{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!isDisposed)
{
if (disposing)
{
// Code to dispose managed resources
// held by the class
}
}
// Code to dispose unmanaged resources
// held by the class
isDisposed = true;
base.Dispose(disposing);
}
~Base()
{
Dispose (false);
}
}

public class Derived: Base


{
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Code to cleanup managed resources held by the class.
}

// Code to cleanup unmanaged resources held by the class.

base.Dispose(disposing);
}
// Note that the derived class does not // re-implement IDisposable
}
In the preceding code, what if the Dispose method were to throw an exception? In that case, the Finalize
method would exit prematurely, and the memory would never be reclaimed. Hence, in such situations, it
is advisable to wrap the Dispose method in a try-catch block. This will prevent finalization exceptions
from orphaning the object.

Note the following points when implementing disposable types:

 Implement IDisposable on every type that has a finalizer


 Ensure that an object is made unusable after making a call to the Dispose method. In other
words, avoid using an object after the Dispose method has been called on it.
 Call Dispose on all IDisposable types once you are done with them
 Allow Dispose to be called multiple times without raising errors.
 Suppress later calls to the finalizer from within the Dispose method using the
GC.SuppressFinalize method
181
 Avoid creating disposable value types
 Avoid throwing exceptions from within Dispose methods

In a managed environment, the GC takes care of freeing unused objects. In contrast, in unmanaged
languages such as C, developers had to release unused objects explicitly that were created dynamically
in the heap. However, a proper understanding of both the Dispose and Finalize methods goes a long way
toward designing efficient applications.

Delegates and Events

1) What does mean Type safe in .Net and is delegate type safe, if yes then explain it?
a. Type-safe code accesses only the memory locations it is authorized to access.
b. Type-safe code cannot directly read values from another object's private fields or code
areas.
c. It accesses types only in well-defined, allowable ways, thereby preventing overrun
security breaches.
d. Type safety helps isolate objects from each other and therefore helps protect them from
malicious corruption.
e. It also provides assurance that security restrictions on code can be reliably enforced.
A delegate is essentially a type-safe pointer to a method. The .NET runtime enforces a check against
the method signature and only the method with the proper signature will execute.

2) Delegate always needs to declare as public or can we declare as private or protected?


Delegate can declare as private and protected but scope of that delegate will inside the class
in case of private.

3) Can we declare delegate as static, if no then explain it?

Can somebody answer this question with example?

4) What is "call back". When and how to use it scenarios?


Callback is method which can use by delegate. Let’s try to understand delegate with
Example :
Consider a multi-tier application for loan processing that has a business logic component
containing loan-processing rules. During processing, a decision tree determines the
applicant's overall credit rating score. This calculation is complex, often involving a number
of variables and taking varying lengths of time to complete. Suppose that while the
application is processing an applicant, a loan officer learns something that requires another
applicant's credit score to be updated. Rather than have the UI wait until the processing
finishes, which prevents the officer from updating the other applicant's score, the application
makes a request and will notify the UI when processing is complete. In order for this
notification to occur, the business logic component needs the address of the method to call in
the UI when processing is complete. This is the essence of a callback method. It is a pointer
to a method in the client to call when processing is complete

You might also like