Skip to content

Compliance guide for ioc integration

jeremydmiller edited this page Apr 12, 2011 · 14 revisions

Compliance Guide for IoC Integration with FubuMVC

FubuMVC extensively uses the power of your IoC container, more so that other .Net options. That integration affords a great deal of power to the framework while making the implementation of FubuMVC simpler than it would be otherwise. The downside of that IoC usage is that integrating a new type of IoC container is somewhat more complicated than other .Net frameworks.

FubuMVC was built to be IoC agnostic. If an IoC integration isn't already available for your container of choice, this guide will walk you through creating a new IoC integration with FubuMVC.

At a high level, you can integrate an IoC tool with FubuMVC by:

  1. Implementing a new IContainerFacility class
  2. Create a new IBehaviorFactory class
  3. Register a Common Service Locator adapter for the IoC container

Assumptions and Requirements for IoC Behavior

FubuMVC was originated by the core StructureMap [LINK] team and much of the IoC usage in FubuMVC is admittedly skewed to StructureMap's behavior. Before you integrate FubuMVC with a new IoC container, make sure your IoC tool can behave according to these assumptions (some IoC tools require optional addon's or configurations to do these things):

Arbitrary concrete types -- FubuMVC assumes that an IoC container can resolve arbitrary concrete types upon request, regardless of whether or not that concrete type has been explicitly registered with the IoC container:

    public class ArbitraryConcreteClass
    {
        // I should be able to resolve or "get" this from 
        // the IoC container, with the IService dependency resolved,
        // without having to explicitly register ArbitraryConcreteClass
        public ArbitraryConcreteClass(IService dependency)
        {
        }
    }

Common Service Locator -- The CSL [LINK] library is used to provide a service locator gateway in some of the internals. The IoC container must be able to resolve a CSL facade in constructor functions like this:

        // IServiceLocator should be injected into the constructor as
        // a dependency
        public DisplayFormatter(IServiceLocator locator, Stringifier stringifier)
        {
            _locator = locator;
            _stringifier = stringifier;
        }

IEnumerable / IList Dependencies -- There are a couple FubuMVC services that have constructor arguments that take either an IList or an IEnumerable of T. While the ObjectDef model certainly allows you to explicitly configure these how these constructor arguments will be resolved, FubuMVC takes advantage of the fact that StructureMap (and other tools) will fill the argument with every possible instance of T configured in the container:

        // When ModelBinderCache is resolved by the IoC container, the container should fill the "binders" argument
        // with every possible instance/component of IModelBinder registered with the IoC container
        public ModelBinderCache(IEnumerable<IModelBinder> binders, IPropertyBinderCache propertyBinders, ITypeDescriptorCache types)
        {
            // DO NOT put the standard model binder at top
            _binders.AddRange(binders.Where(x => !(x is StandardModelBinder)));
            _binders.Add(new StandardModelBinder(propertyBinders, types));

            _cache.OnMissing = type => _binders.FirstOrDefault(x => x.Matches(type));
        }

Interception or Decorators -- Using request tracing [LINK] with the diagnostics requires the IoC container to apply some interception or decorators to all instances created of IActionBehavior if the diagnostic level is turned up for request tracing. For example, the StructureMap implementation is:

            if (diagnosticLevel == DiagnosticLevel.FullRequestTracing)
            {
                _container.Configure(x =>
                {
                    x.For<IActionBehavior>().EnrichAllWith((context, behavior) =>
                    {
                        if (behavior is BehaviorTracer || behavior is DiagnosticBehavior) return behavior;

                        var tracer = context.GetInstance<BehaviorTracer>();
                        tracer.Inner = behavior;

                        return tracer;
                    });
                });
            }

Service Scoping

Creating an IContainerFacility

Registering services with ObjectDef's and BehaviorNode's