Friday, February 26, 2010

Caching in ASP.NET

Introduction

I have no clue who first thought of it, but caching is a great idea. You just use a small amount of something fast to make something slow seem much faster then it really is! It's done by motherboards, hard drives, operating systems, and in some form or another by almost everything where speed is important. That's why it was so upsetting that classic ASP had so little support for caching. The web server would do some caching of scripts on it's own, but it was pretty rudimentary and you had very little say in it what got cached and for how long. There are some third party alternatives and some scripts to enable caching in ASP (see the related links below), but they all have their problems. ASP.NET fixes this by including some first-rate caching support built right into the platform.

The Types of Caching in ASP.NET

ASP.NET supports three types of caching:

  • Output Caching: Caches the output from an entire page and returns it for future requests instead of re-executing the requested page.
  • Fragment Caching: Caches just a part of a page which can then be reused even while other parts of the page are being dynamically generated.
  • Data Caching: Programmatically caches arbitrary objects for later reuse without re-incurring the overhead of creating them.

Which type of caching you decide to use obviously depends on your situation, but I'll briefly cover them all so you can make an informed decision.

Output Caching

Output caching is the simplest of the caching options offered by ASP.NET. It is useful when an entire page can be cached as a whole and is analogous to most of the caching solutions that were available under classic ASP. It takes a dynamically generated page and stores the HTML result right before it is sent to the client. Then it reuses this HTML for future requests bypassing the execution of the original code.

Telling ASP.NET to cache a page is extremely simple. You simply add the OutputCache directive to the page you wish to cache.

<%@ OutputCache Duration="30" VaryByParam="none" %>

The resulting caching is similar to the caching done by browsers and proxy servers, but does have one extremely important difference... you can tell a page which parameters to the page will have an effect on the output and the caching engine will cache separate versions based on the parameters you specify. This is done using the VaryByParam attribute of the OutputCache directive. The code listing below illustrates a very simple example of output caching.

 
<%@ Page Language="VB" %>
<%@ OutputCache Duration="30" VaryByParam="test" %>
 

This page was generated at: <%= Now() %>

 

This piece of code will cache the result for 30 seconds. During that time, responses for all requests for the page will be served from the cache. It also specifies that the caching should vary by the parameter "test". As such, the page will cache a different version for each value of "test" that it is passed and will return the appropriate version based on the value of "test" in the incoming requests.

Fragment Caching

Sometimes it's not possible to cache an entire page. For example, many shopping sites like to greet their users by name. It wouldn't look very good if you went to a site and instead of using your name to greet you it used mine! In the past this often meant that caching wasn't a viable option for these pages. ASP.NET handles this by what they call fragment caching.

Honestly, I find this a little misleading... while you can technically cache part of a page, in order to do so you need to make the section to be cached into a user control and set the OutputCache directive in the new user control. Then you use this control from your dynamic page. The solution works well, but in my mind I think of it as caching a separate mini-page and not really a fragment of a page. I guess it's just semantics, but it is a separate file so it can be a little bit of work to implement.

The caching part is very similar to the code above. Aside from making the section a user control and then using the user control (which we covered in our User Controls lesson) it's pretty boring. There's a sample in the zip file, but I'm not including the code here.

Data Caching

This is the most powerful of the caching options available in ASP.NET. Using data caching you can programmatically cache anything you want for as long as you want. The caching system exposes itself in a dictionary type format meaning items are stored in name/value pairs. You cache an item under a certain name and then when you request that name you get the item back. It's similar to an array or even a simple variable.

In addition to just placing an object into the cache you can set all sorts of properties. The object can be set to expire at a fixed time and date, after a period of inactivity, or when a file or other object in the cache is changed.

The main thing to watch out for with data caching is that items you place in the cache are not guaranteed to be there when you want them back. While it does add some work (you always have to check your object exists after you retrieve it), this scavenging really is a good thing. It gives the caching engine the flexibility to dispose of things that aren't being used or dump parts of the cache if the system starts running out of memory.

 
<%@ Page Language="VB" %>
 
 

This page was generated at: 

 
 

Friday, February 19, 2010

SQL injection

Constrain input.
We should validate all input to your ASP.NET applications for type, length, format, and range. By constraining the input used in your data access queries; you can protect your application from SQL injection.

Constrain Input in ASP.NET Web Pages

Constrain Input in Data Access Code

Use parameters with stored procedures.
Using stored procedures does not necessarily prevent SQL injection. The important thing to do is use parameters with stored procedures. If you do not use parameters.

Use parameters with dynamic SQL.
If you cannot use stored procedures, you should still use parameters when constructing dynamic SQL statements. The following code shows how to use SqlParametersCollection with dynamic SQL..

Thursday, February 4, 2010

AutoEventWireup attribute in ASP.NET

AutoEventWireup attribute in ASP.NET

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

The ASP.NET page framework supports an automatic way to associate page events and methods. If the AutoEventWireup attribute of the Page directive is set to true, the page framework calls page events automatically, specifically the Page_Init and Page_Load methods. In that case, no explicit Handles clause or delegate is needed.

  • AutoEventWireup is an attribute in Page directive.
  • AutoEventWireup is a Boolean attribute that indicates whether the ASP.NET pages events are auto-wired.
  • AutoEventWireup will have a value true or false. By default it is true.

There is no event or method associated with Page_Load. Those events whose inline event is not there but that should be executed, for that purposed AutoEventWireup="true".

Disadvantages of AutoEventWireup attribute

  • AutoEventWireup uses fixed naming convention for the events. Page events handlers have specific predictable names. This limits your flexibility in how you name event handlers.
  • If you do set AutoEventWireup to true, Visual Studio will generate code to bind the events and the page framework will automatically call events based on their names. This can result in the same event code being called twice when the page runs. As a consequence, you should always leave AutoEventWireup set to false when working in Visual Studio.
  • Another disadvantage is that performance is adversely affected, because ASP.NET searches for methods at run-time. For a Web site with high traffic volumes, the impact on performance could be significant.

AutoEventWireup="true" target is for page events only. In case of AutoEventWireup method are not case sensitive. (Page_Load or page_load both will work).

If AutoEventWireup="false" but still you want to executed Page event (Page_Load). In this you have to explicitly code for it.

<form id="form1" runat="server" onload="Page_Load">


Conclusion

I hope that this article would have helped you in understanding AutoEventWireup attribute in ASP.NET. Please share it if you know more about this attribute. Your feedback and constructive contributions are welcome.

Tuesday, February 2, 2010

Difference between user defined function and stored procedure

Advantages of User Defined Functions

Before SQL 2000, User Defined Functions (UDFs), were not available. Stored Procedures were often used in their place. When advantages or disadvantages of User Defined Functions are discussed, the comparison is usually to Stored Procedures.

One of the advantages of User Defined Functions over Stored Procedures, is the fact that a UDF can be used in a Select, Where, or Case statement. They also can be used to create joins. In addition, User Defined Functions are simpler to invoke than Stored Procedures from inside another SQL statement.

Disadvantages of User Defined Functions

User Defined Functions cannot be used to modify base table information. The DML statements INSERT, UPDATE, and DELETE cannot be used on base tables. Another disadvantage is that SQL functions that return non-deterministic values are not allowed to be called from inside User Defined Functions. GETDATE is an example of a non-deterministic function. Every time the function is called, a different value is returned. Therefore, GETDATE cannot be called from inside a UDF you create.

Types of User Defined Functions

There are three different types of User Defined Functions. Each type refers to the data being returned by the function. Scalar functions return a single value. In Line Table functions return a single table variable that was created by a select statement. The final UDF is a Multi-statement Table Function. This function returns a table variable whose structure was created by hand, similar to a Create Table statement. It is useful when complex data manipulation inside the function is required.

Scalar UDFs

Our first User Defined Function will accept a date time, and return only the date portion. Scalar functions return a value. From inside Query Analyzer, enter:

CREATE FUNCTION dbo.DateOnly(@InDateTime datetime)
RETURNS varchar(10)
AS
BEGIN
        DECLARE @MyOutput varchar(10)
        SET @MyOutput = CONVERT(varchar(10),@InDateTime,101)
        RETURN @MyOutput
END

To call our function, execute: SELECT dbo.DateOnly(GETDATE())

Notice the User Defined Function must be prefaced with the owner name, DBO in this case. In addition, GETDATE can be used as the input parameter, but could not be used inside the function itself. Other built in SQL functions that cannot be used inside a User Defined Function include: RAND, NEWID, @@CONNCECTIONS, @@TIMETICKS, and @@PACK_SENT. Any built in function that is non-deterministic.

The statement begins by supplying a function name and input parameter list. In this case, a date time value will be passed in. The next line defines the type of data the UDF will return. Between the BEGIN and END block is the statement code. Declaring the output variable was for clarity only. This function should be shortened to:

CREATE FUNCTION testDateOnly(@InDateTime datetime)
RETURNS varchar(10)
AS
BEGIN
        RETURN CONVERT(varchar(10),@InDateTime,101)   
END
Inline Table UDFs

These User Defined Functions return a table variable that was created by a single select statement. Almost like a simply constructed non-updatable view, but having the benefit of accepting input parameters.

This next function looks all the employees in the pubs database that start with a letter that is passed in as a parameter. In Query Analyzer, enter and run:

USE pubs
GO
 
CREATE FUNCTION dbo.LookByFName(@FirstLetter char(1))
RETURNS TABLE
AS
RETURN SELECT *
FROM employee
WHERE LEFT(fname, 1) =  @FirstLetter

To use the new function, enter:

SELECT * FROM dbo.LookByFName('A')

All the rows having a first name starting with A were returned. The return is a Table Variable, not to be confused with a temporary table. Table variables are new in SQL 2000. They are a special data type whose scope is limited to the process that declared it. Table variables are stated to have performance benefits over temporary tables. None of my personal testing has found this result though.

Multi Statement UDFs

Multi Statement User Defined Functions are very similar to Stored Procedures. They both allow complex logic to take place inside the function. There are a number of restrictions unique to functions though. The Multi Statement UDF will always return a table variable–and only one table variable. There is no way to return multiple result sets. In addition, a User Defined Function cannot call a Stored Procedure from inside itself. They also cannot execute dynamic SQL. Remember also, that UDFs cannot use non-deterministic built in functions. So GETDATE and RAND cannot be used. Error handling is restricted. RAISERROR and @@ERROR are invalid from inside User Defined Functions. Like other programming languages, the purpose of a User Defined Function is to create a stand-alone code module to be reused over and over by the global application.

For a Multi Statement test, we will create a modified version of the LookByFName function. This new function will accept the same input parameter. But rather than return a table from a simple select, a specific table will be created, and data in it will be manipulated prior to the return:

CREATE FUNCTION dbo.multi_test(@FirstLetter char(1))
RETURNS @Result TABLE
        (
        fname varchar(20),
        hire_date datetime,
        on_probation char(1)
        )
AS
BEGIN
        INSERT INTO @Result
               (fname, hire_date)
               SELECT fname, hire_date
               FROM employee
               WHERE LEFT(fname, 1) =  @FirstLetter
        
        UPDATE @Result
        SET on_probation = 'N'
        
        UPDATE @Result
        SET on_probation = 'Y'
        WHERE hire_date < '01/01/1991'
        
        RETURN
END

To use the new function, execute:

SELECT * FROM dbo.multi_test('A')

With the new Multi Statement Function, we can manipulate data like a Stored Procedure, but use it in statement areas like a View.

For example, only specific columns can be returned.

SELECT fname FROM dbo.multi_test('A')

The function can also be joined like a view:

SELECT e.lname, f.fname
FROM employee e INNER JOIN dbo.multi_test('A') f ON e.fname = f.fname
 
Conclusion

User Defined Functions offer an excellent way to work with code snippets. The main requirement is that the function be self-contained. Not being able to use non-deterministic built in functions is a problem, but if it can be worked around, UDFs will provide you with a programming plus.