2

I want to have StructureMap return a Special Case called "None" for a certain instance.

Say I Have this class MyUser which is scoped as HttpContext. I want to have a nested, dreived class None (ie. MyUser.None) which is returtned for the type MyUser when there is no HttpContext (for example, like in bootstrapping, Application_Start() etc).

This would mean that certain calls could check for the Special Case type instead of null (more readable) like

if(value is MyUser.None)
  // do special case things
else
  // do normal case things

What SM config do I need to achieve this? I have tried the ConditionallyUse method without much success. I keep getting NullReferenceExceptionS throwing from within SM itself.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79

2 Answers2

2

This code should work (to test, you can replace the check for HttpContext.Current with something like DateTime.Now.Millisecond % 2 == 0 to more easily see the different behavior):

class Program
{
    static void Main(string[] args)
    {
        ObjectFactory.Initialize(x =>
        {
            x.For<IUser>().ConditionallyUse(cond =>
            {
                cond.TheDefault.Is.Type<MyUser>();
                cond.If(ctx =>
                {
                    var hasContext = false;
                    try
                    {
                        hasContext = HttpContext.Current == null;
                    }catch
                    {
                        // HttpContext.Current sometimes throws when there isn't one
                    }
                    return hasContext;
                }).ThenIt.IsThis(new MyUser.None());
            });
        });

        var instance = ObjectFactory.GetInstance<IUser>();
        Console.WriteLine(instance.GetType());
    }

    public interface IUser{}
    public class MyUser : IUser { public class None : IUser {} }
}

Since the ConditionallyUse() API is a little strange, you might just want to use the Use() overload that takes a Func<> and do the conditional check yourself with an if statement.

Joshua Flanagan
  • 8,527
  • 2
  • 31
  • 40
1

Turns out I had underlying SM configuration issues.

I am using the ConditionallyUse method still however:

        For<User>().ConditionallyUse(config =>
            {
                config.If(ctx => ctx.GetInstance<HttpContextBase>().User == null)
                    .ThenIt.Is.Type<User.None>();
                config.TheDefault.Is.Type<User>();
            });

I had to be more careful about NullReferenceExceptionS from within SM - my underlying cause it seems was a scoping issue.. specifically how I was wanting to access a HttpContext scoped instance in a test. I'm now using the HybridHttpOrThreadLocalScoped() config and being more careful by using TryGetInstance() where appropiate instead of GetInstance().

Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79
  • It looks like you used my answer, wrote it up as yours, and accepted it. Shouldn't you accept mine and just add a comment to it that you had missed some NullReferenceExceptions or something? – Joshua Flanagan Aug 16 '11 at 21:22
  • No disrespect Josh. I didn't mean to make it appear like that. The truth is I was already using the `ConditionallyUse` much like your answer suggested (even tho my question only mentioned _that_ I used it, not how). It's really the explanation of how I solved by underlying issue (after the code snip) which I thought would potentially be more valuable to others. That's why I wrote a new answer. I did actually sit pondering for some time on how to do this on your answer FYI. I do appreciate your help. – Matt Kocaj Aug 17 '11 at 00:31
  • None taken, just trying to understand. Glad you solved your problem. – Joshua Flanagan Aug 18 '11 at 01:08