in

 

Chad Myers' Blog

Department of Problem Prevention

July 2008 - Posts

  • StructureMap: Interlude

    I'm trying to wrap up the "StructureMap: Advanced Scenarios Usage" post. In the meantime, I wanted to make you aware of a few things:

    • I just updated my StructureMap: Basic Scenario Usage post with a correction. I was mistaken about being able to set properties on configured objects. Currently, you cannot configure properties on configured objects unless the property has the [SetterProperty] attribute defined.  This was on purpose since there is a good argument that property injection is 'bad' (i.e. leads to problems later, can complicate configuration and testing, etc).  There are, however, scenarios where property injection is acceptable so being able to configure properties without using the attribute is being seriously considered for the StructureMap 2.5 release.
    • Derik Whitaker posted about how to use StructureMap in an MSTest situation to work around some of MSTest's quirks. He used StructureMap's ability to configure itself through XML in your web.config/app.config file rather than having a separate XML file. Or you could, of course, save half your time and tons of complexity and just use NUnit/MBUnit/XUnit and not deal with the hassle. But it's good for those people required to use MSTest to still be able to take advantage of StructureMap.
    • You should know that Joshua Flanagan was the one who contributed that feature (the app.config configuration stuff) to StructureMap which is useful for a variety of reasons -- not just the MSTest reason.  The reason you should know of him is because...
    • The same Joshua just posted a great post on how to get started from the most basic level with StructureMap. It's a "Hello World" type app, but shows off some of the ways StructureMap works. Of course it's overdone as a Hello World app, but that wasn't the point.  The point is to show how to get started with StructureMap and I think it does a really good job at that.
  • StructureMap: Medium-level Usage Scenarios

    This is a follow-on to my previous post about basic usage scenarios for StructureMap.  This post will focus on slightly more advanced usage scenarios and how StructureMap handles them.  For those playing the home game, I’m still working on the ‘Exploring ShadeTree’ series, but it’s hit a small roadblock because there are some design changes pending on the NHibernate stuff I was going to cover. Please bear with me.  Anyhow, in the meantime, I hope you find these StructureMap guides helpful.

    Auto-wiring Factory

    I have many objects I wish to manage who have dependencies upon each other. Managing the construction and assembly of these objects is complicated and tedious. When I request an IFoo, I want to get back an instance of Foo with all its dependencies satisfied.

    Let's assume you have the IFoo/Foo combination, in addition to IBar/Bar, and IBaz/Baz.   Let's also say that Foo has a dependency on both IBar and IBaz.  The current recommended way of handling this situation is to define a constructor for Foo() that receives an instance of IBar and IBaz.

    Consider this type structure:

    public interface IBar{}
    public class Bar : IBar{}
    
    public interface IBaz{}
    public class Baz : IBaz{}
    
    public interface IFoo{}
    
    public class Foo : IFoo
    {
        public Foo( IBar bar, IBaz baz )
        {
        }
    }

    The StructureMap configuration for this structure would look like this:

    StructureMapConfiguration
        .ForRequestedType<IBar>().TheDefaultIsConcreteType<Bar>();
    
    StructureMapConfiguration
        .ForRequestedType<IBaz>().TheDefaultIsConcreteType<Baz>();
    
    StructureMapConfiguration
        .ForRequestedType<IFoo>().TheDefaultIsConcreteType<Foo>();

     

    And then, to get a Foo instance with all its dependencies satisfied, simply use ObjectFactory.GetInstance like normal:

    IFoo fooInstance = ObjectFactory.GetInstance<IFoo>();

     

    Note that no where did you have to explain to StructureMap that Foo was dependent upon Bar or Baz. StructureMap figured it out automatically!  This concept is known as "autowiring".  By default, StructureMap will attempt to satisfy as many dependencies as it can.  It will attempt to use the 'greediest' constructor (the one with the most parameters).  If your class has two constructors, one has just IBar and the other has IBar and IBaz, StructureMap will try to use the IBar and IBaz constructor.

    Isolated Configuration (Registration of Dependencies)

    I have many objects in many assemblies (some of which may not be known at compile time). Or, I don't like having every single object in my StructureMap configuration defined in my startup routine. Is there a way that each unit of deployment can specify it’s own object dependency registration?

    So in our project at work, we have a few assemblies that have varying concerns such as Web (our ASP.NET MVC project) and Core (pretty much everything else).  Within Core, we have several areas of concern such as Domain model, Persistence, Web (everything related to Web applications in general – stuff we can reuse on other web projects).  Each of these areas of concern has a class that derives from Registry. No, this has nothing to do with the Windows Registry, this is in the context of ‘object dependency registration.’  You can create a class which derives from StructureMap.Configuration.DSL.Registry and override the configure() method.  In this method, you should register the objects that are “local” to the Registry class. For example, your ‘WebRegistry’ class would register all the controllers, any HttpContext abstractions, and things like that.

    Another, perhaps better, example case for this might be a composite UI/SmartClient type application (think CAB, Prism, etc) where entire portions of the application are loaded at runtime from external assemblies. It’s actually impossible for the central application startup code to know all the components that will be loaded into the system. In this case, Registries really shine.

    Consider this contrived example of what a PersistenceRegistry class might look like:

    public class PersistenceRegistry : Registry
    {
        protected override void configure()
        {
            ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
            ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>();
            ForRequestedType<ISecurityDataService>().TheDefaultIsConcreteType<SecurityDataService>();
        }
    }

    Notice how it has only the stuff related to persistence and nothing about controllers or anything like that? 

    In order for these Registries to take effect, you must let StructureMap know of their existence. One way is to tell it implicitly using the AddRegistry method, like so:

    StructureMapConfiguration.AddRegistry(new PersistenceRegistry());

    Auto-discovery of Configuration

    I have several registries including ones that I don’t know about at compile time. It would be nice if these could be auto-discovered.

    Another way in which to invoke StructureMap Registries, which also happens to be the the preferred method of doing so, is to tell StructureMap to scan through the assemblies you tell it to scan through (including the current one, if you tell it to do so). StructureMap will automatically recognize types deriving from Registry and invoke their configure() method.  There are two primary use cases for this behavior: 1.) You know all the assemblies at compile time and 2.) You do not know all the assemblies at compile time.  For the first case, consider the following example:

    StructureMapConfiguration
        .ScanAssemblies()
        .IncludeTheCallingAssembly()
        .IncludeAssemblyContainingType<CoreRegistry>()
        .IncludeAssemblyContainingType<PersistenceRegistry>()
        .IncludeAssemblyContainingType<WebSharedRegistry>()
        .IncludeAssemblyContainingType<OurWebApplicationRegistry>();

    As you can see here, we’re explicitly telling StructureMap to load the current assembly, plus our contrived “Core”, “Persistence”, “WebShared”, and “OurWebApplication” assemblies which each have their own Registry implementations.  Note that if it just so happened that TheCallingAssembly was also OurWebApplicationRegistry’s assembly, StructureMap would handle that gracefully and would not result in duplicate registrations.

    As for the other case -- the dynamically-loading-assemblies case – you’ll just need to call ScanAssemblies().IncludeTheCallingAssembly() from the initialization/startup/bootstrap method of your plugin.  For example, assuming you’re using some sort of SmartClient/Composite UI application, when you load in a new module, you’re likely going to have some sort of entry point into the module (i.e. a well known IModule interface that some class implements that has an Initialize() method on it of some sort).  Put your ScanAssemblies().IncludeTheCallingAssembly() call in there or have it called by your Initialize() method.  Your module/plug-in’s Registry implementation will know all about the dependencies of your module and when you inform StructureMap of this, the module and all its dependencies will be loaded into the container and your module will be ready to go.

    Profiles, Alternate Configurations

    Certain objects I’ve defined in my container are not appropriate in all circumstances. I would like to have one concrete instance returned when my application is running in Mode A and a different instance returned when my application is running Mode B.

    A common scenario we use at work is “Live” and “Stubbed” where live usually means “connected to the database and external services” and “stubbed” means “it’s not connected to anything outside the application.”  This is, of course, useful for integration testing and for quick smoke tests, etc where full connectivity might not be required. Another example might be the “Google Map API” or “Yahoo Map API” profiles where some different services with different underlying implementations may be warranted, etc.

    First, declare your dependencies like normal. Then, create a new profile and declare the differences. New profiles will gain all the configuration of the default/unnamed profile, so you only need to define what is different.  Remember our PersistenceRegistry up above?  He’s an example of how it might change when the concept of profiles are introduced:

    public class PersistenceRegistry : Registry
    {
        protected override void configure()
        {
            ForRequestedType<IValidator>().TheDefaultIsConcreteType<Validator>();
            ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>();
            ForRequestedType<ISecurityDataService>().TheDefaultIsConcreteType<SecurityDataService>();
    
            CreateProfile("Stubbed")
                .For<IRepository>().UseConcreteType<InMemoryRepository>()
                .For<ISecurityDataService>().UseConcreteType<StubSecurityDataService>();
        }
    }

    Note the ‘CreateProfile’ call.  When StructureMap’s current profile changes to “Stubbed”, requests for IRepository will receive an InMemoryRepository instead of a normal Repository object.

    In order to use this profile, you can do a number of things (this list is not comprehensive, I’m sure I’m missing something else): 1.) Call TheDefaultProfileIs(“YourProfileName”), 2.) Drop a StructureMap.Config file in your bin folder or web root.

    #1 is easy, somewhere in your startup code, when you’ve determined (somehow) that you need to load a specific profile, you can simply call StructureMapConfiguration.TheDefaultProfileIs(“SomeOtherProfile”).

    #2 is also pretty easy. When we want to run in ‘stubbed’ mode, we simply drop a mostly-empty StructureMap.config file into our web root (see example below). When we want to run ‘live’ again, we remove the file. Pretty easy, huh?  Here’s what our stubbed file looks like:

    <StructureMap MementoStyle="Attribute" DefaultProfile="Stubbed">
    </StructureMap>

    Conclusion

    That’s a good chunk of stuff for right now, there may be a few other medium scenarios that aren’t coming to mind right now. Please feel free to suggest some and I’ll look into it.

    In the next post, I’m going to go into some more advanced scenarios such as convention scanners, more manual/fine-grained object construction, construction-via-lambda, direct object container injection, and possibly a few others.

  • StructureMap: Basic Scenario Usage

    First, I'm going to assume that you are somewhat already familiar with the concepts of Dependency Injection and what, in general, an Inversion of Control Container is for. If not, you may find these links helpful:

     

    I'm also going to assume that you know what I'm talking about when I say "StructureMap".  If not, then you should check out this link:

     

    If I've lost you with any of these assumptions, please leave a comment and I'll step back and go into these some more for you!

    Most Common Usages

    I'm going to cover three of the more common usage scenarios and how you accomplish these with the upcoming StructureMap 2.5.

    Simple Factory

    I have an interface IFoo with a concrete implementation Foo. When IFoo is requested, new up and return a Foo.

    First, somewhere in the startup code area of your application, register the two types with the container, like so:

    StructureMapConfiguration
        .ForRequestedType<IFoo>()
        .TheDefaultIsConcreteType<Foo>();

    Next, to retrieve the instance elsewhere in your code, use the ObjectFactory class in StructureMap:

    // fooInstance is actually of type Foo
    IFoo fooInstance = ObjectFactory.GetInstance<IFoo>();

     

    Object Lifetime Manager

    I have a session-type object I need kept alive for the entire thread or ASP.NET request.  When IFoo is requested, return me a Foo instance specific to this ASP.NET request or thread

    StructureMap can create an instance of an object for you and manage it's life time according to the life of the current Thread or, in an ASP.NET scenario, the life of the current HTTP request.  This is useful for caching things like database connection sessions or user credentials, etc.

    First, when you define your object in your startup code, add the CacheBy() option:

    StructureMapConfiguration
        .ForRequestedType<IFoo>()
        .TheDefaultIsConcreteType<Foo>()
        .CacheBy(InstanceScope.HttpContext);

    You can also use InstanceScope.ThreadLocal for non-ASP.NET multithreaded scenarios, InstanceScope.Singleton which means the object will live for the entire life of your AppDomain, and InstanceScope.Hybrid which will choose HttpContext if available, otherwise it'll revert to ThreadLocal. Hybrid is particularly handy in a unit testing scenario where your tests will automatically adapt to either a live ASP.NET scenario or a test threading scenario.

    Then, request your object just like normal:

    IFoo fooInstance = ObjectFactory.GetInstance<IFoo>();

    If you've called GetInstance<IFoo> more than once in that same ASP.NET request, you'll get the same Foo instance.  If there are two requests executing simultaneously on your web server, they'll each get their own Foo instance.

     

    Object Assembler

    I have an object that needs to have a value set from the application configuration on startup. When IFoo is requested, new up a Foo, set it's NumberOfChickens property from the AppSettings/NumChickens setting in my app.config and return me the instance.

    UPDATE 7/26/2008:  My apologies -- at the time of this post and updating, StructureMap does not currently set property values unless they have the [SetterProperty] attribute.  The 'WithProperty' and 'SetProperty' methods are misleading as they apply normally to CONSTRUCTOR parameters by that name OR properties with the [SetterProperty] attribute placed upon them.  There have been several requests for this in the past and there is likelihood the ability to set properties without requiring attributes will be added to the final StructureMap 2.5 release (currently version is 2.4.9).

    Like the previous examples, define your object in your startup code, but change it slightly to have StructureMap automatically take care of getting the property for you:

    StructureMapConfiguration
        .ForRequestedType<IFoo>()
        .TheDefaultIs(
            new ConfiguredInstance()
                .UsingConcreteType<Foo>()
                .WithProperty("NumberOfChickens")
                .EqualToAppSetting("NumChickens")
        );

    Just like the others, the business end is still the same:

    IFoo fooInstance = ObjectFactory.GetInstance<IFoo>();
  • Project anti-pattern: Many projects in a Visual Studio Solution File

    I've been hearing from several colleagues about how their Visual Studio solution files have many (i.e. more than 10, and usually more than 30 -- in one case, more than 100!).  So far, none of them have been able to give me any good explanation for why this is and most of them hate it but they can't change it because their architect/lead/whatever won't let them.

    I'm hoping that by getting the discussion going on this in the greater community, we can try to discourage everyone from having lots of projects in a solution. 

    Why are lots of projects in a single solution not good?

    Aside from some of the more obvious arguments about performance, runtime optimization, PDB and assembly size, etc, etc, etc -- actually, wait. These are obvious, right? Anyone who's ever loaded a VS solution file with more than 20 projects should know exactly what I'm talking about.  And if you've made the mistake of kicking off a build in Visual Studio with this solution, you know that you're in for a 1-5 minute sit-on-your-hands party.  And also -- and I could be wrong about this, but it was true as of .NET 2.0 -- the JIT cannot optimize code across assembly boundaries (or at least it can't do ALL its optimizations).  Then there's the inherent overhead of each DLL file and assembly metadata being loaded for each assembly, not to mention the extra overhead of having so many PDB/symbols loaded in Debug mode, etc, etc, etc.  If you need more proof of the performance problems caused by lots of assemblies, let me know and we'll go deep. I'm hoping that these facts are well established in the wide, wide world of .NET.

    Ok, so hopefully we're past the obvious arguments, let's get back to some of the more subtle ones.  Why do you need so many assemblies? Is it namespace control? Why not put them in one big assembly and use namespaces there?  Is it Strong Naming? Ok, I'll give you that one, strong naming does throw a wrench in things sometimes, but I'd still challenge whether you need 30+ assemblies in your solution just due to strong naming.  Is it licensing? Security?  All of these problems have a better solution that usually doesn't require more assemblies.

    One common argument I've heard is 'dependency' management. That is, I don't want my XYZ.Foo assembly to reference System.Web or something like that. My counter to this is: Why not? What does it matter? It's usually an aesthetic argument that comes back and has little to do in the way of any real merit from a business value perspective.  In fact, I can usually counter back with arguments that more business value is gained by having things easier to use and package and not worrying about dependencies for dependency's sake.  System.Web is in the GAC just as much as System or mscorlib are. You're not saving yourself any problems by having an assembly that has references to all of those.

    Another argument is that I don't want my different 'layers' all in the same assembly. Why not, I ask?  Sometimes there's a valid argument here because you need to deploy these things separately to separate physical layers. Ok, I'll grant you that one, but remember, we're talking 3-4 assemblies here, TOPS. If you're over 20, something is probably seriously wrong. It's a smell, not a sure sign of fire, so your mileage may vary here, but 20 is definitely a line that I would try very hard not to cross. In fact, 10 is probably pushing it.

    What are some exceptions when consolidating assemblies?

    Utility/console application projects. Unit test projects. Integration/longer-running test projects might do well to be in their separate project.  Interface assemblies for remoting/serialization/integration purposes. Plug-in/frequently changing assemblies, resource assemblies, etc.

    In the case of utility/console application assemblies and things like resource or satellite assemblies, you might consider a separate solution for these since they are likely not built or used as often as the main-line code.  You can have multiple SLN files reference a single project, so you can mix and max your SLN files. Be careful though, as the management of these things can get out of hand, so make sure you always have a core SLN file that you trust as the definitive source for what 'works' in your project.

    Also, consider an automated build and test process (NAnt, Rake, Bake, etc) that can independently build and verify the fitness of the build after tests and such so that you remain honest.

    Posted Jul 15 2008, 08:17 PM by chadmyers with 35 comment(s)
    Filed under:
  • StructureMap Users mailing list set up

    In preparation for the upcoming 2.5 release of StructureMap, and since I can't stand SourceForge's mailing list and forum capabilities, I set up a mailing list via Google Groups for users of StructureMap to discuss usage, give and receive support, etc.

    We'd like to start moving all support and discussion to the mailing list (instead of the SourceForge forums).

    Anyone can subscribe and post to the mailing list via email or online from this link:
    http://groups.google.com/group/structuremap-users


    You can also subscribe or unsubscribe via email at the following address:
    structuremap-users@googlegroups.com


    You can track the discussion via RSS using this URL:
    http://groups.google.com/group/structuremap-users/feeds

     

    Developer Mailing List Set Up, Too!

    http://groups.google.com/group/structuremap-devel


    You can also subscribe or unsubscribe via email at the following address: 
    structuremap-devel@googlegroups.com


    You can track the discussion via RSS using this URL: 
    http://groups.google.com/group/structuremap-devel/feeds

  • Exploring ShadeTree Features, Part 2: Cache<KEY, VALUE>

    Or, as I like to call it: "That stupid dictionary thing we've all written a thousand times but were too lazy to component-ize for reuse"

    How many times have you written code like this in your C# 2.0-and-later life?

    Foo foo = null;
    
    if( ! fooCache.TryGetValue(key, out foo))
    {
        foo = new Foo();
        fooCache.Add(foo.Key, foo);
    }
    
    return foo

    Well, no more!  Enter ShadeTree.Core.Cache!

    Nifty features:

    1. Automatic cache miss value creation: When you attempt to get an item from the cache that's not there, if configured to do so, it'll new one up for you, add it, and return it.
    2. Quiet Add: Call the Store method to add an item if it's not already added (otherwise, it'll do nothing)
    3. Quiet Remove: Remove won't throw an error if the item isn't in the Cache
    4. Each(): Handy lambda-friendly version of 'for each'
    5. Exists(): Handy lambda-friendly version of TryGetValue

    Cache Miss Handling Example

    This one I particularly like, especially when you need something like this: Dictionary<string, IList<Foo>>.

    Consider this example: We want to have a Cache<string, IList<Foo>>.  We want to add a new key "Blah" and add a new Foo to it's list.

    With Dictionary<T,U>, you have to do something like:

    Dictionary<string, IList<Foo>> dict = new Dictionary<string, IList<Foo>>();
    
    IList<Foo> fooList = null;
    
    if( ! dict.ContainsKey("Blah") )
    {
        fooList = new List<Foo>();
        dict.Add("Blah", fooList);
    }
    
    fooList.Add(new Foo());

    But with Cache, it's much simpler:

    Cache<string, IList<Foo>> cache = new Cache<string, IList<Foo>>(k => new List<Foo>());
    cache.Get("Blah").Add(new Foo());

    The trick is that little lambda expression (k => new List<Foo>()).  When the call to Get("Blah") fails to find anything in the underlying dictionary, it'll add a new entry to the dictionary with key "Blah" and the result of that lambda expression (i.e. a new List<Foo>).

  • Exploring ShadeTree Features, Part 1: Static Reflection with ReflectionHelper

    At work, Jeremy and I have been using -- and contributing to -- some of the code he's put together over the past few years.  He's created the 'ShadeTree' project which is currently housed in the Storyteller Project source repository. I'd like to do a few blog posts to share with you some of the really neat gems in this project that you can you use in your projects to help accelerate your development.

    The first thing I'd like to cover in ShadeTree is the ReflectionHelper class. ReflectionHelper aids with static reflection and the elimination of many 'magic strings'.  Static reflection is a process I first became aware of on Daniel Cazzulino's blog post "Statically-typed Reflection with Linq."  With the new Expression Trees feature of .NET 3.5, there are some interesting things you can do that aren't necessarily query-related.  The subject of Expression Trees is a very complicated one, but they are very powerful and worth some cursory investigation.  Fortunately, you can "dip your toe" into Expression Trees without understanding how everything works and build up from there (at least, that's what I'm doing, so there!).

    First, let's start with a problem...

    Classic Reflection with Magic Strings

    Let's pretend we had an object-to-object mapping problem. Let's say that we have some sort of web service which returns a simple DTO (data transfer object -- a flattened, simple object usually used for the purpose of communicating between two different systems with different models).  So we want to take our rich domain model object graph and flatten it into a DTO in order to send to our remote client. Let's also say that we have a lot of these situations and that it's going to be too much work to write one-off mapping functions for each scenario.  We've decided we need to build a basic object-to-object mapper that can handle common problems like nulls, string conversion, etc. Please don't get hung up on these details, the point is: We need a scenario that involves some sort of reflection. Please use your own imagination if my scenario isn't working for you.

    Consider this simple model with the red lines representing the intended mapping from the model to the DTO:

    CustomerDTODiagram 

    In the past, we may have pulled out our Mighty Hammer of XML +1 for this problem and ended up with something like this:

    <DtoMap dtoClass="SomeProject.CustomerDTO, SomeProject" 
            srcRootClass="SomeProject.Domain.Customer, SomeProject">
    
        <DtoProperty name="Name" mapsToSrcProperty="Name"/>
    
        <DtoProperty name="SiteName">
            <DtoSourcePropertyMap propretyOnSourceObject="Site" propertyToAccess="Name"/>
        </DtoProperty>
    
        <DtoPropety name="PostalCode">
            <DtoSourcePropertyMap propretyOnSourceObject="Site">
                <DtoSourcePropertyMap propretyOnSourceObject="PrimaryAddress" propertyToAccess="PostalCode"/>
            </DtoSourcePropertyMap>
        </DtoPropety>
        
    </DtoMap>

    This would probably work with a little tweaking, but the fundamental problem with this is: Magic strings everywhere!  Our refactoring tools are now likely defeated.  If we ever rename the 'Site' property on 'Customer', it's unlikely most refactoring tools would know to change this XML map appropriately.  It's possible we'd catch this and other similar problem through tests, but it's just more work and more friction that we don't need (in this case, at least).  One other problem with this XML is that it's very verbose, there's lots of  language overhead here (extra angle brackets, etc). In general, it'd be nice to stick to code if we can (with nice, safe compilers to keep us on the straight and narrow).

    You could accomplish this in other ways (without XML). But the code ends up looking something like this:

    Type srcType = Type.GetType("SomeProject.Domain.Customer, SomeProject");
    PropertyInfo nameProp = srcType.GetProperty("Name");

    This code has much of the same problem that the XML-based mapping syntax has (i.e. some refactoring tools may not pick up changes, etc).

    Magic strings cause problems, let's face it. So what can we do, instead?

    Static Reflection with Expression Trees and ShadeTree.Core.ReflectionHelper

    With static reflection we can build maps in code that reference the types and members directly. This is made easier using ShadeTree.Core.ReflectionHelper.

    First, let me show you what our end-result mapping code might look like now that we can use Static Reflection:

    DtoMap<CustomerDto> map = new DtoMap<CustomerDto>();
    
    map.AddPropertyMap(
        new DtoMapProperty<CustomerDto, Customer>
            {
                DtoPropertyReference = (dto => dto.Name),
                SourcePropertyReference = (src => src.Name)
            }
        );
    
    map.AddPropertyMap(
        new DtoMapProperty<CustomerDto, Customer>
            {
                DtoPropertyReference = (dto => dto.SiteName),
                SourcePropertyReference = (src => src.Site.Name)
            }
        );
    
    map.AddPropertyMap(
        new DtoMapProperty<CustomerDto, Customer>
            {
                DtoPropertyReference = (dto => dto.PostalCode),
                SourcePropertyReference = (src => src.Site.PrimaryAddress.PostalCode)
            }
        );

     

    Not bad, but pretty verbose.  Maybe we could tighten it up a bit with a Fluent API:

    var map = new DtoMap<CustomerDto, Customer>()
        .Property(dto => dto.Name).ToSource(src => src.Name)
        .Property(dto => dto.SiteName).ToSource(src => src.Site.Name)
        .Property(dto => dto.PostalCode).ToSource(src => src.Site.PrimaryAddress.PostalCode);

    Now, that's pretty funky, huh? It threw me for a loop when I first saw that.  My first thought was: "But src=>src.Name isn't a valid expression in this context! You can't just reference a member without an assignment, for the compiler tells me so!"

    You might, rightly, expect to get this compile error:

    error CS0201: Only assignment, call, increment, decrement, 
    and new object expressions can be used as a statement

    So why don't you?  Well, the trick is that your method or property must take a parameter of type Expression<Func<T,object>>.  Not just a System.Func<T,object>, but you have to have the Expression<> around it. This causes the C# compiler to behave strangely -- namely it does not treat the code inside the expression as executable code, but as a parsed language element for LATER evaluation.  "dto.Name" is a valid expression in certain contexts, so the compiler allows it as an Expression<>. If you later try to execute/invoke that expression, THEN you'll get an error similar to the CS0201 above.  But for right now, the compiler lets it pass, and will generate the IL to pass your method or property a type of Expression<>.

    UPDATE: (HT to commenter Paul Batum for catching me on this): Lambda expressions have an implied “return” statement in them, so they will compile *and execute* without the CS0201 issue because they are not a pure member access expression they are a return statement combined with a member access expression.

    What can you do with this Expression<> type?  Well, lots of things, but that's a much larger topic. For right now, you can pass it to the ShadeTree ReflectionHelper and request to get a PropertyInfo from it.  Here, let me show you.  Remember our mapping Fluent API up above? Here's a crude start on what the DtoMap<DTO, SRC> class might look like:

    public class DtoMap<DTO, SRC>
    {
        private PropertyInfo _lastDtoProperty;
    
        public DtoMap<DTO, SRC> Property(Expression<Func<DTO, object>> expression)
        {
            _lastDtoProperty = ReflectionHelper.GetProperty(expression);
            return this;
        }
    }

    So I have an Expression<> of a lambda (Func<T,object>). That lambda currently holds an expression which can be evaluated into a direct member reference (i.e. the Name property).  We can use some LINQ stuff under the covers to turn that Expression<> into a .NET reflection element: a PropertyInfo.  We've now accomplished the same thing as someType.GetProperty("Name"), but without any magic strings!

    Now, your refactoring tool should be able to directly pick up the dto.Name reference and, if you ever change the name of the Name property, change that reference for you automatically.

    Deep Access Static Reflection and the Accessor interface

    We have a big problem with that last code sample, though.  GetProperty() will explode if you pass it something like src.Site.Name (n-level deep property accessors).   ReflectionHelper, fortunately, has a way of dealing with this. It will create the accessor graph for you and return to you the path it took from 'dto' to 'Name' and add some nifty convenience in there for you as well!  There's a method on ReflectionHelper called 'GetAccessor()'.  It's very similar to GetProperty(), but it handles deep accessor paths.

    Let's look at the 'ToSource()' method of our DtoMap now.  ToSource is going to need this deep access because our second call to it uses 'src.Site.Name' which would cause GetProperty() to throw an exception.   Here's the updated DtoMap source with new Accessor goodness:

    public class DtoMap<DTO, SRC>
    {
        private Accessor _lastDtoAccessor;
        private Accessor _lastSrcAccessor;
    
        public DtoMap<DTO, SRC> Property(Expression<Func<DTO, object>> expression)
        {
            _lastDtoAccessor = ReflectionHelper.GetAccessor(expression);
            return this;
        }
    
        public DtoMap<DTO, SRC> ToSource(Expression<Func<SRC, object>> expression)
        {
            _lastSrcAccessor = ReflectionHelper.GetAccessor(expression);
            return this;
        }
    }

    You should notice that I changed the Property() method to use GetAccessor and I've added the new ToSource() method which uses GetAccessor as well.

    The ShadeTree.Core.Accessor interface gives us some extra information above and beyond just the straight PropertyInfo as well as two very important methods: SetValue() and GetValue().  These methods expect an object of the root type (in our case, Customer) and will navigate the graph to get or set the value on the property on the object in which we're interested.  For example, if I have my _lastSrcAccessor we just built in our ToSource() method, we can call GetValue() and pass in a Customer object and get, for example, it's Site's Name property.  Consider this example:

    var customer = _customerRepository.GetCustomer(9);
    customer.Site.Name = "NewSiteName";
    
    string ourName = (string) _lastSrcAccessor.GetValue(customer);
    
    // the _ourName_ variable will now equal "NewSiteName"

     

    So Accessor.GetValue() will walk down the path from Customer to Site and from Site to Name and return the Name property value.  If any value in the chain is null, GetValue() will return null.  This is the current behavior, if you don't like it, please submit a patch (take a look at the ShadeTree.Core.PropertyChain implementation for starters).

    Conclusion

    There's one other thing on ReflectionHelper I didn't mention: GetMethod() which allows you to pass an Expression that references a method and get a MethodInfo back from it so you can use static reflection on more than just properties.  There are a few other things on Accessor that I didn't mention either that I think are worth you giving a glance at.

    I plan on doing a few more of these ShadeTree posts, so please check back later.

Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems