November, 2007

  • Never doubt thy debugger

    Posters, posters and again posters...

    • 11 Comments

    First link-only post on this blog, it was supposed to happen sooner or later, I guess... smile_embaressed  Here is a list of technology posters you can download, my favorites are the keyboard shortcut ones! By the way, thanks to Paulo for collecting the links! smile_regular

    Developer

    Microsoft® Visual Basic® 2008 Default Keybindings

    Visual C# 2008 Default Keybindings

    Visual C++ 2008 Default Keybindings

    Microsoft® Visual C#® 2005 Default Keybindings

    Microsoft® Visual Basic® 2005 Default Keybindings

    Microsoft® Visual C++® 2005 Default Keybindings

    Microsoft .NET Framework 3.5 Commonly Used Types and Namespaces

    Windows Presentation Foundation

    .NET Compact Framework Versions (on OpenNETCF)

    Microsoft® Silverlight™ 1.1 Developer Reference Poster

    Smart Client Poster

    Developer Map for the 2007 Microsoft® Office system

    Microsoft® Office InfoPath® 2007 Managed Object Model

    Developer Map for SharePoint® Products and Technologies

    Platform

    Windows Server 2008 Active Directory Feature Components

    Windows Server 2008 Feature Components

    Microsoft Windows Server 2003 Active Directory Component Jigsaw

    BizApps

    Exchange Server 2007 Component Architecture

    Exchange Server 2007 Edge Transport Server Role Architecture

    Exchange Server 2007 Hub Transport Server Role Architecture (RTM)

    Exchange Server 2007 Hub Transport Server Role Architecture (SP1)

    BizTalk Server 2006 R2 Capabilities

    BizTalk Server 2006 R2 Runtime Architecture

    BizTalk Server 2006 R2 Scale-Out Configurations

    Upgrade Project Server with Windows SharePoint Services

    Upgrade Project Server without Windows SharePoint Services

    Upgrade large SharePoint Portal Server 2003 intranet portals to SharePoint Server 2007

    Upgrade SharePoint Portal Server 2003 to SharePoint Server 2007

    Others

     

    2007 Microsoft Office System Logical Architecture

    Project Server 2003 Setup Flow

    Microsoft CRM 3.0 Logical Database Diagrams

    Microsoft CRM 1.2 Logical Database Diagram

    PnP Overview Poster

    MSIT SOI System Poster

    MSIT SOI Runtime Poster

    Carlo

    Quote of the day:
    Whenever I dwell for any length of time on my own shortcomings, they gradually begin to seem mild, harmless, rather engaging little things, not at all like the staring defects in other people's characters. - Margaret Halsey
  • Never doubt thy debugger

    The error indicates that IIS is not installed on the machine. Please install IIS before using this tool

    • 7 Comments

    Yesterday I was working on a sample project got from a customer, when Visual Studio 2005 showed this dialog:

    Visual Studio error message 

    Ok I thought, let's fix the application mappings. I did, but got the following:

    aspnet_regiis -i 

    What? Are you kidding me? smile_omg Of course IIS is installed, I'm using it every day...

    But wait a minute, I'm running on Vista x64 and this rings a bell to me... Let's use the x64 Visual Studio command prompt and give it another try:

    aspnet_regiis -i x64 

    Much better... and now Visual Studio does not complain anymore! smile_nerd

     

    Carlo

    Quote of the day:
    We are inclined to believe those whom we do not know because they have never deceived us. - Samuel Johnson
  • Never doubt thy debugger

    Does hot deployment really means "HOT"?

    • 5 Comments

    Every now and then we get calls from customer having troubles with ASP.NET deployment, usually in cluster/NLB environment but sometimes also in single servers; what they usually have in common is the complexity of the web application, maybe made of dozens (if not hundreds) of pages, controls etc... Typical questions are:

    • I am deploying my new pages and dlls but then suddenly the application is restarted, and my user lose their work and have to login again
    • After the deployment the application is slow at startup
    • In my NLB I randomly get inconsistent behaviors and weird exceptions we never got before
    • We are using a tool to synchronize files and folders, and during the sync for a few seconds we receive a lot of errors telling that some dlls are not available, but after some more seconds everything is running fine again

    There are a few variations to the above, but you got the point. I think this might be due to a misunderstanding (of should I say the documentation is not clear enough?) about deployment capabilities of ASP.NET and what is recommended for complex/full loaded applications; the point is that ASP.NET supports hot deployment meaning that whenever you update a "core" component (the content of the /bin folder, for instance) the runtime finishes serving queued requests and then reload the application to reflect your changes. But this also means that a number of things are happening, (roughly) including recompiling the the new assemblies, re-creating the AppDomain to host the application, go through security checks and load the modules into the AppDomain.

    You can easily imagine that for a complex application those steps might require some time during which we application is not able to respond to incoming user's requests. If we then consider a cluster/NBL environment, where every request from your users might be served by a different server... if you're in the middle of your deployment a user might be "bounced" from a server with the new dlls already installed and another with the old ones still in place, bad thinks will happen then... smile_confused

    A few days ago one of those cases came in, and the customer was reporting a deadlock problem in his w3wp.exe, with the following entry in his event log:

    Event Type:     Warning 
    Event Source:   W3SVC-WP 
    Event Category: None 
    Event ID:  2262 
    Date:      18/10/2007 
    Time:      15:46:10 
    User:      N/A 
    Computer:  <computername> 
    
    Description: 
    ISAPI 'c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll' reported itself as unhealthy for the following reason: 'Deadlock detected'. 
    
    
    
    
    Event Type:     Warning 
    Event Source:   W3SVC 
    Event Category: None 
    Event ID:  1013 
    Date:      18/10/2007 
    Time:      15:47:43 
    User:      N/A 
    Computer:  <computername> 
    Description: 
    A process serving application pool 'DefaultAppPool' exceeded time limits during shut down. The process id was '5780'. 

    We captured a dump as described in How to generate a dump file when ASP.NET deadlocks in IIS 6.0, and the first thing to note is that almost all the threads in the process were waiting on a stack exactly like the following:

    [HelperMethodFrame: 06f9e968] System.Threading.Monitor.Enter(System.Object) 
    System.Web.Compilation.CompilationLock.GetLock(Boolean ByRef) 
    System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(System.Web.VirtualPath, Boolean, Boolean, Boolean) 
    System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(System.Web.HttpContext, System.Web.VirtualPath, Boolean, Boolean, Boolean) 
    System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(System.Web.VirtualPath, System.Web.HttpContext, Boolean, Boolean) 
    System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(System.Web.VirtualPath, System.Type, System.Web.HttpContext, Boolean, Boolean) 
    System.Web.UI.PageHandlerFactory.GetHandlerHelper(System.Web.HttpContext, System.String, System.Web.VirtualPath, System.String) 
    System.Web.UI.PageHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(System.Web.HttpContext, System.String, System.Web.VirtualPath, System.String) 
    System.Web.HttpApplication.MapHttpHandler(System.Web.HttpContext, System.String, System.Web.VirtualPath, System.String, Boolean) 
    System.Web.HttpApplication+MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef) 
    System.Web.HttpApplication.ResumeSteps(System.Exception) 
    System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object) 
    System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest) 
    System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest) 
    System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32) 
    [ContextTransitionFrame: 06f9ee00] 
    [GCFrame: 06f9ee50] 
    [ComMethodFrame: 06f9efa8] 

    As you can see we are in the middle of a massive compilation, most likely triggered by the application update the customer mentioned.

    In the meantime there was one AppDomains which was shutting down because it reached its allowed compilation limit before recycling (again, this sound really like a consequence of the massive compilation going on in the meantime in other threads):

    HttpRuntime 0x143fcc24: 
    _shutDownStack:    at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) 
       at System.Environment.get_StackTrace() 
       at System.Web.HttpRuntime.ShutdownAppDomain() 
       at System.Web.Hosting.HostingEnvironment.ShutdownThisAppDomainOnce() 
       at System.Web.Hosting.HostingEnvironment.InitiateShutdownWorkItemCallback(Object state) 
       at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state) 
       at System.Threading.ExecutionContext.runTryCode(Object userData) 
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) 
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) 
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state) 
    
    _shutDownMessage: Recompilation limit of 15 reached 
    HostingEnvironment caused shutdown 
    _shutdownInProgress: 1 
    _requestQueue: 0x144255a0 
    _appDomainAppPath: C:\Inetpub\wwwroot 
    _appDomainAppId: /LM/W3SVC/235991876/Root 

    Imagine a situation where while the server is still receiving incoming request from the clients, the application's files are being update and the runtime needs to go through the initialization steps: it's a risky situation where it's easy to find yourself stuck in the middle of something, likely with performance and locking problems and eventually with a hang or even worse a deadlock.

    Despite the fact that ASP.NET supports “hot deployment” (i.e. you can override application files and the runtime will automatically load the new version at next request), but this is not recommended in “hot” production environments and in particular in a cluster/NBL configuration, where there is always the risk that a request is served first by the updated server, while the next one might be served by the second server which is not updated yet, causing unpredictable behaviors; in such situations it’s always a good idea to schedule your deployments in a “maintenance window” where you can temporarily take offline the application, update everything you need and put it back online when done (if you’re just updating application’s files should be a matter of a couple of minutes, just the time needed for the transfer and restart the services).

    Depending on your needs you may also want to edit your web.config and increase the number of compilations allowed before recycling the AppDomain by setting a higher value for numRecompilesBeforeAppRestart (I suggest to not set it higher than 50)

    <compilation 
        tempDirectory = "" 
        debug = "false" 
        strict = "false" 
        explicit = "true" 
        batch = "true" 
        urlLinePragmas = "false" 
        batchTimeout = "900"  
        maxBatchSize = "1000" 
        maxBatchGeneratedFileSize = "1000" 
        numRecompilesBeforeAppRestart = "15" 
        defaultLanguage = "vb" 
        assemblyPostProcessorType = "" 
    /> 

     

    Carlo

    Quote of the day:
    First you're an unknown, then you write one book and you move up to obscurity. - Martin Myers
  • Never doubt thy debugger

    Visual Studio designer, CodeDom and InitializeComponent()

    • 4 Comments

    The code problem

    A few days ago I had the chance to work on a case not concerning ASP.NET or IIS, but rather an interaction with Visual Studio designer with classes from System.CodeDom namespace. The customer was developing a custom control meant for other developers to use it in their projects, and upon adding the control to the form, the former had to automatically modify the some codebehind files for example to add some custom methods and register itself in the InitializeComponent method to add events etc... The problem was that we were able to add new methods to the form, but despite our attempts nothing was added to InitializeComponent smile_thinking

    Initiallize component

    Here's the chunk of code we were using:

    private void AddCode(Form form)
    {
       IDesignerHost host = null;
       host = (IDesignerHost)form.Site.GetService(typeof(IDesignerHost));
    
       //Add method "Form1_Load" on Form1
       //---------------------------------------------------------------------------
       CodeMemberMethod member = new CodeMemberMethod();
       member.Name = "Form1_Load";
       member.Parameters.Add(new CodeParameterDeclarationExpression("System.Object", "sender"));
       member.Parameters.Add(new CodeParameterDeclarationExpression("System.EventArgs", "e"));
       CodeSnippetExpression sn;
       sn = new CodeSnippetExpression("MessageBox.Show(\"Hello world\")");
       member.Statements.Add(sn);
       member.Attributes = MemberAttributes.Private;
       CodeTypeDeclaration typedecl = (CodeTypeDeclaration)form.Site.GetService(typeof(CodeTypeDeclaration));
       typedecl.Members.Add(member);
       //---------------------------------------------------------------------------
    
    
       //This code will add the following line to the "InitializeMethod" method
       // this.Load += new System.EventHandler(this.Form1_Load);
       //---------------------------------------------------------------------------
       member = new CodeMemberMethod();
       foreach (CodeTypeMember typememb in typedecl.Members)
       {
           if (typememb.Name == "InitializeComponent")
           { member = (CodeMemberMethod)typememb; }
       }
       CodeDelegateCreateExpression createDelegate1;
       createDelegate1 = new CodeDelegateCreateExpression(new CodeTypeReference("System.EventHandler"), new CodeThisReferenceExpression(), "Form1_Load");
       CodeAttachEventStatement attach = new CodeAttachEventStatement(new CodeThisReferenceExpression(), "Load", createDelegate1);
       member.Statements.Add(attach);
       typedecl.Members.Add(member);
       //---------------------------------------------------------------------------
    
    
       //Add and remove a label because otherwise the code to add the method seems to stay "inactive,
       //while in this way it works
       //---------------------------------------------------------------------------
       Label lbl = (Label)host.CreateComponent(typeof(Label));
       host.DestroyComponent(lbl);
       //---------------------------------------------------------------------------
    }

    private void InitializeComponent()

    Interestingly beside InitializeComponent Visual Studio was showing the yellow line which means that the code has been changed and still needs to be saved, so something was actually happening... so I tried to add the event in another method and it worked fine; an also adding a MessageBox inside the foeach loop to display LinePragma.FileName and LinePragma.LineNumber showed we were working on the appropriate code file and code line (the InitializeComponent declaration)... So there is a problem with InitializeCompoent itself?

    Well, yes.

    I remember I read about it long time ago when I was getting my hand dirty with the emerging .NET technology (it was back in 2001 I think), but then I moved to web applications and this went somewhere in the back of my mind... the InitializeComponent is a very important method for Visual Studio, which protects it from custom manipulations which might compromise good working of the designer, and this is actually explained in a KB article: Code comments that you add in the InitializeComponent method are lost when you add a control in Visual Studio .NET or in Visual Studio 2005.

    And that was actually the exact situation we where into: for some reason the code was not added as expected unless we were adding and removing a control to the From (a Label in our case) and this simple trick had the effect to somehow activate the code (I guess that way we were calling some specific method otherwise we were not touching), but his also had the side effect to put us in the situation described in the article. And even if our was were working fine, sooner or later we would have stumbled in this kind of Visual Studio protection anyway, because a developer would have certainly added other controls to the form anyway...

    So we had two problems here:

    1. Find a way to add event lines to the Form initialization
    2. Find a way to "refresh" the code without adding/removing fake controls to the Form

    To resolve point one we decided to create an InitializeComponent2 method still inside Form1.Designer.cs (to have it consistent with the default InitializeComponent added by Visual Studio) so we were now able to add our events and custom properties, and add a call to our InitializeComponent2 in Form1 construction, right below the standard InitializeComponent() call, and this way we had our event working as expected smile_regular.

    Chain of Events

    When using design-time controls, it's important to know what happens behind the scenes when you drop a control on your design surface—or for controls such as a Form, what happens when you create a Form that is inherited from another Form you created.

    When an object is opened in the design environment, the class that the object is inherited from (not the newly created class) is constructed by Visual Studio. Remember, a control that is created fires its constructor, which also fires the InitializeComponent() method within the base class's constructor. Once the derived class is constructed, that magically named method within your newly created class, InitializeComponent(), is parsed line-by-line by Visual Studio. The only thing magic about this method is its name. Visual Studio just knows to look for this method.

    In Visual Basic .NET, if Visual Studio can't understand the line of code, the line is removed (a nice way of saying eaten). The Visual Basic team felt it was more important to maintain the design-time environment. The C# team felt it was more important to maintain the code, so if Visual Studio can't parse InitializeComponent() you'll get the text of the exception presented to you. This includes inherited Forms, or controls placed on the design surface of another component class control.

    Any property that is part of your base object is set by the base object and its constructor. When the InitializeComponent() method runs, the values are changed to the values you have set on the property sheet. In Visual Studio, the property sheet is just a graphical representation of the InitializeComponent() method. If your base class performs some sort of functionality in the constructor, be careful; it will be executed in the design environment as well.

    You do have some control over this, however. Any class that derives from the Component class has a property called DesignMode that is set to true when the code is executing within the constructs of the Visual Studio designer. So you have the option to wrap code within an if statement. There's one more trick, however. The DeisgnMode property isn't set to true in the constructor. Remember, there's no real magic here. Visual Studio creates your object as it parses the InitializeComponent() method. Once the object is constructed, Visual Studio keeps track of the objects it creates, and simply says:

    newlyCreatedObject.DesignMode = true

    Next steps

    The argument intrigued me, so I was curious to further explore the capabilities offered by the CodeDom namespace; doing some researches on the Internet you can quite easily find articles which describes how to create a class from crash, create the source file and compile it on the fly to have the resulting assembly and this is quite a standard usage of CodeDome, here are just a couple of references:

    But I've not been able to find good articles about how to customize the current code graph, the one we're currently using (instead of creating a completely new class/component from scratch), so I made some tests myself with conflicting results (something's working the way I like, something don't...). Here's what I've come up with, it's still not perfect (continue reading to find out what's wrong) but even if far from being perfect at least it works:

    private void AddCode(Form form)
    {
        //Hook to the designer
        IDesignerHost host = (IDesignerHost)form.Site.GetService(typeof(IDesignerHost));
    
    
    
        //Add method "Form1_Load" on Form1
        CodeMemberMethod member = new CodeMemberMethod();
        member.Name = "Form1_Load";
        member.Parameters.Add(new CodeParameterDeclarationExpression("System.Object", "sender"));
        member.Parameters.Add(new CodeParameterDeclarationExpression("System.EventArgs", "e"));
        CodeSnippetExpression sn = new CodeSnippetExpression("MessageBox.Show(\"Hello world\")");
        member.Statements.Add(sn);
        member.Attributes = MemberAttributes.Private;
        CodeTypeDeclaration typedecl = (CodeTypeDeclaration)form.Site.GetService(typeof(CodeTypeDeclaration));
        typedecl.Members.Add(member);
        //---------------------------------------------------------------------------
    
    
    
        //Create an InitializeComponent2() method
        member = new CodeMemberMethod();
        member.Name = "InitializeComponent2";
        typedecl.Members.Add(member);
        //---------------------------------------------------------------------------
    
    
    
        //Find the constructor and add a call to my "InitializeComponent2()" method
        //CodeConstructor ctor = new CodeConstructor();
        CodeConstructor ctor = null;
        foreach (CodeTypeMember typememb in typedecl.Members)
        {
            if (typememb.Name == ".ctor")
            {
                ctor = (CodeConstructor)typememb;
                break;
            }
        }
    
        CodeMethodInvokeExpression invokeExpression = new CodeMethodInvokeExpression();
        invokeExpression.Method = new CodeMethodReferenceExpression(
            new CodeThisReferenceExpression(), "InitializeComponent2");
    
        ctor.Statements.Add(invokeExpression);
        typedecl.Members.Add(ctor);
        //---------------------------------------------------------------------------
    
    
    
        //This code will add the following line to the "InitializeMethod2" method
        // this.Load += new System.EventHandler(this.Form1_Load);
        member = new CodeMemberMethod();
        foreach (CodeTypeMember typememb in typedecl.Members)
        {
            if (typememb.Name == "InitializeComponent2")
            {
                member = (CodeMemberMethod)typememb;
            }
        }
    
        CodeDelegateCreateExpression createDelegate1 = new CodeDelegateCreateExpression(
            new CodeTypeReference("System.EventHandler"), new CodeThisReferenceExpression(), "Form1_Load");
        CodeAttachEventStatement attachStatement1 = new CodeAttachEventStatement(new CodeThisReferenceExpression(), "Load", createDelegate1);
    
        member.Statements.Add(attachStatement1);
        typedecl.Members.Add(member);
        //---------------------------------------------------------------------------
        
    
    
        //Add and remove a label because otherwise the code to add the method seems to stay "inactive",
        //while in this way it works
        Label lbl = (Label)host.CreateComponent(typeof(Label));
        host.DestroyComponent(lbl);
        //---------------------------------------------------------------------------
    }

    The debug problem

    Debugging design time controls is not part of my daily job (I've never saw one, in web development), so while working on this case I had to figure out out to debug one of those... At the beginning I just needed to check a couple of variable values so to make things simple I just added a couple of MessageBox.Show() where I needed (like I used to fill my old ASP pages with Response.Write() statements long time ago). As you can guess this is not a practical approach. And at the same time I could not imagine to be the only person facing this problem, so there must be some article outside on the Internet dealing with this issue... and here is it, just in case you need it: Walkthrough: Debugging Custom Windows Forms Controls at Design Time.

    Start external program Essentially what needs to be done is set the control's project as the startup progect, change the debug start action for the control you need to debug, setting it to "Start external program" and pointing it to the Visual Studio executable (default path is C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe), then set a breackpoint where you want to stop in its code and press F5 to start debugging. A new instance of Visual Studio is created, and from it you can open once again the Solution which contains the control you want to debug; now simply do what you need to run the control (add it to a new form for example) and hit the breakpoint (within the first Visual Studio instance, of course). Here we are, now you can step through, inspect variables and do whatever you usually do while debugging. smile_nerd

    Note that the breakpoint icon in the first instance of Visual Studio will display the "breakpoint not hit" icon and tooltip until you cause the code to run, through the second Visual Studio instance

    Breakpoint will not currently be hit

    What's still missing

    To have a well designed component I wanted to be able to create the InitializeComponent2 method where I wanted (possibly in the Designer.cs file to have it together with the standard InitializeComponent created by Visual Studio), remove the "#line" entries in the class constructor to have the code clean and easy to read and avoid the ugly trick to ad/remove a label to the form for activate the code. Unfortunately those are three problems I've still not resolved smile_thinking.

    Creating a new method in Form1.cs is not a big deal, nor is adding some lines of code to it; but problems arise when trying to interact with the class constructor. This is not a protected method as we saw for InitializeComponent(), but no matter what I tried, there are always a few "#line" statements added:

    public Form1()
    {
    
    #line 17 "C:\Temp\TestForMS\TestForMS\TestForm\Form1.cs"
        this.InitializeComponent();
    
    #line default
    #line hidden
        this.InitializeComponent2();
    
    }

    Interestingly those nasty "#line" does not appear if we create a new code constructor, I guess that's because in that case we're working with a new object we created and have "full control" on it; for example creating a constructor overload and adding a call to my InitializeComponent2() produces perfectly clean code. Based on this assumption (still to verify, anyway) I tried to replace the class constructor with a new object created for this purpose, but when adding it to the class code graph still produces those lines... smile_eyeroll. Those are C# Preprocessor Directives and luckily the compiler does not complain, so for the moment I had to give up and live with them... smile_sad; but that's just for now, hopefully I'll find a way to get rid of them.

    Ideally I wanted to create my InitializeComponent2() method to the Form1.Designer.cs file, but the default behavior is to add it to the Form1 class (in Form1.cs); the nice thing is that we have a LinePragma property which "Gets or sets the line on which the type member statement occurs", it contains a FileName and LineNumber property to clearly identify where the statement is executed. So I thought to use it to instruct the CodeDom to add my method in the code file I wanted with the following code (and quite a few variations of it):

    //Create an InitializeComponent2() method
    member = new CodeMemberMethod();
    member.Name = "InitializeComponent2";
    foreach (CodeTypeMember typememb in typedecl.Members)
    {
        if (typememb.Name == "InitializeComponent")
        {
            member.LinePragma = new CodeLinePragma();
            member.LinePragma.FileName = typememb.LinePragma.FileName;
            break;
        }
    }
    typedecl.Members.Add(member);
    //---------------------------------------------------------------------------

    Despite my attempts, InitializeComponent2() is always created in Form1.cs... still something to look into smile_eyeroll.

    Finally, the ugly workaround (or should I say "alternative solution"? smile_tongue) of adding and removing the fake label to the form to activate the changes made to the code; I guess this invokes a sort of refresh mechanism, so I tried to dig into those calls with Reflector because I wanted to find the property to set or the method to call to activate the refresh without adding the label, but again with no luck... third (and hopefully last) point to clarify.

    Conclusion

    CodeDom offers some interesting capabilities to control developers but also has some limitations, here's a list (likely not complete):

    • CodeCompile unit does not have space for using directives or namespace members, so they are placed now into first default namespace
    • using alias directive - no support found
    • nested namespaces - no support found (so parser is flattening namespace hierarchy)
    • variable declaration list (int i,j,k;) - no support - transformed to individual var declarations
    • pointer type - no support found
    • jagged array type (array of arrays) - CSharpCodeProvider reverses order of ranks
    • params keyword - not supported - param is omitted in parsing and param is then an ordinary array type param
    • private modifier on nested delegate is not shown by CSharpCodeProvider (all other nested types works fine)
    • unsafe modifier - no support found
    • readonly modifier - no support found
    • volatile modifier - no support found
    • explicit interface implementation - not implemented yet (I think this can be done)
    • add and remove accessors for Event - no support found
    • virtual and override modifiers do not work in CSharpCodeProvider for events
    • Operator members and Destructors - no support found
    • Expressions - no unary expressions(operations), only one dimension array, some operators not supported
    • Attribute targets - no support found
    • Attributes on accessor - no support found
    • If CompileUnit contains custom attributes in global scope, CSharpCodeProvider prints then before global using directives (because using has to be in the first namespace)

    Back to the sample treated in this post, I'll try to resolve those 3 open problems I mentioned above, but if any of you have some details to add (or a solution to share smile_wink) please leave a comment, I'll be happy to correct the post! smile_nerd

     

    Carlo

    Quote of the day:
    Addresses are given to us to conceal our whereabouts. - Saki
  • Never doubt thy debugger

    HTTP error 406 with .NET Framework 3.0

    • 2 Comments

    I got a couple of cases about this problem recently... Imagine this scenario: you install the .NET Framework 3.0 on your client, and then browse an ASP.NET based web site; you get a 406 HTTP return code from the web server, which means "Client browser does not accept the MIME type of the requested page" (see IIS status codes). Uninstalling the .NET Framework 3.0 corrects the problem, and you're finally able to successfully browse the site.

    The problem proved itself in two different ways and apparently for two different reasons, but the underlying cause was actually the same. The 406 return code also means that any of the configuration limits has been reached, and digging into IIS logs we found that the problem was actually due to the length of the "Accept" header which has a limit of 256 bytes. Installing the .NET Framework 3.0 you receive support for a few additional file formats, here is how it looks the Accept header on Windows Vista (where the .NET Framework 3.0 is preinstalled):

    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, 
    application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, 
    application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*

    In this case there was a custom ISAPI extension which was actually filtering the incoming headers, and was blocking our request because it exceeded the configured length: to resolve the problem the customer simply increased the size limit configured within that specific ISAPI to let the requests to through. Anyway another solution was to reduce the number of Accept types, just the standard ones.

    The second customer was using a third party web server which we then discovered was able to accept a relatively short User-Agent string; the customer did not have any "power" on the web server to reconfigure it, so we only possibility left was reduce the header as much as possible on the client. The nice thing is that the User-Agent string is stored in a couple of registry key and even if that's not an ideal solution it was the only possibility we had, we decided to manually tweak those values; the first we looked at was HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform. On the right side you have a list of strings added to the User-Agent string which will be appended after the platform string (as the Post Platform name suggests); in case you need to add a custom string before the platform string, you can add a Pre Platform key. Just in case you're curious (or you're really desperate trying to reduce your User-Agent as much as possible) the platform part of the string is stored in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings > User Agent. For further infos have a look at Understanding User-Agent strings and Internet Explorer 7 User-Agent string.

    If you need to tweak the User-Agent string be very careful and test it closely before deploying into production, since you might break client-side scripts which needs to identify the specific browser or platform version you're using; ASP.NET also relies on the User-Agent string to identify the browser and produce markup compliant with that specific platform (does it support javascript? embedding videos? is a mobile browser? does it support CSS? etc...). See Determining Browser Capabilities in ASP.NET and Control adapters.

    Carlo

    Quote of the day:
    Your manuscript is both good and original, but the part that is good is not original and the part that is original is not good. - Samuel Johnson
  • Never doubt thy debugger

    Procmon on x64? "/?" will help :-)

    • 7 Comments

    Maybe some of you already know this trick, but if you don't... here it is smile_regular

    I've been running a Vista x64 as my main machine in office for a few months now, and when I had to analyze a Process Monitor trace received from a customer, but if the log was coming from a x86 machine (that's still the most common for customer calls we see today) I was not able to open it on my desktop, and always had to rely on my laptop (where I run Windows XP Pro) or on my second desktop (Windows 2003).

    Process Monitor invalid argument

    I took this for granted for a while, but then this morning I thought to have a look at the command line options (procmon /?) and got a nice surprise:

    Process Monitor usage

    Tried it, and (of course) I was finally able to open the 32bit trace on my 64bit machine.. smile_nerd

     

    Carlo


    Quote of the day:
    It's amazing that the amount of news that happens in the world every day always just exactly fits the newspaper. - Jerry Seinfeld
Page 1 of 1 (6 items)