Injecting a Factory that accepts a Parameter with AutoFac - autofac

I've read over several examples that were more complex then I needed and I'm having trouble distilling this down to a simple, concise pattern.
Let's say I have an interface names ICustomService and multiple implementations of ICustomService. I also have a class Consumer that needs to determine at run time which ICustomService to use based upon a parameter.
So I create a classes as follows:
public class Consumer
{
private CustomServiceFactory customServiceFactory;
public Consumer(CustomServiceFactory _customServiceFactory)
{
customServiceFactory = _customServiceFactory;
}
public void Execute(string parameter)
{
ICustomService Service = customServiceFactory.GetService(parameter);
Service.DoSomething();
}
}
public class CustomServiceFactory
{
private IComponentContext context;
public CustomServiceFactory(IComponentContext _context)
{
context = _context;
}
public ICustomService GetService(string p)
{
return context.Resolve<ICustomService>(p); // not correct
}
}
public class ServiceA : ICustomService
{
public void DoSomething()
{
}
}
public class ServiceB : ICustomService
{
public void DoSomething()
{
}
}
Is there an advantage to having my factory implement an interface? How do I fix my factory and register these classes with Autofac so that Consumer.Execute("A") calls DoSomething on WorkerA and Consumer.Execute("B") calls DoSomething on WorkerB?
Thank you

You would register your implementations of ICustomService with keys. For example:
builder.RegisterType<FooService>.Keyed<ICustomService>("someKey");
builder.RegisterType<BarService>.Keyed<ICustomService>("anotherKey");
and then your factory method would be:
public ICustomService GetService(string p)
{
return context.ResolveKeyed<ICustomService>(p);
}
But, you can take this a step further and decouple CustomServiceFactory from IComponentContext:
public class CustomServiceFactory
{
private Func<string, ICustomService> _create;
public CustomServiceFactory(Func<string, ICustomService> create)
{
_create = create;
}
public ICustomService GetService(string p)
{
return _create(p);
}
}
which you would register like so:
builder.Register(c => {
var ctx = c.Resolve<IComponentContext>();
return new CustomServiceFactory(key => ctx.ResolveKeyed<ICustomService>(key));
});
And at that point, assuming CustomServiceFactory doesn't have any other behavior that was omitted for the question, then you as might as well just use and register Func<string, ICustomService> directly.

Related

Autofac: registering hierarchy of classes

I am struggling to register with Autofac a hierarchy of classes and interfaces.
I have an interface IMyService defined as below:
public interface IMyService
{
void DoMyService();
}
And I have two abstract classes with implement this interface and called MyServiceA, and MyServiceB:
public abstract class MyServiceA : IMyService
{
public abstract DoMyService();
}
public abstract class MyServiceB : IMyService
{
public abstract DoMyService();
}
Moreover I have a second-level hierarchy for each of the two aforementioned services: MyServiceA1, MyServiceA2, MyServiceB1 and MyServiceB2:
public class MyServiceA1 : MyServiceA
{
public MyServiceA1() : base() {}
public void DoMyService()
{
// Implementation goes here
}
}
public class MyServiceA2 : MyServiceA
{
public MyServiceA2() : base() {}
public void DoMyService()
{
// Implementation goes here
}
}
public class MyServiceB1 : MyServiceB
{
public MyServiceB1() : base() {}
public void DoMyService()
{
// Implementation goes here
}
}
public class MyServiceB2 : MyServiceB
{
public MyServiceB2() : base() {}
public void DoMyService()
{
// Implementation goes here
}
}
I have in input two enums FirstEnum and SecondEnum used to select which of the four concrete types to instantiate:
public enum FirstEnum
{
SvcA,
SvcB
}
public enum SecondEnum
{
Svc1,
Svc2
}
I want to register IMyService and by providing two enums, It will automatically instantiate the good concrete type.
For instance, if I want to resolve an IMyService and I provide FirstEnum.SvcB and SecondEnum.Svc2, it should instantiate the concrete type MyServiceB2 class. Moreover this hierarchy might be updated by adding some other concrete types etc, so I need a generic way of doing it
Does anyone have a clue to help me?
Thanks
If you want to create a specific service dynamically depending on a set of parameters, this is a good use case for an abstract factory:
public interface IMyServiceFactory
{
IMyService Create(FirstEnum e1, SecondEnum e2);
}
public class MyServiceFactory : IMyServiceFactory
{
private readonly ILifetimeScope scope;
public MyServiceFactory(ILifetimeScope scope)
{
if (scope == null)
throw new ArgumentNullException("scope");
this.scope = scope;
}
public IMyService Create(FirstEnum e1, SecondEnum e2)
{
if (e1 == FirstEnum.SvcA)
{
if (e2 == SecondEnum.Svc1)
{
return scope.Resolve<MyServiceA1>();
}
else //svc2
{
return scope.Resolve<MyServiceA2>();
}
}
else //B
{
if (e2 == SecondEnum.Svc1)
{
return scope.Resolve<MyServiceB1>();
}
else //svc2
{
return scope.Resolve<MyServiceB2>();
}
}
}
}
And now your consumer need to get the factory injected instead of the service:
public class MyServiceConsumer
{
private readonly IMyServiceFactory factory;
public MyServiceConsumer(IMyServiceFactory factory)
{
this.factory = factory;
}
public void Do()
{
//var service = this.factory.Create
}
}
Registration :
Autofac.ContainerBuilder builder = new Autofac.ContainerBuilder();
builder.RegisterType<MyServiceA1>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<MyServiceA2>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<MyServiceB1>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<MyServiceB2>().AsSelf().AsImplementedInterfaces();
builder.RegisterType<MyServiceFactory>().As<IMyServiceFactory>();
builder.RegisterType<MyServiceConsumer>();
//and quick test resolve
var container = builder.Build();
var test = container.Resolve<MyServiceConsumer>();

How to change base url endpoint for errai jaxrs proxy?

I' need to call different endpoint located on different server, i try to change value of base url of my rest services.
but i found only this method
RestClient.create(MyService.class, otherServiceBaseUrl,
myCallback,
200).doStaf() ;
Any suggestion to more elegant way for setup the base url for all services in my MyService class ?
I found this solution.
I create a abstract class DinamicCaller.
public abstract class DinamicCaller<T> {
public T call() {
T call = getCaller().call();
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
public T call(RemoteCallback<?> callback) {
T call = getCaller().call(callback);
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
public T call(RemoteCallback<?> callback, ErrorCallback<?> errorCallback) {
T call = getCaller().call(callback, errorCallback);
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
protected abstract Caller<T> getCaller();
protected abstract String getBaseUrl();
}
I create a Concrete Class
public class CallerCORSNegoziService extends DinamicCaller<CORSNegoziService> {
#Inject
NegozioManager negozioManager;
#Inject
Caller<CORSNegoziService> caller;
#Override
protected Caller<CORSNegoziService> getCaller() {
return caller;
}
#Override
protected String getBaseUrl() {
return negozioManager.getNegozio().getUrl();
}
}
On my class I inject the concrete class
#Inject
CallerCORSNegoziService service;
And I use it
#UiHandler("testButton")
public void testButtonClick(ClickEvent event) {
service.call(testCallback, testCallback).findAllNegozi();
}
Is ugly but work.

Unreachable security context using Feign RequestInterceptor

The goal is to attach some data from security context using RequestInterceptor, but the problem, that the calling SecurityContextHolder.getContext().getAuthentication() always returns null even though it is not null (I am sure 100%).
As I understand that's because the Interceptor is created and is being run in other thread.
How could I solve this problem and get actual data from security context?
My service:
#FeignClient(value = "api", configuration = { FeignConfig.class })
public interface DocumentService {
#RequestMapping(value = "/list", method = RequestMethod.GET)
DocumentListOperation list();
}
My FeignConfig class:
#Bean
public RequestInterceptor requestInterceptor() {
return new HeaderInterceptor(userService);
}
public class HeaderInterceptor implements RequestInterceptor {
private UserService userService;
public HeaderInterceptor(UserService userService) {
this.userService = userService;
}
#Override
public void apply(RequestTemplate requestTemplate) {
Authentication a = SecurityContextHolder.getContext().getAuthentication()
requestTemplate.header("authentication", a.toString());
}
}
I managed to figure it out, thanks to the article I found here
Firstly you need to initiliaze HystrixRequestContext HystrixRequestContext.initializeContext();.
You have to create your own Context in which you will store information you need to pass to Hystrix child threads.
Here is example:
public class UserHystrixRequestContext {
private static final HystrixRequestVariableDefault<User> userContextVariable = new HystrixRequestVariableDefault<>();
private UserHystrixRequestContext() {}
public static HystrixRequestVariableDefault<User> getInstance() {
return userContextVariable;
}
}
You have to register new concurrency strategy that would wrap Callable interface
#Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
public CustomHystrixConcurrencyStrategy() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}
#Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
return new HystrixContextWrapper<T>(callable);
}
public static class HystrixContextWrapper<V> implements Callable<V> {
private HystrixRequestContext hystrixRequestContext;
private Callable<V> delegate;
public HystrixContextWrapper(Callable<V> delegate) {
this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
this.delegate = delegate;
}
#Override
public V call() throws Exception {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
return this.delegate.call();
} finally {
HystrixRequestContext.setContextOnCurrentThread(existingState);
}
}
}
}
So before calling Callable object we set new thread's Context to parent's context.
After that is done you should be able to access your new defined context inside Hystrix child threads
User = UserHystrixRequestContext.getInstance().get();
Hope that will help someone.

MvvmCross: IoC with Decorator pattern, two implementations of the same interface

I'd like to implement the Decorator pattern in one of my Mvx projects. That is, I'd like to have two implementations of the same interface: one implementation that is available to all of the calling code, and another implementation that is injected into the first implementation.
public interface IExample
{
void DoStuff();
}
public class DecoratorImplementation : IExample
{
private IExample _innerExample;
public Implementation1(IExample innerExample)
{
_innerExample = innerExample;
}
public void DoStuff()
{
// Do other stuff...
_innerExample.DoStuff();
}
}
public class RegularImplementation : IExample
{
public void DoStuff()
{
// Do some stuff...
}
}
Is it possible to wire up the MvvmCross IoC container to register IExample with a DecoratorImplementation containing a RegularImplementation?
It depends.
If DecoratorImplementation is a Singleton, then you could do something like:
Mvx.RegisterSingleton<IExample>(new DecoratorImplementation(new RegularImplementation()));
Then calls to Mvx.Resolve<IExample>() will return the instance of DecoratorImplementation.
However, if you need a new instance, unfortunately the MvvmCross IoC Container doesn't support that. It would be nice if you could do something like:
Mvx.RegisterType<IExample>(() => new DecoratorImplementation(new RegularImplementation()));
Where you'd pass in a lambda expression to create a new instance, similar to StructureMap's ConstructedBy.
Anyway, you may need to create a Factory class to return an instance.
public interface IExampleFactory
{
IExample CreateExample();
}
public class ExampleFactory : IExampleFactory
{
public IExample CreateExample()
{
return new DecoratorImplementation(new RegularImplementation());
}
}
Mvx.RegisterSingleton<IExampleFactory>(new ExampleFactory());
public class SomeClass
{
private IExample _example;
public SomeClass(IExampleFactory factory)
{
_example = factory.CreateExample();
}
}

creating NHibernate repositories in view models with IoC

I would like to how to correct build and handle with NHibernate repository and session in view models classes.
For example I use Caliburn Micro framework with Castle Windsor boostraper.
First I created NHibernate repository:
public interface IRepository{//I omitted not needed code for simplification}
public class NHibRepository: IRepository
{
private ISession _session;
public NHibRepository(ISession session)
{
_session=session;
}
// I omitted not needed code for simplification
}
Second I definied some POCO class and mapping class with Fluent NHibernate.
public class User{}
public class Profile{}
public class Album{}
public class UserMap : ClassMap<User>{}
public class ProfileMap : ClassMap<Profile>{}
public class AlbumMap : ClassMap<Album>{}
Now I need use NHibernate repositories in my view models.
public interface IViewModelA{}
public class ViewModelA : ScreenViewModel, IViewModelA
{
public NHibRepository<User> UserRepo{get;set;}
public NHibRepository<Profile> ProfileRepo{get;set;}
}
public interface IViewModelB{}
public class ViewModelB : Screen, IViewModelB
{
public NHibRepository<Profile> ProfileRepo{get;set;}
public NHibRepoistory<Album> AlbumRepo{get;set;}
}
When I am creating repository class for some entity class I need pass session to NHibRepository construtor.
UserRepo= new NHibRepository<User>(NHIBERNATE SESSION);
Until now I used some helper class for creating Nhibernate session and init repository.
Helper class is here:
public class FluentNHibHelper
{
private ISessionFactory _sessionFactory;
public FluentNHibHelper(IPersistenceConfigurer db, Assembly asm)
{
InitializeSessionFactory(db, asm);
}
private void InitializeSessionFactory(IPersistenceConfigurer db, Assembly asm)
{
_sessionFactory = Fluently.Configure()
.Database(db)
.Mappings(m => m.FluentMappings.AddFromAssembly(asm))
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true))
.BuildSessionFactory();
}
public ISession OpenSession()
{
return _sessionFactory.OpenSession();
}
}
with this class I created repository class:
private const string ConnString =
#"Server=TestMachine\SQLEXPRESS;Database=TEST;Trusted_Connection=True;";
UserRepo = new NHibRepository<User>(
new FluentNHibHelper(MsSqlConfiguration.MsSql2008.ConnectionString(ConnString),
Assembly.GetExecutingAssembly())
.OpenSession());
Now I am confuse I don’t what is the best way for creating repository object in view models.
For example in bootstraper class can I somehow register repository class ?
public class CastleBootstrapper : Bootstrapper<IShellViewModel>
{
private IWindsorContainer _windsorContainer;
protected override void Configure()
{
_windsorContainer = new WindsorContainer();
//register repository class here ???
}
}
Can anybody help me? Thank you very much
Sorry for my english.
I use the following in an ASP.net MVC application. Castle.Windsor takes care of creating the ISession dependency for each repository.
//Located in your application startup
protected IWindsorContainer CreateContainer()
{
container = new WindsorContainer();
container.Install(
new PersistenceInstaller(),
new RepositoryInstaller()
//, other installers here
);
return container;
}
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<PersistenceFacility>();
}
}
public class PersistenceFacility : AbstractFacility
{
protected override void Init()
{
NHibernate.Cfg.Configuration config = BuildDatabaseConfiguration();
Kernel.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod(config.BuildSessionFactory),
Component.For<ISession>()
.UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
.LifeStyle.Trasient
);
}
private NHibernate.Cfg.Configuration BuildDatabaseConfiguration()
{
return Fluently.Configure()
.Database(SetupDatabase)
.Mappings(m => m.HbmMappings.AddFromAssemblyOf<Entity>())
.ExposeConfiguration(ConfigurePersistence)
.BuildConfiguration();
}
protected virtual IPersistenceConfigurer SetupDatabase()
{
return MsSqlConfiguration.MsSql2008
.UseOuterJoin()
.ConnectionString(x => x.FromConnectionStringWithKey("ApplicationServices"))
.ShowSql();
}
protected virtual void ConfigurePersistence(NHibernate.Cfg.Configuration config)
{
SchemaMetadataUpdater.QuoteTableAndColumns(config);
}
protected virtual bool IsDomainEntity(Type t)
{
return typeof(DomainBase).IsAssignableFrom(t);
}
}
public class RepositoryInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Find().Configure(ConfigureLifeStyle()));
}
private ConfigureDelegate ConfigureLifeStyle()
{
return c => c.LifeStyle.Transient;
}
private BasedOnDescriptor Find()
{
return AllTypes.FromAssemblyContaining<NHRepository>()
.Where(type => type.Name.EndsWith("Repository"))
.WithService
.AllInterfaces();
}
}