March 2008 - Posts

Making the UpdatePanel accessible
Mon, Mar 31 2008 22:30

Bertrand has written a great article for the dotnetslackers web site on how to make the UpdatePanel acessible. Great read, don't miss it!

by luisabreu | with no comments
Filed under: ,
WCF again: the slow problem attacks again
Wed, Mar 26 2008 0:22

On a different set of machines...I'm stumped. I mean, I though I'd nailed it with the proxy problem, but unfortunately there are still some machines where the 1st call is really really slow and removing the proxy isn't helping. I've even profiled the code but  I still can't see where the problem lies. I've written a post on the WCF forum, but there are still no clues on how to solve this. Anyone wants to give it a try?

by luisabreu | 1 comment(s)
Filed under:
The dataItems dictionary
Mon, Mar 24 2008 20:50

Today I noticed that there are still many guys that don't know about the dataItems property which is exposed by the Sys.WebForms.PageRequestManager. So, I decided to write a small sample that will show you how to use it when you're using partial updates and need to send some info back to the client during a partial postback.

So, here's a really simple example which really doesn't do anything but show how to use this property. Lets suppose that I need to send an object (which has two properties called Name and Date) from the server side to the client during a partial postback. There are several options for achieving this but the easiest is to use the dataItems property.

Lets start with a simple page:

<asp:ScriptManager ID="manager" runat="server" />
<div>
<asp:UpdatePanel runat="server" ID="panel">
   <ContentTemplate>
     <asp:Button runat="server" ID="bt" Text="Get stuff" OnClick="HandleClick" />
   </ContentTemplate>
</asp:UpdatePanel>
</div>

On the server side, all the action happens in the HandleClick method:

protected void HandleClick(Object sender, EventArgs e)
{
        if (!(IsPostBack && manager.IsInAsyncPostBack)) return;
        var obj = new { Name = "Luis", Date = DateTime.Now };
        manager.RegisterDataItem(panel, new JavaScriptSerializer().Serialize(obj), true);

}

Thank god we have C# 3.0! Without it I'd have to write a dumb class just for demonstration purposes :) After checking if I'm in a partial postback, I'll just go ahead and serialize my object and pass it to the RegisterDataItem method. Notice that I'm also passing the panel since it will be used as the key to index the data. Now I can show you the Javascript code that will recover those values:

<script type="text/javascript">
  Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(handleLoaded);
  function handleLoaded(sender, e){
    if( sender.get_isInAsyncPostBack() ){
      var aux = e.get_dataItems()["<%= panel.ClientID %>"];
      alert( aux.Name + ":" + aux.Date );
    }
  }
</script>

As you can see, I need the client ID of the panel in order to retrieve the info I've just serialized in the server side. The cool thing about this is that I'm getting a JS object which has exactly the same properties as the object that was serialized in the server side. Notice also that I'm using the isInAsyncPostBack property to run my code only after running a partial postback (and I'm doing it from the pageLoaded event).

Ok, there might not be many scenarios where you'll need this but this technique really shines when you need to get back more info during a partial postback.

by luisabreu | with no comments
Filed under: ,
ASP.NET MVC source code available on codeplex
Fri, Mar 21 2008 16:12

I've just read about it on ScottGu's blog. It seems like the MVC code is live on the codeplex site.

by luisabreu | with no comments
Filed under:
xUnit.NET RC2 released
Thu, Mar 20 2008 23:00

I've just noticed that xUnit.NET RC2 was released a few days ago. It seems like it has several cool things, though there still isn't a runner for R# 4.0.

by luisabreu | with no comments
Filed under: ,
WCF client calls slow
Fri, Mar 14 2008 12:09
Today I was able to get back to my previous WCF client problem that I had described here. After looking at the old logs again, it was clear that the delay was on the server discoverability. The problem was that pinging was really fast, so it seemed like there was no client/server communication problem. You can say that I'm a curious stubborn guy and since I thought the discovery thing was the problem, I decided to look at the IE settings. And guess what? It had the automatically detect settings of the LAN Settings option turned on. Turning it off solved the 1st time request. After knowing the problem, it was really easy to get a confirmation for it: Dr. Nicholas Allen had already a great entry which discusses this kind of problems.
by luisabreu | with no comments
Filed under:
It's official: the latest version of my ASP.NET PT book is out
Thu, Mar 13 2008 11:10
The most interesting thing about the release (besides the new chapter and updates I've made to the content) is that my friends Paulo and Israel managed to blog about it before me :)
by luisabreu | 7 comment(s)
Filed under:
More on the MVC approach
Thu, Mar 13 2008 0:27

It seems like I wasn't the only one trying to reuse the MVC routing engine with ASP.NET: check the Chris' post and Haack's reply. Haack's code is really cool and shows an even easier way to pass data to the page...
by luisabreu | with no comments
Filed under:
Using the routing MVC API with classic ASP.NET
Wed, Mar 12 2008 1:07

I admit it: I'm getting rusty on web development! In these last months I've been building Windows Forms apps with C#. So, I still didn't had the time to look at the ASP.NET MVC platform or the new Silverlight release. Anyway, I'm hoping that this will change in a near future (which can happen even faster if I'm able to get a job that will let me write ASP.NET code full time - anyone has any offers? :) ).

When I fired .NET Reflector today and loaded the MVC dlls, I got a pleasant surprise: there's System.Web.Mvc assembly! To me this means that the routing engine got decoupled from the MVC platform, which leads me to conclude that it should be possible to reuse the routing engine with classic ASP.NET apps (ie, Web Forms applications). When would you want to do this? Well, how about reusing it for url rewriting?

Lets try something simple built in 5 minutes by a guy (ie, me:)) which hasn't built anything with MVC yet nor has had any time to look at its internals. First, we need to add the UrlRoutingModule (so that it is able to process the custom urls we're adding to the routing table) by adding a new entry to the httpModule section (btw, I'm assuming that you've already dropped the System.Web.Routing and the System.Web.Abstractions assemblies on the bin folder of your web app):

<add name="urlRouting" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing"/>

After doing this, I created 2 simple pages (called Default.aspx and Default2.aspx -as you can see, I was inspired:) ). In this stupid example, I'm going to say that principal will redirect to default and other should redirect to Default2.aspx (not really what you 'd do on a real app, but my time is really limited today :( ). So, what I need to do is add these entries to the rounting table and specify the IRouteHandler that will be responsible for handling the request. The IRouteHandler's job is returning an IHttpHandler which will handle the request and return a response to the user. In this case, we only need build a class that implements the IRouteHandler and let it instantiate the page that should handle the current request.

Lets start by specifying the entries on the routing table. You can do it on the global.asax file with this code:

static void RegisterRoutes()
{
        System.Web.Routing.RouteTable.Routes.Add(
            new System.Web.Routing.Route("principal", new LA.Handlers.PageHandler() ) );

        System.Web.Routing.RouteTable.Routes.Add(
            new System.Web.Routing.Route("other", new LA.Handlers.PageHandler()));
}
void Application_Start(object sender, EventArgs e)
{
        // Code that runs on application startup
        RegisterRoutes();
}

What we're saying here is that all the requests to principal should be redirected to the PageHandler route handler (don't forget to add the mvc extension if you're trying this with IIS 6).

The PageHandler class is really simple:

namespace LA.Handlers
{
    public class PageHandler:IRouteHandler
    {

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            IHttpHandler handler = GetHandlerFromRequestContext(requestContext);
            return handler;
        }

        private IHttpHandler GetHandlerFromRequestContext(RequestContext requestContext)
        {
            VirtualPathData pathData = requestContext.RouteData.Route.GetVirtualPath(requestContext, requestContext.RouteData.Values);
            return pathData.VirtualPath.Contains("principal") ?
                (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath("~/Default.aspx", typeof(Page))
                :
                (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath("~/Default2.aspx", typeof(Page));
        }       
    }
}

We start by getting the VirtualPathData object form the current RequestContest. This object will lets us know the current requested url and you'll be able to create an instance of the page by using the BuildManager.CreateInstanceFromVirtualPath method. Again, do notice that the comparison I'm using is really too simple for real production code: my objective is to show how you can reuse the routing engine on a traditional ASP.NET app.

Ok, I can hear you saying: man, what about query string parameters? I'll only use url rewriting to hide those ugly urls. Ok, no problem! here's what you can do

  1. add an entry to the route table and specify the parameters you need
  2. pass those values to the page.

Now, the hard part is passing the values to the instantiated page. The easiest way I can think of is using the HttpContext.Items property to pass that data around. So, let's change the principal entry so that it receives another parameter:

System.Web.Routing.RouteTable.Routes.Add(
            new System.Web.Routing.Route("principal/{id}", new LA.Handlers.PageHandler() ) );

The {id} will automatically collect the info you pass after principal and add it to the RouteData dictionary exposed by the RequestContext object you'll receive on the IRouteHandler.GetHttpHandler method. The only change needed on our handler is presented on the next snippet:

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
            IHttpHandler handler = GetHandlerFromRequestContext(requestContext);
            foreach (var aux in requestContext.RouteData.Values)
            {
                HttpContext.Current.Items[aux.Key] = aux.Value;
            }
            return handler;
}

And now you'll only have to change your page so that it checks if there's a valid Id on the query string parameter (if you're expecting a direct access to the page) or on the Items property of the current context. Simple, right?

by luisabreu | 4 comment(s)
Filed under:
WCF+Windows Forms = lots of problems with some services
Tue, Mar 11 2008 0:15

In these last days I've been really busy finishing an application which consists of a Windows Forms app that gets its data from serveral WCF services (which, btw, use basic HTTP binding + SSL). Now, most of the services work really smoothly, but...there are 2 which are really making me go crazy: they are SLOW when run in Windows XP Pro machines! Now, I'm talking about really simple services which should really execute under 300 ms!

As you might expect, the first thing I did was use fiddler to see what was going on. According to it, the request was taking 15 seconds, which seemed to confirm my initial impression that there was something wrong with the service. The next logical step was enabling tracing on the WCF service. I couldn't really believe in what my eyes were seeing: instead of seeing several seconds on processing time, the traced shown <300 ms. Could it be something wrong with IIS (which, btw, is IIS 6 on  Windows 2003 Server machine)? To answer this, I enabled IIS logging. Guess what: IIS logging confirms the WCF tracing entries: requests were served in <300 ms!

Maybe there something wrong with the network? Pinging revealed nothing wrong...So I went ahead and installed netmon on my machine. After filtering the traffic, I was able to see that request/response from client to server were consistent with the logging info I was getting from WCF and IIS. So, I've just went ahead and tried using ngen with my client windows forms app. It didn't made any difference though...it was time to try one more thing: logging on the client side.

The SvcTraceViewer tool has a really great feature: you can open several trace files at the same time. When I did this, I got the following results (just copy/paste it here: on each line you'll see a description, the number of traces, the start and end time of the action):

 

000000000000 8 13s 9:21:20 9:21:34
Construct ChannelFactory. Contract type: 'SRA.Mercados.Servicos.IServicoUtilizador'. 4 328ms 9:21:20 9:21:21
Open ChannelFactory. Contract type: 'SRA.Mercados.Servicos.IServicoUtilizador'. 4 31ms 9:21:21 9:21:21
Process action 'http://sra.pt/Mercados/IServicoUtilizador/ObtemUtilizador'. 24 14s 9:21:21 9:21:35
Receive bytes on connection 'http://bksrv.sranet.local:8080/ServicosMercados/UtilizadorImpl.svc'. 17 437ms 9:21:34 9:21:35
Close ChannelFactory. Contract type: 'SRA.Mercados.Servicos.IServicoUtilizador'. 4 0ms 9:21:34 9:21:34

Construct ServiceHost 'SRA.Mercados.ServicosImpl.ServicoUtilizador'. 10 109ms 9:21:34 9:21:35
Open ServiceHost 'SRA.Mercados.ServicosImpl.ServicoUtilizador'. 64 93ms 9:21:35 9:21:35

Listen at 'http://bksrv.sranet.local:8080/ServicosMercados/UtilizadorImpl.svc'. 6 62ms 9:21:35 9:21:35
Listen at 'https://bksrv.sranet.local/ServicosMercados/UtilizadorImpl.svc/mex'. 4 15ms 9:21:35 9:21:35
Processing message 1. 5 15ms 9:21:35 9:21:35
Execute 'SRA.Mercados.Servicos.IServicoUtilizador.ObtemUtilizador'. 4 265ms 9:21:35 9:21:35

The bold lines are where the problems are happening. Now, I really don't understand why it takes 13 seconds for the process action on the client to hit the server (notice that server will only start its processing at 9:21:34 and that the client opens the channel at 9:21:21!). Now, I'm not really an expert on WCF, but it does seem like there's something wrong going on here. What's bothering me is that I don't know what it is :)

It was getting late, so I only had time for testing one more thing: using perfmon and see if I can get any info from it. I've only tried seeing one thing: the % of JIT time spent on a process. Guess what: the counter goes through the roof when I call a method of one of those services that take a long time! I'm still trying to understand what's going on with those XP machines (specially because on my Windows 2008 server everything is working out smoothly), but it seems like there's something that is making the Jitter do a lot of work when one of those methods gets called. I'm not sure on what it is since, as I've said, it's really a simple method and I've already run ngen on my code.

If anyone has any idea on what's going on here please do share it with me! I'm running out of them and I still don't understand what's going on...thanks.

by luisabreu | 2 comment(s)
Filed under: ,
Silverlight 2.0 beta 1 is out
Wed, Mar 5 2008 22:30

So, while I was busy playing with my new HTC Touch, it seems like MS has presented Silverlight 2.0 beta 1. Now, this is really a tough choice...

by luisabreu | with no comments
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