- combine small files. A lot of small files is slower to download than a few large files
- move static resource files such as images, CSS, and JS files off of the ASP.NET servers, and set cache settings on that server. A server tuned for ASP.NET is not especially well-suited to server these files. From the client side, the browser can open two additional concurrent connections to download the static files. Another benefit is that the browser doesn't need to send the cookies to the static files (ASP.NET cookies will be sent to web apps otherwise).
- think twice before breaking services into different server. All those out-of-process calls between the web servers and business object servers create a lot of overhead.
- IP affinity might be easier at the beginning (so that session can be managed in-process), but will create grief in the long run/bigger load. Scenarios: IIS process recyles, some megaproxy (ie AOL) will be bound to a single server etc
- use compression. Yes it costs processor cycles but you typically have plenty of extra CPU capacity on a dedicated web server. IIS7 is even optimized so that when the processor gets really busy, it will suspend compression. Or check http://www.port80software.com/ for 3rd party solutions
- optimizing the HTTP pipeline. There are some HTTP Modules that sit in the ASP.NET request pipeline by default that you may not need. For example, if you don't need session management, and only use FormAuthentication, you can remove Session, WindowsAuthentication, PassportAuthentication and FileAuthorization in httpmodules section.
- reduce or even completely disable the ViewState
- GET is preferred over POST for AJAX calls. GET carries much smaller footprint than POST and POST costs one extra HTTP call than GET.
- Put CSS Files on Top and JS Files at the Bottom. This way, the page would start displaying as soon as the CSS files are downloaded on the client side and won't wait for the JavaScript files which could be loaded in the end once the page is fully loaded and client could interact with it. ScriptManager also has a parameter LoadScriptsBeforeUI which can be used for this purpose
- programmatic caching add complexity but has great benefit too
- scaling database. Move to cluster, partition the tables, use dedicated reader and writer databases (and of course the sync process too)
Monday, January 12, 2009
Strategies to improve ASP.NET web app performance
There are few more things you can do other than adding hardware and caching...
Thursday, December 18, 2008
A tricky side effect of Firefox's "remember password" feature
I think this is worth sharing.
I have a page that allows customer to modify their account password. The password field and 'password again' field are pre-filled with user's password (encrypted). (I know this is not the best practice and they should be left blank - this is a purchased software package).
What happens is that if no change made to the password, the client script that verifies password match always report unmatched password. The HTML source code does show both password fields are the same. But somehow this code
Lesson learned: use different ID for login and password change screen. However the best practice is to leave it blank and not to update it if password is blank.
I have a page that allows customer to modify their account password. The password field and 'password again' field are pre-filled with user's password (encrypted). (I know this is not the best practice and they should be left blank - this is a purchased software package).
What happens is that if no change made to the password, the client script that verifies password match always report unmatched password. The HTML source code does show both password fields are the same. But somehow this code
document.getElementById("password").valuealways gets user's real password, not the encrypted one in the HTML source code. It turns out that it's the Firefox's "Remember Password" feature automatically puts in the remembered password, regardless the specified value in the source.
Lesson learned: use different ID for login and password change screen. However the best practice is to leave it blank and not to update it if password is blank.
Friday, December 12, 2008
Cache with HttpContext.Current.Items
This is a often overlooked yet very powerful cache option. In my BlogEngine multiple user project, multiple components of the page need to resolve blogName/ID, user roles etc. Since each time same user may hit different blog and this user will have different role for each blog, this is a ever-changing value. This per-request cache is a perfect solution.
if (HttpContext.Current.Items["blogName"] != null)
return HttpContext.Current.Items["blogName"].ToString();
else
// parse the blogName
SLOX RecordChanges not working
It's confirmed that "RecordChanges" checkbox on a controls property doesn't always work (SLXDev forum). Today I testified it too:
select * from sysdba.history where datediff( hour, startdate, GetUTCDate()) < 48It only gives me a handful records while there are so many updates. The returned history are all in default SLOX objects. So I guess the custom objects/tables (e.g. Policy etc) have problems. I was thinking to put change logging in database triggers, but a few concerns:
- it may not always have valid ModifyUser value
- to add a new field to be logged is tedious and error-prone
- when we remove a database field, we have to remember to remove it from the trigger
- any unhandeled error will prevent saving.
Redirect any pages in a old site to corresponding pages in new site
This mostly involves moving a site to another hosting company, since we can't simply change the IP address of the new server to be the DNS-registered IP. DNS will be changed to the new IP but it takes hours for it to populate to all ISPs. We can blindly redirect all request to the home page of the new server, but that means no matter what page/querystring user requests, he/she will see the home page. Not very user friendly.
Step 1: register a new sub domain (e.g. new.myblog.com), so that user's ISP will get the brand new IP address.
Step 2: in old server, add a Wildcard application maps to have ASP.NET engine handle all requests (html, gif etc)
Step 3: in global.asax, redirect user in Application_BegineRequest:
Step 1: register a new sub domain (e.g. new.myblog.com), so that user's ISP will get the brand new IP address.
Step 2: in old server, add a Wildcard application maps to have ASP.NET engine handle all requests (html, gif etc)
Step 3: in global.asax, redirect user in Application_BegineRequest:
string url = HttpContext.Current.Request.Url.AbsolutePath;
string QueryParams = HttpContext.Current.Request.QueryString.ToString();
if ( QueryParams != "")
{ Response.Redirect("http://new.myblog.com" + url + "?"+ QueryParams); }
else
{ Response.Redirect("http://new.myblog.com" + url ); }
Tuesday, December 2, 2008
DateTimeEdit Readonly and UTC conversion
If a DateTimeEdit control is set to ReadOnly, user can still modifiy it through the popup date picker and the change WILL be saved. So uncheck "Enabled" is safer.
=============================================
SLOX DB provider has Date and DateTime 2 different data types - even though in SQL server they are all created as DateTime. However SLOX DB provider treats them differently. If it's a DateTime type, it converts it to UTC time and convert back to local time when getting it. However if it's a Date type, when saving the data, SLOX DB provider will always use the local date value and either 1) use current local time as time 2) use 00:00:00. (Among other scenarios, if the editing is done directly in a grid view control, 00:00:00 will be used) When retrieving the data, it doesn't do any conversion - except the Crystal Report, in which case it always try to convert to local time. This is annoying.
Some of the fields should be date only but were created as DateTime type. It created problem when I try to copy that field to another table which I created the field as Date type. The copying was done in SQL so SLOX doesn't get a chance to do the appropriate conversion. The outcome is some dates are displayed one day ealier in UI. I had to do the UTC to local conversion in SQL query to fix it.
However since it always converts to local time regardless of date type in Crystal Report, I would recommend to always use DateTime type.
===========================================
Internally, SLX stores it's schema information in SECTableDefs table. This command will list all fields that has Date type:
The Architech interface does not allow you to change the data type of an existing field. However here is a workaround in database level:
=============================================
SLOX DB provider has Date and DateTime 2 different data types - even though in SQL server they are all created as DateTime. However SLOX DB provider treats them differently. If it's a DateTime type, it converts it to UTC time and convert back to local time when getting it. However if it's a Date type, when saving the data, SLOX DB provider will always use the local date value and either 1) use current local time as time 2) use 00:00:00. (Among other scenarios, if the editing is done directly in a grid view control, 00:00:00 will be used) When retrieving the data, it doesn't do any conversion - except the Crystal Report, in which case it always try to convert to local time. This is annoying.
Some of the fields should be date only but were created as DateTime type. It created problem when I try to copy that field to another table which I created the field as Date type. The copying was done in SQL so SLOX doesn't get a chance to do the appropriate conversion. The outcome is some dates are displayed one day ealier in UI. I had to do the UTC to local conversion in SQL query to fix it.
However since it always converts to local time regardless of date type in Crystal Report, I would recommend to always use DateTime type.
===========================================
Internally, SLX stores it's schema information in SECTableDefs table. This command will list all fields that has Date type:
select * from sysdba.sectabledefs where datetimetype='D''U' in above field indicates a DateTime type.
The Architech interface does not allow you to change the data type of an existing field. However here is a workaround in database level:
- UPDATE sysdba.sectabledefs SET datetimetype='U' WHERE TableName='[my-table]' AND FieldName='[my-field]' AND datetimetype='D' -- this changes the date type
- UPDATE [my-table] SET [my-field] = DateAdd(hour, 8, [my-field]) WHERE DatePart(hour, [my-field]) < 8 -- this fixes the existing data so that it works for conversion.
Monday, November 24, 2008
GetSubDomain
private static string GetSubDomain(Uri url)
{
if (url.HostNameType == UriHostNameType.Dns)
{
string host = url.Host;
if (host.Split('.').Length > 2)
{
int lastIndex = host.LastIndexOf(".");
int index = host.LastIndexOf(".", lastIndex - 1);
return host.Substring(0, index);
}
}
{
if (url.HostNameType == UriHostNameType.Dns)
{
string host = url.Host;
if (host.Split('.').Length > 2)
{
int lastIndex = host.LastIndexOf(".");
int index = host.LastIndexOf(".", lastIndex - 1);
return host.Substring(0, index);
}
}
return null;
}
From: http://www.webpronews.com/expertarticles/2006/11/30/retrieve-subdomain-from-a-url-in-c
Subscribe to:
Posts (Atom)