Li Chen's Blog

  • Getting Started with Prism (aka Composite Application Guidance for WPF and Silverlight)

    Overview

    Prism is a framework from the Microsoft Patterns and Practice team that allow you to create WPF and Silverlight in a modular way. It is especially valuable for larger projects in which a large number of developers can develop in parallel.

    Prism achieves its goal by supplying several services:

    · Dependency Injection (DI) and Inversion of control (IoC): By using DI, Prism takes away the responsibility of instantiating and managing the life time of dependency objects from individual components to a container. Prism relies on containers to discover, manage and compose large number of objects. By varying the configuration, the container can also inject mock objects for unit testing. Out of the box, Prism supports Unity and MEF as container although it is possible to use other containers by subclassing the Bootstrapper class.

    · Modularity and Region: Prism supplies the framework to split application into modules from the application shell. Each module is a library project that contains both UI and code and is responsible to initialize itself when loaded by the shell. Each window can be further divided into regions. A region is a user control with associated model.

    · Model, view and view-model (MVVM) pattern: Prism promotes the user MVVM. The use of DI container makes it much easier to inject model into view. WPF already has excellent data binding and commanding mechanism. To be productive with Prism, it is important to understand WPF data binding and commanding well.

    · Event-aggregation: Prism promotes loosely coupled components. Prism discourages for components from different modules to communicate each other, thus leading to dependency. Instead, Prism supplies an event-aggregation mechanism that allows components to publish and subscribe events without knowing each other.

    Architecture

    In the following, I will go into a little more detail on the services provided by Prism.

    Bootstrapper

    In a typical WPF application, application start-up is controls by App.xaml and its code behind. The main window of the application is typically specified in the App.xaml file. In a Prism application, we start a bootstrapper in the App class and delegate the duty of main window to the bootstrapper. The bootstrapper will start a dependency-injection container so all future object instantiations are managed by the container.

    Out of box, Prism provides the UnityBootstrapper and MefUnityBootstrapper abstract classes. All application needs to either provide a concrete implementation of one of these bootstrappers, or alternatively, subclass the Bootstrapper class with another DI container.

    A concrete bootstrapper class must implement the CreateShell method. Its responsibility is to resolve and create the Shell object through the DI container to serve as the main window for the application.

    The other important method to override is ConfigureModuleCatalog. The bootstrapper can register modules for the application. In a more advance scenario, an application does not have to know all its modules at compile time. Modules can be discovered at run time. Readers to refer to one of the Open Modularity Quick Starts for more information.

    Modules

    Once modules are registered with or discovered by Prism, they are instantiated by the DI container and their Initialize method is called. The DI container can inject into a module a region registry that implements IRegionViewRegistry interface. The module, in its Initialize method, can then call RegisterViewWithRegion method of the registry to register its regions.

    Regions

    Regions, once registered, are managed by the RegionManager. The shell can then load regions either through the RegionManager.RegionName attached property or dynamically through code.

    When a view is created by the region manager, the DI container can inject view model and other services into the view. The view then has a reference to the view model through which it can interact with backend services.

    Service locator

    Although it is possible to inject services into dependent classes through a DI container, an alternative way is to use the ServiceLocator to retrieve a service on demard. Prism supplies a service locator implementation and it is possible to get an instance of the service by calling:

    ServiceLocator.Current.GetInstance<IServiceType>()

    Event aggregator

    Prism supplies an IEventAggregator interface and implementation that can be injected into any class that needs to communicate with each other in a loosely-coupled fashion. The event aggregator uses a publisher/subscriber model.

    A class can publishes an event by calling eventAggregator.GetEvent<EventType>().Publish(parameter) to raise an event.

    Other classes can subscribe the event by calling eventAggregator.GetEvent<EventType>().Subscribe(EventHandler, other options).

    Getting started

    The easiest way to get started with Prism is to go through the Prism Hands-On labs and look at the Hello World QuickStart. The Hello World QuickStart shows how bootstrapper, modules and region works.

    Next, I would recommend you to look at the Stock Trader Reference Implementation. It is a more in depth example that resemble we want to set up an application.

    Several other QuickStarts cover individual Prism services. Some scenarios, such as dynamic module discovery, are more advanced.

    Apart from the official prism document, you can get an overview by reading Glen Block’s MSDN Magazine article.

    I have found the best free training material is from the Boise Code Camp.

    To be effective with Prism, it is important to understands key concepts of WPF well first, such as the DependencyProperty system, data binding, resource, theme and ICommand. It is also important to know your DI container of choice well. I will try to explorer these subjects in depth in the future.

    Testimony

    Recently, I worked on a desktop WPF application using Prism. I had a wonderful experience with Prism. The Prism is flexible enough even in the presence of third party controls such as Telerik WPF controls. We have never encountered any significant obstacle.

  • Getting started with ASP.NET Web API quickly

    Web API is a feature of ASP.NET MVC 4. It is an API for writing REST web services. One might ask why we need another API. After all, we already have WCF Rest Service a few years ago. It is also fairly easy to return JSON from an ASP.NET MVC controller using JsonResult. For a long answer, it is best read ScottGu;s blog or the WCF site. The short answer is that Microsoft want a way to make it extremely easy to create REST services and to provide lots of features. ASP.NET MVC is the best place. Currently, the .Net REST/Json story is fragmented and there are several Json serializers in .Net. ASP.NET Web API represents the future, consolidated API for this feature.

    It is fairly easy to get started with ASP.NET Web API. For those who likes to watch video, Jon Galloway’s 6 short videos provides a very quick start and it takes only 24 minutes to watch them all. For those who like read and type, the ASP.NET site has 7 short chapters that can be read in an hour or two. Many bloggers are blogging the Web API. I would recommend Stephen Walter’s blog for a quick introduction. Finally, I strongly recommend looking into some of the samples.

  • Experimenting with ASP.NET 4.5 beta

    The next version of ASP.NET is 4.5. The official information is at http://www.asp.net/vnext.

    There are two ways to experiment with ASP.NET 4.5 beta. The first is to install Visual Studio 11 beta. The second way is to install ASP.NET MVC 4 beta on Visual Studio 2010 to experiment with a subset of the features. Visual Studio 11 beta contains .Net Framework 4.5 beta. .Net Framework 4.5 is a highly compatible in-place update of .Net Framework 4.0. If you uninstall .Net Framework 4.5 beta, you will have to reinstall .Net Framework 4.0. For this reason, I would suggest you to experiment with Visual Studio 11 beta on an experimental machine, perhaps on a Windows 8 consumer preview VHD.

    On the other hand, ASP.NET MVC 4 beta consists of a set of new assemblies that can run side-by-side with MVC 3. It also has a new set of templates for MVC 4 projects. The only thing that affects MVC 3 work is that it changes the intelligence for web pages (.cshtml and .vbhtml) to support web pages 2 features. You need to build your web application before you edit any .cshtml or .vbhtml pages to overcome a bug.

    The following features can be experimented with ASP.NET MVC 4 beta on VS 2010:

    Not part of ASP.NET MVC 4 beta, there is an exciting open source framework from the ASP.NET team called SignalR that be experimented in VS 2010. SignalR allows developing long polling Comet type of applications using .NET. The ASP.NET team has also created an open source chat application called JabbR as a case study.

    In future blogs, I will blog my experiment with each of these exciting new areas.

  • Uploading large files to WCF web services

    Recently, we need to allow users to upload large files to a web service. Fortunately, WCF does support this scenario (see MSDN: Large Data and Streaming). MSDN recommends:

    The most common scenario in which such large data content transfers occur are transfers of binary data objects that:

    • Cannot be easily broken up into a message sequence.
    • Must be delivered in a timely manner.
    • Are not available in their entirety when the transfer is initiated.

    For data that does not have these constraints, it is typically better to send sequences of messages within the scope of a session than one large message.

    Since our files do not have these constraints, we decide to break them up into sequences of segments, and pass the segments to the web service as byte arrays. There are several remaining issues: 

    Firstly, by default, WCF uses Base64 encoding to encode byte arrays, resulting 4:3 ratio in encoding overhead. To avoid this overhead, WCF support both MTOM and Binary encoding. MTOM is a widely supported format that sends large binary data as MIME attachments after the soap message. Binary encoding is a WCF proprietary encoding format. It is extremely easy to use either formats. Just change the messageEncoding attribute in the binding element in the configuration from Text to Mtom or Binary.

    Secondly, experiment shows that high level handshake through web service is fairly slow. Better performance can be achived by using a larger chunk size. By default, the maximum message size is 65536 and maximum array size is 8192. In order to transmit larger chunks, we need to increase the maximum message and array size. This can be done by increasing the maxBufferSize and maxReceivedMessageSize attributes of the binding element and the maxArrayLength attribute of the readerQuotas element. Note that increasing the maximum sizes also increases the risk of denial of service attack so select the size carefully.

    image

    Thirdly, although it is possible to configure the IIS to automatically compress HTTP responses, HTTP clients cannot be configured to automatically compress the HTTP requests. WCF has a sample custom compression encoder. It is fairly easy to use the compression encoder. Just reference the GZipEncoder.dll on both the server and the client side. The configuration settings can be extracted from the sample. The only thing that is not apparent from the sample is how to increase the message size. The maxReceivedMessageSize  attribute can be configured on the httpTransport element:

    image

    To change the maxArrayLength in readerQuotas, I actually have to make a modification to the sample code:image

    The finish proof-of-concept application can be downloaded here.

     

    
    
  • LINQ and IEnumerable may surprise you

    Let us examine the following code snippet:

        class Candidate
        {
            public string Name { get; set; }
            public bool Hired { get; set; }
        }
        class Program
        {
            static void Main(string[] args)
            {
                string[] names = { "Adam", "Byron", "Charles" };
                var candidates = names.Select(n => new Candidate()
                {
                    Name = n,
                    Hired = false
                });
                //now modify the value of each object
                foreach (var candidate in candidates)
                {
                    candidate.Hired = true;
                }
                //noew print the value of each object
                foreach (var candidate in candidates)
                {
                    Console.WriteLine(string.Format("Name:{0} Hired:{1}", 
                        candidate.Name, candidate.Hired));
                }
                Console.Read();
            }
        }
    

    Basically, I create an IEnumerable<Candidate> from LINQ, and them loop through the results to modify each object. At the end, you might expect each candidate hired. Wrong! Here is the output:

    image

    What happened was LINQ actually delayed the object generation until enumeration. When we enumerate again to print the objects, LINQ actually generated a new set of objects. If you use ToList() to convert the IEnumerable to List, you will get the expected result:

                var candidates = names.Select(n => new Candidate()
                {
                    Name = n,
                    Hired = false
                }).ToList();
    

    ToList() will instantiate the objects immediately and the subsequent enumeration will be on the same objects. That is why you cannot find the .ForEach() extension method on IEnumerable<T>. You have to convert it to IList<T> to use the method.

  • Upgrading database to SQL Server 2008

    There are minor syntax changes in Transact-SQL that prevent applications written for earlier SQL Server versions from running in SQL Server 2008. It is possible to set the Compatibility Level of a database to support earlier versions of Transact-SQL. The following statement will alter the database to run at full SQL Server 2008 mode:

    Alter Database Set COMPATIBILITY_LEVEL = 100

    One of the typical problem is that older, non-ANSI style outer join using *= or =* does not work in SQL 2008. It is possible to do a quick assessment of offending queries in stored procedures, functions and views using the following SQL statements:

    select r.ROUTINE_NAME from INFORMATION_SCHEMA.ROUTINES r where r.ROUTINE_DEFINITION like '%*=%' or r.ROUTINE_DEFINITION like '%=*%'

    select v.TABLE_NAME from INFORMATION_SCHEMA.VIEWS v where v.VIEW_DEFINITION like '%*=%' or v.VIEW_DEFINITION like '%=*%'

  • Sharing session between ASP Classic and ASP.NET using ASP.NET Session state server

    The different session state used by ASP Classic and ASP.NET is the most significant obstacle in ASP and ASP.NET interoperability. I started an open source project called NSession with the goal to allow ASP Classic to access ASP.NET out-of-process session stores in the same way that ASP.NET accesses them, and thus share the session state with ASP.NET.

    How does ASP.NET access session state?

    The underpinning of ASP.NET session state was discussed in detail by Dino. ASP.NET retrieves the session state from the session store and de-serializes it into an in-memory session dictionary at the beginning of page request. If the page requests for a read-writable session, ASP.NET will lock the session exclusively until the end of the page request, and then serialize the session state into the session store and release the lock. If a page requests for a read-only session, session state is retrieved without an exclusive lock.

    We intend to mimic the behavior of ASP.NET in ASP Classic.

    How does NSession work?

    You need to instantiate one of the COM objects in your ASP classic page before it accesses session state, either:

    set oSession = Server.CreateObject("NSession.Session")

    or

    set oSession = Server.CreateObject("NSession.ReadOnlySession")

    If you instantiate NSession.Session, the session state in the session store will be transferred to the ASP Classic session dictionary, and an exclusive lock will be placed in the session store. You do not need to change your existing code that accesses the ASP Classic session object. When NSession.Session goes out of scope, it will save the ASP Classic session dictionary back to the session store and release the exclusive lock.

    If you have done with the session state, you can release the lock early with

    set oSession = Nothing

    If you instantiate NSession.ReadOnlySession, the session state in the session store will be transferred to the ASP Classic session dictionary but no locks will be placed.

    Installation

    You may download the binary code from the Codeplex site. There are 2 DLLs to register. The first dll NSession.dll is a .net framework 4.0 dll and it is independent of 32 or 64 bit environment. Since it is accessed by ASP Classic, it needs to be registered as a COM object using RegAsm. It also needs to be place in global assembly cache using gacutil. You need .NET framework 4 on the machine but you can run any version of ASP.NET as the DLL is not loaded into the same AppDomain as the ASP.NET application. The reason that I chose .NET framework 4.0 is that I can use the C# dynamic feature to cut down the reflection.
    The second dll NSessionNative.dll is a C++ dll and is platform dependent. You need to register the appropriate version depending on whether you are running the 32 or 64 bit application pool. The reason that we need a C++ dll is that we need deterministic finalization to serialize the session at the end of page request. We chose C++ over VB6 because it can create both 32 bit and 64 bit COM objects.

    As this is still a beta ware, I suggest that you use it like any pre-release software. Please report any bug and issue to the project site forum.

    Future works

    As this time, I have only implemented the code to access ASP.NET state server. The following are some of the ideas that I have in mind. Throw in yours in the Issue Tracker at the project site.

    1. Support Sql Server session store.

    2. Optimization. ASP.NET caches some configuration and objects. NSession could use the idea too.

    3. Configuration setting to allow clearing of ASP Classic session dictionary and the end of page request.

    4. Implement a filter mechanism. The ASP.NET may store some objects that do not make sense for ASP Classic and vice versa. A filter mechanism can be used to filter out these objects.

  • I was asked to install .net framework 3.5 even though I already have it on my machine

    Today, when I try to install a Click Once application, I was asked to install .net framework 3.5 even though I already have it on my machine. It turns out that the web application relies on the User-Agent header to determine if I have .net framework 3.5. However, IE9 no longer sends feature token as part of User-Agent. Instead, feature tokens are included in the value returned by the userAgent property of the navigator object. The work around? Just set the IE9 to IE8 compatibility mode and the website is happy.