Current Code
public class SystemUserController : ApiController
{
ISystemUserDataAccess dataAccess;
public SystemUserController(ISystemUserDataAccess userDataAccess)
{
dataAccess = userDataAccess;
}
//Other api methods
}
And ISystemUserDataAccess is the interface which contains all the data access methods. I have following installer code, which is being called by the Global.asax
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(typeof(IConnectDB)).ImplementedBy(typeof(ConnectDB)),
Component.For(typeof(ISystemUserDataAccess)).ImplementedBy(typeof(SystemUserDataAccess));
}
}
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container,
Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
Container Initialization at Global.asax
container = new WindsorContainer();
container.Install(FromAssembly.This());
It is all working fine. userDataAccess get injected properly and i can call all the DataAccess method without any problem.
My Data Access class looks like below.
public class SystemUserDataAccess : ISystemUserDataAccess
{
IConnectDB connectionManager;
public SystemUserDataAccess(IConnectDB connection)
{
connectionManager = connection;
}
//Data access methods
}
Actual Problem
Now I need an instance of SystemUserDataAccess within a non ApiController class (this is a static class). When I tried below code, but it is giving an exception, saying it couldnt find any component registered.
IWindsorContainer container = new WindsorContainer();
var asas = container.Resolve<ISystemUserDataAccess>();
When I inspect the container object, "All component" property is 0. Which is why it is throwing the error. What am I doing wrong here? Do i need another installer for that non ApiController class?
Instead of doing container.Install(FromAssembly.This()); in global.asax, use container.install(new RepositoriesInstaller());
Related
I have a TypeFilterAtrribute which instantiates and ActionFilter. The ActionFilter needs two services injected.
public class ValidateUserAttribute : TypeFilterAttribute
{
public ValidateUserAttribute() : base(typeof(AuthenticationFilter))
{
}
private class AuthenticationFilter : ActionFilterAttribute
{
private readonly IActiveDirectoryService ActiveDirectoryService;
private readonly MessageService MessageSerivce;
public AuthenticationFilter(IActiveDirectoryService activeDirectoryService, MessageService messageSerivce)
{
ActiveDirectoryService = activeDirectoryService;
MessageSerivce = messageSerivce;
}
I have it working with the default IOC container of dot net core 2 but I could not use Funq container to do it.
I am reading from appsettings.json (I think I read on the docs ServiceStack does not support this) and registering
var config = Configuration.GetSection("LdapAuth");
services.Configure<LdapAuthenticationOptions>(Configuration.GetSection("LdapAuth"));
services.AddActiveDirectoryService(options =>
Configuration.GetSection("LdapAuth"));//uses collection.AddTransient<IActiveDirectoryService, ActiveDirectoryService>()
services.AddMessageService(); //same as above
I can't think of a way to inject into the filter a parameterized service.
So this does not work at all because I don't have a default constructor.
public class AuthenticationFilter : ActionFilterAttribute
{
public IActiveDirectoryService ActiveDirectoryService {get; set;};
But this below at least should have worked. I'm not using an interface here though.
public class AuthenticationFilter : ActionFilterAttribute
{
public MessageService MessageService{get; set}; //notice not using interface here although this as default constructor.
Where this gets really ugly is then I have controllers that inherit ServiceStackController and I inject services using ResolveService from the Funq container.
public class MessageController : ServiceStackController
{
...
var messageService = ResolveService<MessageService>()
I re-register them.. like below.
public override void Configure(Funq.Container container)
{
SqlServerDialect.Provider.RegisterConverter<TimeSpan>(new ServiceStack.OrmLite.SqlServer.Converters.SqlServerTimeConverter
{
Precision = 7
});
var connectionString = GetConnectionString(AppSettings);
container.Register<IDbConnectionFactory>(
new OrmLiteConnectionFactory(connectionString, new SqlServerOrmLiteDialectProvider()));
LdapAuthenticationOptions options = GetLdapAuthenticationOptions(AppSettings); //notice now I have to read from AppSetting.. which is appsettings.txt file.
container.Register(c => new ActiveDirectoryService(options));
container.Register(c => new MessageService());
}
I would like to know where can I find samples the explains the differences among services.AddInstance, services.AddScoped, services.AddSingleton and service.AddTransient.
I found some articles that explain the point in a generic way, but I think a source sample is much more clear.
The scope of this questions is rather large, but since it seems you are specifically looking for AddScoped information I narrowed the sample down to scoping inside a web application.
Inside a web application AddScoped will mean pretty much the scope of the request. EntityFramework is using scoping internally, but it doesn't affect the user code in most cases so I'm sticking with the user code as shown below.
If you register a DbContext as a service, and also register a scoped service, for each request you will get a single instance of the scoped service where you resolve the DbContext.
The example code below should make it clearer. In general I would recommend just trying it out the way I'm showing it below to familiarize yourself with the behavior, by stepping through the code in the debugger. Start from an empty web application. Note the code I'm showing is from Beta2 (since in Beta2 we added the [FromServices] attribute which makes it easier to demonstrate, the underlying behavior is the same regardless of version.
startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<UserDbContext>();
services.AddScoped<UserService>();
// Add MVC services to the services container.
services.AddMvc();
}
UserDbContext.cs
public class UserDbContext : DbContext
{
public UserService UserService { get; }
public UserDbContext(UserService userService)
{
_userService = userService;
}
}
HomeController.cs
public class HomeController : Controller
{
private UserDbContext _dbContext;
public HomeController(UserDbContext dbContext)
{
_dbContext = dbContext;
}
public string Index([FromServices]UserDbContext dbContext, [FromServices]UserService userService)
{
// [FromServices] is available start with Beta2, and will resolve the service from DI
// dbContext == _ctrContext
// and of course dbContext.UserService == _ctrContext.UserService;
if (dbContext != _dbContext) throw new InvalidOperationException();
if (dbContext.UserService != _dbContext.UserService) throw new InvalidOperationException();
if (dbContext.UserService != userService) throw new InvalidOperationException();
return "Match";
}
}
Alternatively if you resolve the user service from another service, this time registered as transient the transient service will have a new instance everytime it is resolved, but the scoped service will remain the same within the scope of the request.
Create the new service
public class AnotherUserService
{
public UserService UserService { get; }
public AnotherUserService(UserService userService)
{
UserService = userService;
}
}
Add the following lines to startup.cs
services.AddTransient<AnotherUserService>();
And rewrite the HomeController.cs as follows
public class HomeController : Controller
{
private AnotherUserService _anotherUserService;
public HomeController(AnotherUserService anotherUserService)
{
_anotherUserService = anotherUserService;
}
public string Index([FromServices]AnotherUserService anotherUserService,
[FromServices]UserService userService)
{
// Since another user service is tranient we expect a new instance
if (anotherUserService == _anotherUserService)
throw new InvalidOperationException();
// but the scoped service should remain the same instance
if (anotherUserService.UserService != _anotherUserService.UserService)
throw new InvalidOperationException();
if (anotherUserService.UserService != userService)
throw new InvalidOperationException();
return "Match";
}
}
Hi I am trying to change a code example found here
http://imar.spaanjaars.com/577/aspnet-n-layered-applications-implementing-a-repository-using-ef-code-first-part-5
In his example he uses structure map, when I converted it to windsor I can get it to work with the one repository using the following.
container.Register(Component.For<IUnitOfWorkFactory>().ImplementedBy<EFUnitOfWorkFactory>(),
Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>(),
Component.For<Model.Repositories.IPeopleRepository>().ImplementedBy<PeopleRepository>().LifestyleTransient());
But what I really want to do is to map all the irepository based interfacees to thier implementation.
Here is the IRepository, T is the entity, K is the prmiary key type
public interface IRepository<T, K> where T : class
{
}
Its implementation Is
public abstract class Repository<T> : IRepository<T, int>, IDisposable where T : DomainEntity<int>
{
}
My controller has the interface IPeopleRepository as a constructor paramerter.
public interface IPeopleRepository : IRepository<Person, int>
{
}
public class PeopleRepository : Repository<Person>, IPeopleRepository
{
}
I want to have one register to register all repositories, something like this, but it wont match and i get the error Service 'Spaanjaars.ContactManager45.Model.Repositories.IPeopleRepository' which was not registered
container.Register(Component.For(typeof(IRepository<,>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
What am i missing in regards to this? is it because my irepository has 2 generic types?
In order to map all the IRepository based interfaces to their implementations .WithService.AllInterfaces() should be used.
This registration should solve your issue.
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerWebRequest());
There are some tests to test it. I claim they are green.
[TestClass]
public class InstallerTest
{
private IWindsorContainer container;
[TestInitialize]
public void Init()
{
container = new WindsorContainer().Install(new Installer());
}
[TestMethod]
public void ResilveTest_ResolvesViaIRepository()
{
// act
var repository = container.Resolve<IRepository<Person, int>>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
[TestMethod]
public void ResilveTest_ResolvesViaIPeopleRepository()
{
// act
var repository = container.Resolve<IPeopleRepository>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
}
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerThread());
}
}
I am using StructureMap as DI with MVC 4. I am pushing certain objects in the constructor via StructureMap.
Following I have in the the bootstraper
public static void ConfigureDependencies()
{
ObjectFactory.Initialize(IE =>
{
IE.UseDefaultStructureMapConfigFile = true;
});
}
Controller Factory is as following
public class ControllerMyFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return ObjectFactory.GetInstance(controllerType) as IController;
}
}
Then I am plugging this in Global.asax
BootStrapper.ConfigureDependencies();
ControllerBuilder.Current.SetControllerFactory(new ControllerMyFactory());
Following is one of my Controller
public class SomeController : Controller
{
ISomeService service;
public SomeController(ISomeService service)
{
this.service = service;
}
}
Now my problem is object Instantiation, which are being passed in the constructor.
I used to construct this object like Following
ISomeService service = CommonGateway.GetChannnel<ISomeService>();
How do I plugin this with StructureMap? How do I change the way StructureMap will instantiate the objects?
Please let me know if I am not very clear?
Thanks,
A
You just need to configure StructureMap to know about your ISomeService and how to instantiate it like this:
ObjectFactory.Initialize(IE =>
{
IE.For<ISomeService>().Use(() => CommonGateway.GetChannel<ISomeService>() as ISomeService);
});
This will then call your factory method when instantiating your controller, because your controller is already being created by StructureMap.
Here is the set up that is not working
Using Ninject V3.0
public class LoggerModule : NinjectModule{
public override void Load()
{
Bind<ILogger>.ToProvider(MyLoggerProvider);
}
}
public class MyLoggerProvider: IProvider<ILogger>
{
public object Create(IContext context){
return new OneOfMyLoggers();
}
}
In my application wherever I inject instance of ILogger (using constructor or property injection, just does matter) I never get instance of ILogger resolved.
But If do not use module and/or povider, and bind when kernel is created, everything works like a charm. The following works
public class MyDiResolver()
{
public MyDiResolver()
{
MyKernel = new StandardKernel();
MyKernel.Bind<ILogger>().To<OneOfMyLoggers>();
}
}
The same arrangement of modules and providers works fine in Ninject2.x version. Is there something different about Ninject V3.0 that I am missing?
Thanks
Try passing the module into the StandardKernel so it knows to use it:
using (IKernel kernel = new StandardKernel(new LoggerModule()))
{
ILogger logger = kernel.Get<OneOfMyLoggers>();
}