This project is read-only.

Simple Injector IIS

Jul 29, 2014 at 4:05 PM
Hi there!
Im using Simple Injector in my WCF service. While in running from VS2010 everything is fine. However, when I publish it to my server using IIS 7, after some time (10 min, counted) my WCf loses all registered assemblies, modules, classes in container.
Any tips?
Jul 29, 2014 at 4:08 PM
Can you be more specific? What do you mean by losing all registered assemblies, modules and classes? Is your app domain recycled? How does your registration look like? How is IIS configured?
Jul 29, 2014 at 4:12 PM
I publish my website + wcf service. I access via browser my webpage, everything is fine. After 10min (using app or not), if I try to access it again, i get an exception "No registration for Type could be found".

My registration is PerWcfOperation fired in Application_Start of WCF global.asax.

In using IIS default configurations (just activated it, opened manager, created inside Default Web Site 2 application using ASP.NET 4.0 Integrated Application Pool
Jul 29, 2014 at 4:50 PM
Does this only happen during development, or does this happen when you deploy the application to IIS and access it from there (with no debugger attached)?
Jul 29, 2014 at 5:11 PM
this happen only when I deploy the application to IIS.
Jul 29, 2014 at 5:19 PM
Can you post your configuration?
Jul 29, 2014 at 5:35 PM
IIS configuration, app configuration or SimpleInjector config?
Jul 29, 2014 at 5:44 PM
Any configuration you think is interesting to see, but especially the Simple Injector configuration, since I assume you suspect this is related to Simple Injector.
Jul 29, 2014 at 6:08 PM
My web.config
<?xml version="1.0"?>
<configuration>

<appSettings>
<add key="DbConnectionName" value="Oracle"/>
<add key="PluginFolder" value="..\..\bin\"/>
</appSettings>

<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="2147483647"/>
</system.web>

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
  multipleSiteBindingsEnabled="true" />
<bindings>
  <wsHttpBinding>
    <binding  name="WSHttpBinding_Custom"
              closeTimeout="00:10:00"
              openTimeout="00:10:00"
              receiveTimeout="00:10:00"
              sendTimeout="00:10:00"
              bypassProxyOnLocal="false"
              transactionFlow="false"
              hostNameComparisonMode="StrongWildcard"
              maxBufferPoolSize="2147483647"
              maxReceivedMessageSize="2147483647"
              messageEncoding="Text"
              textEncoding="utf-8"
              useDefaultWebProxy="true"
              allowCookies="false" >

      <readerQuotas maxDepth="2147483647"
                    maxStringContentLength="2147483647"
                    maxArrayLength="2147483647"
                    maxBytesPerRead="2147483647"
                    maxNameTableCharCount="2147483647" />

      <reliableSession ordered="true"
                       inactivityTimeout="00:10:00"
                       enabled="false" />

      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"  realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>



<services>
</system.serviceModel>

<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

<connectionStrings>
<add name="Oracle" connectionString="Data Source=DATABASE;User Id=USER;Password=PASSWORD"/>
</connectionStrings>

</configuration>
Jul 29, 2014 at 6:09 PM
Bootstrapper
namespace Application1
{
public static class Bootstrapper
{
    public static void Initialize()
    {
       PluginContainer.Bootstrap(container =>
        {
            container.RegisterPerWcfOperation<RequestScope>(() =>
            {
                var headerID = OperationContext.Current.IncomingMessageHeaders.FindHeader(AuthMessageHeader.appInfoKey, "");

                var scope = OperationContext.Current.IncomingMessageHeaders.GetHeader<RequestScope>(headerID);
                scope.VersionDA = GetVersion(scope.Context);

                return scope;
            });
            container.RegisterPerWcfOperation<ITransactionManager, TransactionManager>();
            container.RegisterPerWcfOperation<IScopeManager, ScopeManager>();
            container.InterceptWith<PersistenteInterceptor>(type =>
                {
                    var isBO = type.GetInterface(typeof(IBaseBO).Name) != null;

                    return isBO;
                });
            LoadPlugins(container);
        });


    }

    private static void LoadPlugins(SimpleInjector.Container container)
    {
        using (var catalog = new AggregateCatalog())
        {
            string pluginDirectory = ConfigurationManager.AppSettings["PluginFolder"];
            var dirCat = new DirectoryCatalog(pluginDirectory);
            catalog.Catalogs.Add(dirCat);

            var pluginContainer = new CompositionContainer(catalog);

            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            RegisterBO(container, assemblies, pluginContainer);
            RegisterDA(container, assemblies, pluginContainer);

        }
    }

    private static void RegisterBO(SimpleInjector.Container container, Assembly[] assemblies, CompositionContainer pluginContainer)
    {
        var interfacesPluginAssemblies = assemblies.Where(k => k.GetName().Name.Contains(".Interfaces."));
        var serviceTypes =
               (from assembly in interfacesPluginAssemblies
                from type in assembly.GetExportedTypes()
                where (typeof(IBaseBO).IsAssignableFrom(type) || typeof(IBaseBO<>).IsAssignableFrom(type))
                where type.IsAbstract
                where !type.IsGenericTypeDefinition
                select type).ToList();

        Type[] t = new Type[0];
        var methodInfo = pluginContainer.GetType().GetMethod("GetExportedValueOrDefault", t);
        var wcfOperationLifestyle = new WcfOperationLifestyle(true);

        var baseBOInterface = typeof(IBaseBO<>);
        dynamic genericBOImplementation = typeof(GenericBO<>);


        container.RegisterPerWcfOperation<ILockBO, LockBO>();
        foreach (var service in serviceTypes)
        {
            var genericMethod = methodInfo.MakeGenericMethod(service);

            var exportedMatches = (from plugin in pluginContainer.Catalog.Parts
                                   where plugin.ExportDefinitions.Any(k => k.ContractName == service.FullName)
                                   select plugin).ToList();


            if (exportedMatches.Count > 1)
                throw new Exception("Multiple exports found to service " + service.FullName);

            dynamic baseInteface = service.GetInterface("IBaseBO`1");

            if (exportedMatches.Count == 1)
            {
                //registrar serviço para a implementação exportada
                var part = exportedMatches.First();
                var partType = ReflectionModelServices.GetPartType(part);
                var implementation = partType.Value;
                container.Register(service, implementation, wcfOperationLifestyle);

                //registrar IBaseBO<Model> para implementation;
                if (baseInteface != null)
                {
                    var modelType = baseInteface.GetGenericArguments()[0];
                    var type = baseBOInterface.MakeGenericType(new Type[1] { modelType });

                    container.Register(type, implementation, wcfOperationLifestyle);
                }
            }
            else
            {
                //registrar o serviço para GenericBO<T>. 
                //SÓ FUNCIONA EM DEBUG MODE
                if (baseInteface != null && Debugger.IsAttached)
                {
                    var modelType = baseInteface.GetGenericArguments()[0];
                    var type = baseBOInterface.MakeGenericType(new Type[1] { modelType });
                    var implementation = genericBOImplementation.MakeGenericType(new Type[1] { modelType });
                    container.Register(type, implementation, wcfOperationLifestyle);
                }

            }
        }
    }
    private static void RegisterDA(SimpleInjector.Container container, Assembly[] assemblies, CompositionContainer pluginContainer)
    {

        var interfacesPluginAssemblies = assemblies.Where(k => k.GetName().Name.EndsWith(".DA"));

        var serviceTypes =
            (from assembly in interfacesPluginAssemblies
             from type in assembly.GetExportedTypes()
             where (typeof(IBaseDA).IsAssignableFrom(type) || typeof(IBaseDA<>).IsAssignableFrom(type))
             where type.IsClass
             where !type.IsGenericTypeDefinition
             select type).ToList();

        Type[] t = new Type[0];
        var methodInfo = pluginContainer.GetType().GetMethod("GetExportedValueOrDefault", t);
        var wcfOperationLifestyle = new WcfOperationLifestyle(true);

        var baseBOInterface = typeof(IBaseDA<>);
        dynamic genericBOImplementation = typeof(GenericDA<>);

        foreach (var service in serviceTypes)
        {
            var genericMethod = methodInfo.MakeGenericMethod(service);

            var exportedMatches = (from plugin in pluginContainer.Catalog.Parts
                                   where plugin.ExportDefinitions.Any(k => k.ContractName == service.FullName)
                                   select plugin).ToList();


            if (exportedMatches.Count > 1)
                throw new Exception("Multiple exports found to service " + service.FullName);

            dynamic baseInteface = service.GetInterface("IBaseDA`1");

            if (exportedMatches.Count == 1)
            {
                //registrar serviço para a implementação exportada
                var part = exportedMatches.First();
                var partType = ReflectionModelServices.GetPartType(part);
                var implementation = partType.Value;
                container.Register(service, implementation, wcfOperationLifestyle);
            }
            else
            {

                container.Register(service, service, wcfOperationLifestyle);
                //registrar IBaseDA<Model> para implementation;
                if (baseInteface != null)
                {
                    var modelType = baseInteface.GetGenericArguments()[0];
                    var type = baseBOInterface.MakeGenericType(new Type[1] { modelType });

                    container.Register(type, service, wcfOperationLifestyle);
                }
            }

        }
    }
    private static string GetVersion(string context)
    {

        return "1.0.0.0";

    }

}
}
Jul 29, 2014 at 6:09 PM
the container
namespace Application1
{
public static class PluginContainer
{
    internal static Container container;
    public static void Bootstrap(Action<Container> register)
    {
        container = new Container();
        if (register != null)
            register(container);


        SimpleInjectorServiceHostFactory.SetContainer(container);

    }



    public static TService Resolve<TService>() where TService : class
    {
        return container.GetInstance<TService>();
    }
}
}
Jul 29, 2014 at 9:34 PM
Where do you call Bootstrapper.Initializer() ?
Jul 29, 2014 at 9:45 PM
WCF Service Global.asax file. The code only invokes Bootstrapper.Initializer() in Application_Start, no other implementations there
Jul 29, 2014 at 10:05 PM
I'm not sure, but it seems like if IIS resets the application without tearing down the app domain causing the Global.asax not to be fired again. This however is behavior I only have ever seen during development, causing new types not to be registered. It seems very unlikely to me that this is caused by Simple Injector, since once a registration is made in the container, its impossible to ever remove it. So if you're seeing an uninitialized container, somehow your initialization code isn't called after the application restarts.
Jul 29, 2014 at 10:33 PM
Yeah, i guess thats it, but my IIS config is the default one. I tried some steps:
  • Even restarting IIS, i get the same error (guess it does not fire application_start again);
  • If i open global.asax in root folder, edit and save, app comes back to work;
  • Tried to log Application_end and session_end, but it is never fired;
Jul 29, 2014 at 10:39 PM
And what happens when you set <compilation debug="false"> ?
Jul 29, 2014 at 11:15 PM
same problem
Jul 30, 2014 at 9:36 AM
I'm sorry, but I'm out of ideas.
Jul 30, 2014 at 8:16 PM
Hi @leonardolb560

these are really just long shots but if you're still struggling with this issue then I am sure you're willing to try just about anything.

I noticed that there are a number of 10 minute settings in your config file - I wonder if setting them to all be different values, something like 10, 15, 20 etc would lead to any clues ....
<binding  name="WSHttpBinding_Custom"
          closeTimeout="00:10:00"
          openTimeout="00:10:00"
          receiveTimeout="00:10:00"
          sendTimeout="00:10:00"
and
  <reliableSession ordered="true"
                   inactivityTimeout="00:10:00"
something else that springs to mind is that the error kind of sounds like the Container is being replaced with a new instance at some point - because a Container simply cannot lose all of the registrations ...
Jul 31, 2014 at 4:45 AM
qujck wrote:
Hi @leonardolb560

these are really just long shots but if you're still struggling with this issue then I am sure you're willing to try just about anything.

I noticed that there are a number of 10 minute settings in your config file - I wonder if setting them to all be different values, something like 10, 15, 20 etc would lead to any clues ....
<binding  name="WSHttpBinding_Custom"
          closeTimeout="00:10:00"
          openTimeout="00:10:00"
          receiveTimeout="00:10:00"
          sendTimeout="00:10:00"
and
  <reliableSession ordered="true"
                   inactivityTimeout="00:10:00"
something else that springs to mind is that the error kind of sounds like the Container is being replaced with a new instance at some point - because a Container simply cannot lose all of the registrations ...
I followed your suggestion, but nothing changed. While working on these changes, I accidentally hit recicle button and my app got down by the same error - all references were lost.
Is that possible my application pool is recycling and unregistering all classes from container - as it drops my memory?
How can i solve that? I disabled recycling in app pool but still getting same error;
Jul 31, 2014 at 5:40 AM
thats it, i noticed my IIS keeps recycling Application Pool and do not create a new worker with same app pool asa before, help please!
Jul 31, 2014 at 6:29 AM
I'm sorry Leonardo, but we are not WCF experts. I think it's best you ask this at Stackoverflow or some Microsoft forum. Good luck!
Jul 31, 2014 at 8:40 AM
What happens if you remove the check for null in PluginContainer?
public static class PluginContainer
{
    internal static Container container;
    public static void Bootstrap(Action<Container> register)
    {
        container = new Container();
        register(container);

        SimpleInjectorServiceHostFactory.SetContainer(container);
    }
    //....
}
Jul 31, 2014 at 8:45 AM
Edited Jul 31, 2014 at 9:08 AM
I think @qujck is on to something. Try changing your bootstrap method to the following:
    internal static Container container;
    public static void Bootstrap(Action<Container> register)
    {
        if (register == null) throw new ArgumentNullException("register");

        if (container == null)
        {
            container = new Container();
            register(container);
            SimpleInjectorServiceHostFactory.SetContainer(container);
        }
    }
or perhaps even better:
    internal static Container container;
    public static void Bootstrap(Action<Container> register)
    {
        if (register == null) throw new ArgumentNullException("register");
        if (container != null) throw new InvalidOperationException("Already bootstrapped");

        container = new Container();
        register(container);
        SimpleInjectorServiceHostFactory.SetContainer(container);
    }
Jul 31, 2014 at 4:53 PM
I guess it will not change anything since my Bootstrap is invoked only in ApplicationStart and this event isn't fired again.

Since people use Simple Injector and it is elected as the best DI framework, I wonder why nobody got this problem or know a configuration for IIS? Is this an deprecated practice and pattern?
Jul 31, 2014 at 5:33 PM
Hi @leonardolb560

With 66,841 downloads and counting I suggest this is almost certainly something in your implementation and not Simple Injector - would you mind just trying it for us?
Jul 31, 2014 at 5:56 PM
sure, i tried, same problem
Jul 31, 2014 at 6:00 PM
thank you - did you get any errors in the Event Log?
Jul 31, 2014 at 6:04 PM
nop,i checked windows event viewer and no errors
Jul 31, 2014 at 6:23 PM
:-(

you must be really frustrated!
Jul 31, 2014 at 6:29 PM
yeah, since i updated my entire project to use simple injector instead of MEF based on community posts... But its impossible nobody published it on iis
Jul 31, 2014 at 6:31 PM
Try switching to a different container and see if the problem dissappears.
Jul 31, 2014 at 6:31 PM
Edited Jul 31, 2014 at 6:31 PM
My stuff runs fine on IIS 7 for weeks without any issue
protected void Application_Start()
{
    Container container = new Container();
    var web = new BootStrapper();
    web.BootStrap(container);

    GlobalConfiguration.Configuration.DependencyResolver = 
        new SimpleInjectorHttpDependencyResolver(container);
}
Jul 31, 2014 at 6:43 PM
Maybe GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorHttpDependencyResolver(container); instead of
SimpleInjectorServiceHostFactory.SetContainer as enlisted in doc files, let me try that
Jul 31, 2014 at 7:46 PM
I'm not sure - my code is a WebAPI implementation so there will be a subtle difference to the way you inform the framework about your Container
Jul 31, 2014 at 8:05 PM
Yeah... no ideas,, no errors, just this.. container is not null (as I can invoke container.Resolve) but all registration are lost...
Its a shot in the dark, but i have a feeling about IIS recycling... Which IIS config and version are you using?
Aug 1, 2014 at 9:01 AM
Are you able to create a Visual Studio solution and project with the minimal amount of code that allows to reproduce the issue? If you can upload it somewhere, or send it through the mail, I will try to have a look at it this weekend.