I'm trying to use Castle Windsor to reuse a single instance of my WebApp settings class (MySettings).
This settings rarely changes, but when it changes, I need to update the instance in the container.
I can easily track when the Settings changes, but I can't figure out the right way to do it, can anybody help me?
The Windsor Installer class is bellow:
public class SettingsInstaller : IWindsorInstaller
{
private MySettings Settings { get; set; }
public void Install(IWindsorContainer container, IConfigurationStore store)
{
UpdateSettings();
container.Register(
Component.For<MySettings>()
.Instance(this.Settings));
}
public MySettings UpdateSettings()
{
using (DbContext db = new DbContext())
{
this.Settings = db.Settings.FirstOrDefault();
}
return this.Settings;
}
}
How can I call the UpdateSettings() and make sure that the container will use the updated Settings in the next Dependency Injection resolution?
I think what you want is for MySettings to be a singleton whose state you can then update in other parts of the application. If you register MySettings as a singleton, then whenever the container resolves a MySettings for you, it will return the same instance. This is essentially what you are doing in your answer, but you're just storing the instance in a local variable (instead of letting the container do it for you).
Your registration code can then get very simple:
public class SettingsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<MySettings>().LifestyleSingleton());
}
}
Whenever you need to access the settings, you can request a MySettings from the container using constructor injection (or any other method of getting an instance from a container):
public class ClientClass
{
private readonly MySettings _settings;
public ClientClass(MySettings settings)
{
_settings = settings;
}
public void UpdateSettings()
{
_settings.SomeSetting = myNewSetting; // reset them however you need to here
}
}
After you've called UpdateSettings() in your application somewhere, then the instance the container is holding on to (a singleton) will be updated with myNewSetting, and when the next class requests a MySettings you'll get the same instance with the updated value.
If you actually need a new instance of MySettings, then in your UpdateSettions() method you can create an entirely new one using
_settings = new MySettings() and the container will serve up the new instance for you from then on.
I had no answer yet. I have done this, and it is working:
public class SettingsInstaller : IWindsorInstaller
{
private static MySettings Settings { get; set; }
public void Install(IWindsorContainer container, IConfigurationStore store)
{
UpdateSettings();
container.Register(
Component.For<MySettings>()
.UsingFactoryMethod(() =>
{
return SettingsInstaller.Settings;
})
.LifestyleTransient());
}
public static MySettings UpdateSettings()
{
using (DbContext db = new DbContext())
{
SettingsInstaller.Settings = db.Settings
.AsNoTracking()
.FirstOrDefault();
}
return SettingsInstaller.Settings;
}
}
Related
The UnityMvcActivator is called right out of the gate when starting my MVC application, and it instantiates, configures, and sets the container to the DependencyResolver:
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
Which immediately registers all the types via:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterMvcComponents();
}
...but I'm trying to register types that aren't created until a little further down the road:
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container)
{
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterInstance<HttpSessionStateBase>(
new HttpSessionStateWrapper(HttpContext.Current.Session), lifetimeManager);
container.RegisterInstance<HttpContextBase>(
new HttpContextWrapper(HttpContext.Current), lifetimeManager);
container.RegisterInstance<HttpServerUtilityBase>(
new HttpServerUtilityWrapper(HttpContext.Current.Server), lifetimeManager);
container.RegisterInstance(HttpContext.Current.User.Identity, lifetimeManager);
return container;
}
I can't get the container back from the DependencyResolver when I finally make it to my OWIN Startup class - which is where all the other initialization is taking place - so how can I register these types?
EDIT:
Thinking I was clever, I tried adding some post-start action to the activator by adding this assembly directive and moving my configuration method call to the newly created method:
[assembly: WebActivatorEx.PostApplicationStartMethod(
typeof(CCCS.Admin.Web.Ui.UnityMvcActivator),
nameof(CCCS.Admin.Web.Ui.UnityMvcActivator.PostStart))]
public static void PostStart() => UnityConfig.Container.RegisterMvcComponents();
... and that got me halfway, but the User and Session still aren't available.
This is more of an XY problem related to your design, as all the HttpContext related members wont be available at startup.
You would better off creating abstractions to defer the access to those implementation concerns.
public interface IHttpContextAccessor {
HttpContextBase HttpContext { get; }
}
public class HttpContextProvider : IHttpContextAccessor {
public virtual HttpContextBase HttpContext {
get {
return new HttpContextWrapper(HttpContext.Current);
}
}
}
Now all those registrations can be replaced with the one abstraction which would provide access to all the other related types.
public static IUnityContainer RegisterMvcComponents(this IUnityContainer container) {
var lifetimeManager = new HierarchicalLifetimeManager();
container.RegisterType<IHttpContextAccessor, HttpContextProvider>(lifetimeManager);
return container;
}
Note that the container should ideally only be accessed in the composition root of the application and not passed around as a dependency. That is seen as a code smell and an indicator that the design should be reviewed and refactored if possible.
When access is needed to HttpContext related members it is now a matter of injecting the accessor
private readonly IHttpContextAccessor accessor;
public MyDependent(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void SomeMethodAccessedInAnAction() {
var context = access.HttpContext; // HttpContextBase
var session = context.Session; // HttpSessionStateBase
var server = context.Server; // HttpServerUtilityBase
var user = context.User; // IPrincipal
//...
}
I am using Unity for dependency injection so far its working fine except using dependency in singleton class.
I have one static class to access database functions
public class DB
{
private static readonly Lazy<DB> lazy = new Lazy<DB>(() => new DB());
public static DB Instance { get { return lazy.Value; } }
private readonly IContactService _contactService;
private DB() { }
public DB(IContactService contactService)
{
_contactService = contactService;
}
}
Now, the issue is IContactService is dependent on ContactService class as DB uses _contactService in order to make web service call. Even after registering DB as singleton using Unity, i am getting _contactService as null.
registering DB class
_container = new UnityContainer();
_container.RegisterSingleton<DB>();
Change your DB class to something like:
public class DB {
private readonly IContactService _contactService;
public DB(IContactService contactService) {
_contactService = contactService;
}
...
}
Wherever you were using DB.Instance, inject DB as a dependency and use that. Or use Locator.Instance.Resolve<DB>() although using a ServiceLocator is considered an anti pattern (depends).
Since you are registering DB as singleton in your DI container, it is the responsibility of the container to always return the same instance wherever it is injected. You don't need to write code in DB to make it a singleton.
I decided to clean this post up and I posted a sample project at ge.tt/3EwoZEd/v/0?c
Spent around 30 hours on this already and still can't figure it out... help would be really appreciated!
I have an ASP.NET Web API solution that uses this code: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/ to implement "Basic HTTP authentication in ASP.NET Web API using Message Handlers". I'm new to IoC/DI and I'm trying to get this to work with Castle Windsor.
I've been trying a lot of different things but I get 1 of the following errors depending on what I did wrong:
"Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule"
"Object reference not set to an instance of an object." for the PrincipalProvider in BasicAuthMessageHandler
"No component for supporting the service *.DummyPrincipalProvider was found"
Below is my code:
Global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var config = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
IncludeErrorDetailPolicy errorDetailPolicy;
switch (config.Mode)
{
case CustomErrorsMode.RemoteOnly:
errorDetailPolicy
= IncludeErrorDetailPolicy.LocalOnly;
break;
case CustomErrorsMode.On:
errorDetailPolicy
= IncludeErrorDetailPolicy.Never;
break;
case CustomErrorsMode.Off:
errorDetailPolicy
= IncludeErrorDetailPolicy.Always;
break;
default:
throw new ArgumentOutOfRangeException();
}
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = errorDetailPolicy;
ConfigureWindsor(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler()
{
PrincipalProvider = _container.Resolve<IProvidePrincipal>()
});
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
// Create / Initialize the container
_container = new WindsorContainer();
// Find our IWindsorInstallers from this Assembly and optionally from our DI assembly which is in abother project.
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
//Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
// Set the WebAPI DependencyResolver to our new WindsorDependencyResolver
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
Windsor Installer:
public class PrincipalsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<DelegatingHandler>());
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
}
}
Modified DummyPrincipalProvider (from the original I got from the URL above):
public class DummyPrincipalProvider : IProvidePrincipal
{
private IUserRepository _userRepo;
public DummyPrincipalProvider(IUserRepository userRepo)
{
this._userRepo = userRepo;
}
public IPrincipal CreatePrincipal(string username, string password)
{
try
{
if (!this._userRepo.ValidateUser(username, password))
{
return null;
}
else
{
var identity = new GenericIdentity(username);
IPrincipal principal = new GenericPrincipal(identity, new[] { "User" });
if (!identity.IsAuthenticated)
{
throw new ApplicationException("Unauthorized");
}
return principal;
}
}
catch
{
return null;
}
}
}
WindsorDependencyResolver.cs:
internal sealed class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public void Dispose()
{
}
}
WindsorDependencyScope.cs:
internal sealed class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
_scope = container.BeginScope();
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public void Dispose()
{
_scope.Dispose();
}
}
I assume IProvidePrincipal is your own implementation.
Best way, the only one IMHO, to use an IoC container is the Composition Root.
The entry point/composition root for web api has been well explained by ploeh's blog.
DelegatingHandler are not part of the "request resolving", so you may choose to resolve it within global asax Application_start where the container lives as private variable.
GlobalConfiguration.Configuration.MessageHandlers.Add(container.Resolve<BasicAuthMessageHandler>());
If you properly registered your handler and all its dependencies in the container, nothing else has to be done: handler instance you extracted from the container and added among MessageHandlers will have an IPrincipalProvider and (I)UserRepository. Keep in mind BasicAuthMessageHandler will act a singleton, so if you need a new instance of (I)UserRepository on each method call... you may consider TypedFactory to create your (I)UserRepository as late dependencies
Of course, any component starting from you top graph component have to be register in the container.
That's the easy way... in case you need somenthing more sophisticate, you may end up creating your "composition root" for DelegatingHandlers as well.
BTW: never, ever, doing somenthing like
UserRepository userRepo = new UserRepository();
or PrincipalProvider = new DummyPrincipalProvider()
none of the "Behaviour instance" should be created explicitly: container take care of providing right instance at the right time...
As per Jon Edit:
now DummyPrincipalProvider looks fine: just keep in mind since DummyPrincipalProvider is created among the message handler(act as singleton due to global registration), you are reusing always same instance.
Instead of your plumbing
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
I rather use ploeh implementation(see above).
Your registration
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
.UsingFactoryMethod(kernel => kernel.Resolve<DummyPrincipalProvider>())
);
should be replaced with
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
that's wrong... container has to resolve it, not you explicitly
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());
stick with my configuration as above: BasicAuthMessageHandler resolved via container.
Let me know if it works.
PS: You registered the TypedFactory facility in the container, but you are not using it... just to let you know.
You registered DelegatingHandler(s) as Transient, but keep in mind they gonna be "singleton" by design: adding it to the MessageHandlers collection imply they gonna be reused on each request.
As per Jon Edit 2:
I added a sample on github. You should be able to build it and run it using NuGet Package Restore
Your issue about PerWebRequestdepends on the depencies of UserRepository on the NHibernate factory session creating session "PerWebRequest": you cannot resolve IPrincipalProvider->IUserRepository->ISession in Application_Start due to HttpContext. If you really need a IUserRepositry working w/ IPrincipalProvider dependency has to be to a IUserRepositoryFactory(TypedFactory) instead.
I tried to fix your sample using the typed factory and it works, but than I had an issue w/ NHibernate configuration and since I'm not an expert of that, I didn't go any further.
If you need help w/ the factory thing... LMK and I'll update my git sample using a factory within the DummyPrincipalProvider
I am trying to configure some properties of a concrete implementation of a service that has some properties set to different values depending on which profile is selected at startup, but NSB doesn't seem to allow configuration of properties on the implementation of an interface. We are using Castle Windsor for the container, if that's relevant.
We set up the container initially with a service installer that is run from the EndpointConfig class like this:
public class EndpointConfig : IConfigureThisEndpoint,
AsA_Publisher,
IWantCustomInitialization
{
public void Init()
{
Configure.With()
.CastleWindsorBuilder(CreateContainer(new ServiceInstaller()))
.UnicastBus()
.XmlSerializer()
;
}
protected WindsorContainer CreateContainer(IWindsorInstaller installer)
{
var container = new WindsorContainer();
container.Register(Component.For<IWindsorContainer>().Instance(container));
container.Install(installer);
container.Kernel.ReleasePolicy = new Castle.MicroKernel.Releasers.NoTrackingReleasePolicy();
return container;
}
}
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IService>().ImplementedBy<ServiceAdapter>());
// ...
}
}
ServiceAdapter has some string properties that aren't in the interface that need different settings depending on which profile is selected:
public interface IService
{
}
public class ServiceAdapter : IService
{
public string Url;
}
The profile handler does:
Configure.Instance.Configurer.ConfigureProperty<ServiceAdapter>
(x => x.Url, "http://url.goes.here");
but when the profile is loaded, it throws System.InvalidOperationException: Cannot configure property for a type which hadn't been configured yet. Please call 'Configure' first..
Is it possible to do property injection on the concrete implementation without adding the properties into the interface?
I am currently attempting to remove a number of .Resolve(s) in our code. I was moving along fine until I ran into a named registration and I have not been able to get Autofac resolve using the name. What am I missing to get the named registration injected into the constructor.
Registration
builder.RegisterType<CentralDataSessionFactory>().Named<IDataSessionFactory>("central").SingleInstance();
builder.RegisterType<ClientDataSessionFactory>().Named<IDataSessionFactory>("client").SingleInstance();
builder.RegisterType<CentralUnitOfWork>().As<ICentralUnitOfWork>().InstancePerDependency();
builder.RegisterType<ClientUnitOfWork>().As<IClientUnitOfWork>().InstancePerDependency();
Current class
public class CentralUnitOfWork : UnitOfWork, ICentralUnitOfWork
{
protected override ISession CreateSession()
{
return IoCHelper.Resolve<IDataSessionFactory>("central").CreateSession();
}
}
Would Like to Have
public class CentralUnitOfWork : UnitOfWork, ICentralUnitOfWork
{
private readonly IDataSessionFactory _factory;
public CentralUnitOfWork(IDataSessionFactory factory)
{
_factory = factory;
}
protected override ISession CreateSession()
{
return _factory.CreateSession();
}
}
Change the registration to do the resolve manually:
builder.Register(c => new CentralUnitOfWork(c.Resolve<IDataSessionFactory>("central")))
.As<ICentralUnitOfWork>()
.InstancePerDependency();