March, 2007

  • Never doubt thy debugger

    If an EventHandler is called twice...

    • 4 Comments

    ...take a close look at your code smile_regular.

    This comes from a case I worked on in the last couple of days: a customer reported a problem in one of his ASP.NET 2.0 pages, which is meant to perform some sort "long running" operation on the server. What puzzled me a bit (well... quite a bit, at the beginning) is the fact that after the user clicked posted the page (clicking on a submit button) and the long operation begun on the server, after about 90 seconds they noticed a new click button for the submit event was fired, thus restarting the whole "long" operation (and of course leading of all sort of problems this implies for the application's logic).

    Doing some tests we found that more that the above, even if he closed the browser on the client immediately after submitting the form, after about 90 seconds they still got a second click event firing for the submit button! smile_whatchutalkingabout Of course if the browser is closed on the client, it's hard to believe that the new click and subsequent post is coming from the user... smile_sarcastic

    We looked and the page source produced by the server, here is an interesting excerpt:

    <input type="button" name="ctl00$ContentPlaceHolder$ButtonSubmit" value="Submit data" 
        onclick="this.disabled=true; this.value='Please wait...';
        __doPostBack('ctl00$ContentPlaceHolder$ButtonSubmit','');
        __doPostBack('ctl00$ContentPlaceHolder$ButtonSubmit','')" 
        id="ctl00_ContentPlaceHolder_ButtonSubmit" 
    />

    (note that I broke the onclick Javascript line value only for formatting purposes in this post, that was on a single line) 

    It is clear that ASP.NET generate that button with wrong content for the onclick event handler, note the duplicated "__doPostBack(...) call". Question is: why?

    The customer sent me the click event handler method and the button declaration, which looked like the following:

    <asp:Button ID="ButtonSubmit" runat="server" CausesValidation="False" 
        Text="Submit data" OnClick="ButtonSubmit_Click" 
        UseSubmitBehavior="false" 
    />

    (they also had AutoEventWireup="true" in their @Page directive, and this is what actually put us on the right track even if not directly involved in this problem)

    The customer then reviewed more closely some of their code (unfortunately he inherited this project and did not worked directly on the code, so he didn't know all the details...), and found that in the Page_Load handler they dynamically added a Javascript call to __DoPostBack(...) using code similar to the following:

    ButtonSubmit.OnClientClick = ButtonSubmit.Page.ClientScript.GetPostBackEventReference(ButtonSubmit, null);

    So, now is clear that the problem was cause by both ASP.NET adding the callback handler because of UseSubmitBehavior="false" in the button declaration, and the GetPostBackEventReference(...) call in the Page_Load method; the customer was therefore able to fix the problem simply changing the button declaration to use UseSubmitBehavior="true" (which, by the way, is the default, read the MSDN reference for further details.

     

    Cheers

  • Never doubt thy debugger

    CSSVista and IE Developer Toolbar to easily customize how your site/blog looks

    • 2 Comments

    While working to customize a bit my blog (and you can easily see I'm not a graphic designer! smile_thinking) I struggled trying to understand and sort out the tangle of CSS styles I can override to change how these pages look (at this is still "work in progress").

    Luckily in our internal blogger discussion list someone (don't remember exactly who, sorry...) suggested to use CSSVista, a cool tool which allows you to edit your CSS styles and have a "live" preview of what the results are. If you use this in combination with the IE Developer Toolbar, which allows you to easily inspect the DOM in your page and find which CSS style is applied to every element (among many other things you can discover with the toolbar) and with some experience with CSS editing, it should not be that hard to restyle your page.

    The only problem left is how it will look like at the end... fingerscrossedsmile_sarcastic (I definitely need some graphic advices...)

     

    Cheers

  • Never doubt thy debugger

    New hotfix for ASP.NET 2.0 (CS0006 & FileNotFoundException)

    • 1 Comments

    I recently worked with Jerry and Doug on a sporadic problem reported by a customer (Compiler Error Message: CS0006: Metadata file 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\<path>\<assembly>.dll' could not be found), and doing some researches I found they were already working on a fix for this problem (and a couple of other ones related to the same code area). I sent the private fix to the customer for testing in his real (non production!) environment, and after he confirmed the problem was solved without side effects, the Product Team went ahead and produced the final fix. Here are the error messages:

    • Exception message: Could not load file or assembly '<assembly>, Version=<version>, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified
    • Compiler Error Message: CS0006: Metadata file 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\<path>\<assembly>.dll' could not be found
    • System.InvalidOperationException: The resource class for this page was not found. Please check if the resource file exists and try again

    Typically you get those errors when the application is running under high load (but that may not only be the only case), and the workaround to resolve the situation is to clear the Temporary ASP.NET Files folder and/or restart the application pool.

    The KB article for this is still a draft (but I guess it should be published soon, I'll link to it when available), but the fix you can request to CSS in case you need it, is 934839.

    Update (30/3/2007):
    The KB article as been published a couple of days ago, read it here.

     

    Cheers

  • Never doubt thy debugger

    Session_OnEnd not firing after applying Windows 2003 Service Pack 2

    • 48 Comments

    We very recently discovered a bug in classic ASP (asp.dll) you get installing the Service Pack 2 for Windows 2003; removing the SP2 makes it work again as expected, so this is a regression bug introduced by the service pack itself. Basically with SP2 installed, the Session_OnEnd() method in classic ASP is not fired anymore, thus breaking all applications which rely on that event to run cleanup code.

    We already have some reports from customers, either directly to CSS or in Newsgroups. I know my colleagues are already well on this, a private fix has been produced and is being tested internally (as far as I know it works) and we are writing a KB article to document this.

    The process is still ongoing so I don't have (and can't give you) further details on this, but I guess it's a matter of days before this will be publicly available; of course I'll update this post when we'll have the KB available.

    Update (03/04/2007)
    The KB article is still a draft and not public yet (should be released soon, anyway) but the fix is ready; you can get it calling CSS and ask for the hotfix #934903.

    Update (17/04/2007)
    The KB article has been published: http://support.microsoft.com/default.aspx?scid=kb;EN-US;934903

     

    Cheers

  • Never doubt thy debugger

    Charting in ASP.NET (alas: GDI+ not supported in a service)

    • 6 Comments

    A few weeks ago we had an interesting discussing in my team (triggered by a customer's request for some hints on charting in ASP.NET) about the use of GDI+: here is what the documentation states on the subject (and what spurred the customer on opening a Service Request with CSS):

    Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.
    (from http://msdn2.microsoft.com/en-us/library/system.drawing.aspx)

    Just to clarify: they were not experiencying any particular problem and you can go with GDI+ if that workes fine according to your requirements, but the statement above means that CSS can't help you if you are running into troubles with it...

    Customer concern and question: Searching the internet, most of the samples for ASP.NET applications providing charting work with GDI+; there are even books on this topic. Why Microsoft is not supporting GDI+ in ASP.NET? If we want to build charts on our own, what design can we use which Microsoft DO support?

    Well... GDI+ ins't supported from a service because those components/classes where not designed/tested to run without an interactive desktop in a high-load environment.

    Even using pure native GDI from a non interactive context has always been a pain (at least from my experience). All GDI functions are based on a device context that we have to map to an existing device, especially when using non interactive context; those libraries work great from MFC or any other interactive application, but were just not designed for silent applications.

    As far as I know GDI+ is mostly a managed wrapper on GDI (but I'm not a real expert in this area, so feel free to correct me if you wish smile_wink), so I assume the test cases for those wrapper were not deep enough to ensure all external calls will be handled correctly without an interactive desktop attached. In my experience with GDI+ within ASP.NET application, even if it’s not supported in most of cases it works fine.

    We had cases in our team where the process was hung, and it turned out that most of time the hang was caused by GDI+ critical sections not correctly released because of lack of Dispose() calls. That’s very important in GDI+ to always have reliable Dispose(), since most of GDI+ critical sections are released there. We mostly had problem with Fonts, process was stucked in GdiPlus!GdipNewPrivateFontCollection(), GdiPlus!GdipGetGenericFontFamilySerif(), etc…

    Often, the problem was coming from exceptions raised in the Dispose call (from the Finalizer or explicit ones)  that were not handled correctly, and leading to that critical section lead. From what we saw, having reliable exception handling/GDI+ objects disposition allows to have a stable situation (but still unsupported…) .

    Then what Microsoft can recommend to generate graphs from an ASP.NET  application/service?

    I would say the more reliable way is a GDI COM component, developed in a smart way, and tested enough in non interactive contexts. That’s the way all good third party native charts components are developed. The other points I was thinking about are native enhanced metafiles, or maybe even OpenGL code. I’m not experienced enough with it, but I think you have less requirements from a non interactive desktop.

    From a pure managed perspective, I doubt you’ll find a reliable & supported way to generate such graphs. From the non deterministic way of managed code works, it’s really hard to interact with GDI subsystem in a highly reliable way…. So in my opinion… that’s just a not-any-supported-way issue…

    Cheers

    P.s.
    Thanks to my colleagues Nicolas Dietrich from CSS France and Stefano Pronti from CSS Italy for sharing their thoughts on this topic! smile_nerd

  • Never doubt thy debugger

    Advanced ASP.NET 2.0 and deep dive Ajax training

    • 0 Comments

    Last week I attended an advanced ASP.NET 2.0 training with deep Ajax dive in our sub in Munich; for my convenience I flew in on Monday morning (I had to wake up at 4 a.m. to go to the airport smile_yawn), jumped on a S-Bahn train to the station of Lohhof and after that I had almost no idea where to go exactly because that was my first time there, but right out the station there is a nice road sign indicating "Microsoft -->"  smile_regular, and then signed-in right on time for the first day start.

    It was a Develop Mentor training set up just for us CSS Engineers (well, actually the only 5 attendants are all from my virtual team smile_omg); the weather in Germany has been quite bad, lots of rain and icy wind (I actually got a cold with a temperature, a cough... all the stuff smile_sniff), all the hotels in town where full because of some kind of industrialists meeting (not exactly understood what) so I had to accept the only with some rooms available... not a good experience for my first time in Germany, but at least the training was well worth all of those troubles!

    The trainer (Dan Amiga) left me a very positive impression, we also had some discussions on the inside of the technology which is what we as Support Engineers most need to do our job, and this also raised some discussions on topic I thought were clear for everyone, but maybe it worth spending a few words on them...

     
    Shared AppDomain... shared what??

    Speaking about AppDomains, we have one of them for every application running inside the worker process (plus of course any additional AppDomain you create, or created by other components you are using), there are three more special domains: the System Domain, the Default Domain and the Shared Domain (which is where assemblies from the GAC are loaded). So even if you run a simple ASP.NET application on your web server, you'll have at least 4 AppDomans: further details here and here.

     

    maxWorkerThreads default value

    The default value for this property is "20". Remember that if you are running on Windows 2003, most of the values from the <processModel> section will be ignored but the following:

    • autoConfig
    • maxIoThreads
    • maxWorkerThreads
    • minIoThreads
    • minWorkerThreads
    • requestQueueLimit
    • responseDeadlockInterval

     

    What can unload my AppDomain?

    One of the following:

    • Machine.Config, Web.Config or Global.asax are modified
    • The bin directory or its contents is modified
    • The number of re-compilations (aspx, ascx or asax) exceeds the limit specified by the <compilation numRecompilesBeforeAppRestart=/> setting in machine.config or web.config (by default this is set to 15)
    • The physical path of the virtual directory is modified
    • The CAS policy is modified
    • The web service is restarted
    • (2.0 only) Application Sub-Directories are deleted (see Todd’s blog http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx for more info)

    So in 2.0 if we precompile our site using "Use Fixed naming and single page assemblies" setting, we can update just one "page" (one dll) instead of redeploying the entire application, but this will trigger an AppDomain restart anyway.

     

    Cheers

  • Never doubt thy debugger

    Watch out your Web Events!

    • 0 Comments

    In ASP.NET 2.0 we have a new powerful monitoring feature called "Web Events" which help keep track of important events happening during your application's lifetime, such as the application is starting, is stopping, it has been recompiled, exceptions etc... Web events are consumed by providers (listeners), which read the information packaged with the event and then record the information. Each provider is written to record the Web event data in a different way. For example, one provider might write to the Windows event log, while another might send an e-mail message.

    We have several built-in Web Events and 3 Providers available, and of course you can build your own using the classes provided in the System.Web.Management namespace; however there are only two events enabled in the rules element: All Errors and Failure Audits. Both are enabled and are subscribed to by the EventLogProvider.

    In it's simplest form, for example, you can tell ASP.NET to make an event log entry each time an application starts or shuts down by adding this to the <system.web> section of the web.config file for the application:

    <healthMonitoring enabled="true" heartbeatInterval="0">
        <rules>
            <add name="Lifetime event logging rule" 
                eventName="Application Lifetime Events" 
                provider="EventLogProvider" />
        </rules>
    </healthMonitoring>
    

    The sample code above creates new entries in the Application event log, but you can also choose to store them in Sql Server, or use the WMI provider, or send them by email etc...
    Of course this has a performance cost: you can limit the number of event notifications that occur in a given time span and specify the interval between events using attributes of the rules element. The following example shows a fragment from the configuration file in which the Default profile is configured for Failure Audit events. The Default profile specifies the following settings

    • The minimum number of times an event can occur before an event notification is sent is 1
    • The maximum number of times an event can occur before notifications stop is 2147483647 (infinite)
    • The minimum time interval between two events is one minute

    By default, the ASP.NET health-monitoring system can deliver Web event data using the built-in providers (EventLogWebEventProvider, SqlWebEventProvider, WmiWebEventProvider, SimpleMailWebEventProvider, TemplateMailWebEventProvider and TraceWebEventProvider); more than one provider can listen for the same event, and more than one event can be consumed by the same provider.

    Back to the sample code above, I used it in a case where a customer reported some unexpected AppDomain restarts; after enabling Web Events for the target application we got several entries in the Application event log similar to the following:

    Event Type: Information
    Event Source: ASP.NET 2.0.50727.0
    Event Category: Web Event
    Event ID: 1305
    Date: 10/03/2007
    Time: 10.53.47
    User: N/A
    Computer: CARLOC02
    Description:
    Event code: 1002
    Event message: Application is shutting down. Reason: Configuration changed.
    Event time: 10/03/2007 10.53.47
    Event time (UTC): 10/03/2007 9.53.47
    Event ID: 62cf5eed0f54464396b8f4d84e966a43
    Event sequence: 12
    Event occurrence: 1
    Event detail code: 50004
    Application information:
    Application domain: 85c63a25-1-128179939913281250
    Trust level: Full
    Application Virtual Path: /WebEventsTest
    Application Path: C:\Carlo\Progetti\VS2005\WebEventsTest\
    Machine name: CARLOC02

    Quite clear, isn't it? It turned out that their antivirus was "touching" their web.config and this triggered a change notification the runtime interpreted as if someone had modified the application configuration file.

    The above is just a sample, if you want to know more and take advantage of this new cool feature have a look at ASP.NET health monitoring overview, Web Events in ASP.NET 2.0, Quick Start Tutorials: Web Events.

     

    Cheers

  • Never doubt thy debugger

    ASP.NET incorrectly raises a CheckChanged event for a read only checkbox

    • 0 Comments

    Here's another interesting one: we had a .aspx page with some controls on it, and one of those controls were a CheckBox; upon a postback, we were trying to set the CheckBox as readonly. What we obtained is that ASP.NET incorrectly raised a CheckChange event even though none clicked on the CheckBox and so that event was not expected to fire; it seems as if the viewstate handler incorrectly detects a change to the checked value.

    First of all, Internet Explorer does not include the value of disabled controls in a postback to the server; secondly, an unchecked checkbox is not included in the post back either. So the way ASP.NET detects if a CheckBox has been unchecked, is assume that if checkbox is missing in the postback then it is unchecked, otherwise checked.

    It also turned out that the customer was overriding the RenderChildren method for his purposes, and in that method he disabled some of the controls sent to IE after the controls have any chance to store their new state in view state. Then keeping the browser's behavior in mind, ASP.NET believes the CheckBox was unchecked, and fired the onCheckedChange event.

    In summary, upon a post back here, roughly the following operations/events take place in the ASP.NET framework:

    1. Initialization - Controls are initialized
    2. LoadViewState - Checkboxes' are found to be present in the viewstate. Some of these are checked
    3. LoadPostbackData - IE does not post back any checkboxes that are either disabled or unchecked. Alas ASP.NET believe the checkboxes to be unchecked by the client IE user
    4. Load on controls are performed
    5. RaisePostBackEvent - onCheckChanged event is fired
    6. SaveViewState - When SaveViewState has been called, no changes to the controls performed afterwards are recorded
    7. Render - In this step you override RenderChildren and change the controls so their sent disabled to IE, but no ViewState information has been recorded. Thus from an IE perspective, they are not needed to be posted back

    The solution to this one was: do not change a control's state while overriding the RenderChildren event.

    For further details, please see "Understanding ASP.NET View State". Check out Fiddler for capturing and monitoring the HTTP traffic.


    Cheers

Page 1 of 1 (8 items)