Saturday, April 14, 2007

Summary:

This one is not short. Better sit down.

I am going to discuss a common problem with web controls that are heavy on client-side javascript code and AJAX requests, and suggest a solution I came up with.

Right.

An Example Control

We'll be working with a sample control. Our control will be a stock ticker control that presents a current price for a stock and periodically gets price updates from the server.

Here's an example of such a thing, taken from Yahoo! Finance:

Stock Ticker from Yahoo! Finance

You can see, that it displays the current stock price, a change in percent from some base price (opening price) and an arrow indicating the change trend.

It also highlights in green values that were recently changed (like the google stock in the screenshot).

(The coding examples are pretty sloppy. It's just an example, remember.)

The basic implementation allows setting the ticker to be displayed and renders a simple HTML table:

public class StockTicker : WebControl

{

public string Ticker

{

get

{

String s = (String)ViewState["Ticker"];

return ((s == null) ? String.Empty : s);

}

set

{

ViewState["Ticker"] = value;

}

}

Code Snippet

private int GetStockValue()

{

Random r = new Random();

return r.Next(1, 100);

}

}

We have a method GetStockValue that returns the current stock price. In our sample implementation it just returns a random value between 1 and 100. In real life it will probably access a database or use a webservice.

Lets test the control by placing it on a web form and running the application:

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

<%@ Register Assembly="SampleApp01" Namespace="SampleApp01" TagPrefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

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

<div>

<cc1:StockTicker ID="StockTicker1" runat="server" Ticker="CSCO" />

</div>

</form>

</body>

</html>

We get a result similar to this:

First Version of Ticker Control

Adding Dynamic AJAX Updates

Now, lets add to our control the ability to receive dynamic price updates from the server using AJAX requests.

I will use the Prototype javascript library to simplify some client-side code.

Let's add a javascript file to the project (I named it StockTicker.js) and add the following code:

function requestPriceUpdateFromServer()

{

var request = new Ajax.Request(

"StockTicker.ashx",

{method:'get',parameters:'', onComplete:showResponse}

);

}

function showResponse(request)

{

$('priceCell').innerText = request.responseText;

}

function periodicallyUpdatePrice()

{

var periodicExecutor = new PeriodicalExecuter(requestPriceUpdateFromServer,3);

}

periodicallyUpdatePrice();

We are sending an AJAX request to to the URL StockTicker.ashx every 3 seconds. You can see that using the Prototype library it's literally a few lines of javascript.

Now let's add an HttpHandler to respond to the requests with the updated price of the stock:

public class StockTickerHandler : IHttpHandler

{

public void ProcessRequest(HttpContext context)

{

context.Response.ContentType = "text/plain";

context.Response.Expires = -1;

context.Response.Write(StockDataProvider.GetStockValue("CSCO"));

}

public bool IsReusable

{

get

{

return false;

}

}

}

The request handler is very simple. You can see that I've refactored the stock data provider into a seperate class StockDataProvider as it is used in both the http handler and the control server code. Also, out of sheer laziness I have hard-coded the CSCO ticker into the parameter. In real life this should be passed from the client as a parameter of the AJAX request. If you run the example now, you will see that the price gets updated every 3 seconds, without re-sumbitting the page.

Some Bells and Wistles

Now let's add some logic to our control. First, after the price of the stock is changed, we will color green or red according to the change in the price (up or down). To achieve this, we modify the showResponse javascript function:

function showResponse(request)

{

var newPrice = request.responseText;

var oldPrice = $('priceCell').innerText;

$('priceCell').innerText = newPrice;

if(newPrice>oldPrice)

$('priceCell').bgColor = 'green';

else if(newPrice<oldPrice)

$('priceCell').bgColor = 'red';

}

The second addition will be to show the change in percent relative to the previous price.

We will modify in three places, first, communication between client and server:

1. Pass the current price from client.

2. Respond with the new price and the change in percentage from the server.

Second - calculate the precent of change on the server.

Thirs - display the change on client, after getting a response from the client.

Here's the modified code on client side:

function requestPriceUpdateFromServer()

{

var data = $('priceCell').innerText;

var currentPrice = data.split('(')[0];

var request = new Ajax.Request(

"StockTicker.ashx",

{method:'get',parameters:'price='+currentPrice, onComplete:showResponse}

);

}

function showResponse(request)

{

var data = request.responseText.split('|');

var newPrice = data[0];

var oldPrice = $('priceCell').innerText;

var change = data[1];

$('priceCell').innerText = newPrice + '(' + change + '%)';

if(newPrice>oldPrice)

$('priceCell').bgColor = 'green';

else if(newPrice<oldPrice)

$('priceCell').bgColor = 'red';

}

And in the http handler:

public void ProcessRequest(HttpContext context)

{

context.Response.ContentType = "text/plain";

context.Response.Expires = -1;

int oldPrice = Convert.ToInt32(context.Request.Params["price"]);

int newPrice = StockDataProvider.GetStockValue("CSCO");

double change = ((double)newPrice / oldPrice - 1) * 100;

context.Response.Write(newPrice + "|" + change);

}

Now that we have a working and functional control, we can take a look at some problems with my implementation.

What's Wrong

I think the current implementation is fairly representative of how many modern working web controls are implemented. A major issue with this kind of implementation is the presence of logic on the client side and the mixing-and-matching of logic between server code and client code.

Let me expand on this issue. Here are some specific problems that we are lead to by this approach:

1. Logic in javascript is bad on it's own right:

a) javascript is harder to develop and to debug - it is a more error-prone language than, for example, c#. It has weaker development tool support.

b) A lot of javascript logic code can lead to performance issues because it's executed on a potentially weaker, client-side, machine.

c) All javascript code is visible to the user, what is in many cases problematic because of security and intellectual property issues.

2. Usually, the logic in your code will be scattered (just like in our example control) across server and client. This leads to:

a) Code that is very hard to understand and debug - there is no single place to look.

b) It's a horror to modify - notice how we had to modify many places when we wanted to show the change in percentage of the stock price.

At this point it's important to understand that I'm not bashing javascript code or the language as a whole. The language is extremely powerful and I like it personally. The browser support for javascript is actually what allows us to write truly powerful, usable and feature-rich applications on the web. So I do not, for a second, call to abandon it's use.

What is bad, is how logic gets tangled up inside javascript.

Les Arcs Chairlift

A Better Approach

I have a suggestion for a better approach, that will keep the benefits of having controls that are rich on the client side but still have all the logic in one place, on the server.

The solution outline is this: we extract all the decision making from javascript and move it to the server while keeping the performing of actions on the client side. The server will decide what to do, and call (we'll see how in a second) the specific javascript actions that are needed.

First, let's map out all the things that are "logic" inside javascript in our current implementation: (logical decisions in bold)

1. Immediately at the beginning of the page's "life on the client", javascript starts a periodic request to the server for price updates. This fact is a logic decision.

2. It sets the interval of updates to 3 seconds.

3. When requesting update from server, it sends to the server the current price.

4. It knows the structure of the response from the server, parsing it into (a)price and (b)change in percent, then injects these values in specific locations in the display.

5. It checks the kind of change (up or down) and colors the display accordingly.

Note how I am religious about this. We have to seperate every tiny bit of logic from the rest of the code.

Now, let's take a look at a better implementation where all the above logic parts are performed by the server.

Here's an implementation that removes the first three issues. The javascript:

function requestPriceUpdateFromServer()

{

var request = new Ajax.Request(

"StockTicker.ashx",

{method:'get',parameters:postBackParams, onComplete:showResponse}

);

}

function showResponse(request)

{

var data = request.responseText.split('|');

var newPrice = data[0];

var oldPrice = $('priceCell').innerText;

var change = data[1];

$('priceCell').innerText = newPrice + '(' + change + '%)';

if(newPrice>oldPrice)

$('priceCell').bgColor = 'green';

else if(newPrice<oldPrice)

$('priceCell').bgColor = 'red';

postBackParams = 'price=' + newPrice;

}

function periodicallyUpdatePrice()

{

var periodicExecutor = new PeriodicalExecuter(requestPriceUpdateFromServer,interval);

}

You see that now, periodicallyUpdatePrice is not called right away from inside the javascript file itself. It also uses a variable for the interval of the periodic update requests. The call and the variable will be created by server-side code.

Also, requestPriceUpdateFromServer now uses a variable to hold the parameters to be sent to the server. It is also created by the server.

(showResponse still has knowledge of how this parameter is built, we'll remedy that in a sec.)

Now, let's take a look at the server:

private int value = -1;

private int GetStockValue()

{

if(value==-1)

value = StockDataProvider.GetStockValue(Ticker);

return value;

}

protected override void OnInit(EventArgs e)

{

base.OnInit(e);

Page.ClientScript.RegisterClientScriptInclude("prototype", "prototype.js");

Page.ClientScript.RegisterClientScriptInclude("tickerScript", "StockTicker.js");

string periodicUpdateScript = @"var interval = "+ periodicUpdateInterval + @"

Event.observe(window, 'load', periodicallyUpdatePrice, false);";

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "periodic update", periodicUpdateScript, true);

Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "postback params", "var postBackParams='price='+" + GetStockValue().ToString() + ";", true);

}

So far I only modified the web control code, not the HTTP handler.

GetStockValue is now used twice, so it caches it's value.

OnInit is where the interesting changes are made. It emits code that defines a javascript variable for the periodic request interval and also the initial call to periodicallyUpdatePrice (which will be done in the onload event handler in javascript).

It also creates the variable that holds the update request parameters, assigning to it it's initial value.

Now let's move to fixing the remaining issues. As a first step, I will refactor the javascript code into seperate actions, without shifting responsibilities to the server: (showing changed functions only)

function showResponse(request)

{

var data = request.responseText.split('|');

var newPrice = data[0];

var oldPrice = $('priceCell').innerText;

var change = data[1];

displayNewValues(newPrice, change);

colorCellBasedOnChange(oldPrice, newPrice);

updatePostBackParams('price='+newPrice);

}

function displayNewValues(newPrice, change)

{

$('priceCell').innerText = newPrice + '(' + change + '%)';

}

function updatePostBackParams(newValue)

{

postBackParams = newValue;

}

function colorCellBasedOnChange(oldPrice, newPrice)

{

if(newPrice>oldPrice)

colorCell('green');

else if(newPrice<oldPrice)

colorCell('red');

}

function colorCell(color)

{

$('priceCell').bgColor = color;

}

Now it's all set for a one-move, guilliotine-like shift of logic to the server.

Here are the changes to the HTTP handler:

public void ProcessRequest(HttpContext context)

{

context.Response.ContentType = "text/plain";

context.Response.Expires = -1;

int oldPrice = Convert.ToInt32(context.Request.Params["price"]);

int newPrice = StockDataProvider.GetStockValue("CSCO");

double change = ((double)newPrice / oldPrice - 1) * 100;

string color = (change>0)?"'green'":"'red'";

string response = "displayNewValues("+newPrice.ToString()+","+change.ToString()+");"+@"

colorCell(" + color + ");" + @"

updatePostBackParams('price='+" + newPrice + ");";

context.Response.Write(response);

}

The server decides on the logic that will be performed on client-side, and sends it to the client as a snippet of javascript to be injected.

All the client has to do is run the returned code:

function showResponse(request)

{

eval(request.responseText);

}

Notice that because it's extremely uncomfortable to "embed" javascript inside a server language like c#, I made a point out of making the actions on the javascript all seperate and easy to call.

Also, you can see, that the details of performing client-side work are still all on client side. The only thing that moved to the server is the decision what and how should be done (specifically function calls and parameters).

Conclusion

Even though the presented implementation is still not polished, it shows how you can develop a client-heavy control or page, while keeping all logic in one place, where it's easy to develop and maintain.

Here's another analogy: the javascript part of your controls should be treated much like SQL embedded in the code. You can have logic in your SQL statements, but it's considered a well-known bad practice, for the same reasons I described here for javascript. The better approach is to have your SQL perform just the data access actions while the application code (which is in your chosen language) ties it all together and makes the logic decisions.

Sunday, April 15, 2007 2:34:18 AM (Jerusalem Daylight Time, UTC+03:00)  #    Disclaimer  |  Comments [2]  | 
 Sunday, March 18, 2007

If you use dasBlog, the endpoint for Blogger API is:

http://<your address>/Blogger.aspx

Sunday, March 18, 2007 11:02:05 PM (Jerusalem Standard Time, UTC+02:00)  #    Disclaimer  |  Comments [1]  | 
 Thursday, March 15, 2007

Here's another short trick for the NMock mock objects framework:

To mock an indexer use the syntax (for the getter):

Stub.On(...).Method("get_Item").Will(Return.Value(..));

And for the setter:

Stub.On(...).Method("get_Item").Will(Return.Value(..));

*Update*

Via Paul Pierce's post I found a better way:

Stub.On(...).Get[...].Will(Return.Value(..));

Friday, March 16, 2007 12:20:14 AM (Jerusalem Standard Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 

If you are using the NMock mock objects framework, you are probably familiar with the following syntax:

Stub.On(...).Method(...).Will(Return.Value(...));

This will cause your mock object to return a specific value from some invoked method.

Now, for something less not documented:

To mock a method that sets value of an out parameter, use:

Stub.On(...).Method(...).Will(new SetNamedParameterAction([parameter name], [value]));

You can also use the SetIndexedParameterAction class.

This is not in the documentation, so using Reflector on the NMock2.dll helped find this.

Thursday, March 15, 2007 8:09:03 PM (Jerusalem Standard Time, UTC+02:00)  #    Disclaimer  |  Comments [3]  | 
 Tuesday, March 13, 2007

This is the second part in an article series about setting up SSL in an ASP.NET application.

You can read the first part here. Go ahead, read it now.

Okay.

Now, that we've created an SSL certificate for testing and development purposes, we are ready to make the required configuration in IIS.

Setting Up IIS to Work with SSL

First thing we have to do is configure the web site to use the certificate we created:

  1. From the IIS MMC snap-in, select your web site, right-click "properties" and under "directory security" click "Server Certificate...".
  2. Click "Assign an existing certificate". You should be able to see the self-signed certificate you created. Select it and finish the wizard.

At this state IIS is able to respond to SSL HTTP requests with this certificate.

To test that everything is okay, try to navigate to an existing URL in your application, with https in the beginning of the URL.

Forcing SSL for an application

If your application requires SSL encryption for all traffic you want to force the application to only handle SSL requests.

You can do this on the application level (so that other applications on the same web site in IIS will not require SSL) or on the web site level.

Here's how:

  1. In IIS MMC, right click the application virtual directory or the web site.
  2. Select "Directory Security" tab and click "Edit...".
  3. Check "Require secure channel" and "Require 128-bit encryption".

Now, any request to a URL that starts with http and not https - will receive a 403.4 error from the web server.

Supporting Debugging in Visual Studio

Now that you've setup the web server on your machine to require SSL traffic, you need to update the application URL in Visual Studio in order to be able to run the application from Visual Studio:

  1. Right click the project in Solution Explorer and select "Properties".
  2. Under the "Web" tab change the value of "Project Url" to start with https.

Auto-Redirecting non-SSL Traffic

Perhaps some of your users will try to navigate to your application via a non SSL URL (most users assume a web page URL starts with http).

You can silently redirect your users to the correct SSL address using the following technique:

Users trying to reach a non-SSL URL will be automatically redirected by IIS to the standard 403.4 error page. First step is to change that page to your own page:

  1. In your project, create a new web form called "NonSslRedirect.aspx".
  2. In IIS MMC, right click your application virtual directory, click the "Custom Errors" tab and select the 403;4 error.
  3. Click "Edit Properties...", select "URL" in "Message Type" and type the address of the page you added in step 1 (for example: /MyApp/NonSslRedirect.aspx).

Try again to navigate to a URL starting with http. You should be redirected by IIS to NonSslRedirect.aspx.

Now, in the code-behind file of NonSslRedirect.aspx, add code similar to the following to automatically redirect the users to the matching SSL URL:

protected void Page_Load(object sender, EventArgs e)

{

string originalUrl = Request.Url.ToString().Split(new char[1] { ';' })[1];

string urlWithHttps = "https" + originalUrl.Substring(4);

Response.Redirect(urlWithHttps);

}

This code will replace the http prefix in the requested URL with an https prefix and redirect the user to new URL.

Tuesday, March 13, 2007 8:21:00 PM (Jerusalem Standard Time, UTC+02:00)  #    Disclaimer  |  Comments [2]  | 
 Saturday, February 03, 2007

SSL is the standard protocol to secure communications of web sites and applications. If you are developing your application using ASP.NET on a windows server, making the necessary configurations for SSL is not very difficult.

Unfortunately, while trying to accomplish this task at work, I discovered there isn't one good source of information to get the whole job done.

In this series of (about) three posts I will try to get you up to speed on everything you need to do and how it's done.

So, on to part one: "What is SSL and How Do We Create a Certificate?". Let's go.

A Short Intro on SSL

(Ugly oversimplification coming at you)

SSL is the standard protocol for (1)authenticating one or both parties and (2)encrypting communication between the parties.

Authentication is accomplished by a party presenting a valid certificate.

Encryption is accomplished in two steps:

  1. Negotiating encryption key(s).
  2. Encrypting communication using the negotiated key.

Setting up SSL for an ASP.NET App

The basic steps to do this are:

  1. Obtaining a certificate for use by the server.
  2. Configuring IIS.
  3. (Optional) Enforcing the use of SSL by creating a redirection mechanism in IIS and ASP.NET.

Usually, it's desired to create the setup at the development stage so you will be able to develop, debug and test your application in the same structure it will exist come production-time. So, in this post I will explain the whole setup for you developer station (referred to as localhost).

Obtaining a Server Certificate

What's a certificate? A certificate is simply a character string that contains the public key of some entitiy (like your server) signed by a third party. Presenting a valid certificate guarantees to the person who wants to communicate with you that you are who you claim you are (think drivers license).

To have SSL working in the real world you need to buy a certificate from an Authorized Certification Authority (CA) like Verisign, for example. An authorized CA is an organization that is recognized ("trusted") by client software (the web browser you're using, for example). Continuing with the driver's license metaphor, the CA in that case is the state government that issues the license.

A verified certificate costs money and is only valid for the specific machine it was issued to, so for development and testing purposes you can create your own "self-signed" certificate.

On a side note, the fellows over at Verisign are basically charging people 1,500 USD for a short string in a file. Talk about a sweet and sustainable business model - no advertising revenue required, thank you very much.

Introducing makecert.exe

Luckily, on a Windows mcahine you can use the makecert command-line utility to create a self-signed certificate.

It has a s**t-load of arguments, so here is the minimal command you need to run on the machine that hosts the application:

makecert -pe -n "CN=localhost" -ss my -sr localMachine -sky exchange

The interesting bits are:

  • -n "CN=localhost" : creates the certificate suitable for use by server "localhost". Remember that every certificate is server-specific.
  • -ss my : places the certificate in the "personal" certificates folder.

Last argument deserves a word: to view all certificates installed on your machine - use the Certificates MMC snap-in. Choose "local computer" and you are presented with various "stores" which are basically folders of certificates. To consume a certificate in IIS you need it to reside in the "personal" store of local computer.

There are additional useful arguments to the makecert utility, but the basic ones I presented will get you up an running. If you can see a certificate named "localhost" in your personal certificates store you are doing fine so far.

Stay tuned for the next part, where I will cover configuring IIS for SSL support using the certifcate we created.

Sunday, February 04, 2007 2:57:54 AM (Jerusalem Standard Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, September 07, 2006

Here's a look at how attempts to measure quality in three seemingly unrelated scenarios affect the results of what is measured, , and what can we do about it.

 

We'll start with measuring in the software development process. Joel often claims that introducing metrics into software development usually does not work. That's because programmers are smart enough to work around the metric, optimizing the specific thing that is being measured, with the end product not necessarily improving. For example: when you say that you measure programmers by the amount of bugs that are found in their code, they work out a way to get bug reports from QA without submitting them to the bug tracking software or just don't accept bugs as bugs instead of fixing them.

 

Where else does a similar situation arise?

 

Example # 1 – Measuring the Risks of Cigarettes

A recent Slate article, Nicotine Madness, discusses how measuring the levels of dangerous chemicals(nicotine, tar and others) in cigarettes, done by the U.S. government since the late 1960's didn't make the cigarettes any healthier, even though the government did punish makers with higher rates of dangerous materials.

The measuring strategy did succeed in one thing. Making the measured properties of cigarettes lower.

Here's why: the measurements are performed by a smoking-machine that simulates a human smoker. Yes, they stick the cigarette in and the machine starts puffing away, recording the levels of the dangerous chemicals. The problem is – it does not really simulate the way a human smoker smokes. Human smokers will smoke in a way that extracts the (ever growing) craved amounts of dangerous chemicals from the cigarette.

So what do the tobacco companies do? Hire the brightest scientists(they can afford it) to develop cigarettes that will score better on the machine tests but allow the smokers to inhale more and more nicotine and tar.

 

Example #2 – Doping in Sports

You have probably witnessed the hoopla surrounding use of illegal substances in sports. Here are some examples.

Am I the only one who feels it gets more and more common for top athletes to get caught using performance-enhancing drugs? I think not. But what else is growing at an even faster pace? You guessed it right – drug testing. The authorities that govern the various sports declared an all-out war on doping and drug testing became a fact-of-life for most (if not all) professional sportsmen. The punishments for those who break the rules get tougher all the time – multiple-year career-ending suspensions are now the norm.

Lo and behold: more and more athletes use the drugs. For every researcher that develops innovative drug tests, there are two who develop drugs that cannot be tested against. Once again, a measurement strategy backfires and makes the result even worse.

 

 

bolivia01.jpg

 

So Pasha, What to Do?

First, I recommend you read an excellent book called First, Break All the Rules. The authors suggest some uncommon knowledge ideas to get better results when managing people. One of them is define the goal very well, let the people decide on how to reach it.

This can also be a solution for our "Measuring Paradox":

The problem with measuring is not that it doesn't work. It's that it works. We just measure the wrong thing. What do we measure? We measure some properties that we suspect to be correlated with the desired result. A lower bug count is a sign for a program with few bugs. Lower nicotine levels are a sign for a healthier cigarette. More cheating athletes caught is a sign for a cleaner sport.

This approach doesn't seem to work.

Why don't we, instead of measuring properties that might lead to a better outcome and rewarding for better measurements, just measure the outcome itself and reward for a better one?

Specifically:

1. Award the programmer with a bonus when the software makes money ("profit sharing"). Instead minimizing bug counts she will do anything to make the product a success.

2. Award the tobacco companies when less people die because of smoking. For example – make them pay a special tax that grows with the number of people dying because of smoking-related reasons. Now instead of minimizing machine-tested nicotine levels they will do anything to make cigarettes healthier.

3. Totally allow the use of performance-enhancing drugs, then integrate drug use in the result. For example: if you use drug A – 2 tens of a second are added to your 100 meters dash time. Now instead of thinking how to pass the drug-test, the athletes will concentrate on training for the best result. Using drugs will not give you an edge anyway.

 

The sad truth is that most metric-systems for performance are not very good at improving the outcome. So, the only thing you should really be measuring and trying to optimize is the desired outcome itself.

And don't smoke, it's not good for you.

Friday, September 08, 2006 5:09:51 AM (Jerusalem Daylight Time, UTC+03:00)  #    Disclaimer  |  Comments [2]  | 
 Monday, August 28, 2006

Sometimes it's amazing to realize how total is Google's domination in web 2.0 type apps. They have everything. I didn't even know they have a notebook app. Or an html builder(which is a free hosting service as well).

And then in a review of web 2.0 apps Google gets picked as the top app in almost every category.

Part of the reason for such domination is that they have a broad offering. So most people are already their users. I have a gmail account. So now when they roll out some new service, I can just login with my existing gmail account and voila, I can use the new app. So my barrier to entry is extremely low. It's easy to test their new app. If it's good (that's another important issue) - I become a user.

Now imagine potential-competitor-startup-firm launches their super-cool new app. I want to try it, because everyone's blogging it. But I don't want to sign up. Because it will take five minutes. And I will have to tell them stuff about myself. And go to my email (gmail anyone?) and click something to confirm something. And that's no good.

So the number one lesson, I think, to someone who wants to make a new web app is make your sign up process seamless.

And here is a great example - check out Zoho. They have what seems like a very nice web based office suite. But that's no biggie. What really got me (and remember how important first time user experience is) is the signup. It's as quick and as easy to sign up as a new user as it is to log in as an existing user!!

You just tick the "I am a new user" checkbox, and type-in your password twice instead of once. That's it. No personal info. No signup page. No wizard. No email confirmation. The next page you see is the editor itself (I logged into Zoho Writer).

That's fun. And this is how apps should be.

I know I am going to make the signup in my apps like this from now on.

By the way, this post was written with Zoho Writer. And yesterday's was written with Writely (which is Google owned). Maybe I'll post reviews of the apps later.

Tuesday, August 29, 2006 5:06:46 AM (Jerusalem Daylight Time, UTC+03:00)  #    Disclaimer  |  Comments [4]  | 
 Sunday, August 27, 2006

Summary: In this short article I will describe the creation of a Visual Studio.NET 2005 macro that speeds up the process of adding localizable controls to ASP.NET web pages, briefly touching on the subjects of ASP.NET localization, regular expressions and world peace.

Not really world peace.

I will assume you are familiar with writing ASP.NET pages and working with regular expressions.

 

 

Intro on ASP.NET Globalization

Globalization is the process of building an application in a way that it's GUI can appear in diferrent languages and cultural formats. ASP.NET 2.0 has some mechanisms that simplify building globalized apps with (relatively) little hassle.

One of the widest used mechanisms is called implicit localization expressions. It works by placing a special attribute, meta:resourcekey on an ASP.NET control in the page:

 

<asp:label id="Header" runat="server" meta:resourcekey="Header"></asp:label>

 

Now, you can create resource files in the App_LocalResources directory of the web project. The resource files must adhere to the naming convention:

 

[LocalizedWebFormName].resx

 

So if the above asp:label is in a file named Default.aspx, the resource file will be named Default.aspx.resx.

In the resource file you can now add resources with names that match the values in the meta:resourcekey attributes of the localized controls and the property names of the controls that you want to localize(such as the Text property of an asp:label control).

For example:

 

When you run the page, ASP.NET will automatically populate the properties of the localized control with the values from the resource file.

Now for the localization part - you can supply resource files for every language and culture you wish to support by creating a resource file named in the following convention:

 

[LocalizedWebFormName].[Language Code].resx

 

For example:

Default.aspx.en.resx

Default.aspx.fr.resx

Default.aspx.he.resx

 

The beauty is that ASP.NET will load properties with values from the resource file that matches the culture of the current thread, based on the current culture of the requesting user's machine. So when a user from Israel will request the page she will get the Hebrew values automatically.

 

Very Cool, But There's a Rub

Now you can build globalized web pages by dragging controls, adding the meta:resourcekey attribute and adding the needed property resources to the resource file.

One problem is that creating even simple pages that contain many controls can become tedious, because now you have to spend much more time on every control you drag to the web page.

How can we automate the process of adding the extra attributes and resources?

 

VS Macros 101

Visual Studio.NET 2005 contains two main customization and extension mechanisms: Macros and Add-Ins. Generally speaking Macros are less powerful but easier to create. Add-Ins are more powerful and are a bit more complicated to create.

VS Macros are actually Visual Basic for Applications code (that's right, no VB.NET and definitely no C#) intended primary for automating repetitive tasks in  Visual Studio.

The easiest way to create a macro is by using the Record Macro command:

 

Recording a macro in this way actually creates VBA code behind the scenes. You then can edit that code and also create new macros programmatically using the Macros IDE. This code can access many parts of the Visual Studio environment such as the files ad the code inside them, via different classes in the EnvDTE namespace.

Good places to start learning about how you can access the various parts of VS are:

1. Automation and Extensibility reference on MSDN.

2. Opening the Macros IDE and reading the code in the Samples project.

3. Recording macros and going through the code that VS creates automatically.

 

Back to the Problem, Macro For Localized Controls

Lets draw an outline for one possible solution:

The user will create the controls normally, then select in the editor all the controls that need to be localized and run the macro. The macro will go through the controls that are found within the selection, creating a meta:resourcekey attribute for each one (the attribute value will be the same as the value of the id attribute) and also creating a resource for each control in the appropriate resource file.

 

Writing the Macro - Adding Localization Attributes to the Web Page

We'll start out by adding a new public method to the macros module:

 

Sub LocalizeControls()

End Sub

 

The procedure is public by default. Private procedures will not be accessible from the IDE and cannot be used as macro entry-points.

We will use regular expressions to find all the ASP.NET controls inside the selection and to append the meta:resourcekey attributes. The following code section does just that:

 

Const ControlsMatchingPattern = "(?<tag><asp[^>]*id=" & Chr(34) & "(?<id>[^" & Chr(34) & "]*)" & Chr(34) & "[^>]*text=" & Chr(34) & "(?<text>[^" & Chr(34) & "]*)" & Chr(34) & "[^>]*)>"

 

Function AddMetaResourceKeyToControls(ByVal ControlsHtml As String)

Dim ControlsRegexExpression As New Regex(ControlsMatchingPattern, Re