Archive for the ‘How To’ Category

September 24th, 2008

How NOT To Optimize LINQ Statements

About a month ago I was experimenting with different ways to optimize my LINQ queries against the IdeaPipe database, in order to improve the read times. I wanted to improve the read times because our new Facebook Application was being launched and I anticipated an increase in our traffic to the server, which is used to host IdeaPipe and the Facebook Application component.

Whenever I am trying to optimize SQL queries I fire up SQL Server Profiler and take a look at how the queries are performing. This helps me identify queries that are taking a longer time to execute and probably need to be looked at or re-thought. One of the queries that I identified as needing improvement was the following LINQ query:

Old Query

from i in source
join xgl in GroupIdeaLinks on i.IdeaId equals xgl.IdeaId into groupLinksGroup
from gl in groupLinksGroup.DefaultIfEmpty()
let visibility = (gl == null ? 'O' : gl.Group.VisibilityPermission)
let groupId = (gl == null ? -1 : gl.GroupId)
where visibility == 'O' || GroupMembers.Count(m => m.GroupId == groupId && m.IsApproved && m.UserId == userId && (visibility == 'G' || (m.RoleId & (int)Role.Manager) == 0)) == 1
select i;

That produced this monster of a SQL statement:

SELECT [t5].[IdeaId], [t5].[CategoryId], [t5].[UserId], [t5].[IsPopular], [t5].[PopularOn], [t5].[Title], [t5].[SafeDescription], [t5].[Description], [t5].[Path], [t5].[Score], [t5].[Rank], [t5].[ExternalLink], [t5].[VideoLink], [t5].[BumpUpCount], [t5].[BumpDownCount], [t5].[TotalBumpCount], [t5].[TotalCommentCount], [t5].[CreatedOn], [t5].[rowversion]
FROM (
    SELECT [t4].[IdeaId], [t4].[CategoryId], [t4].[UserId], [t4].[IsPopular], [t4].[PopularOn], [t4].[Title], [t4].[SafeDescription], [t4].[Description], [t4].[Path], [t4].[Score], [t4].[Rank], [t4].[ExternalLink], [t4].[VideoLink], [t4].[BumpUpCount], [t4].[BumpDownCount], [t4].[TotalBumpCount], [t4].[TotalCommentCount], [t4].[CreatedOn], [t4].[rowversion], [t4].[value],
        (CASE
            WHEN [t4].[test] IS NULL THEN @p1
            ELSE [t4].[GroupId]
         END) AS [value2]
    FROM (
        SELECT [t0].[IdeaId], [t0].[CategoryId], [t0].[UserId], [t0].[IsPopular], [t0].[PopularOn], [t0].[Title], [t0].[SafeDescription], [t0].[Description], [t0].[Path], [t0].[Score], [t0].[Rank], [t0].[ExternalLink], [t0].[VideoLink], [t0].[BumpUpCount], [t0].[BumpDownCount], [t0].[TotalBumpCount], [t0].[TotalCommentCount], [t0].[CreatedOn], [t0].[rowversion], [t2].[test], [t2].[GroupId],
            (CASE
                WHEN [t2].[test] IS NULL THEN @p0
                ELSE CONVERT(NChar(1),[t3].[VisibilityPermission])
             END) AS [value]
        FROM [Ideas].[Ideas] AS [t0]
        LEFT OUTER JOIN (
            SELECT 1 AS [test], [t1].[GroupId], [t1].[IdeaId]
            FROM [Groups].[GroupIdeaLink] AS [t1]
            ) AS [t2] ON [t0].[IdeaId] = [t2].[IdeaId]
        INNER JOIN [Groups].[Groups] AS [t3] ON [t3].[GroupId] = [t2].[GroupId]
        ) AS [t4]
    ) AS [t5]
WHERE (UNICODE([t5].[value]) = @p2) OR (((
    SELECT COUNT(*)
    FROM (
        SELECT
            (CASE
                WHEN ([t6].[GroupId] = [t5].[value2]) AND ([t6].[IsApproved] = 1) AND (([t6].[UserId]) = @p3) AND ((UNICODE([t5].[value]) = @p4) OR (([t6].[RoleId] & @p5) = @p6)) THEN 1
                WHEN NOT (([t6].[GroupId] = [t5].[value2]) AND ([t6].[IsApproved] = 1) AND (([t6].[UserId]) = @p3) AND ((UNICODE([t5].[value]) = @p4) OR (([t6].[RoleId] & @p5) = @p6))) THEN 0
                ELSE NULL
             END) AS [value]
        FROM [Groups].[GroupMembers] AS [t6]
        ) AS [t7]
    WHERE [t7].[value] = 1
    )) = @p7)

So I started playing around with the LINQ statement until I reduced the size of my SQL query significantly. The following is the result of that optimization:

New Query

var groupMembership = (from gm in GroupMembers
                       let visibility = gm.Group.VisibilityPermission
                       where visibility == 'O' || (gm.IsApproved && gm.UserId == userId && (visibility == 'G' || (gm.RoleId & (int)Role.Manager) == 0))
                       select gm.GroupId).Distinct();

from i in Ideas
join xgl in GroupIdeaLinks on i.IdeaId equals xgl.IdeaId into groupLinksGroup
from gl in groupLinksGroup.DefaultIfEmpty()
where gl == null || groupMembership.Contains(gl.GroupId)
select i;

Which outputs the following SQL query:

SELECT [t0].[IdeaId], [t0].[CategoryId], [t0].[UserId], [t0].[IsPopular], [t0].[PopularOn], [t0].[Title], [t0].[SafeDescription], [t0].[Description], [t0].[Path], [t0].[Score], [t0].[Rank], [t0].[ExternalLink], [t0].[VideoLink], [t0].[BumpUpCount], [t0].[BumpDownCount], [t0].[TotalBumpCount], [t0].[TotalCommentCount], [t0].[CreatedOn], [t0].[rowversion]
FROM [Ideas].[Ideas] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[GroupId], [t1].[IdeaId]
    FROM [Groups].[GroupIdeaLink] AS [t1]
    ) AS [t2] ON [t0].[IdeaId] = [t2].[IdeaId]
WHERE ([t2].[test] IS NULL) OR (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM (
        SELECT DISTINCT [t3].[GroupId]
        FROM [Groups].[GroupMembers] AS [t3]
        INNER JOIN [Groups].[Groups] AS [t4] ON [t4].[GroupId] = [t3].[GroupId]
        WHERE (UNICODE([t4].[VisibilityPermission]) = @p0) OR (([t3].[IsApproved] = 1) AND (([t3].[UserId]) = @p1) AND ((UNICODE([t4].[VisibilityPermission]) = @p2) OR (([t3].[RoleId] & @p3) = @p4)))
        ) AS [t5]
    WHERE [t5].[GroupId] = [t2].[GroupId]
    ))

As you can tell the second query is much more compact and it does the exact same thing as the first query. I was pretty proud of my self and riding high on my genius, until this happened:

Well this didn’t really happen, but you get the point. I quickly came down from my high when I tested the performance of the new query in SQL Server Profiler, and received these results from the two queries:

  • OLD QUERY (Reads 130, Durration 5)
  • NEW QUERY (Reads 218, Durration 28)

That is right my optimization increased the number of times SQL has to read the table by 68% and time it takes to execute by 460%. So I reversed all my changes and learned a lesson on how not to optimize a LINQ statement.

The moral of the story is you probably don’t need to optimize your SQL query through LINQ, just keep it simple and optimize your LINQ statement and leave the rest up to the professionals at Microsoft who created the LINQ to SQL expression query generator.

Tags: , , ,

Posted in C#, How To, SQL | kick it on DotNetKicks.com | Bookmark | View blog reactions | 7 Comments »

August 25th, 2008

Deadlocked!: “read committed snapshot” Explained

I just recently read Jeff Atwood’s Deadlocked! article. I just wanted to give some more insight in to the read committed snapshot so that it is not perceived as “magic”. It has some definite advantages when dealing with deadlocks, however if your code relies on row level locking you are not going to be able to use this type of reading in SQL Server.

First lets talk about how you enable it. It is not a transactional isolation level, so if you set it, it will effect your whole database. You have been warned!

alter database [YourDatebaseHere]
set read_committed_snapshot on
go

Basically what this does is create a snapshot or read-only database of your current results that is separate from your live database. So when you run a SELECT statement, to read your data, you are reading from a read-only copy of your database. When you change your database, it happens on the live database, and then a new copy or snapshot is created for reading against.

Personally I am using it on IdeaPipe, because like most Web 2.0 applications there are a heavy amount of reads and very few updates that effect the row. So chances are if you have a website this will decrease your number of deadlocks. But make sure to test thoroughly before implementing read committed snapshot.

When I was doing my initial research a while ago I found this article talking about how snapshot isolation can bite you where it hurts.

For example, suppose READ COMMITTED SNAPSHOT is not enabled in the database and you want to assign one more ticket to a person, but only if that user does not already have high priority tickets:

BEGIN TRANSACTION
UPDATE Tickets SET AssignedTo = 6 WHERE TicketId = 1
AND NOT EXISTS(SELECT 1 FROM Tickets WHERE AssignedTo = 6 AND Priority='High')
--- do not commit yet

Note that you have not explicitly specified an isolation level, so your transaction runs under the default READ COMMITTED level. If another connection issues a similar update:

UPDATE Tickets SET AssignedTo = 6 WHERE TicketId = 2
AND NOT EXISTS(SELECT 1 FROM Tickets WHERE AssignedTo = 6 AND Priority='High')

it will hang in a lock waiting state. Once you commit your first transaction the second one will complete, but it will not assign ticket 2 to user 6, which is the correct behavior as designed.

However if read committed snapshot is enabled on the database the user will end up with two high priority tickets, because the first read happens against a snapshot and the update happens against the live database. So this will obviously cause problems for specifications and business rules that rely on row level locking. So be careful, and make sure you specifically know what is happening with your code before turning this on

Note: Chances are if you are using LINQ you don’t have to worry about the above scenario, however I am not a DBA expert, only a student of the practice. So take what I say with a grain of salt.

Tags: , , ,

Posted in How To | kick it on DotNetKicks.com | Bookmark | View blog reactions | 1 Comment »

June 24th, 2008

MVC CAPTCHA for Preview Release 3

Since my last release of the MVC toolkit some major changes have taken place in the MVC Framework. I am going to do a quick run through of how they changed the MVC CAPTCHA for the better.

Originally in MVC Preview Release 1 for the MVC CAPTCHA many of you remember that the indicator for a valid CAPTCHA was passed through the parameters of the action method like so:

[ControllerAction]
[CaptchaValidation("captcha")]
public void Register(bool captchaValid, string otherParameters)
{
    // do stuff
}

However when Preview Release 2 came out the ability to pass the parameter through the action method was broken. So I had to create a hack around this:

[CaptchaValidation("captcha")]
public void Register(string otherParameters)
{
    bool captchaValid = (bool)RouteData.Values["captchaValid"];
    // do stuff
}

Apparently without realizing it in Preview Release 1, I had discovered a major feature that everybody that I explained it to saw great potential in. So I submitted a feature request and waited for the ASP.NET Team to get back to me. With the release of Preview Release 3, they finally answered my prayers and added the parameter injection feature back in to the framework.

So now this code works again in the Preview Release 3 version of the MVC CAPTCHA control.

[CaptchaValidation("captcha")]
public void Register(bool captchaValid, string otherParameters)
{
    // do stuff
}

This works because of a new property called ActionParameterson the ActionExecutingContext. It can be used to test and change any of the action methods parameters before the action method has been executed. For the purpose of the MVC CAPTCHA control it allows me to inject a true or false value in to a parameter called captchaValid, so that the action method knows that the CAPTCHA validation passed or failed.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
	// make sure no values are getting sent in from the outside
	if (filterContext.ActionParameters.ContainsKey("captchaValid"))
		filterContext.ActionParameters["captchaValid"] = null;

	// get the guid from the post back
	string guid = filterContext.HttpContext.Request.Form["captcha-guid"];

	// check for the guid because it is required from the rest of the opperation
	if (String.IsNullOrEmpty(guid))
	{
		filterContext.RouteData.Values.Add("captchaValid", false);
		return;
	}

	// get values
	CaptchaImage image = CaptchaImage.GetCachedCaptcha(guid);
	string actualValue = filterContext.HttpContext.Request.Form[Field];
	string expectedValue = image == null ? String.Empty : image.Text;

	// removes the captch from cache so it cannot be used again
	filterContext.HttpContext.Cache.Remove(guid);

	// validate the captch
	filterContext.ActionParameters["captchaValid"] =
		!String.IsNullOrEmpty(actualValue)
		&& !String.IsNullOrEmpty(expectedValue)
		&& String.Equals(actualValue, expectedValue, StringComparison.OrdinalIgnoreCase);
}

Notice in the code above all the filterContext.ActionParameters references, that is the CAPTCHA validation checking for the parameter in the method parameters list and adding the value of the CATPCHA validation to the list. Note that in order for this to work you must already have the captchaValid attribute present in your method, these actions merely fill in the value of the captchaValid placeholder.

For anybody who hasn’t used my MVC CAPTCHA control before, you only need to do two things:

1. You need to register the CAPTCHA image handler.

<httpHandlers>
    <add verb="GET" path="captcha.ashx" validate="false" type="ManagedFusion.Web.Handlers.CaptchaImageHandler, ManagedFusion" />
</httpHandlers>

2. Add the following to the View that you want the CAPTCHA to show in. Note the extension, CaptchaTextBox in HtmlHelper, generates a text box with autocomplete=”off” so that the CAPTCHA box will not have an auto-complete show up.

<label for="captcha">Enter <%= Html.CaptchaImage(50, 180) %> Below</label><br />
<%= Html.CaptchaTextBox("captcha") %>

Which generates the following.

Example of CAPTCHA

If you would like to download the latest copy of the MVC CAPTCHA it is available in my MVC Toolkit.

Download: Coder Journal MVC Toolkit
Source: Coder Journal MVC Toolkit

Tags: , ,

Posted in ASP.NET, C#, How To | kick it on DotNetKicks.com | Bookmark | View blog reactions | 10 Comments »

June 12th, 2008

Turn Google App Engine into your own Personal Content Delivery Network (CDN)

As anybody who has run a growing website or blog knows, response time is going to get worse with the more users you have visiting your site. The users come from all angles, RSS feeds, homepage visits, search engine visits, people sealing your static files that you host, and pretty much anything else that can be served over HTTP. The solution to this problem is to off load your static content on to a Content Delivery Network or CDN. CDN providers cost a lot of money though, so it is nothing for us mere mortals with one server can afford.

But thanks to Google anyone can now run their own CDN for free on Googles servers. Lucky for you and me Google has made the process really painless and you can even have the CDN under you own domain name. In my case static.coderjournal.com.

What Is A Content Delivery Network?

According to Wikipedia:

A content delivery network or content distribution network (CDN) is a system of computers networked together across the Internet that cooperate transparently to deliver content most often for the purpose of improving performance, scalability, and cost efficiency, to end users. The first web content based CDNs were Speedera, Sandpiper, Mirror Image and Skycache, followed by Akamai and Digital Island.

Basically it is a network of computers around the world that serves your content to the end user closest to one of those many servers around the world. This method of delivery cuts down on server overload, DNS hops, and delivery time.

When sites like Microsoft, Yahoo, Google, or Amazon delivery content they use Content Delivery Networks (CDN’s) to host most of their content, especially static files such as images, stylesheets, downloads and anything else you can think of. The reason they do this is to reduce load on their application servers, that serve dynamic content, such as PHP or ASP.NET pages.

What Is Google App Engine?

So you may ask what is Google App Engine:

Google App Engine lets you run your web applications on Google’s infrastructure. App Engine applications are easy to build, easy to maintain, and easy to scale as your traffic and data storage needs grow. With App Engine, there are no servers to maintain: You just upload your application, and it’s ready to serve your users.

You can serve your app using a free domain name on the appspot.com domain, or use Google Apps to serve it from your own domain. You can share your application with the world, or limit access to members of your organization.

App Engine costs nothing to get started. Sign up for a free account, and you can develop and publish your application for the world to see, at no charge and with no obligation. A free account can use up to 500MB of persistent storage and enough CPU and bandwidth for about 5 million page views a month.

Google has also announced a very very affordable price plan that any mere mortal can afford. They are not ready to start charging people yet, but here are the details:

  • $0.10 - $0.12 per CPU core-hour
  • $0.15 - $0.18 per GB-month of storage
  • $0.11 - $0.13 per GB outgoing bandwidth
  • $0.09 - $0.11 per GB incoming bandwidth

How do I setup my own CDN using Google App Engine?

To use Google App Engine you need to do a couple things that readies you computer to publish your static content to Google. Please take note that my setup is for Windows, but you can easily modify the process for any other OS.

Setup

  1. You need to download and install Python on your computer. You may already have it if you are using a Unix environment (i.e. Linux or Mac OS X). If you need to download it or would just like to check to see if it is up to date, please visit http://www.python.org/download/ and download the correct version for you operating system.
  2. Install Python to c:\Program Files\ (all my scripts that I have designed to make the publishing to Google are going to be using this path).
  3. You will also need Google App Engine SDK which is available at http://code.google.com/appengine/downloads.html. Download the version that is for you OS. Note that the SDK will check for the Python install, so make sure you install it before the SDK.
  4. Sign up for Google App Engine at http://appengine.google.com/, you will need a valid Google account. I suggest you sign up for a Google Apps account and use that as your Google account. Why I suggest this will become apparent later on.
  5. Once you are done with the setup process you need to create an application. Click the “Create an Application” and give your application a name (called “application identifier”). This is a unique name for all Google App Engine applications. For example I set my application identifier to “coderjournal”. Click though to the next part of the application, if this is your first time registering an application you need to specify your cell phone number and confirm your account with a SMS code that Google sends you.

Publish To Your CDN

  1. Download my publishing files, hosted on my CDN, at http://static.coderjournal.com/downloads/coderjournal-cdn.zip
  2. Create a directory on your computer specifically for you CDN files. My directory is c:\websites\static.coderjournal.com. Fill this directory with all your static files you want hosted on your CDN. Fill it full of all your css, downloads, flash, images, javascripts, videos, and anything else you want hosted.
  3. Unzip the files I provided to you in step 1 into the directory you created in step 2.
  4. Next we need to edit the YAML configuration file. Open the app.yaml file in your favorite text editor and change application: coderjournal to application: {your application identifier}.
  5. Next go down and edit your static directories, in mine I have css, downloads, flash, images, and js. You can create your own by just modifying the ones I put in the file.
  6. If you installed the Google App Engine SDK in the default directory and Python in c:\Program Files\ then skip to step 7. The next part is also required if you are using the x64 version of Windows, because Google App Engine SDK installs in c:\Program Files (x86)\. So change the paths in publish-cdn-coderjournal.bat to your actual paths.
  7. Now double click on publish-cdn-coderjournal.bat and a command window will display. Fill in your Google account and password that you used to sign up for the Google App Engine account. And you content will start to publish.
  8. You now have you own private CDN that can be accessed at http://application-identifier.appspot.com.

Using Your Own Domain (Optional)

  1. If you created your own Google App as suggested up in Setup step 4, you can create your own custom domain for your CDN. If you didn’t, don’t worry just create one, and follow the steps below.
  2. Go to the dashboard of your Google Apps and click “Add more services”.
  3. Under other services you will see Google App Engine and a place to enter your application identifier. Enter you application identifier and click “Add It Now”.
  4. It will take you to the next page where you enter in the domain you want for your CDN, I suggest something simple like static.yoursite.com.
  5. Then you just need to follow the steps for adding a CNAME to your DNS and you are ready to go with you custom domain.

IdeaPipe Logo

How do I use my own CDN?

Well this is the cool part! You just use the absolute path to your files. For example if you wanted to host the image to your right you would just use the following in your HTML:

Potential Gotcha: I forgot to mention that currently the files hosted statically are case-sensitive. I have reported this issue to Google, hopefully they will correct it soon. http://code.google.com/p/googleappengine/issues/detail?id=466

<img src="http://static.coderjournal.com/images/ideapipe-logo.png" />

It is really that simple. Now comes the cool part that I need your help with, and proof that this is really a true CDN. I would like to see how many different IP Addresses my CDN points to. So far I was able to find the following IP addresses:

  1. 72.14.207.121
  2. 64.233.179.121
  3. 66.249.91.121

That point to:

static.coderjournal.com

To see what IP Address you get on your local machine just pull up the command prompt and type:

ping static.coderjournal.com

Please report your findings in the comments below. I am sure everybody would love to see how big Google’s CDN really is.

Tags: , , ,

Posted in ASP.NET, How To, JavaScript, Programming, SEO | kick it on DotNetKicks.com | Bookmark | View blog reactions | 34 Comments »

June 6th, 2008

MVC + Facebook == Wonderful Development Platform

Just recently I started experimenting with the ASP.NET MVC Framework and the Facebook Development Platform, it has been a very bumpy road, but I have ironed out some major issues that I would like to share with you today. I will start with a little history of what I am trying to do. For about a month and a half I have had one of my IdeaPipe interns, Dimitry, experimenting with creating a FBML (Facebook Meta Language) Application with MVC. MVC is an ideal platform for FBML because with MVC you have total control over your markup which is needed to have a lean FBML application. I am not going to go in to the differences of developing an FBML vs IFrame Facebook Application, because that information is easily found with a Google Search. What I am going to talk about is the hurdles I overcame and the custom software I had to develop to get MVC working smoothly with Facebook.

In my last post on the subject I was using the Facebook Developer Toolkit, however because of various implementation problems that were at the foundation of the software when working with MVC, I moved to Facebook.NET which is a object based model for implementing the Facebook Session instead of an inheritance model. What you will need in order to get started is:

One of the problems I ran into was creating a Facebook Session from my Action Method. To remedy this issue I created a FacebookAttribute that is an ActionFilterAttribute and a FacebookWebSession based off of the work done on Facebook.NET.

FacebookAttribute

The FacebookAttribute is added to your Action Methods and will look like the following:

[Facebook(ApplicationName = "IdeaPipe")]
public ActionResult SomeAction(FacebookService facebookService, FacebookSession facebookSession, int myOtherVariables)
{ ... }

As you can see the FacebookAttribute just attaches to the Action Method and you just have to specify your ApplicationName that you want to instantiate. The FacebookAttribute also passes in a FacebookService and FacebookSession object for use in your method. The other keys get set in your Web.Config as any standard Facebook.NET application would.

<facebook>
    <application name="IdeaPipe" apiKey="1234" secret="5678" type="GlobalApplication" />
</facebook>

The magic behind this attribute is pretty simple.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
	FacebookApplicationSettings settings = FacebookSection.GetApplication(ApplicationName);

	ApplicationKey = ApplicationKey ?? settings.ApiKey;
	Secret = Secret ?? settings.Secret;

	FacebookWebSession session = new FacebookWebSession(ApplicationKey, Secret);
	session.Initialize(HttpContext.Current);

	FacebookService service = new FacebookService(session);

	if (filterContext.ActionParameters.ContainsKey(ActionParameterFacebookSession))
		filterContext.ActionParameters[ActionParameterFacebookSession] = session;

	if (filterContext.ActionParameters.ContainsKey(ActionParameterFacebookService))
		filterContext.ActionParameters[ActionParameterFacebookService] = service;
}

Download: FacebookAttribute.cs

FacebookWebSession

The FacebookWebSession was developed out of necessity because the only other FacebookSession objects in Facebook.NET are strongly tied to a WebForms Control that couldn’t be created as easily as I did in the FacebookAttribute. I am going to fore go the source code since much of this is a copy, paste, and rearrange from the Facebook.NET source. Plus much of it is just boring if-then-else statements that go on for awhile and just do a technical setup from the query string fields.

Download: FacebookWebSession.cs

FacebookSection

This is the file that I had to change the one method from internal to public so that I could get the information contained in the Web.Config configuration for my application. Note this file will not be necessary in the future if my changes get accepted in to the Facebook.NET source tree.

This file replaces the \Web\Configuration\FacebookSection.cs of the Facebook.NET source.

Download: FacebookSection.cs
Download: Facebook.NET Binaries For MVC

So that is all that you should need in order to start working with Facebook Applications in MVC. Note that it is still a good idea to include the FacebookApplication control on your pages because it is still needed. The primary goal of the source code above was to allow the use the the FacebookSession in the Action methods. If you have any questions please post them below.

Tags: , ,

Posted in ASP.NET, C#, How To, Programming | kick it on DotNetKicks.com | Bookmark | View blog reactions | 6 Comments »

May 23rd, 2008

How to create a non-Native jQuery event

Today I had the need to create a custom event using jQuery, in order to launch a customized form validation event from a global submit event. I did this so I could focus in on the first form field that had an error. My event from the global.js script, that is included on every page of IdeaPipe, looks like this:

$("form").submit(function () {
	var valid = $(this).validate();

	// if the form didn't validate then focus the input on the first error
	if (!valid)
		$(this).find(":input[error]:first").focus();

	return valid;
});

This is pretty standard jQuery. What this code above does is set a custom function for the submit event for any <form /> tag on the page. The submit event will only be allowed to continue if a return value of true is returned from the function.

I was able to create this custom jQuery event with the following code:

jQuery.fn.extend({
	validate: function (fn) {
		if (fn) {
			return jQuery.event.add(this[0], "validate", fn, null);
		} else {
			var ret = jQuery.event.trigger("validate", null, this[0], false, null);

			// if there was no return value then the even validated correctly
			if (ret === undefined)
				ret = true;

			return ret;
		}
	}
});

There are two different states to this method. Primarily because in JavaScript all parameters are optional for functions. So the two states of this function are:

  • validate(fn) - sets the event
  • validate() - fires the event

An example of setting the event is:

$("form.user-login").validate(function () {
	var userNameValid = ValidateLoginUserName();
	var passwordValid = ValidateLoginPassword();

	return userNameValid && passwordValid;
});

In this example the form is valid if both the login user name and password validate.

An example of using the event is the same as the method above.

$("form").submit(function () {
	var valid = $(this).validate();
	// do some stuff
	return valid;
});

This may not be the standard bind() and trigger() that most jQuery programmers are use to, but I needed an event that would return a value of true or false, so that I my submit event handler knows if it should focus on errors or continue the submit process.

Hope everybody finds this useful.

Tags: , ,

Posted in How To, JavaScript | kick it on DotNetKicks.com | Bookmark | View blog reactions | 1 Comment »

May 18th, 2008

How to create a YUI Compressor MSBuild Task

Recently for IdeaPipe I have been looking for ways to deliver my content more quickly and reduce unnecessary bandwidth use.

According to Yahoo’s Performance Team more than half of the viewers of the Yahoo websites start with an empty cache, which means the browser has to download all the resources for the first time. This combined with a high traffic website and unneeded white space and comments can really add up to a significant bandwidth use. There are many popular ways to minify your static content tax on your bandwidth, using many popular tools, as described in this excerpt from Yahoo:

In terms of code minification, the most widely used tools to minify JavaScript code are Douglas Crockford’s JSMIN, the Dojo compressor and Dean Edwards’ Packer. Each of these tools, however, has drawbacks. JSMIN, for example, does not yield optimal savings (due to its simple algorithm, it must leave many line feed characters in the code in order not to introduce any new bugs).

The goal of JavaScript and CSS minification is always to preserve the operational qualities of the code while reducing its overall byte footprint (both in raw terms and after gzipping, as most JavaScript and CSS served from production web servers is gzipped as part of the HTTP protocol).

The cream of the crop seems to be a tool Yahoo developed to deliver its own static text content scripts and styles, the YUI Compressor:

The YUI Compressor is JavaScript minifier designed to be 100% safe and yield a higher compression ratio than most other tools. Tests on the YUI Library have shown savings of over 20% compared to JSMin (becoming 10% after HTTP compression). Starting with version 2.0, the YUI Compressor is also able to compress CSS files by using a port of Isaac Schlueter’s regular-expression-based CSS minifier.

The YUI Compressor is a Java JAR file that can be download from Julien Lecomte Blog.

The YUI Compressor yielded exceptional results, however it was missing one thing. Integration in to my build and deployment process. In IdeaPipe I use a MSBuild script to compile, manipulate, and prepare for publishing. So naturally I built a MSBuild Task to minimize my JavaScript and CSS files.

The magic actually happens by invoking Java in an external process for each file passed in to the task.

Process process = new Process();
process.StartInfo = new ProcessStartInfo {
	FileName = @"c:\program files\java\jdk1.6.0_06\bin\java.exe",
	Arguments = String.Format(
		@"-jar ""C:\development\tools\yuicompressor-2.3.5.jar"" --type {0} --charset utf8 {1} -o ""{2}"" ""{3}""",
		type,
		ShowWarnings ? "--verbose" : String.Empty,
		newFile,
		oldFile
		),
	UseShellExecute = false,
	CreateNoWindow = true,
	RedirectStandardOutput = true,
	RedirectStandardError = true
};
process.Start();
process.WaitForExit(5000);

Then I read the warning from the standard error output and send them back to Visual Studio as a compile warning if the ShowWarning property is true.

string[] warnings = process.StandardError.ReadToEnd()
	.Replace("\r", String.Empty)
	.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries);

foreach(string warning in warnings)
	Log.LogWarning(null, null, null, oldFile, 1, 1, 1, 1, FormatWarning(warning), null);

To integrate this in to my MSBuild script I had to first register my task:

<UsingTask TaskName="ManagedFusion.Build.YuiCompress" AssemblyFile="$(ProjectDir)..\ManagedFusion.Build\bin\$(ConfigurationName)\ManagedFusion.Build.dll"/>

Then setup my ItemGroup for the files:

<ItemGroup>
	<JavaScriptContent Include="$(SourceWebPhysicalPath)\**\*.js" />
	<CssContent Include="$(SourceWebPhysicalPath)\**\*.css" />
</ItemGroup>

Then finally I setup my task to perform the minimization against the JavaScript and CSS files seperately:

<Target Name="AfterBuild">
	<!-- do other stuff to prepare for publishing -->
	<YuiCompress Files="@(JavaScriptContent)" Type="JS" />
	<YuiCompress Files="@(CssContent)" Type="CSS" />
</Target>

You can easily incorporate this in to your own MSBuild scripts or even your Visual Studio Project which is just an MSBuild file for compiling your source code for the project. I have included my source code below:

Download: YUI Compressor MSBuild Task Source

Note: There are a couple of static paths to be on the look out for and modify as necessary for your own code. In my code the Java runtime is loaded at c:\program files\java\jdk1.6.0_06\bin\java.exe and the YUI JAR is located at C:\development\tools\yuicompressor-2.3.5.jar.

Update (2008-5-21): Thanks George, apparently IIS doesn’t like serving straight C# files. So I added the code to my Coder Journal Source Control, so that it can be downloaded from there.

Tags: , , , , ,

Posted in ASP.NET, How To, Programming | kick it on DotNetKicks.com | Bookmark | View blog reactions | 15 Comments »

April 14th, 2008

Adding DotNetKicks To FeedBurner FeedFlare

If you are using FeedBurner to manage your feed, and you love DotNetKicks as much as I do, you can now easily add a “Kick It” FeedFlare to it. This will automatically add a “Kick It” link below each post in your FeedBurner feed.

To get started you will need to do the following:

  1. Login To FeedBurner
  2. Go to FeedBurner > Optimize > FeedFlare
  3. Go down to the Personal Flare box.
  4. Copy it and paste this URL in to the box:
    http://www.coderjournal.com/uploads/2008/04/dotnetkicks-feedflare-link.xml
  5. Press “Add New Flare”.
  6. Then check the two checkboxes next to the new entry.
  7. Click “Save” at the bottom of the page.

After all the steps above are completed you should have a FeedFlare example that looks somewhat like this:

Notice the “Kick It” flare link on the left.

Tags: , , ,

Posted in How To | kick it on DotNetKicks.com | Bookmark | View blog reactions | 1 Comment »

April 9th, 2008

Getting IIS 7 to Compress JavaScript

One of the many recommendations that Yahoo makes on optimizing your web site for high amounts of traffic, and to make the response time speedier to your user is GZip encoding all your static content. I usually do this as a standard for setting up any of my Web Servers, in addition to setting expiration headers on my static content, to ensure that I am serving as little content as possible.

IIS 7 has improved and simplified the compression and serving of static files by making it easier to setup and configure than previously in IIS 6.0. The IIS 7.0 compression works perfectly for CSS, HTML, and Text files, however JavaScript is another story. The JavaScript files on my IIS 7.0 server were not being compressed and served with GZip encoding, which is a major problem for any Web 2.0 site where 75% of your content severed per request is JavaScript. (I just made that number up, but it sounds right!)

I found Rick Strahl’s post on this very subject that he wrote up about a 9 months ago. It was helpful in diagnosing my problem, however it didn’t solve it. The HTTP compression is configured in IIS 7.0’s ApplicationHost.config file (c:\windows\system32\inetsrv\config\applicationhost.config), see below for the default settings:

<httpCompression directory="%SystemDrive%\websites\_compressed" minFileSizeForComp="0">
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
    <staticTypes>
        <add mimeType="text/*" enabled="true" />
        <add mimeType="message/*" enabled="true" />
        <add mimeType="application/javascript" enabled="true" />
        <add mimeType="*/*" enabled="false" />
    </staticTypes>
</httpCompression>

As you can see anything that starts with the MIME type of text or message is GZip encoded just fine. However there is also application/javascript as a compressible MIME type, there is nothing wrong with that, because there are 3 accepted ways to set a JavaScript MIME type.

  1. text/javascript
  2. application/x-javascript
  3. application/javascript

However the problem comes in when you look at the default MIME type mappings setup, in the same ApplicationHost.config file, a little further down.

...
    <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
    <mimeMap fileExtension=".js" mimeType="application/x-javascript" />
    <mimeMap fileExtension=".jsx" mimeType="text/jscript" /
...

As you may notice the MIME type for JavaScript files is set to application/x-javascript, which is not the same as the default in the compression section above. So I added the following MIME type, application/javascript, to my Web.config thinking I had the problem licked, and all that I had to do was change the default MIME type for JavaScript files.

<system.webServer>
    <staticContent>
        <remove fileExtension=".js" />
        <mimeMap fileExtension=".js" mimeType="application/javascript" />
    </staticContent>
</system.webServer>

However that didn’t work either, and it should have because the MIME type now matched my compression MIME type. I even verified the MIME type in fiddler. So I then tried my last option to change the MIME type to text/javascript, which is the defacto standard on the internet for JavaScript MIME types.

<system.webServer>
    <staticContent>
        <remove fileExtension=".js" />
        <mimeMap fileExtension=".js" mimeType="text/javascript" />
    </staticContent>
</system.webServer>

Finally, this was the key to getting the JavaScript GZip Compression working IIS 7.0. And this didn’t require me to modify the ApplicationHost.config file get it done. Which is something I love about the new IIS 7.0, I can do my whole server configuration through FTP and my Web.config file.

Tags: , , , ,

Posted in How To | kick it on DotNetKicks.com | Bookmark | View blog reactions | 5 Comments »

March 13th, 2008

ASP.NET MVC: Securing Your Controller Actions (The .NET Framework Way)

So I just read Rob Conery’s blog post on Securing Your Controller Actions in MVC. I was a little perplexed about why guys at Microsoft love to reinvent stuff they have already done. I know Rob Conery is a really smart guy and has a wonderful grasp of the .NET framework, so I would have to assume he knows about what I have outlined below. My only guess is that he just wanted to re-invent something that is already built in to the framework using his own code.

Basically what Rob did was the following, created two attributes for attaching on the MVC Controller Action:

RequiresAuthenticationAttribute

[RequiresAuthentication]public void Index () {
    RenderView("Index");
}

RequiresRoleAttribute

[RequiresRole(RoleToCheckFor = "Member")]public void Index () {
    RenderView("Index");
}

I have accomplished the same thing using an attribute that has been apart of .NET since 1.0. The attribute is called PrincipalPermissionAttribute and is part of the System.Security.Permission namespace. The best thing about it is that it is integrated in to the run time, so there is no chance of unwanted people getting through. It also accomplishes both of Robs attributes up above, plus more. Using the examples up above I will demonstrate how to use PrincipalPermissionAttribute to secure and protect your Controller Actions.

RequiresAuthenticationAttribute

[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]public void Index () {
    RenderView("Index");
}

RequiresRoleAttribute

[PrincipalPermission(SecurityAction.Demand, Role = "Member")]public void Index () {
    RenderView("Index");
}

In addition if you were inclined you can restrict things to just one user name with PrincipalPermissionAttribute. So for instance if you wanted to restrict adding and removing roles and their permissions to only the username “SiteAdmin”, you would do the following.

[PrincipalPermission(SecurityAction.Demand, Name = "SiteAdmin")]public void RolesAdmin () {
    RenderView("RolesAdmin");
}

As you can see this is very powerful. Built in to the run time, by extending the CodeAccessSecurityAttribute, so it operates at a lower level than Rob’s solution. Only requires the use of one attribute, and throws only one exception called SecurityException.

I really hope that ASP.NET MVC doesn’t turn in to a lets-redo-everything-that-already-works framework, because they still have many issues that they need to achieve before ASP.NET MVC is usable, and focusing on things that are already implemented in the .NET framework doesn’t seem like the right course of action when developing a new offering.

Read the rest of this entry »

Tags: , , , , , ,

Posted in ASP.NET, C#, How To, Programming, Rant | kick it on DotNetKicks.com | Bookmark | View blog reactions | 12 Comments »