I am trying to understand the delegate factory pattern with Autofac. I know how to implement factory using IIndex<> with Keyed() registration, which is explained nicely in here: Configuring an Autofac delegate factory that's defined on an abstract class
I would like to know if I can create a factory using Func<>, and how would I do the registrations for the following sample:
public enum Service
{
Foo,
Bar
}
public interface FooService : IService
{
ServiceMethod();
}
public interface BarService : IService
{
ServiceMethod();
}
public class FooBarClient
{
private readonly IService service;
public FooBarClient(Func<Service, IService> service)
{
this.service = service(Service.Foo);
}
public void Process()
{
service.ServiceMethod(); // call the foo service.
}
}
Autofac cannot construct this Func<Service, IService> for you which lets you return different types based on a parameter. This is what IIndex<> is for.
However if you don't want/cannot use IIndex<> you can create this factory function with the help of the Keyed or Named and register your factory in the container:
var builder = new ContainerBuilder();
builder.RegisterType<FooBarClient>().AsSelf();
builder.RegisterType<FooService>().Keyed<IService>(Service.Foo);
builder.RegisterType<BarService>().Keyed<IService>(Service.Bar);
builder.Register<Func<Service, IService>>(c =>
{
var context = c.Resolve<IComponentContext>();
return s => context.ResolveKeyed<IService>(s);
});
Related
I want to implement an annotation which registers classes (not instances of classes) with a factory as soon as the application is started. I am using Spring Framework 4.2.7.
Consider a system with a dashboard and multiple widgets. The dashboard has a configuration file which contains a list of widgets to display for the current user. When displayed it reads the configuration and creates the widgets. The widgets will receive additional parameters from the configuration.
Here is a bit of code illustrating this:
public class TestDashboard implements Dashboard {
public void dashboardPreDisplay() {
List<String> widgets = getWidgetList(/* current user in session */);
for (String widgetId : widgets) {
// create instance of DashboardWidget with given ID
DashboardWidget x = widgetFactory.createWidget(widgetId);
}
}
public List<String> getWidgetList(String user) {
// load list of IDs of DashboardWidgets to be displayed for the user
}
#Autowired
private WidgetFactory widgetFactory;
}
#Service
public class WidgetFactory {
public DashboardWidget createWidget(String widgetId) {
// look up Class<> of DashboardWidget with given id in widgetClasses
// construct and initialize DashboardWidget
}
private HashMap<String, Class<?>> widgetClasses;
}
When implementing my widgets I don't want to deal with registering the widget with the factory class. Ideally I would just annotate the widget like that:
#DashboardWidget(id = "uniqueId")
public class DashboardWidgetA implements DashboardWidget {
// ...
}
When the application starts it should scan the classpath for #DashboardWidget annotations and register the classes with the factory, so that the widgets can be constructed by giving the createWidget-method the id of the widget.
At the moment I am a little bit confused. I think Spring has every tool on board to achieve this behavior. But I cannot think of a way how to do it.
Do you have some advice for me?
Nothing prevents you to create your custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface DashboardWidget {}
Then you can annotate your Widget's classes and make them spring beans. You have to keep in mind if you want to have them as singletons (scope=singleton) , or separate instances per user (scope=prototype).
You have to implement:
public class WidgetInitializationListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
String originalClassName = getOriginalClassName(beanDefinitionName, event);
if (originalClassName != null) {
Class<?> clazz = Class.forName(originalClassName);
if (hasWidgetAnnotation(clazz)) {
registerSomewhereYourWidget(context, beanDefinitionName, originalClassName);
}
}
}
}
private String getOriginalClassName(String name, ContextRefreshedEvent event) {
try {
ConfigurableListableBeanFactory factory =
(ConfigurableListableBeanFactory)event.getApplicationContext().getAutowireCapableBeanFactory();
BeanDefinition beanDefinition = factory.getBeanDefinition(name);
return beanDefinition.getBeanClassName();
} catch (NoSuchBeanDefinitionException e) {
LOG.debug("Can't get bean definition for : " + name);
return null;
}
}
So mostly here is nothing to do with spring except you just run through your beans to find annotated ones.
I am trying to use Ninject to manage my Redis dependencies on a ASP.NET Web Api project.
I do my binding like this:
var clientManager = new PooledRedisClientManager("localhost");
kernel.Bind<IRedisClientsManager>()
.ToMethod(ctx => clientManager)
.InSingletonScope();
kernel.Bind<IRedisClient>()
.ToMethod(k => k.Kernel.Get<IRedisClientsManager>()
.GetClient());
How can I subsequently get access to my redis client in other classes in the project?
I'm not familiar with Redis, so beware...
Now that you've got a binding, you can inject it into a constructor
public class Foo {
public Foo(IRedisClient redisClient) {...}
}
Or you can use a func to access/create it at a specific time:
public class Foo {
private readonly Func<IRedisClient> redisClientFunc;
public Foo(Func<IRedisClient> redisClientFunc)
{
this.redisClientFunc = redisClientFunc;
}
public void DoSomething()
{
IRedisClient client = this.redisClientFunc();
client.SayHello();
}
}
or, equivalently, you can use the ninject factory extension to achieve the same as the func, but with an interface, see https://github.com/ninject/ninject.extensions.factory/wiki. Both Func<> and interface factory need the factory extension.
I'm trying to get the following scenario using autofac but I'm not sure how my code will be built to get this up & running.
I have a repository class, this repository class needs to get a project key (string) on initialization (constructor). I want to instantiate this repository in initialization of my "Initialize" method provided to my by Web Api, because the project key will be available in my route.
so instead of calling "new ProductRepository(projectKey)", I want to use Autofac. Can someone point me in the right direction? I didn't find any way to send in specific data to the container in web api, since the container/builder is only available in the appStart.
Should I make the container available as a singleton so that I can approach it, or is this bad practice?
in your initialization code:
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
in your controller:
public class MyController : ApiController
{
public MyController(IComponentContext container)
{
var key = new NamedParameter("projectKey", "keyFromRoute");
var repository = container.Resolve<ProductRepository>(key);
}
}
That should do it.
There is a nuget package that provides a DependencyResolver for WebApi that integrates with AutoFac. Create the DependencyResolver, assign it to the config, register your controllers in the autofac container.
I'm making some assumptions because you didn't provide your code, but I think you have something like this:
public class ProductRepository
{
public ProductRepository(DbContext dbContext, int projectKey)
{
}
}
public class SomeController : Controller
{
private readonly Func<int, ProductRepository> _repoFactory;
public SomeController(Func<int, ProductRepository> repoFactory)
{
_repoFactory = repoFactory;
}
public void DoStuff(int projectKey)
{
var repo = _repoFactory(projectKey);
repo.DoStuff();
}
}
public class RepositoryModule : Module
{
public override Load(ContainerBuilder builder)
{
builder.RegisterType<ProductRepository>();
}
}
I'm trying to setup a base Repository class that can use the Entity Framework edmx model context. The problem I'm having is that I need to find an interface that the EF EDMX object context implements so I can pass to the constructor via dependency injections. I've got around this before by using a DataFactory that creates it and stores it in the HttpContext but that kills the ability to unit test. Any help would be appreciated. Thanks!
public abstract class BaseRepository<T> where T : EntityObject
{
private MyDataModelContext _dataContext;
private ObjectSet<T> dbset;
protected BaseRepository(IObjectContext dataContext)
{
_dataContext = dataContext;
dbset = _dataContext.CreateObjectSet<T>();
}
.....
I've always created a DataContextFactory that passes my own interface to the Context, and passed that to my repositories like so:
The context interface:
public IMyDataContext {
// One per table in the database
IDbSet<Class1> Class1s { get;set; }
// etc
// The standard methods from EF you'll use
void Add( object Entity );
void Attach( object Entity );
void Delete( object Entity );
void SaveChanges();
}
The context factory:
public class MyDataContextFactory : IMyDataContextFactory {
public IMyDataContext GetContext() {
// TODO: Use the service locator pattern to avoid the direct instanciation
return new MyDataContext();
}
}
The context factory interface:
public interface IMyDataContextFactory {
IMyDataContext GetContext();
}
The repository:
public class MyClass1Repository {
private readonly IMyDataContextFactory factory;
public MyClass1Repository( IMyDataContextFactory Factory ) {
// TODO: check for null
this.factory = Factory;
}
public List<MyClass1> GetAll() {
using ( IMyDataContext db = this.factory.GetContext() ) {
return db.Class1s.ToList();
}
}
// TODO: Other methods that get stuff
}
Then when I want to test the repository, I pass in a fake IMyDataContextFactory that returns a fake IMyDataContext from GetContext().
In time I notice duplication in repositories, and can push certain methods into the base repository: GetAll(), Save(), GetById() sometimes if I have consistent primary keys, etc.
I have a class, RepositoryManager, and I am using this class in some of my controllers:
public RepositoryManager
{
public IGenericRepository Repository {get; set;}
public RepositoryManager()
{
Repository = new GenericRepository(new MyEntities());
}
//...
}
I want to move IGenericRepository to a StructureMap Inversion of control (IoC) container
x.For<IGenericRepository>().Use<GenericRepository>().Ctor<MyEntities>("MyEntities");
Then I change my class constructor to that:
public RepositoryManager(IGenericRepository repository)
{
Repository = repository;
}
But the injection didn't work. I also tried to use the [SetterProperty] attribute on Repository, but still Repository didn't instantiate.
What did I do wrong?
My complete IoC initialization:
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.For<IRepositoryManager>().Use<RepositoryManager>();
x.For<IGenericRepository>().Use<GenericRepository>().Ctor<MyEntities>("MyEntities");
});
return ObjectFactory.Container;
}
}
Basically your IoC initialisation is wrong for IGenericRepository. Change it to:
x.For<IGenericRepository>().Use(() => new GenericRepository(new MyEntities()));
In such a case, the constructor with parameter MyEntities will be called and an instance of MyEntities will be created and passed to that constructor as a parameter.
You do not need to register the concrete types; they will just be resolved by StructureMap. The scanner is already used with default conventions, so for the above example the following registration code is fully sufficient:
ObjectFactory.Initialize(x => x.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
}));