Bruce Hunter - 474 - Mar 5, 2014

I call this line of IoC in the Service Interface  object Any(Request) method.

                //IOC injection at the request level. This will inject a new instance for ATICore database for each request based on Session.
                HostContext.Container.Register<IAtiCoreDbConnectionFactory>(c => new AtiCoreDbConnectionFactory(this.GetATIUserConnectionByAlias(ServiceSettings.ControllerConnectionAliasATICoreCached).ConnectionString)).ReusedWithin(ReuseScope.Request);

I am later doing the following in my repository.

var a = HostContext.Container.TryResolve<IAtiCoreDbConnectionFactory>() as AtiCoreDbConnectionFactory;

This Interface just has 1 property ConnectionString that use to create a 

new SqlConnection(a.ConnectionString)

I’m finding that I have a concurrency issue and the Request level IoC is not working correctly. Not sure what I’m doing wrong, I’m new to IoC.

Our database connection is dynamic each time for each different user. I create a CustomSession object where I store the logged in users connection strings, that I get later and inject for each request Any() call.

Note: you shouldn’t be registering dependencies in the IOC outside of Configre(), which should be immutable thereafter.

Also why aren’t you declaring it to be injected in your repository with a public property?, e.g:

IAtiCoreDbConnectionFactory AtiCoreDbFactory { get; set; }

Typically your Factory dependencies should be singletons and then what you get back from them is a non thread-safe instance, e.g:

using (var userDb = AtiCoreDbFactory.Open(UserConnectionString)) {
  //something with userDb
}

Bruce Hunter:

Really, the word use of “Factory” for this should be removed. It’s an Interface that specifies a specific type of Database with a simple property to be created ConnectionString.

nTier type project setup
WebServiceApplication (Project) -> ServiceInterface (Project) -> Engine (Project) -> Repository (Project).

For each request, I get the connection strings from Session<CustomSession>().ConnectionStrings.

I was trying to utilize IoC at the Interface layer to set my Repository class IAtiCoreDbConnection on the fly from Any(). (The Container only gets called one time, during AppHost.Init())

My Alternatives to IoC
NO IoC : Another way is to pass the loaded Repository class to the Engine, but that is messy and not good form.

NO IoC: Another way is for my Repository classes to hook directly to the Session<CustomSession> object.

Thoughts?

If you’re getting the connectionString at runtime for each request than I would use that to open a new connection that you manage, e.g. if I was sharding with OrmLite (http://bit.ly/1icV0nF) I would do something like:

public class MyService : Service
{
    public IAtiCoreDbConnectionFactory UserDbFactory { get; set; }

    public object Any(Request request)
    {
        var session = SessionAs<MySession>();
        using (var db = UserDbFactory.OpenUserDb(session.ConnString))
        {
            return UserDb.Fetch<Record>(request.Id);
        }
   }
}

If you do this a lot you can wrap it behind some boilerplate like we do with the RepositoryBase/LogicBase: https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/ILogic.cs#L38

public abstract class ServiceBase : Service 
{
    public IAtiCoreDbConnectionFactory UserDbFactory { get; set; }

        IDbConnection userDb;
        public virtual IDbConnection UserDb
        {
            get
           {
               return userDb ??  (userDb = DbFactory.OpenUserDb( SessionAs<MySession>().ConnString));
            }
        }

        public override void Dispose()
        {
            base.Dispose();
            if (userDb != null)
                userDb.Dispose();
        }
}

Then your normal services can look like:

public class MyService : ServiceBase
{
    public object Any(Request request)
    {
        return UserDb.Fetch<Record>(request.Id);
   }
}

Bruce Hunter:

Isn’t there only one instance of Service for all requests? If that is the case wouldn’t userDb not being null possibly return another requests userDb open connection?

If a new Service instance is created each time then this wouldn’t be an issue.

Right, a new instance of each Service is created and autowired on every request.

Bruce Hunter:

Cool, thanks for help. Makes sense.

Bruce Hunter:

Got it working. With the knowledge that the Service object is created for each Request, that really solved my entire issue.

ok awesome, yeah that tidbit is definitely good to know :slight_smile: