SharpRepository in a concurrent system

293 views
Skip to first unread message

Matthew Tolliday

unread,
Jun 20, 2014, 8:14:45 AM6/20/14
to sharpre...@googlegroups.com
First off - amazing work, this really is a great library with some inspired ideas.

I'm considering importing this framework into a legacy system that we're currently supporting that essentially uses the Quartz.NET scheduling framework to run a large number of ETL style imports very freqently. 

The system itself is running under Castle.Windsor as a Windows service.

The issue i'm having that I'm hoping will be as simple as an incorrect configuration is that on multiple Quartz jobs running concurrently, Windsor is seemingly resolving the same instance of the EfRepository class despite having the DBContext registered explictly as Transient. Looking closer at the container registrations it would appear that the IRepository has been registered as Singleton. Assuming my understanding is correct the resulting:

2014-06-20 10:45:59.7940 - ERROR: System: The underlying provider failed on Open.
EXCEPTION: System.Data.Entity.Core.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
   at System.Data.ProviderBase.DbConnectionClosedConnecting.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.<Open>b__38(DbConnection t, DbConnectionInterceptionContext c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.EntityClient.EntityConnection.<Open>b__2()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
   at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
   --- End of inner exception stack trace ---

Is that Windsor is resolving the same repository instance to the Quartz Job thus causing conflicting connection states...Is there a way to configure Sharp to use a transient IRepository lifecycle? Or am i missing something else blindly obvious? 

For reference:

            var config = new SharpRepositoryConfiguration();
            config.AddRepository(new EfRepositoryConfiguration("ef6", "StagingContext"));
            
            config.AddCachingStrategy(new NoCachingStrategyConfiguration("none"));

            config.DefaultRepository = "ef6";
            config.DefaultCachingStrategy = "timeout";
            config.DefaultCachingProvider = "inmemory";

            container.RegisterSharpRepository(config);


and:

            container.Register(Component
                .For<DbContext>()
                .ImplementedBy<StagingContext>()
                .LifestyleTransient());

Thanks for any help/advice anyone can give!

Jeff Treuting

unread,
Jun 20, 2014, 11:37:48 AM6/20/14
to Matthew Tolliday, sharpre...@googlegroups.com

First off thanks for the compliment.

 

You need to tell SharpRepository what IoC you are using if you want it to create the DbContext with the Windsor rules you setup.  This might be the issue but I’m not sure.  Try adding this and seeing if it helps:

 

    RepositoryDependencyResolver.SetDependencyResolver(new WindsorDependencyResolver(container));

 

 

It also sounds like it isn’t creating a new IRepository for you each time.  I don’t use Windsor, so it’s possible that the logic in the container.RegisterSharpRepository isn’t setup properly.

 

Here is what it is doing and it should be setup for IRepository to be transient and not a singleton but maybe I implemented it wrong and my understanding of the Windsor container is incorrect.

 

            container.Register(Component.For(typeof(IRepository<>)).UsingFactoryMethod((c, t) =>

                {

                    var genericArgs = t.GenericArguments;

 

                    return RepositoryFactory.GetInstance(genericArgs[0], repositoryName);

                }));

 

            container.Register(Component.For(typeof(IRepository<,>)).UsingFactoryMethod((c, t) =>

                {

                    var genericArgs = t.GenericArguments;

 

                    return RepositoryFactory.GetInstance(genericArgs[0], genericArgs[1], repositoryName);

                }));

--
You received this message because you are subscribed to the Google Groups "SharpRepository" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sharpreposito...@googlegroups.com.
To post to this group, send email to sharpre...@googlegroups.com.
Visit this group at http://groups.google.com/group/sharprepository.
To view this discussion on the web visit https://groups.google.com/d/msgid/sharprepository/28163eaf-6bcb-4497-9f1b-3d9e62215020%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthew Tolliday

unread,
Jun 20, 2014, 12:05:12 PM6/20/14
to sharpre...@googlegroups.com, matt.to...@gmail.com
Hi Jeff,

Cheers for the reply.

I missed off the resolver registration from my question - but good spot, I did remember to do that.

As far as my knowledge of Windsor takes me it always defaults to the Singleton Lifestyle, even when using the Factory or Facilities.

I'm purely spitballing but something like this as an overload might allow that to be set on the registration. I'm going to test this now against my codebase and see if its the behaviour I would expect.

public static void RegisterSharpRepository(this IWindsorContainer container, LifestyleType lifeStyle = LifestyleType.Singleton, string repositoryName = null)
        {
            container.Register(Component.For(typeof(IRepository<>)).LifeStyle.Is(lifeStyle).UsingFactoryMethod((c, t) =>
            {
                var genericArgs = t.GenericArguments;

                return RepositoryFactory.GetInstance(genericArgs[0], repositoryName);
            }));

            container.Register(Component.For(typeof(IRepository<,>)).LifeStyle.Is(lifeStyle).UsingFactoryMethod((c, t) =>
            {
                var genericArgs = t.GenericArguments;

                return RepositoryFactory.GetInstance(genericArgs[0], genericArgs[1], repositoryName);
            }));

            container.Register(Component.For(typeof(ICompoundKeyRepository<,,>)).LifeStyle.Is(lifeStyle).UsingFactoryMethod((c, t) =>
            {
                var genericArgs = t.GenericArguments;

                return RepositoryFactory.GetInstance(genericArgs[0], genericArgs[1], genericArgs[2], repositoryName);
            }));

Jeff Treuting

unread,
Jun 20, 2014, 12:11:26 PM6/20/14
to Matthew Tolliday, sharpre...@googlegroups.com

If that is the default behavior for Windsor then that would explain what is happening.  Let me know if that works out and if so it would be great if you could send a pull request for that.  I think it is a really nice enhancement.

 

And that makes me think it would make sense to provide similar overrides for the other IoC extension methods as well in the future.

 

Thanks.

 

Jeff

Matthew Tolliday

unread,
Jun 25, 2014, 4:44:09 PM6/25/14
to sharpre...@googlegroups.com, matt.to...@gmail.com
Hi Jeff,

Just to update I'm not totally happy with that implementation fixing the issue - or even if there's a secondary problem causing it where in fact there's no issue - so I'm continuing to test.

Essentially, I'm concerned that Quartz is not pulling new instances from Windsor, and that's the reason new object's are not being resolved further down the chain with Sharp.

It might just be a coincidence but I want to be sure.

Cheers,

Matt

jonatha...@gmail.com

unread,
Jul 2, 2014, 8:16:38 PM7/2/14
to sharpre...@googlegroups.com
I'm having a similar issue using StructureMap. It seems that we're getting a

"The operation cannot be completed because the DbContext has been disposed"

error after the site runs for a short period of time. It seems like the repositories are not being created upon every request. I'm using StructureMap 3.0.3.116. Could this be because the controllers are not being created upon every request?

Our StructureMap configuration looks like so:

public static class IoC {

public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});

x.For<IEventLogRepository>().Use(c => new
EventLogRepository("efLoggingRepository"));


});

return ObjectFactory.Container;
}

}



Jeff Treuting

unread,
Jul 2, 2014, 9:48:55 PM7/2/14
to jonatha...@gmail.com, sharpre...@googlegroups.com
Can you post the code for EventLogRepository?

I usually setup SharpRepository to share the DbContext using StructureMap. Checkout the section title "EntityFramework and Sharing The DbContext" here for some more info: http://fairwaytech.com/2013/02/sharprepository-configuration/

Not sure if that is the issue or not, but you could try it.

You need to use the SharpRepository.Ioc.StructureMap NuGet package and call this code:

RepositoryDependencyResolver.SetDependencyResolver(new StructureMapDependencyResolver(ObjectFactory.Container));

As well as configured StructureMap with how you want it to handle creating a DbContext. I usually do something like this:

For<DbContext>()
.HybridHttpOrThreadLocalScoped()
.Use<CustomEfEntities>()
.Ctor<string>("connectionString").Is(entityConnectionString);
--
You received this message because you are subscribed to the Google Groups "SharpRepository" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sharpreposito...@googlegroups.com.
To post to this group, send email to sharpre...@googlegroups.com.
Visit this group at http://groups.google.com/group/sharprepository.
To view this discussion on the web visit https://groups.google.com/d/msgid/sharprepository/7c7dd8a8-aa2a-42fe-bcc9-20831239573a%40googlegroups.com.

jonatha...@gmail.com

unread,
Jul 16, 2014, 4:44:40 PM7/16/14
to sharpre...@googlegroups.com, jonatha...@gmail.com
Thanks Jeff, but will that work for StructureMap 3? We also have 4 different EDMXs so we have to tell StructureMap to use the right connection string. The custom repositories helps with that because I can set a constant string property on each custom repository that specifies which repository-configuration to use. It would be nice if there was an EFConfigurationBasedRepository to base from.
Reply all
Reply to author
Forward
0 new messages