Boost Performance by Using a CDN in Your ASP.NET Site

A CDN (Content Delivery Network) is simply a network of data centers spread across the globe which serve static content to a user from the nearest available data center. Thus a request for a static file by a user in Australia
would be served from a nearby AsiaPac data center instead of the US (where the main site may to served from). This reduces the latency and therefore boosts performance.

A secondary factor boosting performance is that typically browsers can only open up 2 simultaneous connects to a host, therefore if your web page will require 20 file requests and all static files are on the same server the requests are
queued two at a time. If a CDN is used, the browser can open up more simultaneous file requests and so boost performance.

Which CDN ?

There are numerous CDNs to choose from, personally I use the Rackspace CloudFiles. Rackspace recently partnered with Akamai and so the CDN network is top notch – although the tools are quite weak. It is not possible to FTP a file
to a CDN but the FireUploader utility for Firefox is satisfactory (note that this had some issues with Firefox 4.0 when I tested it and as such I am still using it with Firefox 3.6).

I won’t list all available CDN options as I have not tried that many, but I also had a good experience with MaxCDN, although their pricing structure is quite unusual and so you should carefully examine this to guage your costs.

One thing to note, Amazon’s S3 storage solution is NOT a CDN. All files served from S3 are served from a single location and not from an array of data centers.  Amazon does have a CDN offering – CloudFront, however I would not recommend this as it did not perform well in any of my testing. The Azure CDN offering had a similar performance to the CloudFront product in my experience and so I wouldn’t recommend it.

How to Use a CDN

Using a CDN is very simple, just upload your static files to the CDN and then set the src attribute of the element (such as an <img> tag).

When a file is requested for the first time it will first be served from the central data center and then cached at the edge location (ie worldwide data center nearest to the requesting user). All subsequent requests will be served from the cache of the edge location until the TTL (Time To Live) value has expired. This can be a gotcha if you are updating the files. This typically happens a lot with css files. Therefore if you update your site’s css file, then upload it to your CDN, site users around the worldwide may be served a cached version of the old file. To get around this you can specify version numbers for your css files, in this way each file is unique and when you push an update the CDN will request the new css file from the central store before caching it.
By way of example if you look at the source for this SharePoint article you will see that most of the static files are served from a CDN.

Free SQL Server Backup Script

The SQL Server backup function accessible from SQL Server Management Studio is convenient but crude, the powerful script allows for backing up multiple databases and setting many other parameters such as compression, verification etc. [DatabaseScripts.com].

Including ASP.NET Membership in an Existing Database

By default, when adding ASP.NET Membership to your web app a new ASP.NET Membership database will be created. However, in many circumstances you may wish the Membership database to be part of your  main application database. To do this simply navigate to \Windows\Microsoft.NET\Framework\v2.0.50727 (use this path even if you are using ASP.NET 4.0 in your application as the Membership database has not changed since ASP.NET 2).

Then find and run the aspnet_regsql.exe program. This will bring up a dialog allowing you to specify the target database to incorporate the ASP.NET Membership tables and stored procedures :

ASP.NET Membership database inclusion dialog

The final step is to ensure that the all connection string references to the membership provider in the web.config point to this database. Don’t forget if you are using Roles that the role provider specified in the web.config must also point to this database (otherwise ASP.NET will automatically create a new database for the roles when the app is run).

ASP.NET MVC Authentication using AccountController

The AccountController class is a controller for user authentication which is included in a default MVC project created with Visual Studio. Prior to using this controller, you will need to modify it so that it no longer refers to the HomeController which you most likely will remove. To do this, replace each of these instances:

return RedirectToAction("Index", "Home");

so they are as below:

return RedirectToAction("Index", "Products");

This will cause the authentication controller to redirect a user to the products controller once an authentication action ends. The default ASP.NET MVC master page has links for a  user to log in/out and register. The MVC Authorize filter facilitates control over which users may access the controller methods. Below is an example of the Authorize filter being  applied to the Delete method in the products controller class:

[Authorize]
public ActionResult Delete(int id) {
NorthwindEntities dbObj = new NorthwindEntities();
var data = dbObj.Products.Where(e => e.ProductID == id).Select(e => e).Single();
return View(data);
}

If a user clicks a delete link to delete a record of a product, the MVC framework is then checked. If the user is currently logged in, the action will proceed.. If the user has not logged in they will then be requested to provide their username and password credentials or else to create a new account. This can be made even more restrictive by specifying user names as part of the filter. Below is an example of the Authorize filter applied so the Delete method is only available to Mike Smith:

[Authorize(Users="Mike Smith")]
public ActionResult Delete(int id) {

Now only Mike Smith can perform the delete actions, all other users will be asked for their credentials. The MVC Authorize filter can even be applied to the whole controller class. Below is an example of the Authorize filter being applied to the ProductsController class, so that only authenticated users can access controller actions:

[HandleError(Order=2)]
[Authorize]
public class ProductsController : Controller {

The Authorize filter has an Order property which works just as the HandleError Order property. If the  Authorize filter is applied for the whole controller level and for a specific action method, the controller-wide setting will always have precedence unless the Order property is used.

Sending Mail from a .NET App Using Amazon SES (Simple Email Service)

Amazon’s Simple Email Service (SES) is a great solution for any project which requires bulk emails. the primary advantage of SES is cost, at $0.10 per 1000 emails sent it is between 5-10x cheaper than other alternatives such as SendGrid. There is a downside to the SES service, however and it is that it currently doesn’t provide an SMTP wrapper so whilst SendGrid and others allow you to simple change your SMTP settings, with SES you will have to do a bit more work.

Amazon (AWS) provides a very useful .NET SDK (complete with dll’s for .NET 2.0, 3.5 and 4.0) which you can simply copy into your project and start calling the Amazon functions from a .NET app such as an ASP.NET site. You can download the SDK here.

The below code shows a simple example of how to use the Amazon AWS SDK in .NET to send emails.

Dim listColl As New System.Collections.Generic.List(Of String)
'//TODO - Write a simple loop to add the recipents email addresses to the listColl object.

Dim client As New Amazon.SimpleEmail.AmazonSimpleEmailServiceClient("aws_public_key_here", "aws_private_key_here")

Dim mailObj As New SendEmailRequest
Dim destinationObj As New Destination(listColl)
mailObj.Source = "from@youremail.com"  '//The from email address
mailObj.ReturnPath = "bounce@youremail.com" '//The email address for bounces
mailObj.Destination = destinationObj

'//Create Message
Dim emailSubjectObj As New Amazon.SimpleEmail.Model.Content("This is the Subject")
Dim emailBodyContentObj As New Amazon.SimpleEmail.Model.Content("This is the Body<br /><em>In Html</em>")

Dim emailBodyObj As New Amazon.SimpleEmail.Model.Body()
emailBodyObj.Html = emailBodyContentObj
Dim emailMessageObj As New Message(emailSubjectObj, emailBodyObj)
mailObj.Message = emailMessageObj

Dim response = client.SendEmail(mailObj)

That’s it, there’s really not a lot of heavy lifting to get starting using SES with .NET. the only thing I didn’t show in the code above is the loop for adding email addresses as strings to the generic collection, this loop will vary a lot depending on your exact requirements.
One thing to note above is that you will need to import the namespace Amazon.SimpleEmail.Model

AWS SES is not as full featured as a lot of solutions such as SendGrid, however it does have several useful features out-of-the-box such as the ability to perform email validation:

Dim testEmail As String = "anemail@domain.com"

Dim verRequest As New VerifyEmailAddressRequest()
verRequest.EmailAddress = testEmail
client.VerifyEmailAddress(verRequest)

This should get you going with SES, I will update this page once the service develops.

ASP.NET MVC Error Handling using the HandleError Filter

ASP.NET Errors can be effectively handled using the HandleError filter, which specifies how exceptions which are thrown in a controller method are to be dealt with (note that ASP.NET MVC supports method filters, which allow for annotating controller methods to change their behavior).
Prior to using the HandleError filter, you will need to enable custom error handling for your ASP.NET MVC app in the web.config file by adding the below line in the system.web section:

<customErrors mode="On" />

The below code snippet show the HandleError filter being applied to the controller class. Thus, any exception which is thrown by an action method in the controller will be handled using the custom error policy.

namespace MVCApplicationDemo.Controllers {
[HandleError]
public class ProductController : Controller {

When the HandleError filter is applied without arguments, any exception thrown by the methods covered by the filter will result in the Views/Shared/Error.aspx view being used which just shows the message “Sorry, an error occurred while processing your request.” To test
this process, attempt to view details of a product which does not yet exist, such as with a URL as below:

http://localhost:51823/Product/Details/999990

The error message can be more specific and you may wish to give the user more detailed info. To do this create a view in the Views/Shared folder named NoRecordErr.aspx with the below content:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>
<asp:Content ID="errTitle" ContentPlaceHolderID="TitleContent" runat="server">
Error Occured
</asp:Content>
<asp:Content ID="errContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Sorry, but that record does not yet exist.
</h2>
</asp:Content>

This is a modification of the default error view with a message to show the user that the product request does not yet exist in the database. Next, we can apply the HandleError filter to the Details controller method as in the below snippet:

[HandleError(View="NoRecordErr")]
public ActionResult Details(int id) {

The filter informs the MVC framework that it should use the NoRecordErr view for an exception that is thrown by the Details method. Now, you need to modify the backstop filter to be as show below:

 [HandleError(Order=2)]
public class ProductController : Controller {

An Order value of 2 ensures the controller-wide filter is to be applied only in the event that there is not a HandleError filter with a higher order available. If you do not set a value for Order, the default error view takes precedence.
Now if a user attempts to requests details for a product which does not exist they will be served the new error view. The default error view will be served if other controller methods throw exceptions.

However as it currently stands a user will be informed that they requested a non-existent record for any exception arising from the Details method. Thus you will need to be even more specific.
First, create an exception in the ProductController class which will be used when a record the user has requested is not available:

class NoRecordErr : Exception {
}

The next step is to modify the Details method so that it explicitly checks whether the LINQ query returned a record and if not record was returned throw a new exception.

[HandleError(View="NoRecordErr",
ExceptionType=typeof(NoRecordErr))]
public ActionResult Details(int id) {
NorthwindEntities db = new NorthwindEntities();
var data = db.Products.Where(e => e.ProductID == id).Select(e => e);
if (data.Count() == 0) {
throw new NoRecordErr();
} else {
Product record = data.Single();
return View(record);
}
}

In summery we changed the HandleError filter by including a value for the ExceptionType property, then specifying the type of the exception the filter should to apply to. Now when a NoRecordErr() exception is thrown, the NoRecordErr.aspx view will instead be used. Alternatively, the generic Error.aspx will be used for other exception types (since we applied the controller-wide backstop filter).

Using Sequence in SQL Server 2011 (an Alternative to Identity)

Using the Identity attribute for a column in SQL Server is a very convenient way to auto-increment a field in a row and generate unique ID’s for use as a primary key. SQL Server 2011 introduces Sequence, which is similar in many respects but is offers greater performance and flexibility – read our full tutorial on Using Sequence in SQL Server 2011.

Protect Your ASP.NET App From SQL Parameter Injection

Securing your ASP.NET web app from SQL Injection attacks paramount in the design of any ASP.NET app. Say you are viewing a transaction of customer #448, andyour URL looks something like www.myapplication.com/customer.aspx?customerID=448. What is to stop customer 448 from typing in 449,  and viewing another customer’s transaction details? The situation can even escalate into typing in complete SQL statements and executing them inside the original statements you have coded.  Checking for let’s say a customer sessionID and matching it against the URL and the page will still have to be done by the app developer. This article will demonstrates a simple method of protecting against SQL Injection attacks by checking  for valid parameters in an existing ASP.NET application which can be used in any website. The main idea behind this technique is very simple and includes three components.

The Validation Class
This class contains static methods to check for valid values. For example, if you are expecting a string that is twenty characters long,it can check it for you and notify the application every time itencounters an invalid string on any page. There are several methods implemented in the example code. However, you can add your own and customize them to your needs.

Web.config
This is the file where you keep all of your application keys. So for example, if we would like to check for a customerID and make sure it is an integer, we would add a key named <safeParameters> and set its value to orderID-int32. Now every time our application will encounter an orderID parameter it will automatically check to see if it has a valid integer value.

Global.asax
This file will contain a utility method to match all of our known parameter types to their value. This method will be called isValidParameter. Every time a page is being requested, this method will be executed and will then notify the application if the parameteris valid.

The idea behind these three components working together to prevent SQL Injection attacks  is very simple: prepare all your utility methods to check for valid parameters, define all your valid parameters and check for valid values on each page, take into consideration that if you are using a customerID in twenty pages on your application, they all must be of an integer value. Plugging these components into your application is fairly simple and will ensure that an already   running website will prompt you every time a hacker tries to change a query string regardless of whether your programmers have checked for valid parameters or not. Bear in mind that this is a plug-in, and like all plug-ins it will take its toll on your application performance. A truely secure application will embed any security methods inside the page object only using utility classes to assist. However, if invalid parameters are a problem for you, then this is a good solution.

How to Implement the Example:

Step 1: Add a new utility class and copy and paste the code in parameterCheck.cs into it. Do not forget to change the namespace to fit the needs of the application.

 public class parameterCheck{
public static bool isEmail(string emailString){
return System.Text.RegularExpressions.Regex.IsMatch(emailString,
"['\w_-]+(\.['\w_-]+)*@['\w_-]+(\.['\w_-]+)*\.[a-zA-Z]{2,4}");
}
public static bool isUSZip(string zipString){
return System.Text.RegularExpressions.Regex.IsMatch(zipString ,"^(\d{5}-\d{4})|(\d{5})$");
}
}

Step 2: In the Web.config file, add a key under the <appSettings> tag. This key will contain all of the parameters you wish to check for and the types they need to be. The name of the key is <safeParameters>, and the value can be for example: ordered-int32,customerEmail-email.

<appSettings>
<add key="safeParameters" value="OrderID-int32,CustomerEmail-email,ShippingZipcode-USzip" />
</appSettings>

Step 3: In your Global.asax copy and paste the code in the example into your Application_BeginRequest method.

Continues…