Search code examples
fubumvc

How do you create a FubuMVC behavior that copies site configuration values to an output model?


I'm trying to figure out to create a behavior that will copy a boolean site configuration value to an output model.

This way I don't have to copy the bool in each action who's view requires it, but can simply add the behavior to the controller actions that need this value.

In some of the older versions of FubuMVC, I believe behaviors could modify the output model after it's left the controller. But I'm not sure how to do this in the more recent versions of FubuMVC (or I've forgotten).

Can anyone give me an example of or point me in the direction of the best practice for copying a site configuration value to an output model?


Solution

  • Let's say I had an output model called HomeViewModel that had a property called FooterText that I wanted loaded from settings object (let's say HomeSettings) that was retrieved from the container (i.e. StructureMap).

    The Behavior

    My behavior would look something like this:

    public class HomeFooterBehavior : BasicBehavior
    {
        private readonly HomeSettings _settings;
        private readonly IFubuRequest _request;
    
        public HomeFooterBehavior(HomeSettings settings, IFubuRequest request)
            : base(PartialBehavior.Executes)
        {
            _settings = settings;
            _request = request;
        }
    
        protected override DoNext performInvoke()
        {
            SetupFooter();
    
            return DoNext.Continue;
        }
    
        public void SetupFooter()
        {
            var viewModel = _request.Find<HomeViewModel>().First();
    
            viewModel.HomeFooterText = _settings.FooterText;
        }
    }
    

    This behavior takes in the HomeSettings object and the IFubuRequest object (both injected dependencies) and then gets the HomeViewModel (output model) from the request and then sets the HomeFooterText property on the output model based on the value from the settings object.

    NOTE: I'm assuming that you've already got your HomeSettings object wired up in the container (for example, using the ISettingsProvider stuff built into FubuMVC). If you don't already have this, let me know and I can post some code on how to do that.

    Wiring Up The Convention

    To wire up the behavior, you'll need to define the convention through an IConfigurationAction, for example:

    public class HomeFooterBehaviorConfiguration : IConfigurationAction
    {
        public void Configure(BehaviorGraph graph)
        {
            graph.Actions()
                .Where(x => x.HasOutput && 
                            x.OutputType().Equals(typeof(HomeViewModel)))
                .Each(x => x.AddAfter(Wrapper.For<HomeFooterBehavior>()));
        }
    }
    

    This is a real dumb convention for demonstration purposes. In your project, you might make it a little more generic. For example, any output model that has an attribute on it, or implements a specific interface, etc. In fact, you might want to inspect all output models to see if they contain any properties that match a certain criteria (for example, all properties that end with "Settings" - like "FooterSettings" or something).

    Don't be afraid to define wide sweeping conventions like this due to performance concerns since all this convention code runs at start-up time and not on every request.

    Note the "AddAfter" call and the "Wrapper.For" call. That's the key in that it places your behavior after the controller action is executed, but before the view is rendered.

    Now that you have your behavior and your convention defined, it's time to wire it up in your FubuRegistry.

    Wiring Up Your Convention in your FubuRegistry

    After the call to "Routes." in your FubuRegistry, add a line like this:

    ApplyConvention<HomeFooterBehaviorConfiguration>();
    

    Recompile and it should work.

    Please let me know if you run into any problems.