Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullReferenceException accessing httpContext within WorkContextAccesor when it is called from a Migrations #5490

Closed
jersiovic opened this issue Jul 8, 2015 · 34 comments
Assignees
Milestone

Comments

@jersiovic
Copy link
Contributor

Running 1.9.x branch (08/07/2015 commit) when a migrations like this one is executed:

public int UpdateFrom1()
{
            _contentManager.Get(1)
            return 2;
}

I get NullReference exception at this method at WorkContextAccessor because httpContext is null:

            public HttpContextScopeImplementation(IEnumerable<IWorkContextEvents> events, ILifetimeScope lifetimeScope, HttpContextBase httpContext, object workContextKey) {
                _workContext = lifetimeScope.Resolve<WorkContext>();
                httpContext.Items[workContextKey] = _workContext;

                _disposer = () => {
                    events.Invoke(e => e.Finished(), NullLogger.Instance);

                    httpContext.Items.Remove(workContextKey);
                    lifetimeScope.Dispose();
                };
            }

Looking at the stacktrace problem comes at MvcModule.HttpContextBaseFactory() method when httpContextBase is resolved because it returns null:

var httpContextBase = context.Resolve<IHttpContextAccessor>().Current();

It seems that httpContextBase is not properly instantiated when the call is not initiated by a webrequest, as happens when migrations code is run.

Any idea on how to fix this?

@MpDzik
Copy link
Contributor

MpDzik commented Jul 9, 2015

You shouldn't use the content manager in migrations, because migrations are executed very early when the application is started and is not yet completely initialized. If you really need to use services which rely on the work context in a migration, then you can try to create a work context scope manually.

@jersiovic
Copy link
Contributor Author

In previous versions it was possible to use ContentManager at Migrations. Is not there a possible workaround to Activate AutomaticDataMigration after work context has been initialized?

I followed your advice attempting to get a ContextScope without success:

public int UpdateFrom1()
{
            using (_workContextAccessor.CreateWorkContextScope())
            {
                _contentManager.Get(1);
            }
            return 2;
}

I get the following Autofac Exception:

Autofac.Core.DependencyResolutionException "No scope with a Tag matching 'work' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself."
StackTrace:
 at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)
   at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
   at Orchard.Environment.WorkContextModule.<>c.<Load>b__0_1(IComponentContext ctx) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Environment\WorkContextModule.cs:line 27
   at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p)
   at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<>c__DisplayClass6.<RegistrationsFor>b__1(IComponentRegistration cr)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<RegistrationsFor>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<>c__DisplayClass6.<RegistrationsFor>b__1(IComponentRegistration cr)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<RegistrationsFor>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)

@Piedone
Copy link
Member

Piedone commented Jul 9, 2015

ContentManager should be usable from migrations just as before (and shell event should be wrapped into WCs #4852).

I think @sfmskywalker can help with this.

@sfmskywalker
Copy link
Member

Yes, regardless of whether or not it is good practice to use IContentManager in migrations, the fact that you can't all of a sudden indicates a potential bug. I'll look into it.

@sfmskywalker sfmskywalker self-assigned this Jul 9, 2015
@sfmskywalker sfmskywalker added this to the Orchard 1.9.x milestone Jul 9, 2015
@jafcampos
Copy link

Hello Sipke Schoorstra.
Do you have any preview for this resolution.

@sfmskywalker
Copy link
Member

I'm afraid not, I have yet to look into it. Try and inject it as a Work<IContentManager>, perhaps that makes a difference.

@jersiovic
Copy link
Contributor Author

Inject it as Work<IContentManager> didn't worked :(
In the mean time I'll continue investing time into grasp the work context initialization in Orchard.
It is a hard pending subject for me ;)

@sfmskywalker
Copy link
Member

Sounds good. Have fun. ;-)

@MpDzik
Copy link
Contributor

MpDzik commented Jul 10, 2015

@jersiovic, here's how I create work context scopes in my Orchard PowerShell project:
https://github.com/MpDzik/orchardps/blob/dev/src/Orchard.Web/Modules/Proligence.PowerShell.Provider/TenantContextManager.cs

I'm not sure if this is the best way to do it, but it works.

@jafcampos
Copy link

Hello.
I made this workaround:
In McvModule i changed the line in HttpContextBaseFactory(IComponentContext context) method:
from
var httpContextBase = context.Resolve().Current();
to
var httpContextBase =new HttpContextPlaceholder(baseUrl);

And added the old constructor to HttpContextPlaceholder class

        public HttpContextPlaceholder(Func<string> baseUrl)
        {
            _baseUrl = new Lazy<string>(baseUrl);
            _disposer = () =>
            {
                //Does nothing
            };
        }

Is not a solution but i can now make my import....

@jersiovic
Copy link
Contributor Author

Thank both for you advice
@jafcampos I tried your solution but when I call ContentManager.Get() method from migrations I get the same exception:

StackTrace:
   at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)
   at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
   at Orchard.Environment.WorkContextModule.<>c.<Load>b__0_1(IComponentContext ctx) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Environment\WorkContextModule.cs:line 27
   at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p)
   at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<>c__DisplayClass6.<RegistrationsFor>b__1(IComponentRegistration cr)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<RegistrationsFor>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<>c__DisplayClass6.<RegistrationsFor>b__1(IComponentRegistration cr)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Autofac.Features.Collections.CollectionRegistrationSource.<>c__DisplayClass4.<RegistrationsFor>b__0(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)

@MpDzik I will give a try to your solution

@jersiovic
Copy link
Contributor Author

After posting previous comment I looked twice at the point where exception is thrown (at WorkContextModule.Load() method) I have tried to registerWorkContextProperty for "shell" lifetimescope, that is the one is been used to resolve it :

            builder.RegisterType<WorkContextProperty<HttpContextBase>>()
                .As<WorkContextProperty<HttpContextBase>>()
                .InstancePerMatchingLifetimeScope("shell");

Now it works!! :)

@jersiovic
Copy link
Contributor Author

What do you think of this variation of your solution @jafcampos ?

Instead of replacing var httpContextBase = context.Resolve().Current(); per
var httpContextBase =new HttpContextPlaceholder(baseUrl); I only create Context when it is not available.

HttpContextBaseFactory(IComponentContext context) method:

            ...
            var httpContextBase = context.Resolve<IHttpContextAccessor>().Current();
            if (httpContextBase == null) {
                context.Resolve<IWorkContextAccessor>().CreateWorkContextScope();
                return context.Resolve<IHttpContextAccessor>().Current();
            } 
            context.Resolve<IWorkContextAccessor>().CreateWorkContextScope(httpContextBase);
            return httpContextBase;

In that way there is not need of adding the old constructor to HttpContextPlaceholder class

I've tested it and it seems to work properly.

@jersiovic
Copy link
Contributor Author

It looks this doesn't solves all problems with context.
Now, I'm receiving an exception in normal requests because I have a driver which uses a Service that has a dependency on IWorkContextAccessor. The exception occurs when I access to the RequestContext of the Workcontext returned by the accessor

public ServicioUrlsCatalogo(IWorkContextAccessor wca)
{         
      _workContext = wca.GetContext();
      _urlHelper = new UrlHelper(_workContext.HttpContext.Request.RequestContext);
}

The exception:

Exception:
ValueFactory attempted to access the Value property of this instance.
StackTrace:
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at System.Lazy`1.get_Value()
   at Orchard.ContentManagement.DefaultContentManager.get_Handlers() in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentManager.cs:line 81
   at Orchard.ContentManagement.DefaultContentManager.New(String contentType) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentManager.cs:line 102
   at Orchard.ContentManagement.DefaultContentManager.Get(Int32 id, VersionOptions options, QueryHints hints) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentManager.cs:line 227
   at Orchard.ContentManagement.DefaultContentManager.Get(Int32 id, VersionOptions options) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentManager.cs:line 131
   at Orchard.ContentManagement.DefaultContentQuery.<Slice>b__26_0(ContentItemVersionRecord x) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentQuery.cs:line 193
   at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Orchard.Utility.Extensions.ReadOnlyCollectionExtensions.ToReadOnlyCollection[T](IEnumerable`1 enumerable) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Utility\Extensions\ReadOnlyCollectionExtensions.cs:line 8
   at Orchard.ContentManagement.DefaultContentQuery.Slice(Int32 skip, Int32 count) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentQuery.cs:line 191
   at Orchard.ContentManagement.DefaultContentQuery.ContentQuery`1.Orchard.ContentManagement.IContentQuery<T>.List() in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\ContentManagement\DefaultContentQuery.cs:line 292
   at Orchard.Core.Settings.Services.SiteService.<GetSiteSettings>b__7_0(AcquireContext`1 ctx) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard.Web\Core\Settings\Services\SiteService.cs:line 28
   at Orchard.Caching.Cache`2.CreateEntry(TKey k, Func`2 acquire) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Caching\Cache.cs:line 57
   at Orchard.Caching.Cache`2.AddEntry(TKey k, Func`2 acquire) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Caching\Cache.cs:line 27
   at Orchard.Caching.Cache`2.<>c__DisplayClass3_0.<Get>b__0(TKey k) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Caching\Cache.cs:line 19
   at System.Collections.Concurrent.ConcurrentDictionary`2.AddOrUpdate(TKey key, Func`2 addValueFactory, Func`3 updateValueFactory)
   at Orchard.Caching.Cache`2.Get(TKey key, Func`2 acquire) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Caching\Cache.cs:line 17
   at Orchard.Caching.DefaultCacheManager.Get[TKey,TResult](TKey key, Func`2 acquire) in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Caching\DefaultCacheManager.cs:line 33
   at Orchard.Core.Settings.Services.SiteService.GetSiteSettings() in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard.Web\Core\Settings\Services\SiteService.cs:line 27
   at Orchard.Mvc.HttpContextAccessor.<>c__DisplayClass3_0.<CreateContext>b__0() in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Mvc\HttpContextAccessor.cs:line 24
   at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Lazy`1.get_Value()
   at Orchard.Mvc.MvcModule.HttpContextPlaceholder.get_Request() in D:\PROYECTOS\PCCOMB2B\Orchard Multitenant\src\Orchard\Mvc\MvcModule.cs:line 121

@jafcampos
Copy link

I jersiovic.
Did you solved the problem with this code variation:
...
var httpContextBase = context.Resolve().Current();
if (httpContextBase == null) {
context.Resolve().CreateWorkContextScope();
return context.Resolve().Current();
}
context.Resolve().CreateWorkContextScope(httpContextBase);
return httpContextBase;

Or there are other exceptions?

Since i made my code changed (workaround) i haven't got any exception.

@jersiovic
Copy link
Contributor Author

Yes I did that. It solved problem in migrations. But I found problems with context in other scenarios like I describe in previous post. I'm not sure if it is a colateral problem of this workaround.

I will make some tests with a site from scratch to isolate the problem before con back with more info.

@jersiovic
Copy link
Contributor Author

Finally problem is in this version we cannot access to _workContext.HttpContext.Request.RequestContext from a constructor if the class is a dependency of a handler because it will be called before Request is initialized. I moved this code from the constructor to the methods that need to access RequestContext and the problem was fixed.

So yes, the proposed solution seems to fix the problem.
I will send a pull request

@sebastienros
Copy link
Member

Looking at the commit which might have broken this, the code looks crazy, or at least I will need some time to understand the impact. Linked for ref: ce630f9

@sfmskywalker
Copy link
Member

FYI: That ref is a tad outdated.

@kumards
Copy link
Contributor

kumards commented Aug 24, 2015

Try this, today I got into very similar problem.

public int UpdateFrom1()
        {
            using (var scope = _workContextAccessor.CreateWorkContextScope())
            {
               var contentManager = scope.Resolve<IContentManager>();
                contentManager.Get(1);
            }
            return 2;
        }

@jersiovic
Copy link
Contributor Author

Thank you @kumards I understand my solution of adding ...InstancePerMatchingLifetimeScope("shell") is not good because breaks Orchard. So finally only solution I have found is to resolve ContentManager just when I'm going to use it as you @kumards proposed

Problem of this solution is I have more code in migrations of other modules which uses ContentManager. This code is executed when a new tenant is created, so I will need to fix also that code.

The other problem I see is for new comers to Orchard, this solution is something not obvious. So is likely they waste time trying to understand why ContentManager fails in migrations.

@jersiovic
Copy link
Contributor Author

Take into account problems are not only related with ContentManager, those also happen with WidgetsService.GetLayers(). Furthermore, with this solution what happens when migrations fails? Operations done in a different scope won't be rolled back

@JamesNK
Copy link

JamesNK commented Sep 1, 2015

I also just ran into this bug :(

@kumards
Copy link
Contributor

kumards commented Sep 1, 2015

I am just curios, what happens when the ContentManager is injected as Work object in the constructor?

@jersiovic
Copy link
Contributor Author

@kumards if do you mean to this, it is something I commented on the third comment on this thread

public int UpdateFrom1()
{
            using (_workContextAccessor.CreateWorkContextScope())
            {
                _contentManager.Get(1);
            }
            return 2;
}

@jersiovic
Copy link
Contributor Author

I faced this problem on July 9 when I was completing an upgrade of a multitenant site from version 1.7 to 1.9.1 which will be updated automatically using migrations + recipes + commands.

The point is after two months I'm still stuck at the same point, and I supporting pressure for upgrading to 1.9.1 On Tuesday meeting Committee was said @sfmskywalker was going to undo changes on a previous commit to solve this issue. Do you have any approximate idea of when it will be solved?
I understand you are busy, so if I you give me some indications related with the task to be done I can try to fix it myself and send a pull request.

@harmony7
Copy link
Contributor

harmony7 commented Sep 3, 2015

I've been battling this problem myself too since upgrading to VS 2015. In fact it happens for me not only for 1.9 sites but for 1.8 sites that I have to maintain too, when building under VS2015.

As @Piedone mentioned above, #4852 is the real problem here because there is no work context when Migrations are being run using Automatic Data Migrations. I have implemented a fix to #4852 locally and this has solved the problem for me, in both 1.8 and 1.9. I'll submit a pull request for #4852 in a few hours.

It does worry me that this problem only occurs under VS2015, and not under any previous Visual Studio version. Does anyone know the reason for this?

@jersiovic
Copy link
Contributor Author

Cool, I will be looking forward to hearing from you.

@sfmskywalker
Copy link
Member

The reason I started refactoring IHttpContextAccessor and related autofac registrations was to solve a runtime issue when the solution is built with VS2015. At the time, I was using VS2015 Preview or a RC, both of which using Roslyn. When debugging the code then, I saw that the error made sense and started the refactoring process to remedy the issue. As mentioned on the last two meetings, this refactoring is causing another side effect: not having access to the HttpContext from migrations (not even the HttpContextPlaceholder fake, which should be available, but is not due to a bug).

@sebastienros proposed that we roll back all of my changes to see if the issue still exists with VS2015 RTM. I tried yesterday, and sadly, the issue is still there. I reported this to Sebastien and he'll digg into why the exact same code works when built with VS2013 but not with VS2015.

This is the commit hash to reproduce the issue with HttpContextBase on VS2015: d3ccd74.

To recap, in VS2013 everything up to and including d3ccd74 runs fine, but fails in VS2015.
Orchard errors out right after setup:

i77 cimgpsh_orig

I can think of the following course of actions:

  1. Roll back everything and try a different approach. Perhaps the fix can be simpler than I have been doing.
  2. Fix the issue with migrations we'e currently seeing.

@jersiovic
Copy link
Contributor Author

Thank you @sfmskywalker at least now things are more clear

@kumards
Copy link
Contributor

kumards commented Sep 3, 2015

@jersiovic No, the below implementation is wrong.

public int UpdateFrom1()
{
            using (_workContextAccessor.CreateWorkContextScope())
            {
                _contentManager.Get(1);
            }
            return 2;
}

Because, the _contentManager was not created from using (_workContextAccessor.CreateWorkContextScope()). I assume It was injected by autofac in the class constructor.

If you refer to my comment here #5490 (comment), you will see the implementation difference.

What I meant about injecting ContentManager as Work object was something like below

public class MigrationClass : DataMigrationImpl
    {
        private readonly Work<IContentManager> _contentManager;
        public MigrationClass(Work<IContentManager> contentManager)
        {
            _contentManager = contentManager;
        }

       public int UpdateFrom3()
        {
            _contentManager.Value.Get(1);
        }
    }

@harmony7
Copy link
Contributor

harmony7 commented Sep 3, 2015

I've submitted a pull request.

@jersiovic
Copy link
Contributor Author

The pull request submitted by @harmony7 #5738 looks great. After using his fix the problems has disappeared for me.

Yes you are right @kumards that code was wrong.

@sebastienros
Copy link
Member

I have submitted the VS discrepancy to someone at Microsoft. I will keep you posted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants