Using Unity with WebAPI doesn't work if UmbracoContext is registered as singleton
I'm bulding some web api to extend the backend of Umbraco. I'm already using Unity and Unity.Mvc to inject depenencies in the views.
But to extend the approach to backend web api I also had to install the Unity.WebApi package.
But here I'm encountering some problems. Using the recommended approach of injecting the UmbracoContext.Current as singleton (ContainerControlledLifetimeManager) gives some errors every now and then.
For example, adding a new node or deleting a node raises an exception
System.NullReferenceException: Object reference not set to an instance of an object.
at Umbraco.Web.Security.WebSecurity.IsAuthenticated()
at Umbraco.Web.Security.WebSecurity.ValidateCurrentUser(Boolean throwExceptions)
at Umbraco.Web.WebApi.UmbracoAuthorizedApiController.get_UmbracoUser()
at Umbraco.Web.Editors.ContentController.GetEmpty(String contentTypeAlias, Int32 parentId)
But it does work if instead of registering the UmbracoContext.Current as singleton I register it as "per request" (HierarchicalLifetimeManager).
Since the UmbracoContext.Current just looks inside the HttpContext.Items using one or the other shouldn't be any different.
container.RegisterType<UmbracoContext>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(c => UmbracoContext.Current));
UmbracoContext.Current will be used to create the Singleton object and as it is singleton it will be created only once... the injected value will be the UmbracoContext.Current of your first request.
The only good reason I think it doesn't break the MVC Unity configuration, is that UmbracoContext.Current reference is not widely used through constructors , or if it used maybe it is used for some global properties that are the same through all requests.
Did you manage to resolve your issues with this? Everything appears to be working ok for me except when I try to create a new content item via a list view at which point I get the same exception as you. I am using Unity.Mvc5 and Unity.AspNet.WebApi and in the WebActivator class I have the following in the Start() method:
// Web API
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(UnityConfig.Container); ; ;
// MVC
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(UnityConfig.Container));
UnityConfig.RegisterComponents();
And in my UnityConfig class I have the following:
public static class UnityConfig
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
return container;
});
public static IUnityContainer Container => container.Value;
public static void RegisterComponents()
{
// Register our type mappings
RegisterTypes(Container);
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<UmbracoContext>(new ContainerControlledLifetimeManager(), new InjectionFactory(c => UmbracoContext.Current));
container.RegisterType<ApplicationContext>(new ContainerControlledLifetimeManager(), new InjectionFactory(c => UmbracoContext.Current));
container.RegisterType<ServiceContext>(new ContainerControlledLifetimeManager(), new InjectionFactory(c => UmbracoContext.Current));
container.RegisterType<Umbraco.Web.Mvc.RenderMvcController>(new InjectionConstructor(new ResolvedParameter<UmbracoContext>()));
container.RegisterType<UmbracoHelper>(new InjectionConstructor(new ResolvedParameter<UmbracoContext>()));
container.RegisterType<LegacyTreeController>(new InjectionConstructor());
container.RegisterType<HealthCheckController>(new InjectionConstructor());
container.RegisterType<UsersController>(new InjectionConstructor());
}
}
Like Laurent said, UmbracoContext should be created on a per-request basis, not a lifetime basis. The Umbraco context contains info on the current request, which changes per request. It's equivalent to HttpContext in that regard.
PerThreadLifetimeManager also seems to work and sounds like it might be more suitable:
PerThreadLifetimeManager. For this lifetime manager Unity returns, on
a per-thread basis, the same instance of the registered type or object
each time you call the Resolve or ResolveAll method or when the
dependency mechanism injects instances into other classes. This
lifetime manager effectively implements a singleton behavior for
objects on a per-thread basis. PerThreadLifetimeManager returns
different objects from the container for each thread. If you
registered a type mapping using configuration or using the
RegisterType method, Unity creates a new instance of the registered
type the first time the type is resolved in a specified thread, either
to answer a call to the Resolve or ResolveAll method for the
registered type or to fulfill a dependency while resolving a different
type. Subsequent resolutions on the same thread return the same
instance.
Using Unity with WebAPI doesn't work if UmbracoContext is registered as singleton
I'm bulding some web api to extend the backend of Umbraco. I'm already using Unity and Unity.Mvc to inject depenencies in the views.
But to extend the approach to backend web api I also had to install the Unity.WebApi package.
But here I'm encountering some problems. Using the recommended approach of injecting the
UmbracoContext.Current
as singleton (ContainerControlledLifetimeManager
) gives some errors every now and then.For example, adding a new node or deleting a node raises an exception
But it does work if instead of registering the
UmbracoContext.Current
as singleton I register it as "per request" (HierarchicalLifetimeManager
).Since the
UmbracoContext.Current
just looks inside theHttpContext.Items
using one or the other shouldn't be any different.Anyone else found issues with this?
What's the recommended approach by the core team?
Simone
Simone,
UmbracoContext.Current will be used to create the Singleton object and as it is singleton it will be created only once... the injected value will be the UmbracoContext.Current of your first request.
The only good reason I think it doesn't break the MVC Unity configuration, is that UmbracoContext.Current reference is not widely used through constructors , or if it used maybe it is used for some global properties that are the same through all requests.
Did you manage to resolve your issues with this? Everything appears to be working ok for me except when I try to create a new content item via a list view at which point I get the same exception as you. I am using
Unity.Mvc5
andUnity.AspNet.WebApi
and in the WebActivator class I have the following in theStart()
method:And in my
UnityConfig
class I have the following:Like Laurent said,
UmbracoContext
should be created on a per-request basis, not a lifetime basis. The Umbraco context contains info on the current request, which changes per request. It's equivalent toHttpContext
in that regard.See https://our.umbraco.org/Documentation/Reference/Common-Pitfalls/
Thanks Dan, I misunderstood.
I have replaced:
with…
All good so far!
PerThreadLifetimeManager
also seems to work and sounds like it might be more suitable:is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.