Thursday, August 14, 2008

Invalid postback or callback argument in ASP.Net 3.5

Also, you might get a Sys.WebForms.PageRequestManagerServerErrorException with code 500 when using Ajax. It usually happends when you click on a button in a GridView or another bound control. You expect it to work, but it doesn't, even if the code is relatively clear.

The answer is (probably) that you are binding the container bound control every time you load the page (instead of only on !IsPostBack). The thing is this used to work in ASP.Net 2.0.

Bottom line: check your binding, see if you are not doing any DataBind in between the button click and the eventual event catch.

Wednesday, August 13, 2008

The Transition to LINQ

We started our first ASP.Net 3.5 project and today I had to work with the Linq database access. Heralded by many as a complete revolution in the way of doing ORM, LInQ is not that simple to move to. A lot of stuff that has become second nature for me as a programmer now must be thrown in the garbage bin.

I'll skip the "how to do LInQ" (there are far too many tutorials on the net already) and get down to the problem. Let me give you a simple example. You want to select a User from the Users table. Let's see how I would have done it until now:
User u=User.SelectById(idUser);
or maybe
User u=new User(); u.IdUser=idUser;
u.SelectOne();

In LInQ you do it like this:
var c=new MyDataContext();
User user=(from u in users where u.idUser=idUser select u).FirstOrDefault();
or maybe
var c=new MyDataContext();
User user=c.Users.Select(u=>u.IdUser=idUser).FirstOrDefault();


I am typing this by hand, forgive me the occasional typos or syntax errors.

Well, my eyes scream for an encapsulation of this into the User class. We'll do that by creating a new User.cs file that contains a User partial class that will just mold on the LInQ generated one, then adding methods like SelectById.

Ok, I have the bloody user. I want to change something, let's say rename him or changing the password, then save the changes to the database. Here it gets tricky.
User u=User.SelectById(idUser);
u.Password="New Password";
....?!


In LInQ you need to do a DataContext.SubmitChanges(); but since I encapsulated the select functionality in the User class, I have no reference to the DataContext. Now here are a few solutions for doing this without saving the linq queries in the interface:
  1. Add the methods to the context class itself, stuff like SelectUserById();. You would still need to instantiate the DataContext though, in every query
  2. Add a second out or ref parameter to the methods so that you can get a reference to the DataContext used.
  3. Make a method for each operation, like User.SetPasswordById();, that would become quickly quite cumbersome.
  4. Add a reference to the DataContext in the User object, but that would become troublesome for operations like SelectAll
.

I am still not satisfied with any of these solutions. I am open to suggestions. I will link to this little article I found that suggests encapsulating the LInQ queries in separate extensions methods: Implementing ORM-independent Linq queries

The Augmented Reality business - Total Immersion

Oh, I know you probably have heard of Augmented Reality, but you have never experienced it in a way that is trully easy to use and that really feels... real. Here is a small demo from Total Immersion, a company that uses image recognition software to add computer generated interactive objects to real time videos.

As far as I understand it, they plot some points on the image, they store its contents and the software can recognize it even skewed or warped or even partially visible. In the video you will see how this applies to a classic green-screen-like board that the demonstrator can actually move around, then how it applies to an image on a t-shirt and then, finally, an interaction between computer generated and real objects.

Sunday, August 10, 2008

Snow Crash - Neal Stephenson

I started reading Neal Stephenson at a friend's recommendation. That reminded me of the cyberpunk novels that I used to read in my teenage years and enjoy so much. However, I remember them slightly more fun :) That's why I would call Snow Crash more of a Cy-Fi novel, a piece of cyberpunk with a slightly overexagerated plot. Even Wikipedia calls it a post-cyberpunk novel. You see, when Gibson wrote about hackers and the artificial intelligences and the future, he was actually trying to convey a believable, predictable future. I believe Neal Stephenson actually crossed the line and pushed the vision a little in order to put some ideas on the table.

However, it was still a good novel, with interesting characters, fantastic vision of the future and quite a bit of research, which he modestly attributed to a lot of his friends.

The story revolves around Hiro Protagonist, a sword wielding computer hacker, and Y.T. (Yours Truly - a 15 years old skateboard courier), both caught in a complex plot that I cannot reveal without spoiling the read. It has some of the standard cyberpunk motiffs like the collapse of governments and law, the world being ruled by corporations like the Mafia, the church and Mr. Lee's greater Hong Kong (to name a few) and a focus on the services individual people can provide rather than the material benefits of technological items.

I recommend reading it, although some parts of the "future" are already old and silly by now. I've also read some short novels like The Great Simoleon Caper and Spew, that were both good reads, especially the latter. I am moving on to Diamond Age now.

Wednesday, August 06, 2008

Internet Explorer Cannot Open the Internet Site ... Operation Aborted.

You usually get this using an Internet Explorer version 6 (but also later versions might exibit this) on pages that seem to be loading ok in the background. You press ok and the page disappears and the regular error page is displayed.

What is happening is that javascript is trying to change a html element that has not finished loading. The usual cause of this problem is an embedded script block that executes as it loads, rather than on the onload event of the page.

The fix is easy. Take all the scripts that execute as they load and either mark them as defer or encapsulate those commands in a function that is executed on the onload event of document.body. Be careful with defer. This post describes the various implementations of the keyword in various browsers.

SilverLight 2.0 Beta 1 Relative Uri problem

Yay! My first real SilverLight post :)

Anyway, the problem is with controls in SilverLight that expect an URI as a parameter. It doesn't work. After trying all kind of stuff and googling a litle I found out that
  1. the path is relative to the web application ClientBin directory
  2. the path cannot contain .. or other directory/URI navigation markers like ~
  3. the SilverLight control does not have access to a Request object like a web page does


This link already discusses it: Silverlight 2.0 Beta 1 Uri inconsistency, but I also have an additional solution to the ones listed there.

Here are the solutions for this:
  • Provide an absolute Uri either statically or by generating it with this piece of code:
    New Uri(Application.Current.Host.Source.AbsolutePath + "../../../video.wmv", UriKind.Absolute)
  • Copy the images, videos, files into the ClientBin directory then only provide their name
  • Create virtual directories inside ClientBin that point to your resource directories. For example create a virtual directory Videos that points to the ~/Resources/Videos folder in the site, then simply use Videos/video.wmv as the URI


Of these three, the last I find the most elegant, even if the setup of the website itself might be rendered a lot more difficult by this.

Tuesday, August 05, 2008

Javascript script blocks relative paths in ASP.Net

ASP.Net 2.0 added a very useful thing, the '~' sign, which indicates that a path is relative to the application directory. Since the application itself should be indifferent to its name, this little thing comes in useful when trying to set the location of user controls, style sheets and so on. The problem is that this feature only applies to user controls. That is not a problem for most tags, since even a link tag can be set as a user control with a runat=server attribute.

The problem comes when trying to set the location of javascript script blocks. A script block with runat=server must be a server code block by definition, i.e. C# or VB, whatever the site language is set to. One of the solutions often used to solve this is to use a code block inside the src attribute of the javascript block like this:
<script language="Javascript" type="text/javascript" 
src='<% =ResolveUrl("~/scripts/myScript.js")%>'></script>
.

But this is still a nasty issue, because of the dreaded The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>). error. As in the post I linked to, the solution for this is to place all external script blocks within a server control like a PlaceHolder or a even a div with the runat=server attribute set. The drawback to this solution is that you can't do that in the <head> section of the HTML output.

The other solution is to use from within the server code the ScriptManager.RegisterClientScriptInclude method to add the script programatically to the page. While this is elegant, it also defeats the purpose of the aspx page, that is to separate content from code.

Friday, August 01, 2008

How to add content at the end of an AutoCompleteExtender dropdown

Somebody asked me how to add things at the end of an AutoCompleteExtender div, something like a link. I thought it would be pretty easy, all I would have to do is catch the display function and add a little thing in the container. Well, it was that simple, but also complicated, because the onmousedown handler for the dropdown is on the entire div, not on the specific items. The link was easy to add, but there was no way to actually click on it!

Here is my solution:

function addLink(sender,args) {
var div=sender.get_completionList();
if (div) {
var newDiv=document.createElement('div');
newDiv.appendChild(getLink());
div.appendChild(newDiv);
}
}

function getLink() {
var link=document.createElement('a');
link.href='#';
link.innerHTML='Click me for popup!'
link.commandName='AutoCompleteLinkClick';
return link;
}

function linkClicked() {
alert('Popsicle!');
}

function ACitemSelected(sender,args) {
var commandName=args.get_item().commandName;
if (commandName=='AutoCompleteLinkClick') linkClicked();
}


The AutoCompleteExtender must have the two main functions as handlers for the item selected and popup shown set like this:
<ajaxControlToolkit:AutoCompleteExtender OnClientItemSelected="ACitemSelected" OnClientShown="addLink" ...>


Now, the explaining.

First we hook on OnClientShown and add our link. The link is added inside a div, because else it would have been shown as a list item (with highlight on mouse over). I also added a custom attribute to the link: commandName.

Second we hook on OnClientItemSelected and check if the selected item has a commandName attribute, and then we execute stuff depending on it.

That's it folks!