1

I'm having a problem with ReuseScope.Request. I'm getting the same instance injected on every request even though I specify ReuseScope.Request. I configured the container using these two calls to get a MasterConfig:

this.container.RegisterAutoWiredAs<ApiConfigFactory, IConfigFactory>().ReusedWithin(ReuseScope.Container);
this.container.Register(c => c.Resolve<IConfigFactory>().GetMasterConfig(true)).ReusedWithin(ReuseScope.Request);

The GetMasterConfig(true) method returns a new concrete MasterConfig. However, when I try to use the MasterConfig in the service, I get the same instance on every request.

public class MyService
{
    private readonly MasterConfig masterConfig;

    public SaleService(MasterConfig masterConfig)
    {
        this.masterConfig = masterConfig;
    }

    public object Post(MyRequest request)
    {
        // **masterConfig is the same instance here on every request**
    }
}

If I change the scope on the MasterConfig Register to ReuseScope.None, I get a new MasterConfig loaded as expected. What am I missing? Is there a problem with the way I am registering MasterConfig? Why does ReuseScope.None fix the issue? Why does ReuseScope.Request give me the same instance?

Note:

Bryan Cox
  • 278
  • 2
  • 6

2 Answers2

0

I haven't been able to reproduce this in either a self-host or ASP.NET Host.

This works in the latest version of ServiceStack:

//AppHost
public class RequestScopeAppHost : AppSelfHostBase
{
    public RequestScopeAppHost() 
      : base(typeof(RequestScopeAppHost).Name, typeof(RequestScopeService).Assembly) {}

    private static int counter = 0;

    public override void Configure(Container container)
    {
        container.Register(c => new MasterConfig {
            Id = Interlocked.Increment(ref counter)
        }).ReusedWithin(ReuseScope.Request);
    }
}

Service:

public class MasterConfig
{
    public int Id { get; set; }
}

public class GetMasterConfig : IReturn<MasterConfig> { }

public class RequestScopeService : Service
{
    private readonly MasterConfig config;

    public RequestScopeService(MasterConfig config)
    {
        this.config = config;
    }

    public object Any(GetMasterConfig request)
    {
        return config;
    }
}

Test:

[TestFixture]
public class RequestScopeIssue
{
    private readonly ServiceStackHost appHost;

    public RequestScopeIssue()
    {
        appHost = new RequestScopeAppHost()
            .Init()
            .Start(Config.AbsoluteBaseUri);
    }

    [TestFixtureTearDown]
    public void TestFixtureTearDown()
    {
        appHost.Dispose();
    }

    [Test]
    public void Can_get_RequestScope_dependency()
    {
        var client = new JsonServiceClient(Config.AbsoluteBaseUri);

        Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(1));
        Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(2));
        Assert.That(client.Get(new GetMasterConfig()).Id, Is.EqualTo(3));
    }
}

In your description ReuseScope.None also works as intended, it doesn't re-use instances.

mythz
  • 141,670
  • 29
  • 246
  • 390
0

I also had exactly the same issue, using ServiceStack version 4.5.6

Here is my code for registration

container.RegisterAutoWiredAs<EventConditionalLoadingRepository, IEventConditionalLoadingRepository>()
    .ReusedWithin(ReuseScope.Request);

container.RegisterAutoWiredAs<MetaRiskRepository, IMetaRiskRepository>()
    .ReusedWithin(ReuseScope.Request);

container.RegisterAutoWiredAs<RiskStoreConnectivityService, IRiskStoreConnectivityService>()
    .ReusedWithin(ReuseScope.Request);

container.Register<IUnitOfWork>(c =>
{
    return new UnitOfWork();
}).ReusedWithin(ReuseScope.Request);

container.Register(c => (IUnitOfWorkEnlistable)c.Resolve<IUnitOfWork>())
    .ReusedWithin(ReuseScope.Request); 

And here is my service that takes these dependencies

public AnalysisServiceStackService(
    IEventConditionalLoadingRepository eventConditionalLoadingRepository,
    IMetaRiskRepository metaRiskRepository,
    IUnitOfWork unitOfWork)
{

    _eventConditionalLoadingRepository = eventConditionalLoadingRepository;
    _metaRiskRepository = metaRiskRepository;
    _unitOfWork = unitOfWork;
    _log.Information("AnalysisServiceStackService constructed");
}

You can see that I have a log statement there, which when I hit this service up via postman for sequential requests, I get this sort of thing logged

2017-03-30 15:34:10 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:11 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:12 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:13 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:14 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:15 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:16 [Information] AnalysisServiceStackService constructed
2017-03-30 15:34:17 [Information] AnalysisServiceStackService constructed

So I know the service itself should be attempting to resolve a new PerRequest instance of the IOC components it needs.

If I then use Visual studio and use the Debug "Make Object ID" feature to check what the IOC container is giving me they are the same instance.

Call 1 : 1st Request

see the #1 Object ID created by Visual Studio

#1 Id

Call 2 : 2nd Request

See the #1 Object ID which means its the same instance it should NOT be. It should be a new instance for a new request

Same object

And just to prove that these are different calls, here is the logs for the Constructor being run twice, once for each request

Logging after 2 requests

Only thing that fixed this for me was the suggested fix of Reuse.None

But if I have to do that I might as well just use the AutoFac adapter (which I would prefer to use anyway) and use the standard AutoFac INstancePerLifeTimeScope : http://docs.autofac.org/en/latest/lifetime/instance-scope.html#instance-per-lifetime-scope

Any ideas?

sacha barber
  • 2,214
  • 1
  • 24
  • 37