Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Contents tagged with .NET

  • Silverlight 3 for Kiosk Apps? Of Course!

    Several of the customers I work with are looking to build kiosk or point-of-sale applications with Silverlight. The ease of deployment with browser-based Silverlight applications is definitely appealing. Sharing applications or components between customers’ kiosks and web sites is another appealing reasons to go with Silverlight. This post outlines the architecture decisions between Silverlight and WPF and presents architecture options for Silverlight based solutions. A follow up post will discuss the Silverlight implementation details.

  • Running IBF with the .NET Framework 2.0 installed

    ".NET ends DLL Hell" … that was the message back in the days when the .NET Framework was still in beta.
     
    With .NET, each assembly is easily versioned, global assembly registrations are versions specific and app developers are strongly encouraged to keep their assemblies local. And that can work to solve DLL Hell problems.
     
    However, .NET doesn't completely solve the problem quite yet. There is still the case of unmanaged excutables loading the .NET Framework where DLL Hell is as bad as ever. I've blogged a few times about my problems with BizTalk 2004, NUnit's problem's with different framework versions are pretty well known as well and generally speaking having more than one version of the .NET framework installed is an issue for every unmanaged application, e.g. Internet Explorer, Word, etc. , and managed apps that explicitly load the runtime. The latest victim on my list of apps that break when installing a new version of the .NET Framework is the IBF client.
     
    I found that out, when I was preparing a demo for my last SQL Server XML features talk. I thought it would be a cool idea to consume a native SQL Server 2005 web service in IBF. Unfortunately, I got an error from the smart tag loader from Excel, Outlook, Word and since IBF 1.5 added Internet Explorer support, I even got errors when launching IE. The error was:
     
    There are problems with the Microsoft Information Bridge Framework 1.5 client. Run the client Setup program to repair the installation. The error details are stored in the event log.
     
    But the details in the event log didn't really provide that much more information:
     
    Information Bridge cannot start because Microsoft .NET Framework 1.1 failed. Return Code: 80131604
     
    Since I had the smart tag running on a different VPC image that didn't have SQL Server 2005 or a CTP of .NET installed I suspected once again issues with loading the wrong version of the .NET framework.
     
    When troubleshooting my BizTalk issues I found how you can configure applications to load specific runtime versions. With IBF, I just had to find where I needed to add these configurations. With some help from Ted Howard and Michael Kiselman from the IBF team I found that I need to add .NET app.config files for the unmanaged(!) applications that host the IBF pane, i.e. Word and Excel. That's pretty obvious actually, if you know that Fusion, the .NET assembly loader, does look for app.config files for unmanaged and managed executables alike. Adding WinWord.exe.config, Excel.exe.config, Outlook.exe.config  files in \Program Files\Microsoft Office\OFFICE11 for Word, Excel and Outlook and Iexplore.exe.config in \Program Files\Internet Explorer for Internet Explorer with the following entries:
     
    <?xml version="1.0"?>
    <configuration>
     
      <startup>
        <supportedRuntime version="v1.1.4322" />
      </startup>
     
    </configuration>
     
    fixes the smart tag problems just fine.
     
    Now I still have some issues trying to run VSTO solutions on that VPC image, but I haven't had a chance to get to the bottom of those yet. 

  • Mdi Bug - When Focus isn't enough

     
    We discovered a problem with Mdi-style Windows.Forms applications with the .NET Framework 1.1 with and without SP 1. The problem causes incorrect handling of keyboard input by MdiClient windows.
     
    To reproduce the problem we build a very simple forms application with a toolbar to open client windows. The client window has a text box and some buttons. We wired up a KeyDown handler to the textbox that checks for pressing the enter key while the cursor is in the text box. In the repro example simply shows a MessageBox when you pressed enter. The event handler works fine when you first open a client window.
     
     
     
     
    However, when you click on any of the buttons, then open another client window (or change focus to another window in the Mdi Frame) and then put the cursor back into the text box and hit enter, the form will invoke the event handler for the button you clicked before you switched between child windows. It will no longer invoke the KeyPress handler that's hooked up to the textbox, like it did before we switched focus between the two children.
     
     
     
     
     
    Trying to determine what's going on, we looked at a number of things. First we looked if it was a matter of the current focus on the form, but the Focused property is set to the TextBox when the handler for the button is executed.
     
    Then we checked if the registered event handlers for the textbox were somehow getting messed up, but examining the event handlers with the code below showed that the events were still properly wired up. We also found that the sender object passed to the event handler is indeed the button, therefore we started looking for the problem in other areas.
     
    The realized that the form acted as if it’s executing the event handler for the AcceptButton, but both AcceptButton properties, for the MdiChild and the main frame, were set to null.
     
    We then concluded that it must be a bug in the Mdi Framework and sent it off to Microsoft. In the meantime, the only workaround we came up with was to add code to every button handler on the form to check the Focused property.
     
    private void button2_Click(object sender, System.EventArgs e)
    {
    if( textBox1.Focused )
    {
    MessageBox.Show( "You should really call the text box event handler" );
     
    }
    else
    {
    MessageBox.Show( "Button 2" );
    }
    }
     
    That workaround gets pretty tedious if you have lots of input controls on the form though. I'll post an update when I get a response from Microsoft.

  • Follow up: Workaround for XmlSerializer assembly leaks

     
    A while ago, Paul Wilson and Kirk Allen Evans reported that the XmlSerializer is leaking assemblies when the serializer object was instantiated with any of the constructors but the most basic one. The simple XmlSerializer constructor has logic to re-use the temporary assemblies if it already built them for a given type. The more complex constructors are missing that caching logic and allow the temporary assemblies to leak if you don't keep the serializer instance around in your program.
     
    the other day, I found out that the XmlSerializer assembly leak is not going to be fixed in Whidbey. Within a few days of me reading that, John Bristowe was asking why there isn’t anything in the Mvp.Xml project to work around that issue. And because I didn't have a real good answer to that I sat down and wrote one, because there should be.
     
    The result is the XmlSerializerCache class. It's very easy to use. You simply obtain XmlSerializer instances from the various overloads of XmlSerializerCache.GetSerializer() instead of the instantiating a serializer instance with the XmlSerializer constructor. The signatures of the GetSerializer() method match those of the XmlSerializer constructor.
     
    XmlSerializer ser = XmlSerializerCache.GetSerializer( typeof( MyClass ), "http://www.mvpxml.org/mytool" );
     
    The XmlSerializerCache canonicalizes the contents of the parameter list to reduce the amount of serializer objects in the application. For example, canonicalization recognizes that an XmlSerializer instance created for this request:
     
    XmlSerializerCache cache = new XmlSerializerCache();
    XmlSerializer ser1 = cache.GetSerializer( typeof(MyType), new Type[] { typeof(TypeOne), typeof(TypeTwo) } );
     
    is compatible with this request:
     
    XmlSerializerCache cache = new XmlSerializerCache();
    XmlSerializer ser2 = cache.GetSerializer( typeof(MyType), new Type[] { typeof(TypeTwo), typeof(TypeOne) } );
     
    The GetSerializer method checks cache for compatible instances that are compatible with the method parameters before constructing a new instance to minimize the number of created serializers. The compatibility check computes a fingerprint from the method parameters. This computation looks at every property of the passed in parameters. Yet this operation is still less expensive than reflecting over an object graph to create code and compile temporary assemblies and it prevents "leaking" memory due to orphaned assemblies that you cannot unload.
     
    Parameter canonicalization is not the only feature of the XmlSerializerCache. It also allows you to monitor what it's doing, through raising events and via two performance counters. Both counters are in the category Mvp.Xml.XmlSerializerCache. Make sure you install the Mvp.Xml with the .msi to create and delete the performance counters.
     
    The performance first counter  "Cache Hits" exposes the number of currently cached XmlSerializer instances. The second counter "Cached Instances" reflects the number of cache hits, i.e. how many times the instances were successfully retrieved from the cache instead of creating a new one.
     
    In addition to the performance counters, the XmlSerializerCache also features a pair of events to track its operations from within the program that is using it. The parameters of these events contain the parameter of the request to the XmlSerializerCache's in case you want to track or log what serializers are created for example.

  • C++ support in WSE 2.0 SP2

    WSE 2.0 SP2 adds some support for adding WSE to C++ projects, which had been missing since the initial release last May.
     
    At last, the WSE Configuration Editor, the one that comes up when you right-click in the Solution Explorer and then select WSE 2.0 Settings allows you to enable and disable WSE for C++ project and lets you create policies.
     
     
    Before SP2, nothing would happen when you clicked on the item in the context menu. Unfortunately, other IDE integration, such as automatic generation of WSE proxies in a WSE enabled project is still not happening and probably will never happen in WSE 2 because wsewsdl2.exe does not support generation of C++ code. If you take a look with Reflector, you'll find that for some reason, the tool does not emit the proxy code via CodeDOM, hence it would be really difficult for the WSE team to generate C++ proxy classes.
     
    A general shortcoming of the IDE integration of the configuration tool, that's not specific the C++ projects are the relative references generated for the policy files. When you enable policy for a C++ an application project (not a web service), the tool will add
     
    <policy>
    <cache name="../policyCache.config" />
    </policy>
     
     
    to the application's configuration file. Unfortunately, the relative reference would only valid during development -- if C++ projects behaved like C# projects in the first place. When you deploy the application you most likely will not have the policyCache.config file one directory higher than the application and its config file. To complicate matters a little further, C++ application projects behave differentely than C# of VB.NET projects in Visual Studio. C++ projects don't even copy the app.config file to the output directory. The best solution is to delete the relative path information from the path to the policyCache.config file.
     
    <policy>
    <cache name="policyCache.config" />
    </policy>
     
    and then add a post build event to rename app.config and copy it, together with the policyCache file to the output directory:
     
    copy $(ProjectDir)app.config $(OutDir)\$(TargetFileName).config /Y
    copy "$(ProjectDir)policyCache.config" $(OutDir)\ /Y
     
     
    Changing the path and letting the post build event do the work for you also helps when you build an installer. Simply mark the policyCache.config file as "Content", add "Content File" to the installer project and you're ready to go.
     
    Finally, when you build and ASP.NET Web service in C++ you have to make sure that the policyCache.config file is deployed to the web server.
     

  • ANN: Talking in Austin on 12/13

    I am giving a presentation on Secure Web Services and Secure Office Productivity Solutions based on IBF at ADNUG's December meeting on 12/13. 5:30pm at the Microsoft Technology Center:
     
    About the presentation:
    Web services are making their ways into the enterprise. Yet, Web service technology is continuing its evolution into a mature, full-fledged platform for feature-rich and secure enterprise applications.
     
    This talk presents two second-generation development frameworks: Web services enhancements (WSE) and the Integration Bridge Framework (IBF). WSE adds a number of improvements over the Web services support built into the .NET Framework namely:
    ·  Support for the WS-Security family of specifications
    ·  light-weight Web services without requiring the IIS web serve
    ·  Improved support for message-oriented message exchange patterns
    ·  A declarative, policy driven programming model based on WS-Policy
     
    IBF is an application framework to enhance productivity of information workers by integrating Web services directly into Microsoft Office 2003 documents, such as Word documents or emails displayed in Outlook. Bringing data from other applications directly into office documents eliminates the need of switching between different applications offers and thus streamlines business processes.
     
    Together the two frameworks deliver a secure platform for effective and secure productivity solutions. The talk examines the need for security in a Web services environment and introduces the capabilities of WSE and IBF 
     
    For more details on ADNUG and our monthly meeting schedule please visit http://www.adnug.org.
     
    Hope to see you there.