Contents tagged with CAB

  • Learning the Model View Presenter Pattern

    The guys over at Patterns and Practices got it right. They've put together a package (available via a CodePlex project here) on learning and understanding the Model View Presenter Pattern (MVP). It's kind of a "mini-guidance" package and not the big behemoth you normally see from these guys that:

    • Provides guidance on how MVP to promotes testability and separation of concerns within the UI
    • Illustrates how to implement MVP with standard ASP.NET
    • Illustrates how to implement MVP with ASP.NET and the Composite Web Application Block

    The package contains full documentation on the pattern, unit tests, and source code (for both WinForms and CAB) demonstrating it. Very nice and very easy to digest! Check it out here if you're just getting started and want to see what MVP is about.

  • Taming the ActionCatalog in SCSF

    The Smart Client Software Factory provides additional capbility above and beyond what CAB (the Composite Application UI Block) has. A little known gem is the ActionCatalog which can ease your pain in security trimming your application.

    For example suppose you have a system where you want to hide a menu item from people that don't have access to it. This is pretty typical and generally ends up in having to scatter your code with if(User.IsInRole("Administrator")) statements, which can get pretty ugly real quick. The ActionCatalog system in SCSF helps you avoid this.

    Here's a typical example. I've created a new Business Module and in the ModuleController I'm extending the menu by adding items to it:

    public class ModuleController : WorkItemController

    {

        public override void Run()

        {

            ExtendMenu();

        }

     

        private void ExtendMenu()

        {

            ToolStripMenuItem conditionalMenu = new ToolStripMenuItem("Conditional Code");

            if (canManageUsers())

            {

                conditionalMenu.DropDownItems.Add(new ToolStripMenuItem("Manage Users"));

            }

            if (canManageAdministrators())

            {

                conditionalMenu.DropDownItems.Add(new ToolStripMenuItem("Manage Administrators"));

            }

            WorkItem.UIExtensionSites[UIExtensionSiteNames.MainMenu].Add(conditionalMenu);

        }

     

        private bool canManageAdministrators()

        {

            string userName = Thread.CurrentPrincipal.Identity.Name;

            return

                Thread.CurrentPrincipal.Identity.IsAuthenticated &&

                userName.ToLower().Equals("domain\admin");           

        }

     

        private bool canManageUsers()

        {

            string userName = Thread.CurrentPrincipal.Identity.Name;

            return

                Thread.CurrentPrincipal.Identity.IsAuthenticated &&

                userName.ToLower().Equals("domain\joeuser");

        }

    }

    For each menu item I want to add I make a call to a method to check if the user has access or not. In the example above I'm checking two conditions. First the user has to be authenticated to the domain, then for each specific menu item I'm checking to see another condition (in this case comparing the user name, however I could do something like check to see if they're in a domain group or not).

    Despite the fact that I could do a little bit of refactoring here, it's still ugly. I could for example extract the duplicate code on checking to see if the user is authenticated then do my specific compares. Another thing I could do is call out to a security service (say something that wraps AzMan or maybe the ASP.NET Membership Provider) to get back a conditional true/false on the users access. However with this approach I'm still stuck with these conditional statements and no matter what I do, my code smells.

    Enter the ActionCatalog. A set of a few classes inside of SCSF that makes security trimming easy and makes your code more maintainable. To use the ActionCatalog there are a few steps you have to do:

    • Create a class to hold your actions
    • Register the class with a WorkItem
    • Add conditions for allowing actions to be executed 
    • Execute the actions

    Setting up the Catalog 
    Let's start with the changes to the ModuleController. You'll add some new methods to setup your actions, conditions, and then execute the actions. In this case the actions are directly manipulating the UI by adding menu items to it, but actions can be anything (invoked or tied to CommandHandlers) so you decide where the most appropriate split is. Here's the modified ModuleController:

    public class ModuleController : WorkItemController

    {

        private ToolStripMenuItem rootMenuItem;

     

        public override void Run()

        {

            ExtendMenu();

            RegisterActionCatalog();

            RegisterActionConditions();

            ExecuteActions();

        }

     

        private void ExtendMenu()

        {

            _rootMenuItem = new ToolStripMenuItem("Action Catalog");

            WorkItem.UIExtensionSites[UIExtensionSiteNames.MainMenu].Add(rootMenuItem);

        }

     

        private void ExecuteActions()

        {

            ActionCatalogService.Execute(ActionNames.ShowUserManagementMenu, WorkItem, this, _rootMenuItem);

            ActionCatalogService.Execute(ActionNames.ShowAdministratorManagementMenu, WorkItem, this, _rootMenuItem);

        }

     

        private void RegisterActionConditions()

        {

            ActionCatalogService.RegisterGeneralCondition(new AuthenticatedUsersCondition());

            ActionCatalogService.RegisterSpecificCondition(ActionNames.ShowUserManagementMenu, new UserCondition());

            ActionCatalogService.RegisterSpecificCondition(ActionNames.ShowAdministratorManagementMenu, new AdministratorCondition());

        }

     

        private void RegisterActionCatalog()

        {

            WorkItem.Items.AddNew<ModuleActions>();

        }

    Here we've added an RegisterActionCatalog(), RegisterActionConditions(), and ExecuteActions() method (I could have put these into one method but I felt the act of registering actions, conditions and executing them voilated SRP so they're split out here).

    Action Conditions
    ActionNames is just a series of constants that I'll use to tag my action methods later using the Action attribute. The conditions are where the security checks are performed. Here's the general condition first which ensures any action is performed by an authenticated user:

    class AuthenticatedUsersCondition : IActionCondition

    {

        public bool CanExecute(string action, WorkItem context, object caller, object target)

        {

            return Thread.CurrentPrincipal.Identity.IsAuthenticated;

        }

    }

    Next are specific conditions for each action. As you saw from the AuthenticatedUsersCondition you do get the action passed into to the CanExecute call so you could either pass this off to a security service or check for each action in a common method. I've just created separate classes to handle specific actions but again, how you organize things is up to you.

    class UserCondition : IActionCondition

    {

        public bool CanExecute(string action, WorkItem context, object caller, object target)

        {

            string userName = Thread.CurrentPrincipal.Identity.Name;

            return userName.ToLower().Equals("domain\joeuser");

        }

    }

     

    class AdministratorCondition : IActionCondition

    {

        public bool CanExecute(string action, WorkItem context, object caller, object target)

        {

            string userName = Thread.CurrentPrincipal.Identity.Name;

            return userName.ToLower().Equals("domain\admin");

        }

    }

    Both conditions contain the same code as before but are separated now and easier to maintain. Finally we call the Execute method on the actions themselves. Execute will pass in a work item (in this case the root workitem but it could be a child work item if you wanted), the caller and a target. In this case I want to add menu items to the UI so I'm passing in a ToolStripMenuItem object. The ModuleActions class contains our actions with each one tagged with the Action attribute. This keeps our code separate for each action but still lets us access the WorkItem and whatever objects we decide to pass into the actions.

    The Action Catalog Itself

    public class ModuleActions

    {

        private WorkItem _workItem;

     

        [ServiceDependency]

        public WorkItem WorkItem

        {

            set { _workItem = value; }

            get { return _workItem; }

        }

     

        [Action(ActionNames.ShowUserManagementMenu)]

        public void ShowUserManagementMenu(object caller, object target)

        {

            ToolStripMenuItem conditionalMenu = (ToolStripMenuItem) target;

            conditionalMenu.DropDownItems.Add(new ToolStripMenuItem("Manage Users"));

        }

     

        [Action(ActionNames.ShowAdministratorManagementMenu)]

        public void ShowAdministratorManagementMenu(object caller, object target)

        {

            ToolStripMenuItem conditionalMenu = (ToolStripMenuItem)target;

            conditionalMenu.DropDownItems.Add(new ToolStripMenuItem("Manage Administrators"));

        }

    }

    Registering The Action Strategy
    Calling ActionCatalogService.Execute isn't enough to invoke the action. In order for your Action to be registered (and called) the ActionStrategy has to be added to the builder chain. The ActionStrategy isn't added by default to an SCSF solution (even though you can resolve the IActionCatalogService since services and strategies are separate). Without the strategy in the builder chain, when it constructs the object it doesn't take into account the Action attribute.

    So you need to add this to a stock SCSF project to get the action registered:

    protected override void AddBuilderStrategies(Builder builder)

    {

        base.AddBuilderStrategies(builder);

        builder.Strategies.AddNew<ActionStrategy>(BuilderStage.Initialization);

    }

    Once you've done this your action is registered and called when you invoke the catalog.Execute() method.

    A few things about actions:

    • You don't have to call catalog.CanExecute for your actions. Just call catalog.Execute(). The Execute method makes a call to CanExecute to check if the action is allowed
    • You have to register an implementation of IActionCondition with the catalog in order to do checks via CanExecute. If you don't register a condition, any action is allowed

    Alternative Approach
    There are lots of ways to use the ActionCatalogService, this is just one of them. For example in your ModuleController you can set everything up, disable all commands, then execute your ActionCatalog which will enable menu items based on roles and security.

    The ActionCatalog lets you keep your execution code separate from permissions management and who can access what. This is a simple example but with little effort you can have this call out to say a claims based WCF service, retrieve users and roles from something like an ASP.NET Membership Provider, and make applying feature level security (including UI trimming) to your Smart Client a breeze!

    Hope that helps understand the ActionCatalog in SCSF! It's a pretty cool tool and can be leveraged quite easily in your apps.

  • Acropolis, CAB, WPF, and the future

    "Acropolis, the future of Smart Client"

    So sayeth Glenn Block, product lead for the Smart Client Software Factory and CAB. Glenn's a good friend and he's just doing his job, but I felt a little shafted when Acropolis popped up on the scene. I mean, after the last few weeks of CAB is complex and CAB is this and CAB is that, the last thing we need is a CAB replacement but here it comes and it's called Acropolis.

    There were many requests to ship a WPF version of SCSF/CAB and well, we're actually doing it now with the SCSFContrib project up on CodePlex. Is Acropolis a WPF version of CAB? We'll see but Glenn says "Acropolis takes the concepts of CAB to levels that folks in p&p might have never dreamed". From the initial reaction I'm seeing from people like Chris Holmes and Oren, Acropolis doesn't look all that impressive. Another wrapper on top of WPF, a little orchestration thrown in to "wire up components and dependencies" and the promise of building apps without writing or generating any code. I've heard this story before with CASE and like Oren, I see ugly XAML (or XML or XML-like) code being behind all this which doesn't give me a warm and fuzzy.

    I have yet to setup Acropolis and take it for a real test drive so I have to act like the movie reviewer who's never seen the movie but heard other reviews and has some initial reactions from the trailer. If CAB wasn't on the scene, this would be a great. It's hard enough to get deep into XAML as it is, so layering more complexity on top of that requires something that will help a developer, not hinder him. True, you can still (and will) rip open the XAML to figure out what's going on and make those adjustments but at least it's not that complex right now with POWPF (plain old WPF if there is such a thing). It's 2007 and we've evolved (almost) to the point where we can trust designers and editors. I still have to tweak the .designer generated files [sometimes] to get the right objects parenting in a WinForm app, but I consider that part of the territory. However when I look at what is behind the Acropolis XAML it makes me shudder. There was a quote from another blog that really disturbed me "Probably the best suggestion I can give to my customers, as I always do, is to take inspiration from all of these solutions and to build his own one". Wow. Last option I would ever say to someone especially if there's something out there to do the heavy lifting for you.

    What bothers me about this whole thing is the MS statement of "we currently have no further plans for SCSF releases". I bought into Software Factories and thought the implementation Microsoft chose (the GAT and GAX) was a good option. Building my own factories or modifying others isn't that difficult and I can express what I really intend in a factory quite easily. With no future releases it means not only CAB is stopped in its tracks, so is SCSF. We just launched the SCSFContrib project which was basically a way to extend the core without touching it, however that restriction now becomes a bit of a roadblock, and we haven't really even got rolling on the project yet.

    Maybe we need to go one step further and allow the core of CAB to be modified/rewritten/extended and let the community evolve it. Is that something that would be useful? I mean, after the debate that raged on and Jeremy Miller banging out his own "roll your own CAB framework" maybe we need to open the heart of the beast and give it an implant that will let it live past the Acropolis phase. Some of us have invested already in one framework and I don't think there's a cost benefit to shift to another one, although that seems like the path we're being pushed down. Maybe the SCSFContrib project needs to be modified to support core changes and really divorce CAB from it's over architected implementation. A CAB where the guts are abstractions might help support a more popular community driven adoption and get it past the dependency on using MS tools. How about a CAB where you can use log4net, or Windsor, or pico? If Oren can build his own Event Broker in hours and Jeremy can instruct people on building your own CAB over a dozen blog posts I don't see why this isn't possible given some help from the world around us.

  • Efficiency vs. Effectiveness, the CAB debate continues

    There's been two great posts on the CAB debate recently that were interesting. Jeremy Miller had an excellent post over the brouhaha, citing that he really isn't going to be building a better CAB but supports the new project we recently launched, SCSFContrib. I think Jeremy's excellent "Roll your own CAB" series is good, but you need to take it in context and not look at it as "how to replace CAB" but rather "how to learn what it takes to build CAB". Chris Holmes posted a response called Tools Are Not Evil from Oren's blog entry about CAB and EJB (in response to Glenn Block's enty, yeah you really do need a roadmap to follow this series of blog posts).

    Oren's response to Chris Holmes post got me to write this entry. In it he made a statement that bugged me:

    "you require SCSF to be effective with CAB"

    Since this morning, it looks like he might have updated the entry saying he stands corrected on that statement but I wanted to highlight the difference between being efficient with a tool, and being effective with the technology the tool is supporting.

    Long before SCSF appeared, I was groking CAB as I wanted to see if it was useful for my application or not and what it was all about. That took some time (as any new API does) and there were some concepts that were alien but after some pain and suffering I got through it. Then SCSF came along and it enabled me to be more efficient with CAB in that I no longer had to write my own controller, or implement an MVP pattern myself. This could be done by running a single recipe. Event the entire solution could be started for me with a short wizard, saving me a few hours I would have taken otherwise. Did it create things I don't need? Probably. There are a lot of services there that I simply don't use however I'm not stoked about it and ignore them (sometimes just deleteting them from the project afterwards).

    The point is that SCSF made me more efficient in how I could leveage CAB, just like ReSharper makes me a more efficient developer when I do refactorings. Does it teach me why I need to extract an interface from a class? No, but it does it in less time than it would take manually. When I mentor people on refactoring, I teach them why we do the refactoring  (using the old school manual approach, going step by step much like how the refactorings are documented in Martin Fowlers book). We talk about why we do it and what we're doing each step of the way. After doing a few this way, they're comfortable with what they're doing then we yank out ReSharper and accomplish 10 minutes of coding in 10 seconds and a few keystrokes. Had the person not known why they're doing the refactoring (and what it is) just right-clicking and selecting Refactor from the menu would mean nothing.

    ReSharper (and other tools) make me a more efficient developer, but you still need to know the what and why behind the scenes in order to use the tools. I compare it to race car driving. You can give someone the best car on the planet, but if they just floor it they'll burn the engine out and any good driver worth his salt in any vehicle could drive circles around you. Same as development. I can code circles around guys that use wizards when they don't know what the wizard produces or why. Knowing what is happening behind the scenes and the reason behind it, makes using tools like ReSharper that much more value-added.

    SCSF does for CAB what ReSharper does for C# in my world and I'll take anyone that knows what they're doing over guys with a big toolbox and no clue why they're using them anyday.

     

  • SCSFContrib is Alive!

    I'm pleased to announce the startup of a new project on CodePlex. I'm very happy to be part of the team to bring you SCSFContrib.

    What is SCSFContrib? If you're familiar with NAntContrib where members of the community contribute extensions to NAnt (specific NAnt tasks) then you're on the same wavelength. SCSFContrib is very similar, extra goodness for CAB/SCSF with a few differences:

    • It is based on the Smart Client Software Factory (SCSF) and the Composite Application UI Block (CAB)
    • It allows you, the community, to contibute to an effort that extends patterns and practices deliverables
    • It shortens the time that contributions/changes/extensions to SCSF/CAB will make it into the public. Rather than waiting for a drop from the patterns and practices team, our team will help manage these and make them available through the CodePlex site
    • Provides guideance to the patterns and practices team as to where gaps exist in the current factory and how they can make improvement in the core

    There are three Contrib projects in motion, SCSFContrib being one of them. The other two are EntLibContrib and WCSFContrib (Web Client Software Factory) which allow contributions to each of those projects.

    Note that this project does not allow you to contribute code directly to the core application blocks. We're talking about extensions here (for example there's an Outlook Bar extension that will be one of the first ones we release under the SCSFContrib project) but that doesn't preclude you from creating your own version of a core block. For example you could replace the Dependency Injection block completely if you wanted, but we won't be replacing it directly in the Factory. It could be enabled as part of a recipe (Use ObjectBuilder or XYZ for Dependency Injection). Of course everything generated has to work with the changes, but that would be up to you. In addition, the one small thing we ask for is full unit tests with any new development (although Alpha/Beta projects won't require these).

    While this was initiated by Glenn Block and the Patterns and Practices team (thanks guys!), the SCSFContrib project is run by community folks (myself included). Here's who's on the team:

    Kent Boogaart

    Author of WPFCAB. Kent has done some great work in the CAB space by developing a WPF version of our Windows CAB extensions. He’s graciously created an unmodded version that will be included in the contrib.. This product is in production in several environments today. Kent’s blog is at http://kentb.blogspot.com/.

    Ward Bell

    Ward is the product manager for IdeaBlade, one of Microsofts key partners out there spreading CAB adoption through their Dev Force solution. IdeaBlade was one of the pioneers of Smart client software development in the .NET space. Ward is also extremely seasoned in the industry with 20+ years of experience. Ward’s blog is at http://neverindoubtnet.blogspot.com/

    Matias Woloski

    Matias works at Southworks. Matias and the whole Southworks gang are truly gurus at everything related to CAB, SCSF and WCSF as they helped Microsoft write it. Matias is also the author of the Outlook bar extensions for CAB. Matias’ blog is at http://blogs.southworks.net/blogs/matiaswoloski/default.aspx

    And me, Bil Simser, major geek and general all-around nice guy.

    Here's to the successful launch of another P&P Contrib project and hopefully you'll find use with the SCSFContrib project in your own solutions. You can check out the CodePlex site here and be sure to voice your opinion via the discussion forums or issue tracker as to what you're looking for (or contribute something you've built with CAB/SCSF if that's your thing).

  • Reusability vs. RYO

    Every so often, a topic brushes by my RSS feeds that I have to jump into and comment on. The latest foray is a conversation between Chris Holmes, Jeremy Miller, and Oren Eini. It started with Oren and a post about not particularly caring for what the Microsoft Patterns & Practices guys are producing (EntLib, CAB, SCSF, etc.) and ballooned here, here, and here. Oren started down the path that CAB (and other components produced by P&P) was overly complex and unnecessary. I'll focus on CAB but there are other smatterings of things from EntLib here. The main points Oren was getting across (if I read him correctly) was lack of real world applications backing what P&P is producing and overly complex solutions for simple(r) problems. Oren put together his version of the policy injection block (a recent addition to EntLib) in 40 minutes. Last night I was reading Jeremy Millers response and needed to chime in as I'm very passionate about a few things, namely Agile software development and CAB.

    I'll be the first to admit that CAB is complex. EntLib is large. There is a lot there. As Chris said this morning in what I think was an excellent response to the entire discussion, CAB for example is not just about building maintainable WinForm apps. I like CAB as it gives me a bunch of things and they all work together in a fairly harmonious way. EventBroker is a nice way to message between views and keeping the views separate; ComandHandlers allow me to hook up UI elements indirectly to code to execute them; the ActionCatalog let's me security trim my commands (and in turn my UI); and the implementation of the MVP pattern using views lets me write presenter tests and keep my UI thin. This all makes me feel good. Did it take me a while to get here? Absolutely. I've spent the better part of a year learning CAB, EntLib, ObjectBuilder, WorkItems, and all that jargon but it's no different than learning a dozen different 3rd party libraries. I simply chose the MS path because it was there and everything was in one neat package. If you packaged up Castle, NHibernate, StructureMap, and others together in a single package maybe I would have chosen that path (and is there really two different paths here? I use both tools together anyways).

    Oren's defense is around the fact that he (and Jeremy) follow the guideline of evolving a framework from your application needs, not building one (like what the P&P guys have done). Okay, that's fair but at some point you have to stop building things over and over again. So when does your own work become a framework that you reuse? Is it as lean and mean as what you want it to be. Sure, you can put together the basic needs of an IoC in half a day (half a day Bil time, 40 minutes Oren time) but it's the just the beginning. It serves the need you have today and the problems you might be facing right now. I would argue that if you took something like StructureMap and evolved it to handle scenarios that you're not dealing with today, that you would be starting to build your own implementation of EntLib.

    We all want lean software that does the job however I subscribe to the mentality that if you leverage something else (aka not reinventing the wheel) then do so as long as it doesn't come at a cost higher than doing it yourself. That's a hard decision to make as you don't want to get too predictive on what the future may hold (do we need logging, security, etc. in the future?) but you gauge your response based on current affairs and what feels best. It's more of an art than a science. When I first looked at CAB I thought it was huge, but once I sat down to grok the pieces and how it all fit together, it made sense. EntLib and CAB do include everything and the kitchen sink and you do need to get past the learning curve, but in the end it's a good collection of tools that you can have in your toolbox. Unfortunately it's not something I could introduce at a conference or User Group session and describe the entire stack in an hour, so I tend to avoid showing off applications and concepts using it as it just turns into a discussion of what [SmartPart] means instead of the main goal like describing MVP which I can do with my own code.

    Is EntLib/CAB/etc. doing too much maybe? Perhaps but then if I choose the 3rd party elements I want and wire them together to suit my needs, what kind of Frankenstein have I built in the progress? When I look at CAB holistically, there's a lot there but it's not a bad implementation. I don't think Oren or Jeremy are saying the P&P guys did a bad job on in, they just choose to evolve their own solutions using a minimalist approach. I'm all for that. It's very TDD-like. When I build systems I start by writing single tests against my domain and only doing what I need at the time (the YAGNI principal). However at some point you end up with a very rich domain, hundreds (or thousands) of unit tests, dozens (hundreds) of classes and methods, and a lot of functionality. I argue that is in fact what EntLib and CAB have become. They're rich, re-usable tools that do a lot but frankly you can still use what you need. Maybe you'll deploy all the EntLib assemblies with your application and only use the logging feature, but so what? As an example, I had to implement NHibernate in an application recently to apply persistence to my domain. When I ran some db unit tests, I found out that I need the NHibernate assemblies, log4net, and an assembly from Castle to make it work. Disk space is dirt cheap so having the extra there means nothing (except a few extra seconds of download time).

    I'll cite Rocky and his excellent CSLA.NET as an example. It's a large framework, lots of classes, lots of functionality. That's what frameworks are about. However while I like what Rocky's done and he's had great success at it, I don't subscribe to the approach he took. I'm not a fan of the ActiveRecord pattern and don't like how business objects are tied to data implementation (even if there's a level of abstraction there). I simply cannot use CSLA with DDD. Is the framework a bad product? No way. Would I recommend it to others? Absolutely. Would I use it myself. Nope, but it's a good piece of software and I wouldn't discount it.

    CAB follows similar concepts as it's big and ugly in some places (like ObjectBuilder). Sure I could use Castle to do better (real) dependency injection, but if I don't buy into the MS song and use CAB and EntLib to it's full extent I end up with bits and pieces of goo all over the place. Like I mentioned with NHibernate, I needed to deploy log4net as it needs it, even if I didn't turn on that feature. At least with EntLib, if I'm not using security for example I don't need to deploy the security module. In my case now, I have EntLib logging deployed and now I've got a second logging system deployed because NHibernate dragged it along for the ride. Eventually I could have a really ugly monster on my hands with copies of Castle, StructureMap, CAB, EntLib, NHibernate, log4net, and who knows what else all living (hopefully) together in happy existence. I don't want that.

    CAB gives me most of what I need (except O/R mapping and persistence) so for me I leverage as much as I can from CAB and EntLib and fill in the gaps with things like NHibernate for persistence. I could use EntLibs database factory but then I'm rolling my own DAL and that's not a path I want to take, so I choose to ignore the EntLib database component. The nice thing is that I don't have to deploy it so as long as my code doesn't call it, I'm golden.

    As Jeremy put it, the P&P guys are a good thing as they're out there getting the Agile word out to many more people that we can. While they do produce large(r) tools, frameworks, and components that include perhaps more complexity that you need at the time at the end of the day, you'll probably end up using it. IMHO I'm happy with what CAB and EntLib provide. Could I get the same functionality from the other alteratives? For sure, however I would probably be writing more code to wire things together than I would with CAB. For that reason, I like what the P&P guys do and look forward to the future as to how they'll evolve hoping these kind of discussions will help adjust their path towards a better end game for all of us.

  • Adding a splash screen to a CAB application

    Been awhile since I blogged as I've been sort of out of it missing the MVP Summit and all. Here's a simple way to add a splash screen to your Composite UI Application Block (CAB) based applications. It's pretty simple to implement a splash screen. This is a basic form that will popup with a logo or whatever of your choosing while the application loads. The code below is based on applications generated with the June 2006 version of the Smart Client Software Factory, but the idea is the same and can be applied to any CAB application.

    First, create the splash screen. This will just be a simple Winform you add to your Shell project. Call it ShellForm and give it a splash image to display. it helps if you change a few properties to make it more "splashy":

    • Change the StartPosition property to CenterScreen
    • Change the ShowInTaskbar property to False
    • Change the FormBorderStyle property to None

    Now drop a picture box on the form and load up your image. Any image will do, but you'll probably want to size the splash screen to match the size of the image (otherwise some shearing might occur).

    Now we need to modify two files. ShellApplication.cs and SmartClientApplication.cs. In ShellApplication.cs all you need to do is change the call to the base class of SmartClientApplication to accept your ShellForm. Change the declaration from this:

       22 class ShellApplication : SmartClientApplication<WorkItem, ShellForm>

    to this:

       22 class ShellApplication : SmartClientApplication<WorkItem, ShellForm, SplashForm>

    SplashForm is the name of the class you created for the new form. Finally we get down to the meat of the splash screen. In SmartClientApplication.cs we need to do two things, recognize the new parameter being passed into the class and get the splash screen going.

    First add a generic to the declaration of the SmartClientApplication class as TSplash:

       25 public abstract class SmartClientApplication<TWorkItem, TShell, TSplash> : FormShellApplication<TWorkItem, TShell>

    Then initialize it like the WorkItem:

       25 public abstract class SmartClientApplication<TWorkItem, TShell, TSplash> : FormShellApplication<TWorkItem, TShell>

       26     where TWorkItem : WorkItem, new()

       27     where TShell : Form

       28     where TSplash : Form, new()

    Add a private member variable to hold the splash screen (using the generic type "TSplash"):

       30 private TSplash splash;

    Create the object in the constructor:

       35 public SmartClientApplication()

       36 {

       37     splash = new TSplash();

       38     splash.Show();

       39     splash.Update();

       40 }

    After the shell gets created, we want to kill off the splash screen. We'll do this in the AfterShellCreated method of the SmartClientApplication class by adding an event handler when the Shell gets activated. Change your AfterShellCreated method to look like this:

       46 protected override void AfterShellCreated()

       47 {

       48     base.AfterShellCreated();

       49     Shell.Activated += new EventHandler(ShellActivated);

       50 }

    And create the event handler. The handler will remove the Shell.Activated event and dispose of the Splash form:

       57 private void ShellActivated(object sender, EventArgs e)

       58 {

       59     Shell.Activated -= new EventHandler(ShellActivated);

       60     splash.Hide();

       61     splash.Dispose();

       62     splash = null;

       63 }

    That's it! A cool looking splash screen for your CAB application in about 10 minutes.

    Note: There was a long thread here on the GDN forums (moved to CodePlex) on doing this. That technique works as well, and gives you the ability to intercept the "loading" of the application as it goes through it's paces. We're using it for one app, but the technique above is a more simple approach that just gets the job done so you might find it easier to implement.

  • Using Dependency Injection with CAB

    I was working through a problem tonight regarding dependency injection and CAB. CAB provides a facility to inject services and whatnot into other class using ObjectBuilder, Microsoft's DI framework. ObjectBuilder isn't the same as a DI/IOC container like Windsor Container or Spring.NET (or Jeremy Millers excellent StructureMap) but more like a framework for building containers. However in CAB it serves the purpose we need.

    Let's say I have a service that performs lookups and returns me lists of items from some backend system. I would like to use this LookupService in various modules but I don't want the modules responsible for creating the service (especially since I only want one of them and don't want to deal with singletons) and I want an easy way to ensure the service is loaded and ready to go when I need it. Here's where CAB will help you with this.

    First let's look at our service implementation:

    public class LookupService : ILookupService

    {

        public List<KeyValuePair<int, string>> Items

        {

            get

            {

                List<KeyValuePair<int, string>> items = new List<KeyValuePair<int, string>>();

                items.Add(new KeyValuePair<int, string>(1, "Item 1"));

                items.Add(new KeyValuePair<int, string>(1, "Item 2"));

                return items;

            }

        }

    }

    This is a straight forward service that returns a generic List<> of KeyValuePairs<>. I might use this in my UI in a combo box or whatever, but it's just a lookup of items. The implementation here is hard coded, but you could just as easily have this call out to a database, do an asynchronous web service call, whatever you need.

    To share the service, I'll use the Infrastructure.Module project in my SCSF generated solution. This module gets loaded first and using SCSF I have it set to be a dependency so whenever the system loads any module I'll load this one first, ensuring my service is there. Here's my ProfileCatalog.xml that shows the dependency.

    <SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile/2.0">

        <Section Name="Services">

            <Modules>

                <ModuleInfo AssemblyFile="Infrastructure.Module.dll" />

            </Modules>

        </Section>

        <Section Name="Apps">

            <Dependencies>

                <Dependency Name="Services" />

            </Dependencies>

            <Modules>

                <ModuleInfo AssemblyFile="Project.dll" />

            </Modules>

        </Section>

    </SolutionProfile>

    The module dependency is part of SCSF so it won't exist if you're just using CAB. In my profile catalog, the moment the Project.dll module loads, it will first load it's dependency module(s) from the Services section of the XML file. You can have as many services as you want here and they'll load in reverse order that they're listed in the file.

    To instantiate the service and make it available, I have to load it up and add it to the RootWorkItem and it's list of services. This is done in the ModuleController.cs in the Infrastructure.Module project:

    public class ModuleController : WorkItemController

    {

        public override void Run()

        {

            AddServices();

            ExtendMenu();

            ExtendToolStrip();

            AddViews();

        }

     

        private void AddServices()

        {

            WorkItem.RootWorkItem.Services.AddNew<LookupService, ILookupService>();

        }

     

        private void ExtendMenu()

        {

        }

     

        private void ExtendToolStrip()

        {

        }

     

        private void AddViews()

        {

        }

    }

    If I were to load it up like a regular WorkItem and only use this code:

    private void AddServices()

    {

        WorkItem.Services.AddNew<LookupService, ILookupService>();

    }

    Then I would be loading it into the services for this module only, which is great, but I want this for all modules to use so I add it to my RootWorkItem. RootWorkItem is a property of any WorkItem that refers to the one and only root item created by the Shell. This way I know there's only one and I can access it from any module anywhere.

    Once it's been added to the WorkItems list of Services, I can inject it into any module I need. I'll inject it into my presenter class as that's where I'll use it. The presenter will call the service to get it's values, and set the View with those values to update some GUI element (implementation of the View isn't shown but it just takes the values and binds them to a listbox or whatever you would use them for). I can inject it into the Presenter class two different ways. First, I can use the [ServiceDependency] tag in a parameter passed to the constructor of the Presenter:

    public class ProjectListViewPresenter : Presenter<IProjectListView>

    {

        private ILookupService _lookupService;

     

        public ProjectListViewPresenter([ServiceDependency] ILookupService lookupService)

        {

            _lookupService = lookupService;

        }

    }

    Not that nowhere do I have to call the constructor, this is done with the AddViews method in the ModuleController and it knows that it needs a type of ILookupService to inject during construction. The constructor sets a private member variable of type ILookupService to the value passed in. ObjectBuilder knows it needs to get an object of that type and will find it using the ServiceLocator service, which is constructed by the Shell. The second way is I can set a property and decorate it using the [ServiceDependency] tag like so:

    public class ProjectListViewPresenter : Presenter<IProjectListView>

    {

        private ILookupService _lookupService;

     

        [ServiceDependency]

        public ILookupService LookupService

        {

            get { return _lookupService; }

            set { _lookupService = value; }

        }

    }

    This is the same effect and is done whenever the object is created. Use one technique, not both as they'll both be called. Even though it's the same service object, it's just a waste to do it twice. Finally I just use the service in a method in my presenter when it's ready to update the view:

    public class ProjectListViewPresenter : Presenter<IProjectListView>

    {

        private ILookupService _lookupService;

     

        [ServiceDependency]

        public ILookupService LookupService

        {

            get { return _lookupService; }

            set { _lookupService = value; }

        }

     

        public override void OnViewReady()

        {

            View.Items = LookupService.Items;

            base.OnViewReady();

        }

    }

    The end result is that I have a loosely coupled service that's injected into my presenter and provides my view with the services it needs. You can use either technique to set the service in the presenter and the great thing is that using something like Rhino mocks, you don't need to create the implementation of the service so writing presenter tests is a breeze with this technique, as you can setup whatever conditions you want for your tests.

  • Using MSBuild with Smart Client Software Factories

    The Smart Client Software Factory (SCSF) is an awesome tool. It comes in the form as a guidance package from the patterns and practices guys and kicks off your initial Smart Client app with various services, several projects, and a shell application all built on top of the Composite Application UI Block (CAB).

    I have found one problem with the current version of SCSF and that's when you generate the initial solution and try to build it using MSBuild. Create a solution using the factory and try building the .sln file with MSBuild. You'll get a host of errors about projects referencing projects that don't exist. Here's some sample output:

    SmartClientSolution1.sln : Solution file warning MSB4051: Project {90BC9A2E-DF32-4D50-AB7A-2967B8F5D8D9} is referencing a project with GUID {BE39A9ED-D4C6-42E7-91D6-63D9B1D185C6}, but a project with this GUID was not found in the .SLN file.

    I believe this might be because the .csproj/.sln file is generated before the GUIDs are. It doesn't have a problem in the IDE because it references projects by relative file path, but when you try to build a solution using MSBuild (like via an automated build server) the build fails.

    Just to clarify this. The GUIDs in the solution file and csproj files are correct however where each project references another in the csproj file it contains both a reference location and a GUID. It's that GUID that's incorrect.

    Here's the section in each .csproj I'm referring to:

    <ItemGroup>
    <ProjectReference Include="..\Infrastructure.Interface\Infrastructure.Interface.csproj">
    <Project>{C0143C3B-2D43-4CC3-B593-236D4097F23F}</Project>
    <Name>Infrastructure.Interface</Name>
    </ProjectReference>
    <ProjectReference Include="..\Infrastructure.Library\Infrastructure.Library.csproj">
    <Project>{90BC9A2E-DF32-4D50-AB7A-2967B8F5D8D9}</Project>
    <Name>Infrastructure.Library</Name>
    </ProjectReference>
    </ItemGroup>

    You can fix this without a problem. To do so just open up the .csproj file and in the ItemGroup section, paste in the correct GUIDs for each project it's referring to from the original .sln file. The references that need to be fixed are:

    • Infrastructure.Library referencing Infrastructure.Interface
    • Infrastructure.Module referencing Infrastructure.Interface
    • Shell referencing Infrastructure.Interface
    • Shell referencing Infrastructure.Library

    Once you've updated the GUIDs in the .csproj files, you'll be good to go for automated builds of your CAB projects. I've logged this as an issue here on the new CodePlex site so hopefully they'll get to fixing this as it was a real pain to find.

  • Exposing business objects to the UI

    I've been working the past few months with the Composite UI Application Block (CAB) and the Smart Client Software Factory (SCSF). They're all great but the documentation throws me for a loop sometimes.

    In an entry called "Map Business Entities into User Interface Elements" it suggests creating a mapper class and using it to convert some business object into a UI one. This makes sense however the implementation and references cause my head to hurt.

    In a typical MVP pattern, you have the Model (your business object), the View (the UI), and the Presenter (a go-between guy). The presenter knows about both the view and the model. It needs to inform the model to update based on messages recieved from the view, and tell the view about changes in the model. Neither the model or the view have any knowledge of each other.

    Introduce the mapper which knows about the Model and the View. This is the other side of the equation so when given a business object, the mapper will spit out a drop down list, a grid control, or whatever UI element is appropriate to display something from the business layer (say a list of customers).

    In the example Microsoft provides via the guidance package, the view has a method that accepts a business object which then calls the mapper to translate it into a ListViewItem. The view then updates its UI control (a ListView control) by adding list items to it created by the mapper.

    However this means that you're exposing you business objects to the user interface, which creates a coupling between the UI and the business layer (at least from a deployment perspective). If you don't do it this way you have to have the presenter (which should know about domain objects so that's ok) update the view but what is it going to update it with? Certainly not a ListViewItem which will make the presenter dependent on the windows form control assemblies.

    Without creating a intermediate object (like a CustomerDTO with nothing but getters/setters) are we really bound to have the UI reference the business layer and is the documentation here really a best practice for exposing business objects to the UI? How do you guys do it?