Tuesday, January 22, 2008

request queues ASP.NET

ASP.NET uses two request queues:
•The global queue, which is managed by the process that runs ASP.NET (Aspnet_wp). The global queue is configured in the Machine.config file by the property.
•The application queue, or virtual directory queue, which is managed by the HttpRuntime class. The HttpRuntime class provides run-time services for ASP.NET applications. There is one queue for each virtual directory. The application queue is configured in Machine.config by the property.
When either queue exceeds its default limit, the request is rejected with a 503 error (Service Unavailable).

Wednesday, January 16, 2008

WHY DOT NET application restarts.

Recreating the application domain and recompiling pages takes time, therefore unforeseen application restarts should be investigated. The application domain is unloaded when one of the following occurs:


Modification of machine.config, web.config, or global.asax.
Modification of the application's bin directory or its contents.
When the number of compilations (ASPX, ASCX, or ASAX) exceeds the limit specified by .
Modification of the physical path of a virtual directory.
Modification of the code-access security policy.
The Web service is restarted.

Monday, January 14, 2008

Locking down configuration settings/overriding configuration settings

In addition to specifying path information using the <location>tag, you can also specify security so that settings cannot be overridden by another configuration file further down the configuration hierarchy. To lock down a group of settings, you can specify an allowOverride attribute on the surrounding <location>tag and set it to false. The following code locks down impersonation settings for two different applications.
<configuration>
<location allowoverride="false" path="app1"><system.web><identity username="app1" impersonate="false" password="app1pw"></location>
<location allowoverride="false" path="app2"><system.web><identity username="app2" impersonate="false" password="app2pw"></SYSTEM.WEB></location>
</configuration>
allowdefinition is used to allow child to define tags

allowoverride is used to allow child to override tags

<location path="." inheritInChildApplications="false">

<system.web> ... </system.web></location>

overriding parent web.config

While the ability of applications and folders to inherit settings from parent web.config files is very convenient, it presents security implications. For example, the element can be used to store key/value pairs for runtime retrieval from your application. If this element is used to store values in the machine.config file, these values are available to any application on that machine. In a shared server environment, this could potentially expose information to others in undesirable ways.

Another security issue with both machine.config and web.config is how to prevent modification of inherited settings. For example, a server administrator might want to configure authentication settings globally in the machine.config file and prevent application developers from overriding these settings in their applications. This can be accomplished by using the element, setting its allowOverride attribute to False and optionally, setting the path attribute to an application path (if the locked-down settings are to apply only to a specific file or folder).

It is important to exercise caution when working with the machine.config file to avoid making changes if you are uncertain of their impact (particularly on other applications). Remember that machine.config contains configuration settings not only for all ASP.NET web applications for a given machine, but also for all .NET applications on that machine. Thus, changes to machine.config can have a broad impact. It's a good idea to back up the machine.config file before editing it, so that if your changes result in problems, you can always restore the previous copy. Another alternative is to place the machine.config file under a source code control system, such as Visual Source Safe, and require checkout of the file to make modifications. This provides the ability to roll back changes, as well as the additional ability to track who has made changes to the file.

Finally, your application is required to have a web.config file. If the default settings from machine.config (or a parent web.config) file serve your needs, then omitting this file will simplify your deployment and maintenance tasks. Only use web.config when you need to make changes to the default configuration provided by machine.config.

Probably the most common error that is encountered with web.config and machine.config relates to capitalization. Tags and elements within both these files are case sensitive. Tags and elements follow the naming convention referred to as camel-casing, in which the first letter of the first word of the element or attribute is lowercase, and the first letter of each subsequent word is uppercase. Attribute values are also case sensitive, but do not follow any particular naming convention.

Error handling/ error gathering code

Imports System.Data

Imports System.Data.SqlClientImports dataConnection


Partial Class ErrInfo Inherits System.Web.UI.Page

Public error_ID As String

Public errpath As String

Dim DatabaseObject As New dataConnection

Dim datareader As SqlDataReader
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim strSql As String Dim ex As Exception = dataConnection.LastError Dim ErrMsg, pageUrl, stack_info As String ErrMsg = dataConnection.LastError.InnerException.Message.ToString() pageUrl = dataConnection.lastURL.ToString stack_info = dataConnection.LastError.ToString ErrMsg = ErrMsg.Replace("'", "") ErrMsg = ErrMsg.Replace(".", "")
Dim errLine As String 'errLine = Mid(ex.ToString(), InStr(ex.ToString(), ":line") - 20, InStr(ex.ToString(), "at System") - InStr(ex.ToString(), ":line") + 20) errLine = Mid(ex.ToString(), ex.ToString().LastIndexOf(":line") + 6, 8) 'ex.ToString().LastIndexOf("at System") - ex.ToString().LastIndexOf(":line") + 20)
Dim pageArr As String() = pageUrl.Split(New [Char]() {"/"c})
Dim currDateTime As DateTime = DateTime.Now Dim errorDate As String
DatabaseObject.openDB() errorDate = currDateTime.ToString("dd/MMM/yy")
strSql = "INSERT INTO ERRORLOG VALUES ('" & dataConnection.lastURL & "','" & Request("aspxerrorpath").ToString & "','" & ErrMsg & "','" & errorDate & "')"
DatabaseObject.executeNonQuery(strSql) datareader = DatabaseObject.executeReader("SELECT IDENT_CURRENT('ERRORLOG') as error_id") If datareader.HasRows Then datareader.Read() error_ID = datareader("error_id").ToString End If
datareader.Close() datareader.Dispose()
DatabaseObject.closedb()
'send error mail to admin Dim body As String body = "

<table cellspacing="'3'" cellpadding="'3'" width="'90%'" align="'center'" border="'0'">" body += " Error Date: " & errorDate & "" body += " Error Time: " & Date.Now.ToString("HH:mm:ss tt") & "" body += " User Name: " & Session("userID") & "" body += " OS: " & Request.Browser.Platform & "" body += " Browser: " & Request.Browser.Browser & "" body += " Page: " & Request("aspxerrorpath").ToString & "" body += " URL: " & dataConnection.lastURL & "" body += " Line: " & errLine & "" body += " Error Details: " & ErrMsg & " " body += " Stack Information: " & stack_info & " " body += "</table>

"
Dim page_name As String = Request("aspxerrorpath").Substring(1) 'Response.Write(body & "
" & page_name) DatabaseObject.sendMail1(body, "admin@yoursite.com", "cc", "Error on file " & page_name) 'DatabaseObject.sendMail1(body, "admin@yoursite.com", "cc", "Error on ..") End Sub

End Class

add following in global.asax:

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) ' Code that runs when an unhandled error occurs dataConnection.LastError = Server.GetLastError() dataConnection.lastURL = Request.Url().ToString End Sub

add following in web.config:

<customErrors mode="Off" defaultRedirect="ErrInfo.aspx">

Thursday, January 10, 2008

Optimization Tips and Tricks for Telerik

Top 15 Optimization Tips and Tricks

While we do a lot to help you optimize RadControls in your applications, the Telerik community also does a great job of sharing optimization tips and tricks. One of the best list of optimization tricks ever produced by the community has recently surfaced on the Telerik forums. Some of these ideas are specific to optimizing the RadControls, but many of them are great optimization techniques for ASP.NET in general. So without further ado, here are the "Top 15 Telerik Community Optimization Tips & Tricks" (in no particular order):
1.Make sure browser caching is enabled
Many RadControls must load a fair amount of JavaScript to enable all of the client-side goodness that we love in our modern web apps. To make sure this JavaScript is only downloaded once (instead of on every page request), make sure your users enable caching in their browsers.
2.Move ViewState off of the page
If you've got a lot of controls on your page and ViewState is enabled, chances are it is adding a lot of weight to the page. If turning ViewState off is not an option, you can greatly reduce the HTML sent to the client by moving ViewState off of the page and into Session (or some other server-side storage mechanism). For a good tutorial on this process, check out the following article: http://www.codeproject.com/aspnet/PersistentStatePage.asp.
3.Disable control ViewState
Similar to the previous trick, you can also set "EnableViewState" on each control to False and then manually manage the state on each page postback. Those of us that developed with classic ASP may recall some of the numerous ways this was accomplished before ASP.NET gave us ViewState. Manually managing control state can be time consuming, but it can help you keep your page HTML trim.
4.Use HTML Compression Tools
One of the easiest ways to reduce the HTML that you send to the client is to use an HTML compression tool. Compression tools can reduce the size of the HTML sent over the "tubes" for RadControls by up to 75%. Check out this forum thread for more details: http://www.telerik.com/community/forums/thread/b311D-tdkga.aspx.
5.Background Image Caching in IE
By default, IE will not cache background images. If you use any CSS in your application (which you do if you use RadControls with skins), this can lead to a lot of wasted downloads in IE. Fortunately, there is a way to "trick" IE into caching background images. Check out the details here: http://www.telerik.com/community/forums/thread/b311D-teckk.aspx.
6.Read the Documentation
This may sound like a worthless trick, but don't discount it until you've given it a try. Almost all RadControls have a dedicated "Speed Optimization" topic in their documentation that contains tips specific to each RadControl. Visit the RadControls documentation to find these tips. (Here is a link to RadGrid's optimization documentation to get you started.)
7.Use Http Analysis Tools
How can you solve a problem without seeing it first? Free tools like Fiddler (for IE) and FireBug (for FireFox) help you peel back the curtain on your page's performance and quickly find bottlenecks in your page HTML that need to be optimized.
8.Use 3rd Party Optimization Tools
Still looking for optimization techniques that don't require much work? There are several tools, like port80 and cacheright, that help automate the process of optimizing your page. These tools can help eliminate many of the caching problems that you'd otherwise have to deal with manually.
9.Use External Resources instead of EmbeddedResources
Embedded resources are generally very good and very helpful. They allow you do just deploy a control assembly and not deal with any additional files. When a page uses EmbeddedResources, though, resources are pulled from an assembly using a handler and querystring value (like WebResource.axd?d=HTLSHE...). Unfortunately, these long querystrings are adding bulk to the HTML you are sending to the client. One Telerik community member found that setting "UseEmbeddedResources" to False (and using external resources in the RadControls folder instead) reduced page size from 80 kB to about 50 kB simply due to the shorter resource paths. Your mileage may vary depending on the RadControls you're using.
10.Keep Control IDs Short
Whenever you have deeply nested controls, the ID of the parent control is always appended to child control IDs (if the parents implement INamingContainer). If you have long control IDs, you can cause a fair amount of extra HTML to be rendered to the page. For example, if we have a RadTreeView with ID "RadTreeView1" in ContentPlaceHolder with ID "ContentPlaceHolder1" (in a MasterPage), the resulting client ID of the TreeView is "ctl00_ContentPlaceHolder1_RadTreeView1". If we had used shorter server IDs, we could have trimmed this output to "ctl00_cph1_rtv1" and reduced the overall HTML sent to our page. This trick should always be weighed against making your code difficult to maintain due to cryptic control IDs.
11.Test Sites in IIS (not Cassini)
The web server built-in to Visual Studio is very convenient for development, but it is not a good place to test your site's performance. Cassini does not do any caching of web resources and it is generally slower than IIS. You should always test your site in IIS before deploying it to a PROD environment to make sure you know how it will really perform.
12.Use RamDisks in your Infrastructure
If you have control over your servers and are willing to make some hardware changes to improve performance, RamDisks may be worth checking out. By using RamDisks instead of traditional HDD for things like tempdb storage in SQL Server or HTTP decompression scratch storage, you can (supposedly) deliver performance 50x's normal hard drives. Check out this resource for more details: http://www.superspeed.com/ramdisk.php.
13.Use Incremental Page Fetch
It sounds more exciting than it is, but by using RadAjax and some crafty coding you can help your pages load faster. In essence, you delay loading all of the user controls needed by your page so that the page will initially load faster and then load the controls with RadAjax. For details on this process, check out this link: http://www.telerik.com/community/forums/thread/b311D-tkkce.aspx.
14.Remove Whitespace Characters
You may not realize it, but all of the whitespace characters our page contains to make it easy to read add HTML bulk. We definitely don't want to get rid of all of our page formatting at design time, though, so there are modules like this that remove the whitespace at runtime. By tapping-in to the page's render method, you can easily search for whitespace characters in your page and remove them to keep your pages trim. Warning: this method may cause problems if you use it with the new RadControls "Prometheus".
15.Don't use Label when Literal works
Perhaps one of the most overlooked ASP controls is the "asp:literal" control. There are many times when ASP.NET developers use Label or HyperLink when Literal would do the job and save HTML bulk. For example, if you use a Label like this:

will render:
Some test text

If you use a Literal like this:

will render:
Some test text

The literal will not render any unnecessary span tags and help you reduce HTML sent to the client.
So there you go. The top 15 optimization tips and tricks as suggested by the Telerik community. Special credit goes to Johan, andyk, Martin Bischoff, and Mike for collecting most of these ideas in the forums.

performance setting to achieve good grade in YSLOW











performance setting to achieve good grade in YSLOW

Dummy Credit Card Numbers for Testing

Dummy Credit Card Numbers for Testing
Here is a list of dummy credit card number that can be used while testing your applications involving credit card transactions:
Visa: 4111-1111-1111-1111
MasterCard: 5431-1111-1111-1111
Amex: 341-1111-1111-1111
Discover: 6011-6011-6011-6611
Credit Card Prefix Numbers:
Visa: 13 or 16 numbers starting with 4
MasterCard: 16 numbers starting with 5
Discover: 16 numbers starting with 6011
AMEX: 15 numbers starting with 34 or 37

check credit card /credit card verification

check credit card /credit card verification
http://www.braemoor.co.uk/software/creditcard.shtml

Navigate and Find with javascript

<script language="JavaScript">
function function1() {
window.external.NavigateAndFind('http://www.site.com', 'Java', '');
}
</script>

<input id="myB" type="button" value="Navigate and Find" onclick="function1();">

HTML and Case Sensitivity

HTML and Case Sensitivity
Under HTML 4 and earlier, element and attribute names are case-insensitive. For example, the following two tags are equivalent:
<Increment x>
<Increment x>
This is not a problem in itself. The problem comes when novice programmers see HTML event handlers referenced in two different ways (like ONCLICK and onClick in the previous example) and assume event handlers can be accessed similarly in JavaScript. This is not the case. The corresponding event handler in JavaScript is onclick, and it must always be referred to as such. The reason that ONCLICK and onClick work in HTML is that the browser automatically binds them to the correct onclick event handler in JavaScript.

Javascript syntax rules

Syntax Rules
Statements may contain a semicolon at the end of them as in C, but it is not necessary unless there are multiple statements on one line. Multiple statements on one line must be separated by a semicolon.
JavaScript is case sensitive.
Quotes may be single quote (') or double quote ("). When embedded within each other they must be used consistently as in the following example.
onMouseOver="window.status='To Operating Systems Section' ;return true"
Comments are the same as in C++ with the "//" characters for a single line comment, and the "/*" for the beginning of a multiline comment and the "*/" for the end of a multiline comment.
Variables must be defined before they are used.
----------------
JavaScript Syntax Rules
JavaScript is a simple language, but you do need to be careful to use its syntax—the rules that define how you use the language—correctly. The rest of this book covers many aspects of JavaScript syntax, but there are a few basic rules you should understand to avoid errors.
Case Sensitivity
Almost everything in JavaScript is case sensitive: you cannot use lowercase and capital letters interchangeably. Here are a few general rules:
JavaScript keywords, such as for and if, are always lowercase.
Built-in objects such as Math and Date are capitalized.
DOM object names are usually lowercase, but their methods are often a combination of capitals and lowercase. Usually capitals are used for all but the first word, as in toLowerCase and getElementById.
When in doubt, follow the exact case used in this book or another JavaScript reference. If you use the wrong case, the browser will usually display an error message.
Variable, Object, and Function Names
When you define your own variables, objects, or functions, you can choose their names. Names can include uppercase letters, lowercase letters, numbers, and the underscore (_) character. Names must begin with a letter or underscore.
You can choose whether to use capitals or lowercase in your variable names, but remember that JavaScript is case sensitive: score, Score, and SCORE would be considered three different variables. Be sure to use the same name each time you refer to a variable.
Reserved Words
One more rule for variable names—they must not be reserved words. These include the words that make up the JavaScript language, such as if and for, DOM object names such as window and document, and built-in object names such as Math and Date. A complete list of reserved words is included in Appendix D, "JavaScript Quick Reference."
Spacing
Blank space (known as whitespace by programmers) is ignored by JavaScript. You can include spaces and tabs within a line, or blank lines, without causing an error. Blank space often makes the script more readable.
------------

Makes AJAX Loader/Processing GIF image in seconds

http://www.ajaxload.info
Makes AJAX Loader/Processing GIF image in seconds

What is a normalized/canonical url?


Caching depends upon this...
Q: What is a normalized/canonical url?

A: Canonicalization is the process of picking the best url when there are several choices. For example, most people would consider these the same urls:
www.example.com
example.com/
www.example.com/index.html
example.com/home.asp
Note: But each above URL is treated as a different URL.

always use same case & pattern while typing URL in code.

SQl, T-SQL, Avoid using cursor, alternative of cursor

Avoid using cursor, if primary key is on the working table, in some cases, we can achieve cursor functionality with following

declare @currid int
select @currid = min(OrderID) from Orders where OrderDate < ''7/10/1996' while @currid is not null begin select @currid = min(OrderID) from Orders where OrderDate < '7/10/1996' and OrderID > @currid
end

May be helpful in some cases..

Did you use proper ConnectionPooling in ASP.NET

http://www.codeproject.com/useritems/ADONET_ConnectionPooling.asp
Read & ponder over Min. Pool Size:

Min Pool Size is 0 (by default) The minimum number of connections allowed in the pool. Means we are not allowing connection to swim in the pool

Final Note : Min Pool Size should be set to a optimal number. Microsoft says 5-12 is a good number.

Encrypt and Decrypt of ConnectionString in app.config and/or web.config!

Encrypt and Decrypt of ConnectionString in app.config and/or web.config!

http://www.codeproject.com/useritems/Configuration_File.asp

Don't use Databinder.Eval, improve performance

Use explicit cast instead of using Eval


Eval uses reflection to evaluate argument passed.Reflection is the ability to read metadata at runtime

<%# DataBinder.Eval(Container.DataItem,"myfield") %>

But explicit casting can reduce the cost of reflection. Imagine if there is 30 rows and each row has 6 Eval calls. So there will be calls to Eval 180 times. And we should take this pretty seriously.So you must be thinking what to do. Hey we can simply do something like this and improve significant performance.


Option1=============

<%# ((DataRowView)Container.DataItem)["myfield"] %>

Option2 for DataReader=====================

<%# ((DbDataRecord)Container.DataItem).GetString(0) %>


Option3 use of ItemDataBound Event====================

protected void Repeater_ItemDataBound(Object sender, RepeaterItemEventArgs e){ DataRowView data = (DataRowView)e.Item.DataItem; Response.Write(string.Format("

{0}
",data["myfield"]));}
And if we are using Collection Objects as DataSource we can do something like this List customers = GetCustomers();Repeater1.DataSource = customers;Repeater1.DataBind();....
protected void Repeater_ItemDataBound(Object sender, RepeaterItemEventArgs e){ Customer customer = (Customer)e.Item.DataItem; Response.Write(string.Format("
{0}
",customer.FirstName));

Fetching user's credential from other site: Hacking

Any subscriber/member may get hacked in following way:

1. Open site
2. Become a member
3. Add blogs with title “”Administrator Announcement”
content may be following

Dear User,



This blog is shown to randomly accessed users. If you have got it, means you are lucky. is offering a date with Anjelina Jolie. If interested. you may enroll for the contest here.




  1. User Name










Note: This contest closes on 15th Oct. 2007



Regards,


Administrator




4.Now when other member logsin, he may visit above posted blog.
5.When he may get fool if he enters is username/password & submits
6.his details/session id/cookie info. /username/password will be submitted to http://www.URLofHackerSite.com/coll.aspx
7.coll.aspx will get his details
8.he will be hacked

Developers: How to Save bytes, ASP.NET


For Software Developers: "Save Bytes", Little Thing, Big Effect....e.g.




Here default name has been used. i.e. ContentPlaceHolder1. Web server has to transfer 25 bytes for this particular name.On client side it becomes something like ctl00$ContentPlaceHolder1.... , which again become too long.

Take A Scenario: If above name has 50 occurrences in a webpage & if 1000000 users are using same page then Web server has to transfer 1000000 X 25 X 50 = 125000000 bytes.If Name "ContentPlaceHolder1" is changed to "CPHold", Web Server will transfer 1000000 X 12 X 50= 60000000 bytes, i.e. Saving of 65000000 bytes
Note: This will be one way saving. Finally saying, use short id/names, don't use default/long id/names.

Character Count for Textarea, Remaining Character

Count and Limit Character Input in Text Boxes:


Put this in between the and tags:
Please view in source code

<script language="JavaScript">
function twdCount(field,cntfield,maxlimit)
{
if (field.value.length > maxlimit)
field.value = field.value.substring(0, maxlimit);
else
cntfield.value = maxlimit - field.value.length;
}
</script>


Here is the form code:


characters left


characters left

change Background Color of onfocus of HTML control


Change Background Color of HTML control:onfocus of any control bgcolor of the control should change & onblur it should again become white.this is the code


<script type="text/javascript" language="javascript">
function set()
{

for (i=0; i {

if (document.forms[0].elements[i].type=="text" || document.forms[0].elements[i].type=="password" || document.forms[0].elements[i].type=="textarea")
{
document.forms[0].elements[i].onfocus=function() {this.style.backgroundColor='#E3E0DB';};
document.forms[0].elements[i].onblur=function() {this.style.backgroundColor='#ffffff';};
}


if (document.forms[0].elements[i].type=="text" || document.forms[0].elements[i].type=="password" || document.forms[0].elements[i].type=="textarea")
{
if(document.forms[0].elements[i].value="")
document.forms[0].elements[i].focus();
}

}
}

</script>

Wednesday, January 9, 2008

General practices

MAXLENGTH:The maxlength of each control should be 1 minus the length set in the corresponding column length in databasee.g. fname = 256 in DB
front end- First Name = 255 should be set (even smaller than this is good)
Be careful while setting the column length: Please set minimum required length e.g. for first name 100 characters are to much. If we set 255 for this, that would be a wastage. Specially for char datatype
for username/password/security answer fields: maxlength should not be too large.

FOCUS:Cursor Focus should come at very first control of the form on the page. e.g. first name is the first control on the page, so cursor should focus in this automatically on page load
VALIDATORS:When validation fails, form should not submit i.e. no postback. on enter keypress form should not be submitted till validation messages appearPlease set SetFocusOnError="True" ValidationGroup="name"for all validators.all validators should fire on client side first.

BLANK FORM VALUES:if after submission of any form , if same page appears again, then all textbox/contols should get cleared.
INVALID CHARACTERS:Invalid characters should not be allowed in inputs.Proactive Strategy: e.g. phone textbox, if 0-9 & hypen is allowed in it.Then other characters should not be typed in this textbox.If somebody types invalid character, message should appear

Time taken by a webpage for execution : Page Cost

Following code will help us finding the Time taken by a page for execution i.e. Page CostWe need to use this for testing environment.This will create a log file.
The code calculates the time by calculating the interval between the Application_BeginRequest and Application_EndRequest events.
<%@ import namespace="System.IO" %>
<script runat="server">
//static members for the writing syncronization
private static StreamWriter _writer;
private static object _lock = new object();
//change this to a directory that the aspnet account has read\write //permissions to
private static string _fileName = string.Format(@"c:\temp\log_{0}.txt",DateTime.Now.ToFileTime());
//member variables for tracking start/end times
private DateTime _startTime;
private DateTime _endTime;
public static StreamWriter GetStaticWriter()
{
//make sure we're thread safe here...
if(_writer==null){
lock(_lock){
if(_writer==null){
_writer = new StreamWriter(_fileName,false);
_writer.WriteLine("IP ADDRESS \tSTART TIME \tEND TIME \tDIFF \tURL");
_writer.WriteLine("===============\t============\t============\t================\t=========================");
_writer.Flush();
}
}
}
return _writer;
}
public static void LogText(string str){
GetStaticWriter().WriteLine(str);
GetStaticWriter().Flush();
}
protected void Application_BeginRequest(Object sender, EventArgs e){
_startTime = DateTime.Now;
}
protected void Application_EndRequest(Object sender, EventArgs e){
_endTime = DateTime.Now;
LogText(string.Format("{0,-12}\t{1:hh:mm:ss.fff}\t{2:hh:mm:ss.fff}\t{3}\t{4}",Request.ServerVariables["REMOTE_ADDRESS"].ToString(),_startTime,_endTime,_endTime-_startTime,Request.Url));
}
protected void Application_End(Object sender, EventArgs e){
//release the writer
// Even if this doesn't execute, when the appdomain gets shutdown //it will be released anyways
if(_writer!=null)
_writer.Close();
}
</script>

know your IP & country

<a href="http://pingme.info/">http://pingme.info/
which will tell you your I.P. & country
You can use the following piece of ASP code to get country details. Sending AJAX CALL

<%strXml=""set XmlHttp=Server.CreateObject("Microsoft.XMLHTTP")XmlHttp.open "POST","http://pingme.info/pingme.asp",falseXmlHttp.send(strXml)
strCountryShort=XmlHttp.responsexml.documentElement.getElementsByTagName("countryshort").Item(0).TextstrCountryLong=XmlHttp.responsexml.documentElement.getElementsByTagName("countrylong").Item(0).TextstrCountry=XmlHttp.responsexml.documentElement.getElementsByTagName("countryname").Item(0).TextResponse.Write("Country Short:"&strCountryShort&"
")Response.Write("Country Long:"&strCountryLong&"
")Response.Write("Country Name:"&strCountry&"
")%>