0
votes

I am having an issue trying to get the singleton lifecycle to work with a custom convention in StructureMap.

Basically I have a custom registry type class that contains a dictionary that I would like to be a singleton so that it is created once at startup of the application.

I created a custom convention that will look at an attribute of a class and determine whether or not the class should be HttpContextScoped or Singleton.

The problem is that when I run the application with the Visual Studio debugger the constructor of the object that should be a singleton gets called every time the web page is loaded instead of happening once as I expected. It looks like the object is behaving as a HttpContextScoped instead of a Singleton.

Here are some details:

StructuremapMvc class in app_start folder

public static class StructuremapMvc
    {
        public static void Start()
        {
            IContainer container = IoC.Initialize();
            DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
            GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver(container);
        }
    }

Ioc class

public static IContainer Initialize()

ObjectFactory.Initialize(x =>
{
    x.Scan(scan =>
            {
                scan.TheCallingAssembly();
                scan.AssemblyContainingType<IConfigManager>();
                scan.WithDefaultConventions();
                scan.Convention<CustomConvention>();
            });

CustomConvention : IRegistrationConvention  

public void Process(Type type, Registry registry) public void Process(Type type, Registry registry)
        {
            var attributes = type.GetCustomAttributes(false);
            if (attributes.Length > 0)
            {
                if (attributes[0] is SingletonAttribute)
                {
                    registry.For(type).Singleton();
                }
                else if (attributes[0] is HttpContextScopedAttribute)
                {
                    registry.For(type).HttpContextScoped();
                }
            }
        }


[Singleton]
public class MyRegistry : IMyRegistry
1

1 Answers

1
votes

This questions seems to be quite old but I'll trie to answer it anyway because there could be others which are experiencing the same problem with Structure map. In some cases singleton insances are created "per instance" referring to the instance where they are injected in. This means that you could have different instances of "singleton" when they are injected somewhere else. I've personally seen this behavior with WEBAPI inside MVC app.

The only way I could make it work as "true" global singleton is by using generic interface with specific type parameters to distinguish different types to be used:

public interface ITest<T>
{
}

public class Test1 : ITest<int>
{
}

public class Test2 : ITest<string>
{
}

Scan(x =>
        {
            x.TheCallingAssembly();
            x.IncludeNamespace("MvcApplication1");
            x.ConnectImplementationsToTypesClosing(typeof(ITest<>))
                .OnAddedPluginTypes(a => a.LifecycleIs(InstanceScope.Singleton));
        });

I know that this isn't as ellegant nor usable as approach described above but at least it works as expected. Other approach which works is to do standard mapping one-on-one like:

For<ISingleton>().Singleton().Use<Singleton>();