Professional Documents
Culture Documents
ASP .Net Tutorials
ASP .Net Tutorials
Access Modifiers:
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
Method can be declared as static internal and can be used with Class name.
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.
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
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.
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
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
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 2 - When LoadViewState is fired, controls are populated with the appropriate viewstate
data.
11
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.
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.
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…)
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)
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
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:
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
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:
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.
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.
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
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
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 Int16 ID
{
get{return vid;}
set{vid=value;}
}
32
public string Name
{
get{return vname;}
set{vname=value;}
}
Authors Class
-------------
public class Authors:System.Collections.CollectionBase
{
public Authors()
{
}
//Add author to collection
public void Add(Author oAuthor)
{
List.Add(oAuthor);
}
How To Use?
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.
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.
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
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
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.
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.
Figure A
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
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".
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).
1. In the Run dialog box, type cmd, and then click OK.
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 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.
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.
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.
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
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#.
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:
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.
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;
// Constructor
public SubmitButtonControl()
{
// Create visual controls
InitializeComponent();
}
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());
}
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;
// Constructor
public LoginControl()
{
InitializeComponent();
}
47
....
....
// 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
}
}
}
}
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());
}
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 = "";
}
}
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
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;
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();
Overview
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)
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)
</script>
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.
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:
Control c1 = LoadControl("test.ascx");
Page.Controls.Add(c1);
Note You can add a user control dynamically at certain events of the page life cycle.
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.
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
System
System.Collections
System.ComponentModel
System.Data
5.
System.Web
System.Web.SessionState
System.Web.UI
System.Web.UI.WebControls
Override the Render method to write the output to the output stream.
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.
To instantiate or use the custom control on the Web Forms page, add the following line of code
in the <form> tags.
</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.
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
write.Write("Hello World.."+"<BR>");
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.
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.
DefaultProperty("DefaultProperty"),
// Specify the tag that is written to the aspx page when the
ToolboxData("<{0}:ControlWithAttributes runat=\"server\">" +
"</{0}:ControlWithAttributes>")
]
2.
public class ControlWithAttributes : Control
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
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.
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:
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;
}
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;
}
// set up multicast
strOp = replaceSp;
strOp += reverseStr;
66
// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
}
[/CODE]}
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
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:
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:
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();
}
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.
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.
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.
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."
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 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.
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.
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.
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
24. You mean the steps of the page lifetime? or that .NET is event driven?
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)
36. <asp:HyperLinkColumn>
40. False
42. CurrentPageIndex
43. www.uddi.org
45. DataTextField
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.
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.
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
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.
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.
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.
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.
Garbage Collection
Remoting
Interoperability
Security
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.
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:
3. Use the resource by accessing the instance members of the type (repeat as necessary).
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.
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.
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.
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() {
}
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() {
}
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.
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.
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.
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 {
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 {
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.
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).
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.
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.
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.
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.
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.
// 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.
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.
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
{
}
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:
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.
It is also possible to force the garbage collector to perform a collection by calling one of the two
methods shown here:
123
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:
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.
This section provides a complete example that illustrates the steps required to create a multifile
assembly.
[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.
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.
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.
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.
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.
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.
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.
namespace XmlWebServicesExample
{
[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.
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.
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.
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:
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
Method can be declared as static internal and can be used with Class name.
class?
Ans: base
DataSet?
in C#?
1. int[,] myArray;
2. int[][] myArray;
3. int[2] myArray;
4. System.Array[2] myArray;
Q4 What is a delegate?
1. wading.
2. serialization.
3. crunching.
4. marshalling.
Ans: serialization
{ void MyFun();
{ int aField;
public AClass( ){ }
Console.Write(aClass.MyProp);
aClass.MyFun();
void Inter.MyFun( )
{ Console.WriteLine(" MyFun()");
1. Exception
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' ).
1. True
2. False
Ans: False
Q8. What happens when you include a Throw statement in the catch block?
1. Compilation Error
3. Runtime Error
4. Execution is abandoned
1. True
2. False
3. Don't Know
Ans: False
1. True
2. False
3. Don't Know
Ans: False
4. There is no provision in c#
1. Yes
2. No
4. It depends on sccessspecifiers
Ans: No
Q14. What is the accessibility modifier for methods inside the interface?
1. Private by default
2. Public by default
3. protected
4. Friend
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
byte b1=1;
byte b2=255;
byte total=b1+b2;
Console.WriteLine (total);
3. 256
4. 1
{ void MySub(){ }
{ void MySub(){}
}
140
Public Class MyTest: ITest1, ITest2
3. Compile Time Error - MySub cannot be implemented as both ITest1 and ITest2 have the
same method name
4. Runtime Error
Q6. How many ways are there in asp.net for managing persistent user state ?
1. Nine
2. four
3. five
4. seven
Ans: Nine
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
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
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
Remoting
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.
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!";
}
}
}
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);
}
}
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);
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.
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.
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
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:
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
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
// Static constructor:
static Bus()
{
System.Console.WriteLine("The static constructor 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;
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.
.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:
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.
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.
The following code shows the syntax for compiling the generated code as a library using the C#
compiler (csc.exe).
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")
custCMD.Fill(custDS, "Customers");
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.
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.
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).
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:
2. You need to cast up in order to get your object back to its actual Type
4. It performs no type safety for you (no exceptions are thrown even if you add objects of different
types to a single list)
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:
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.
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:
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:
}
}
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:
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);
}
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:
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:
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
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:
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.
-------------------------------------------------------
----------------------------------------
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:
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.
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.
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:
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.
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.
~Test()
{
Dispose(false);
}
isDisposed = true;
}
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.
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.
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.
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.