Search code examples
fubumvc

How do I find the output model type in a behavior?


With FubuMVC, I'm not sure what the best way is to determine the current action's output model type. I see different objects that I could get the current request's URL from. But that doesn't lead to a very good solution.

What's the easiest way to get the current action's output model type from the behavior?

If this isn't a good practice, what's a better way?


Solution

  • First, I'm assuming you've already got your settings object(s) set up in StructureMap and have the ISettingsProvider stuff already wired up.

    The best, simplest thing to do would be just to pull the settings in the view, like this:

    <%: Get<YourSettingsObject>().SomeSettingProperty %>

    If you insist on having these be a property on your output model, then continue reading:

    Let's say you had a settings object like this:

        public class OutputModelSettings
        {
            public string FavoriteAnimalName { get; set; }
            public string BestSimpsonsCharacter { get; set; }
        }
    

    Then you had an output model like this:

        public class OutputModelWithSettings
        {
            public string SomeOtherProperty { get; set; }
            public OutputModelSettings Settings { get; set; }
        }
    

    You'll need to do a few things:

    1. Wire up StructureMap so that it will do setter injection for Settings objects (so it will automatically inject the OutputModelSettings into your output model's "Settings" property.

      Set up a setter injection policy in your StructureMap initialization code (a Registry, Global ASAX, your Bootstrapper, etc -- wherever you set up your container).

      x.SetAllProperties(s => s.Matching(p => p.Name.EndsWith("Settings")));
      
    2. Create your behavior to call StructureMap's "BuildUp()" on the output model to trigger the setter injection. The behavior will be an open type (i.e. on the end) so that it can support any kind of output model

      public class OutputModelSettingBehavior<TOutputModel> : BasicBehavior
          where TOutputModel : class
      {
          private readonly IFubuRequest _request;
          private readonly IContainer _container;
      
          public OutputModelSettingBehavior(IFubuRequest request, IContainer container)
              : base(PartialBehavior.Executes)
          {
              _request = request;
              _container = container;
          }
      
          protected override DoNext performInvoke()
          {
              BindSettingsProperties();
      
              return DoNext.Continue;
          }
      
          public void BindSettingsProperties()
          {
              var viewModel = _request.Find<TOutputModel>().First();
              _container.BuildUp(viewModel);
          }
      }
      
    3. Create a convention to wire up the behavior

      public class OutputModelSettingBehaviorConfiguration : IConfigurationAction
      {
          public void Configure(BehaviorGraph graph)
          {
              graph.Actions()
                  .Where(x => x.HasOutput &&
                              x.OutputType().GetProperties()
                                  .Any(p => p.Name.EndsWith("Settings")))
                  .Each(x => x.AddAfter(new Wrapper(
                      typeof (OutputModelSettingBehavior<>)
                      .MakeGenericType(x.OutputType()))));
          }
      }
      
    4. Wire the convention into your FubuRegistry after the Routes section:

      ApplyConvention<OutputModelSettingBehaviorConfiguration>();
      
    5. In your view, use the new settings object:

      <%: Model.Settings.BestSimpsonsCharacter %>
      

    NOTE: I have committed this as a working sample in the FubuMVC.HelloWorld project in the Fubu source. See this commit: https://github.com/DarthFubuMVC/fubumvc/commit/2e7ea30391eac0053300ec0f6f63136503b16cca