February 2008 - Posts

Haack on versioning issues on the MVC framework
Thu, Feb 21 2008 23:34

After reading this post, I think that I need to catch up on my sleep :) I'm not sure if I buy the justifications presented by Phil. And it seems that there are other (smarter) guys that aren't buying it either...

by luisabreu | with no comments
Filed under:
Book review: Hunting Security Bugs
Thu, Feb 21 2008 23:18

I've just finished reading my copy of Hunting Security Bugs.I must say that I was really pleased with the quality and coverage of the book.  The authors present several examples that show how things can start going bad really easy. The book will give you several clues and show how you can trace security issues that might appear on your applications. This was one of the best buys I've made on the MS online store. Score: 8/10.

by luisabreu | with no comments
Filed under:
Why did I return to the msmvps.com blogs...
Thu, Feb 21 2008 23:09

[Warning: definitely not a technical post]

Those 3 guys that normally read my blog (yes, I believe that I've managed to overcome my previous record of 2!) may recall the "switch to ASP.NET blogs and then back to msmvps.com again". It seems like I'm not the only one that got pissed with some of the comments that started appearing on the blog. On the other hand, it seemed like I was the only one that got out, but that's another story :)

As you know, the ASP.NET blogs have a global feed. The problem is that this feed publishes all the posts that appear on the weblogs.asp.net site without filtering it by tag (there's an option on the web interface that will let you decide if you're publishing the post on the global feed, but lets face it: how many of you use the web interface to publish a post?).

In practice, this means that if I publish a post on the weblogs.asp.net site, annotate it with something that is not ASP.NET related (ex.: Trivia) you'll automatically receive the post if you subscribe to that global feed. I believe that we can all agree that  in this case it's not really my fault that you end up getting a trivia post when you're only interested in getting ASP.NET content.

Unfortunately, there are some guys that are extremely rude and start adding comments to non-ASP.NET post which say something like: this doesn't help me. don't put it here, etc. etc.. Let me give you an example. Here one of the posts that made me get pissed and that made me close the ASP.NET blog. Ok, let's see what some ass wipe called Mo said:

"I don't care if you are back. This doesn't help me improve my ASP.NET. Stop posting stuff like this to the main feed."

Ok, so lets see if I understand this correctly: Mo is complaining because I've added a personal post to MY BLOG. Interesting... I always thought that my blog was supposed to be managed by me, but it seems like Mo and lots of other guys have other plans...And again, do notice that I'm not posting anything to the main thread. It's the blog that is doing that automatically...

Even though my blog is not the best blog in the world, I think that it does have several posts with technical content and since it's MINE, I'm the one that decides what gets posted. And that's why I've returned to the msmvps blogs.

by luisabreu | 4 comment(s)
Filed under:
MultiView control: should you use it?
Wed, Feb 20 2008 23:10

Today I was called to investigate a performance problem with a page of a web application. It was a simple page, with several tabs where each tab loaded several items from the database. According to the guys that wrote the app, things started getting worse with each tab that got added to the page and, since they didn't have a lot of experience with ASP.NET, they didn't understand what was going on. They were also little bit intrigued by the fact that the site took almost 2 minutes to load in production (compared to the 20 seconds it took on the development machine).

Here's what I found when I looked at the page (just a simple example):

<asp:MultiView runat="server" ID="mview">
        <asp:View>
            <uc1:Demo1 ID="Demo11" runat="server" />
        </asp:View>
        <asp:View>
            <uc2:Demo2 ID="Demo21" runat="server" />
        </asp:View>
</asp:MultiView>

And then, each User Control had similar code to this one:

<%@ Control Language="C#" ClassName="Demo1" %>

<script runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        //assume you have code here that gets something from bd and
        //binds it to a control
    }
</script>
<div>This is user control 1. Assume this is getting data from someplace</div>

By now, you must have noticed the bold on the previous snippets...So, can you see anything wrong here? At first sight, it really looks like there's nothing wrong with the previous example. However, there really are lots of things wrong with this approach

The MultiView control keeps a list of Views and will only render the active one. To the programmer that is using the control and doesn't know its internals, it really looks like a cool control: without almost no work at all, you've just built an interface which will let you toggle the current view that is shown to the user. And have I said that you can do athis without writing ny code (ok, you do need to write at least one line to change the active view, but how difficult can it be to write a single simple line of code, right?)! Wow! This control is really great! Do you agree with this? I really hope not...

To see why, lets use our old friend reflector to take a look at the MutiView class. Lets see the current implementation of the Views property (responsible for keeping the list of views that is defined on the page):

[WebSysDescription("MultiView_Views"), PersistenceMode(PersistenceMode.InnerDefaultProperty), Browsable(false)]
public virtual ViewCollection Views
{
    get
    {
        return (ViewCollection) this.Controls;
    }
}

Now, if you're like me, you should be seeing alarms firing all over the place :) So, when you use this control, all the views (which are just simple controls) are loaded and added to the control collection of the MultiView control. What this means is that all those controls (views) will go through the page life cycle like if they were added directly on the form control. The only difference is that the MultiView control overrides the Render method so that it renders only the active view (by default, all controls maintained on the Controls property are rendered into the page that is sent to the client):

protected internal override void Render(HtmlTextWriter writer)
{
    View activeView = this.GetActiveView();
    if (activeView != null)
    {
        activeView.RenderControl(writer);
    }
}

Btw, if you're thinking about the minutes vs seconds (when comparing the production site with the development site) the answer was also simple: the database was on a different machine (which meant, that the page had to make several remote calls to get the data it needed for rendering each view, even though only one would be rendered to the client). Fixing this was simple: they changed the code so that the active user control was loaded dynamically by the page.

Moral of the story: well, this example demonstrates one of the problems of the web forms approach: too much abstraction will end up hurting you!

by luisabreu | 9 comment(s)
Filed under:
Resharper 4.0 Nightly builds are out!
Mon, Feb 18 2008 23:19

Check them here.

by luisabreu | with no comments
Filed under:
Improving the user experience with BumpTop
Sat, Feb 16 2008 11:52

This is really cool! Just watch the video and see for yourself...

by luisabreu | with no comments
Filed under:
10 ASP.NET Performance and Scalability Secrets
Sun, Feb 10 2008 15:00

Omar Al Zabir has published a cool article on codeproject where he presents several cool tips that will help you improve the performance of your ASP.NET web apps.

by luisabreu | with no comments
Filed under:
Application services IV: authenticating the user in an offline scenario
Thu, Feb 7 2008 14:43

In my previous posts I've been talking about the basic features introduced by the new Applications Services which were added during the latest release of the .NET platform. Today we'll see how easy it is to configure our windows form app so that it is able to authenticate a user in an offline scenario.

As you might expect, you'll only be able to validate a user (on an offline scenario) if that user has already been validated previously in an online scenario. So, the 1st thing you need to do is to change your app.config file so that the hash of the password is stored in the machine. To achieve this, you need to set the savePasswordLocally attribute of the provider entry:

<add name="ClientAuthenticationMembershipProvider"
savePasswordHashLocally="true"
             type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
             serviceUri=http://localhost/login/Authentication_JSON_AppService.axd
             credentialsProvider="login.Login, login" />

Even though this step is required in order to save a local copy of the hash of the password, it is not enough for making the platform authenticate the credentials against the local saved copy of a previously successful authentication. The offline authentication scheme will only be used when the ConnectivityStatus.IsOffline is set to true. So, you need to change your startup code to something like this for authenticating a user in an offline scenario:

ConnectivityStatus.IsOffline = true;
if(! Membership.ValidateUser("", "") )
{
     return;
}
Application.Run(new Form1());

By now you must be wondering where the platform is saving the hash of the password. If you don't do anything, the hash will be saved in a file named User_username.clientdata in a folder named after your windows app (placed inside the user's app data folder). Just replace username with the username of the user that is trying to log on and you should find the file by performing a search on your disk. If you open that file, you should find something like this on it:

<?xml version="1.0" encoding="utf-8"?>
<ClientData>
   <LastLoggedInUserName></LastLoggedInUserName>
   <LastLoggedInDateUtc>1C73F36A9D78ED2</LastLoggedInDateUtc>
<PasswordHash>oSmbK+DdLg9KhsOKZHg5qKisALg=</PasswordHash>
   <PasswordSalt>EUQ3dz7qihlivjokvdkVBg==</PasswordSalt>
   <Roles>
      <item>Role2</item>
   </Roles>
   <RolesCachedDateUtc>1C85E0822CC597B</RolesCachedDateUtc>
   <SettingsNames></SettingsNames>
   <SettingsStoredAs></SettingsStoredAs>
   <SettingsValues></SettingsValues>
   <SettingsNeedReset>0</SettingsNeedReset>
   <SettingsCacheIsMoreFresh>0</SettingsCacheIsMoreFresh>
   <CookieNames>
      <item>9e7450b9c96a487eb57880ecfa4b96c9</item>
   </CookieNames>
   <CookieValues>
    <item>.ASPXAUTH=</item>
   </CookieValues>
</ClientData>

As you can see, there's a lot more info besides the password hash+salt used for authenticating the user in an offline scenario. For instance, roles can also be cached...

Currently, you can also save the user info in an SQL Compact database. To do that, you'll need to specify a SQL Compact connection string or you can simply use the special connection string "Data Source=|SQL/CE|". Here's what you need in order to achieve this:

<add name="ClientAuthenticationMembershipProvider"
            savePasswordHashLocally="true"
connectionStringName="Data Source=|SQL/CE|"
            type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            serviceUri="http://saturn/login/Authentication_JSON_AppService.axd"
            credentialsProvider="login.Login, login"

Do notice that this will only work in x86 builds (ie, SQL Compact will only run in WoW mode in x64 bits systems). So, if you also have a x64 version of an OS installed, don't forget to explicitly set the build to x86 on the configuration of your project. One more thing you might notice after looking at the previous config entry is that I'm passing the special connection string to an attribute which is called connectionStringName. Well, if you want, you can pass it the name of an existing entry on the connectionString section instead (internally, the provider will try to get an existing entry named with the value you pass to the connectionStringName attribute. If it can't find any, it will simply use the value you've passed to that atribute).

If you use reflector to check the code, you'll see that the helper classes do have code that would let you use Isolated Storage for saving these data. However, there's really no way to set it up (at least, I didn't find any - maybe I'm missing something!) so you'll have to choose between using the file system or a SQL compact database.

Before ending this post, there's still one more thing you should keep in mind: you should always set the ConnectivityStatus.IsOffline property. If you explicitely set the property, then that value will be respected. If you don't, then the value returned from the property will depend on the checking of a special file called AppIsOffline. This file is used as a marker and is created when you set the  the ConnectivityStatus.IsOffline property to true (notice that it will be deleted when you set the property to false). What this means is that if you've previously set that property to false and then don't set it back to true, authentication will always be performed offline since that property will return true.

And that's all for today...more to come tomorrow :)

by luisabreu | with no comments
Filed under: ,
London visit photos
Thu, Feb 7 2008 14:43

I've just finished uploading some photos from my trip to London. Check them out in facebook.

by luisabreu | with no comments
Filed under: