Resolving type with ReuseScope.None on separate thread issue

Hi,

If a disposable class is registered (reuse scope: none) using a container and then i try to resolve it, then new app domain creation (in a separate thread) doesn’t work and shows the following exception:

Type is not resolved for member ‘ServiceStack.DispsableTracker,ServiceStack, Version=4.0.56.0, Culture=neutral, PublicKeyToken=null’.

I would appreciate any assistance.
thanks

public class Global : System.Web.HttpApplication
{
    public class TestDisposible : IDisposable
    {
        public void Dispose()
        {
        }
    }
    /// <summary>
    /// Create your ServiceStack web service application with a singleton AppHost.
    /// </summary>        
    public class HelloAppHost : AppHostBase
    {
        /// <summary>
        /// Initializes a new instance of your ServiceStack application, with the specified name and assembly containing the services.
        /// </summary>
        public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }

        /// <summary>
        /// Configure the container with the necessary routes for your ServiceStack application.
        /// </summary>
        /// <param name="container">The built-in IoC used with ServiceStack.</param>
        public override void Configure(Container container)
        {
            //Register user-defined REST-ful urls. You can access the service at the url similar to the following.
            //http://localhost/ServiceStack.Hello/servicestack/hello or http://localhost/ServiceStack.Hello/servicestack/hello/John%20Doe
            //You can change /servicestack/ to a custom path in the web.config.
            Routes
              .Add<Hello>("/hello")
              .Add<Hello>("/hello/{Name}");

            container.RegisterAutoWired<TestDisposible>().ReusedWithin(ReuseScope.None);
        }
    }

    protected void Application_Start(object sender, EventArgs e)
    {
        (new HelloAppHost()).Init();

        new Thread(new ThreadStart(() =>
        {
            // Following test works
            Test();
            
            var d = HelloAppHost.Instance.Container.Resolve<TestDisposible>();

            // Following execution fails
            Test();
        })).Start();
    }

    private void Test()
    {
        var domain = AppDomain.CreateDomain("Test");
        var list = domain.GetAssemblies();
        AppDomain.Unload(domain);
    }

Note: loading ServiceStack inside a separate AppDomains isn’t a supported or tested use-case so it’s possible you could run into further issues that we may not be able to resolve.

With that said, the issue is likely AppDomains don’t play well with CallContext. Normally this wouldn’t be used in an ASP.NET App if you resolve the dependency at runtime since we’d instead maintain them in System.Web.HttpContext.Current.Items but this doesn’t exist when executed outside the context of a HTTP Request, e.g. on Startup or in a background thread at which point it needs to use CallContext.

You can change ServiceStack to use ThreadStatic collection instead by setting:

RequestContext.UseThreadStatic = true;
(new HelloAppHost()).Init();

Which will use ThreadStatic instead of CallContext but this doesn’t play well with async requests where the same request can hop between different threads. So if you’re going to UseThreadStatic you should stick to sync Services.

Another solution is to tell ServiceStack you’re still in AppStartup and to avoid using CallContext by setting AppHost.ReadyAt = null then re-enabling it after your AppHost threads have finished, e.g:

var appHost = new HelloAppHost().Init();
appHost.ReadyAt = null;

new Thread(new ThreadStart(() =>
{
    Test();

    using (var d = appHost.Resolve<TestDisposible>())
    {
        //...                    
    }

    Test();

    appHost.ReadyAt = DateTime.UtcNow;
})).Start();
1 Like

Great, thanks. As it’s for Quartz Scheduler background processing jobs, the first option works well as async not relevant in this scenario and Quartz manages thread creation.