October 2007 - Posts

Hebrew and Arabic Silverlight support
Sat, Oct 27 2007 22:24

Justin-Josef has built a new codeplex project that aims to support Hebrew and Arabic text rendering on Silverlight. There are already some support materials over Justin's site that will help you get started:

Nice work Justin!

by luisabreu | with no comments
Filed under:
Deployment problems with ASP.NET AJAX applications
Fri, Oct 26 2007 14:55

In the last days I've seen several guys reporting problems while deploying ASP.NET AJAX applications to servers which only have  ASP.NET 2.0 + ASP.NET AJAX 1 installed. Generally, the error that has been reported is:

Could not load file or assembly 'System.Web.Extensions, Version=3.5.0.0...

One of the suggestions that I have seen is to add a redirect on the web.config app so that all requests made to the 3.0 dll are redirected to the 1.0 version of the dll. Even though most guys said that this worked, I didn't though it was the correct thing to do since I was positive that if you specify the correct version of the ASP.NET Ajax dll on the config file and that file existed on the server then you should get that file and not the most recent version.

Today, I've  finally managed to get a repro web app from Johnson (thanks!).Since this kind of thing will only happen if you have the .Net 3.5 framework installed, I started by looking at the web.config file. I though that VS might have changed the dll version silently, but no, that was not the case. Then I asked Johnson how he was deploying the app and he told me that he was publishing the app from within the VS. Since I'm running VS 2008 standard, I don't have that option here. So I asked him to publish the site and sent it to me by mail. This was really a simple site that only had one page with an UpdatePanel (or something simple like that)

After looking at the pre-compiled version, the problem was obvious: the assembly that was placed inside the /bin folder (built automatically  when you publish the web app form within VS ) had a dependency on the 3.5 version of the System.Web.Extensions assembly!

The moral of the story is simple: if you're using VS 2008 and you want to build a 1.0 ASP.NET AJAX web app to deploy on a server which is running version 2.0, then don't forget to set up the version you're compiling against on the property pages of the web project. This is specially true when you're using the publish option, since it'll pre-compile the web app and this will create dependencies between the resulting dlls and the platform dlls (which might not be installed on the server where you're deploying the app).

You should also pay attention to external dlls that are added to your project. For instance, if you're using the AJAX Toolkit, then you should check its dependencies and make sure that it was built against the correct version of System.Web.Extensions.dll.

by luisabreu | 10 comment(s)
Filed under: ,
Changes on the configuration of WCF to use JSON
Mon, Oct 22 2007 22:26

A long time ago I wrote a post on how to configure a WCF service so that it uses JSON as its serialization format. It seems like things change in the last CTP. I still didn't had the time to look into everything but it seems like now you don't add a <bindings> element in order to use JSON. So, what this means is that you'll need something like this to get JSON:

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="TestBehavior">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
                <behavior name="jsonBehavior" >
                    <enableWebScript/>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="TestBehavior" name="Test">
                <endpoint address="" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITest"/>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
            </service>
        </services>
</system.serviceModel>

 

If you compare this with the old post entry, you'll see that you no longer have the <bindings> element and we have also dropped the bindingConfiguration attribute on the <endpoint> element. Another thing I've noticed when I've re-run my old code is that now it seems like the return object is wrapped in another anonymous object which only has one property which points to the element that was returned from your service.

 Still no time to investigate on why this is happening...if anyone knows, please put it in the comments since I won't really have much time to investigate into this...

Update: after receiving feedback from Christian Weyer, I've rerun my samples in a new project created with beta 2. Everything is working ok with this new project, so i think that the problem was with my old project...

ASP.NET AJAX: another trick that might help in some specific scenarios
Thu, Oct 18 2007 22:46

Today I've found another interesting post at the AJAX forums (yep, this is the only forum you can say I read frequently nowadays). The scenarios looks like this:

  • a web app has a main page which is uses as the main entry page )lets call it page a)
  • after clicking on a button, the user is redirected to page b through the Server.Transfer method. this is done so that the url doesn't change (at least that's what the guy said in the forums - interestingly, I've never seen this requirement before, but have seen the opposite quite often)
  • page b has a page method that is called after a click

If you try to build 2 simple pages, you'll see that the page method call is broken in this scenario. why? simple: the call will be made over  page a by default. Can you solve this easily? Yes. How? you just need to remember that page method calls are really similar to web service method calls. After you "get" this, you'll see that your job is really easy: just get a reference to the webrequesmanager client object and handle the invokingrequest event. from within that method, you just need to correct the url to the right page. btw, here's the link to the forum where you can see some client code that performs the operations i've mentioned.

by luisabreu | with no comments
Filed under:
ASP.NET AJAX: some ideas on how to export the contents of a GridView to an excel file without a full postback
Wed, Oct 17 2007 23:08

In the last few days I've returned to the ASP.NET AJAX forums. One of the most requested features I've seen is generating "excel responses" (do you think i should copyright the term? :) ) from data presented on a gridview. There's already a known strategy for doing this kind of stuff from a traditional ASP.NET page: we start by clearing the previous contents that might have been written into the stream associated with the HttpResponse object, create a new Stream derived object and render the grid passing it the previously created stream. then it's just a matter of ending the response (oh, and I've also assumed that you've set the correct type for the response). Here's an example for the previous description.

Enters MS ASP.NET AJAX and the UpdatePanel. the problem is that you cannot apply the previous strategy since the client platform expects to receive a response on a predefined format and, if you follow the Response.Write strategy presented on the previous example, you'll probably end up getting a parsing exception on the client side. So, the problem remains: how can you export the contents of a GridView from an ASP.NET AJAX page?

If you've looked at the previous example, it's obvious that the only thing you need is the table's HTML. After getting it, you only need to set the content type of the response so that it is understood by the browser. If you stop to think for a minute, you'll see that in the client side you've already have the HTML for the table (well, at least that is what I'm assuming from now on). The only thing you need to do is save it to the disk. And this is the problem you have to solve.

The solution I'm presenting for this problem consists in performing the following steps:

  1. create a "hidden" iframe and add it to the current page
  2. add a form and an input field to that iframe
  3. get the html from the grid by using the non-standard innerHTML (which is available in all browsers - at least on the ones I use)
  4. set the input field's value to the innerHTML obtained from grid and submit the form
  5. add a handler which receives the previous form submission and just returns the value of the input field (while setting the content type of the message)

Do notice that the code I'm presenting here was written in about an hour and isn't really production code. The main objective is to present the ideas that you might follow if you need to export a GridView to excel while using the traditional Response.Write technique.

Having said that, it's time to present the code. Since I need to have some data to show in my grid, I've started by creating a new cs file with the following contents:

public class Obj
{
    private Int32 _id;
    private String _name;

    public int Id
    {
        get { return _id; }
        set { _id = value; }
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

public class ObjDS
{
    public List<Obj> Get()
    {
        List<Obj> objs = new List<Obj>
        {
          new Obj{Id = 1, Name = "Luis"}  ,
          new Obj{Id = 2, Name = "Jose"} 
        }
        ;
        return objs;
    }
}

The ObjDS class' objective is to feed the grid automatically through an ObjectDataSource control. The basic code of the page is the following:

<form id="form1" runat="server">
  <div>
      <asp:ScriptManager runat="server" ID="manager" />
      <asp:UpdatePanel runat="server" ID="panel">
          <contenttemplate>
              <asp:GridView ID="GridView1" runat="server" DataSourceID="source">
              </asp:GridView>
              <asp:ObjectDataSource  
                  TypeName="ObjDs"
                  SelectMethod="Get"
                  ID="source" runat="server">
              </asp:ObjectDataSource>
          </contenttemplate>
      </asp:UpdatePanel>
  </div>   
  <input type="button" value="save" onclick="save()" />
  </form>

It's really a simple form with a grid and an HTML button which is going to be used to export the contents of the grid. When the user clicks the button, the save method gets called:

function save(){
    var grid   = $get("GridView1");
    var html   = grid.parentNode.innerHTML;
    var frmWnd = getIFrameWnd();
    var txt    = frmWnd.document.getElementById("body");
    txt.value  = encodeURI(html);
    var frm    = frmWnd.document.getElementById("frm");
    frm.submit();
}

After getting the grid's HTML content, we need to get a reference to the window associated with the iframe that will let us get the "excel response" from the server. Notice that we need a reference to the window object associated with the iframe (not a reference the iframe objec that is introduced on the page - they are different kind of objects!).

Through the iframe's window reference, we can get to the textbox maintained by the form that was injected on the iframe and we can set its value. Submiting the form is all that is need to get the traditional dialog that will let you download the excel file with the grid contents.

You can say that the tricky part is the getIFrameWnd:

function getIFrameWnd(){
    var ifr = $get("xslFrame");
    if( !ifr ){
      createFrame();
    }          
    var wnd =  window.frames["xslFrame"];       
    return wnd;
}

 

We start by trying to get a reference to the iframe object (this will return non null if a previous call has been made). When we don't get a valid reference, we need to create the iframe element and set its content to the form we'll use to get the response from the server. Lets start with the createFrame method:

function createFrame() {
  var frame = document.createElement( "iframe" );
  frame.name = "xslFrame";
  frame.id = "xslFrame";

  document.body.appendChild( frame );
  generateIFrameContent();
  frame.style.width = "0px";
  frame.style.height = "0px";
  frame.style.border = "0px";
}

You might be wondering why I simply didn't set the display to none instead of  setting the width, height and border to 0. Well, this was the first thing that worked with both IE and Firefox (in Firefox I was only able to submit the form if i didn't set the display of the iframe to none). The generateIFrameContent method is also simple:

 function generateIFrameContent(){
    var frameWnd = window.frames["xslFrame"];
    var content = "<form id='frm' method='post' enctype='application/data' action='excelHandler.ashx'><input type='text'id='body' name='body' /></form>";
    frameWnd.document.open();
    frameWnd.document.write( content );
    frameWnd.document.close();
}

Again, notice how we must get a reference to the window object associated with the iframe. The contents of the iframe are set up by using the document.write method. The excelHandler.ashx looks like this:

<%@ WebHandler Language="C#" Class="excelHandler" %>

using System;
using System.Web;

public class excelHandler : IHttpHandler {
    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        String info = HttpUtility.UrlDecode(context.Request.Params["body"]);
        context.Response.Clear();
        context.Response.AddHeader("content-disposition", "attachment; filename=file.xls");
        context.Response.Charset = "";

        context.Response.ContentType = "application/vnd.xls";
        System.IO.StringWriter stringWrite = new System.IO.StringWriter();
        context.Response.Write(info);
    }

}

 

As you can see, there really are lots of things which could be improved in the previous code. For instance, it's easy to change the previous snippets so that it doesn't hardcode the handler or event the file name of the "excel response" that is generated by the server. You might even configure the client save method so that it receives a reference to another another method that would let you filter the html that is sent back to ther server (something you might do if you have buttons in your grid - ex.: select button).

In fact, you could even get fancy and generate an extender that encapsulates all this code and exposes several properties that give you extra power over the way things work...As I've said, my main objective was to present some ideas that might help achieving this kind of things. I'll leave that encapsulation for anyone that is interested :)

Now, this solution won't work in all the scenarios. For instance, if you've got paging, you might need to get everything when you export the grid to excel. The current  code won't work because it simply captures the table presented to the user in the page. Another thing that might look strange is that you're sending the HTML back to the server which is sending it back to you again. This is needed so that you can get the "traditional" dialog that will let you save the file. You might be thinking that this isn't really great when you have a huge grid (and yes, you're right). But imagine that you're using the traditional approach...if you don't have the viewstate disabled (and yes, there are still many guys out there that haven't disabled it yet - ok, if you're one of them, you're still in time to do just that :) ), you'll end up sending even more info back to the server (specially if you have more fields on your page).

So, the code I've presented here isn't perfect (far from it) but the ideas might help you in several scenarios. At least, that is what I'm hoping for...

by luisabreu | 4 comment(s)
Filed under:
You shouldn't call $create from within a component to create another component
Tue, Oct 16 2007 23:09

After another busy day at work and half an hour swimming, I went to the ASP.NET AJAX forums to chill out befire going back to the IIS 7 online docs. Today I've found a cool post )man, you gotta love these forums! :) ) which asked why creating a component through the $create method within the initialize method of another component didn't fire the initialize even on the created component. After some debugging, it was obvious that the problem happened in this method:

 

function Sys$_Application$endCreateComponents() {
    var components = this._secondPassComponents;
    for (var i = 0, l = components.length; i < l; i++) {
        var component = componentsIdea.component;
        Sys$Component$_setReferences(component, componentsIdea.references);
        component.endUpdate();
    }
    this._secondPassComponents = [];
    this._creatingComponents = false;
}

 

In the shown example, the page had only one component. so,whem the code enters the for, components.length is 1 and even though that value is updated to 2 because the new component was added  during one of the steps performed within the for, thr l value won't be updated, thus not calling the initialized method of the second component.

Fortunately, Bertrand was around and clarified the whole thing: you should only use $create when you're creating the component from your page. if you're creating the inner component, then you'll really need to:

  1. create the component by using new
  2. set up its properties
  3. call its initialize method
  4. add it to the Sys.Application component collection )use the addComponent method).
by luisabreu | 3 comment(s)
Filed under:
Getting the UpdatePanel "responsible" for the postback
Mon, Oct 15 2007 12:28

Sometimes, you might need to get a reference to the UpdatePanel which was "responsible" for the partial postback. It's important to understant that a postback will always be started by an existing HTML control and that the panel will only be used for delimiting the places where a partial postback might start. It's also important to understand that you can have a postback without associating an HTML control with an UpdatePanel (ie, you can start a partial postback by registering a control with the AsyncPostBackControl method; when you do this, you'll have a partial postback when a user clicks that button, even though the button is not inside the UpdatePanel nor is it set up as a trigger). ok, having said this, lets suppose you want to get a reference to the UpdatePanel that "was responsible for the postback" (ie, you want to get the UpdatePanel that contained the control that started the partial postback or that is associated with the control through an AsyncPostBackTrigger). The following code uses method extensions to add a method that will let you get a reference to that panel (in the cases where that is possible):

[Disclaimer: this code was written without testing so it might not work in complex scenarios.I might come back to it in the future, but for now I really don't have the time to test it in all the available scenarios]

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web.UI;

namespace LA.Extensions
{
    public static class ScriptManagerExtension
    {
        public static UpdatePanel GetUpdatePanelAssociatedWithRefresh(this ScriptManager manager )
        {
            if( !manager.IsInAsyncPostBack)
            {
                return null;
            }
            UpdatePanel panel = null;
            Control ctlId = manager.Page.FindControl(manager.AsyncPostBackSourceElementID);
            if( ctlId == null )
            {
                return null;
            }

            panel = TryInUpdatePanels(ctlId);
            if( panel == null)
            {
                panel = SearchForTrigger(ctlId, manager);
            }

            return panel;
        }

        private static UpdatePanel SearchForTrigger(Control ctlId, ScriptManager manager)
        {
            Type pageRequestManagerType = Type.GetType("System.Web.UI.PageRequestManager,System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            Type scriptManagerType = typeof (ScriptManager);

            Object pageRequestManager =
                scriptManagerType.InvokeMember("PageRequestManager",
                                                BindingFlags.NonPublic | BindingFlags.Instance |BindingFlags.GetProperty,
                                                null,
                                               manager, null, null);
            List<UpdatePanel> updatePanels =
                (List<UpdatePanel>)pageRequestManagerType.InvokeMember(
                                        "_allUpdatePanels",
                                        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
                                        null, pageRequestManager, null, null );

            foreach(UpdatePanel panel in updatePanels)
            {
                foreach(UpdatePanelTrigger trigger in panel.Triggers)
                {
                    AsyncPostBackTrigger t = trigger as AsyncPostBackTrigger;
                    if (t == null)
                    {
                        continue;
                    }
                    if(String.Compare(t.ControlID, ctlId.UniqueID) == 0 )
                    {
                        return panel;
                    }
                }
            }

            return null;
        }

        private static UpdatePanel TryInUpdatePanels(Control ctlId)
        {
            if(ctlId is UpdatePanel)
            {
                return (UpdatePanel) ctlId;
            }

            Control parent = ctlId.Parent;
            while(parent != null )
            {
                if( parent is UpdatePanel && ((UpdatePanel)parent).ChildrenAsTriggers )
                {
                    return (UpdatePanel)parent;
                }
                parent = parent.Parent;
            }
            return null;
        }
    }
}

 

The following page shows how the previous extension can be used:

<%@ Page Language="C#" %>
<%@ Import Namespace="LA.Extensions" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        UpdatePanel panel = manager.GetUpdatePanelAssociatedWithRefresh();
        if (panel != null)
        {
            lbl.Text = panel.UniqueID;
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager runat="server" id="manager" />
        <asp:updatepanel runat="server" id="panel" UpdateMode="Conditional">
            <ContentTemplate>
                <asp:Button runat="server" id="bt1" Text="inside panel" />
                <br />
                <%=DateTime.Now.ToString() %>
                <br />
                <asp:Label runat="server" ID="lbl" />
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="bt2" EventName="Click" />
            </Triggers>
        </asp:updatepanel>
        <asp:Button runat="server" id="bt2" Text="outside panel" />
    </form>
</body>
</html>

The important thing to notice here is the use of the Import directive so that the method extension is introduced on the current namespace. As I've said before, the objective of the code is to show what you might have to write to get the primary panel associated with the partial postback...

IIS 7 and its integration with the ASP.NET engine
Sun, Oct 14 2007 16:54

Until the release of IIS 7, it was fair to say that the ASP.NET application had its own life cycle, which wasn't really integrated with IIS.  For instance, when you're using IIS 6, a request will have to be authenticated by IIS before it's forwarded to the ASP.NET engine. After getting the request, then ASP.NET engine will run its own authentication again (that is, if the web app is configured to require that operation). So, we really have some sort of duplication, even though the authentication algorithms aren't really the same. Besides this duplication, there were also other problems. For instance, the ASP.NET authorization will only be applied to ASP.NET resources.

The good news is that with IIS 7 the ASP.NET engine can really be integrated with IIS and you no longer have the problems I've mentioned inthe previous paragraph. With IIS 7, you'll even be able to build IIS modules in managed code (yep, no need to write unmanaged code if you don't want to).  In other words, you'll be able to, for instance, apply forms authentication to all the resources served from the server. This integration will only be achieved when IIS is running in integrated mode.

In order to achieve this integration, the IIS 7 has its own configuration API (more info on future posts), which is quite similar to the one used on ASP.NET applications (though there are some nasty details that might get in your way, specially if you're building a section that is supposed to be integrated with the IIS 7 admin console). If you've looked at a recent web.config file, you might have seen a <system.webserver> configuration section. That section is specific to the IIS 7 server. The good news is that many of the ASP.NET modules can be used on IIS 7 since the team wrote several classes responsible  for assuring the correct integration with the server :)

I'm finding IIS 7 so interesting that I think I'll write a couple of posts about it in the next days :)

by luisabreu | with no comments
Filed under:
Going crazy while trying to open the config files of IIS
Sat, Oct 13 2007 21:51

Currently, I use VS 2008 to write all the code and Notepad2 to read txt files. I do also use Notepad2 when I just need to take a quick look at some file. It's been a long time since I have used Notepad. In fact, I've already forgotten about it until today :) Let me explain this better...

While trying to study the new IIS 7, I decided to take a quick look at the new config files and their schemas, which are located on the %windir%\system32\inetsrv\config folder. After getting there, I just tried to double clicked the applicationHost.config file. Hum...nothing happened...weird...ok, so how about opening VS and the dropping the file into it? again, it didn't work...

So, lets go through the file open dialog. this was even stranger since the files were not shown on the dialog...well, the same thing happened when I tried to use Notepad2...believe it or not, the only thing that did the trick was droping the file over the good old notepad... And yes, I've tried everything (I did disabled UAC and used an administrator account but none of the previous approaches worked!)

by luisabreu | with no comments
Filed under: ,
The localhost. trick for intercepting no longer works on windows vista?
Wed, Oct 10 2007 20:33

A long time ago I learnt a cool trick for using fiddler with the internal server that comes with VS. Well, when I made the transition to Vista, it simply stopped working and I no longer got the page on IE. I did managed to get it working but it seems like some of my friends started getting this error. The problem was that the server was not configured to listen on IPv6 but its DNS was configured to send back an UPv6 address.

by luisabreu | 2 comment(s)
Filed under:
No, you cannot call Server.Transfer on an ASP.NET AJAX enabled page
Wed, Oct 10 2007 20:24

Even though ASP.NET AJAX has been here for some time, this question still pops up on the forums. So I thought I should put a post here and redirect future questions on the subject to it.

Well, to be precise, what you cannot do is call Server.Transfer (or other transfer method - btw, if you're using IIS 7, there is a new TransferRequest method that might interest you) if you're on  a partial postback (ie, you have an UpdatePanel on your page and, for instance, you're handling the click event of an ASP.NET button that you've dropped inside the UpdatePanel). The reason for this is simple: a partial request is always started by the client PageRequestManager object. This object expects to receive a text response from the server which must follow a specific format (if you're interested in this kind of thing, then just use fiddler to see what's going on) so that it can parse it and change the page DOM according to the changes that have been made on the server side.

Now, if you're calling Server.Transfer, you're really executing the new page (by using the Server.Execute method) and stopping the execution of the current page(ie, the one that has called the Transfer method). This means that the server side of the ASP.NET AJAX platform won't be able to "intercept" the response and change it so that it is sent back on the specific text format that the PageRequestManager object understands. So, in the client side you'll end up getting the HTML generated by the second page. When the PageRequestManager gets the response, it simply doesn't know what to do with it and it ends up generating a parsing exception.

If you need to transfer the user for another page, you can use  the Response.Redirect method since this can be intercepted by the server side of the plaform during a partial postback. When that happens, the "redirect" will be tranformed on a text message that can be understood by the client side, meaning that you'll get your page navigation, instead of the parsing exception you see when you use the Server.Transfer method.

by luisabreu | 5 comment(s)
Filed under:
Book review: ASP.NET AJAX in Action
Wed, Oct 10 2007 18:54

[Disclaimer: I've received a free copy of the book and I'm a friend of one of the authors. However, I can assure you that none of these things influenced my avaliation of this book]

I've just finished reading my copy of ASP.NET AJAX in Action. What can I say? If you're after a book that has  several cool examples and lots of insights on the platform, then go ahead and buy it. It's really a good book to have around, specially if you're working with the platform (shameless plug again: if you prefer to read in PT, why don't you take a look at my book available on the FCA site?). The authors have covered the client and server components in great detail, giving you lots of good advices on what you should and shouldn't do.

The only thing I didn't really like were the diagrams. I mean, the pictures are really cool, but I still think that relations between classes are better expressed with UML than with some custom diagrams (I've read several technical books and the tuth is that most of them don't use UML, which is really shame...). Having said that, I'll give this book a 9/10 for its content and accuracy (which really means that this is a "must have" book if you're trying to learn the ASP.NET AJAX platform).

by luisabreu | 8 comment(s)
Filed under:
At the end of the day, AJAX classes are functions
Tue, Oct 9 2007 23:08

While I was hanging around the AJAX forums, I found this interesting thread. The problem was a stack overflow, but the interesting thing was what was causing that error in the first place.

here's the scenario: a top page has a method that receives an object. It also has an iframe which loads another page. Both pages load the same custom js file that defines an AJAX class (ie, a class defined by using the ASP.NET AJAX OO helpers). The method of the main page did only one thing: it called the IsInstanceOfType method, passing it the parameter the method received. The inner page had one button that would call the main page method and would pass an instance  of the custom class defined on the custom js file (take a look at the thread to see the code).

Even though some might expect that the line

var typeResult1 = JasonSoft.JWindow.isInstanceOfType(arg1); 

will be true, it won't. Internally, that method will end up comparing the constructor of the type (represented by a function object)  with the constructor associated with the object arg1 (which is also a function). If you recall that arg1 was passed from a different window, then you might see that, even though conceptually the object is of the "same" type, the truth is that it's not. Why? simple: the types were defined in different windows, which means that we're talking about 2 different methods (just think about .NET and identity vs equality check between objects). So, the key here is understanding that if you define the same AJAX type on different windows, then you're talking about different types.

by luisabreu | with no comments
Filed under:
Wilkinson cool video
Tue, Oct 9 2007 22:49

Check it out here.

by luisabreu | with no comments
Filed under:
Are you using the new TransferRequest?
Tue, Oct 9 2007 22:21

If so, then read on because you might get caught by some issues associated with the ASP.NET session state. If you haven't heard about this new cool method, then you don't know what you're loosing. The first thing you should know before hand is that you will only be able to use the method if you're hosting your pages on IIS 7 (the method won't work with previous versions of IIS).

ok, so what does this method do? well, for the page programmer, it's really similar to the old Transfer method, but better. When you issued a Server.Transfer, you're basically creating a new instance of the default page destination and executing it. It's really fast, but there were some problems with it. For instance, if you were writing  module, there was simply no way to get a reference to that new page since that page would be instantiated "in-place" in the curren request. That's why Paulo create the cool Page Module concept. Even though that concept would let you get a reference to the page, you'd still have to be very carefull because the new page request wouldn't go through the ASP.NET pipeline (like what happens when you perform a normal request for a page).

Well, I'm glad to see that this no longer happens with the new TransferRequest method. Internally, it'll perform a complete request by using a IIS 7 worker thread. Basically, this means that the page request will go through the complete ASP.NET pipeline, giving every module a chance of interacting with the request. For instance, this means that authorization will be applied to the new url you're asking (which to me is something really cool :) ). Another great thing: you can redirect to any handler (which really didn't happen with the old Transfer method). And it seems like you can even define the headers that will be passed to the new handler you're asking for since one of the overloads of the method expects NameValueCollection parameter (ok, i really didn't test this :)).

Ok, now we know it's cool. but does it have any problems? well, yes, it has one big gotcha: if the parent request (the one from which you call TransferRequest) has acquired session state, then you need to release it before calling the method.  If you don't, then the new request will block for several seconds. Do notice that this will affect mostly pages since the problem won't appear if you call the method before the AcquireRequestState or after the ReleaseRequestState HttpApplication events.

Here's why: if the parent request has acquired session state and calls TransferRequest, it'll wait until  the child request finishes in order to execute the end request notifications. The end request notifications is the place where the request releases the session state (if it has acquired it). Well, it just happens that when the child request starts executing, it tries to  get the session state (again, only if you're using it) which hasn't been released by the parent request. so, we're in a dead lock scenario (to be precise, this is not really a dead lock scenario because there's a timeout which will eventually be responsible for freeing the session and letting the child request go ahead and use it).

Ok, there's a workaround for this, but it's a little messy. The idea is to make sure that the parent request will release the session before starting the child request. To achieve this, you can call the CompleteRequest method and then, from within a method that handles the EndRequest event raised by the HttpApplication, you should perform the TransferRequest method call. Here's a global.asax file that shows how to achieve this easily:

<%@ classname="MyApp" %>

<script language="C#" runat="server">

string _transferRequestPath;

public void TransferRequest(string path) {
    // remember the path for later
    _transferRequestPath = path;

    // short circuit the pipeline by jumping to the
    // end request notifications where we can release
    // session state
    this.CompleteRequest();
}

// In Session_Start, we acquire session state.  This will
// cause TransferRequest to hang unless we release session state first.
void Session_Start() {

}

// By the time Application_EndRequest is called, session state has been released
void Application_EndRequest() {

    // we may need to call TransferRequest
    if (_transferRequestPath != null) {

        // make copy of path and set instance field to null
        // since application instances are pooled and reused.

        string path = _transferRequestPath;
        _transferRequestPath = null;

        Context.Server.TransferRequest(path);
    }
}

</script>

Special thanks go to Thomas Marquardt  for helping me out with this crazy transfer bug that appeared on a simple app when I dropped an empty global.asax file*. Besides finding the bug in a record time, he also wrote a quick workaround for it (shown before). Another thanks to Mike Volodarsky for heping me understand the purpose of  the several methods that let you transfer a request.

 

* guess what, the empty global.asax had an empty Session_Start method. When this happens, you'll end up getting a session ID and you'll end up acquiring the session, leading you to the problem I've just described

by luisabreu | 8 comment(s)
Filed under:
Workaround for Safari on dual monitor Windows OS
Sat, Oct 6 2007 19:05

Today I've received a mail with a comment for an old post I've written about Safari not being ready for dual monitor systems. It seems like Justin Megawarne has got a decent workaround for that problem. here are the necessary steps:

  1. Maximize Safari on second monitor
  2. Press ALT+SPACE to drop down context menu
  3. Press M to select Move
  4. Use LEFT key to move Safari into position
  5. Press ENTER to set position

Thanks Justin!

by luisabreu | with no comments
Filed under:
MS will release the source code for the .NET platform
Wed, Oct 3 2007 22:34

Read more about it here.

by luisabreu | with no comments
Filed under:
Getting along with Access 2007...
Wed, Oct 3 2007 1:09

well, not really :)

It's a fact of live that I have never really enjoyed Access, specially when you use it as database. Unfortunately I had to work with it again, after so many years of joy with SQL Server. Ok, so it seems like Office 2007 introduced new drivers for OLE DB and ODBC drivers. This seems to be confirmed by connectiongstrings.com since they're presenting a new syntax for connecting to a MS Access database:

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;

Ok, now that I've got the connection string, what else can go wrong? As it turned out, plenty of things :) For starters, the new drivers weren't installed with Office, which means that I needed an aditional download. Ok, now that I've installed it, I never though I'd keep seeing the message "Microsoft.ACE.OLEDB.12.0 is not registered local machine".

well, guess what? I'm running Vista 64 bits and the damn drivers are 32 bits. Since VS is automatically compiling to 64 bits (in fact, it's using the "Any CPU option", which means that the JIT will compile it to 64 bits, if i'm not mistaken), then I'm in trouble because i cannot load a 32-bit driver on a 64-bit process. what this means is that i had to change my build configuration so that it'll always compile into 32-bits...

Ok, now I'm really shocked to see that Access still can't support batch statements...I'm really hoping that I'm wrong, but it seems like i still can't do something like this:

sql = "insert into....;select @@identity"

At least it can return you the last ID inserted on the table :) You can say that I really didn't google for it, so please please tell me I'm wrong  (hum...please don't tell i'm wrong using access as a database since I already know that :) ; just tell me that it's possible to run batches and that I don't really need to handle the row updated event like this posts sugests...)

by luisabreu | with no comments
Filed under:
MVP for 2008
Mon, Oct 1 2007 23:56

It seems like my MVP award for ASP.NET has been renewed :) hurray! Thank you MS. Congrats to all those that have also renewed and to the new ones that have just become MVP for the first time!

by luisabreu | 2 comment(s)
Filed under:

Search

This Blog

Tags

Community

Archives

Syndication

Email Notifications

News




  • View Luis Abreu's profile on LinkedIn


    Follow me at Twitter

    My books

    Silverlight 4.0: Curso Completo

    ASP.NET 4.0: Curso Completo

    Portuguese LINQ book cover

    Portuguese ASP.NET 3.5 book cover

    Portuguese ASP.NET AJAX book cover

    Portuguese ASP.NET AJAX book cover