Autofac Binding at Runtime - c#

I currently use Autofac to do simple constructor injection without any issues. However what I would like to know is how to resolve dependencies at runtime. The example below shows multiple ways in which we can export a document. With simple constructor injection the concrete implementation of IExport is resolved at runtime. However what need to do is to resolve IExport on a user selection from a dropdown list which will happen after the construction of my container. Is there any examples of how I can achieve this?
Public interface IExport
{
void Run(string content);
}
public class PDFformat : IExport
{
public void Run(string content)
{
// export in pdf format
}
}
public class HTMLformat : IExport
{
public void Run(string content)
{
// export in html format
}
}
public class RTFformat : IExport
{
public void Run(string content)
{
// export in rtf format
}
}
public class HomeController : Controller
{
IExport Export;
public HomeController(IExport export)
{
Export = export;
}
public void ExportDocument(string content)
{
Export.Run(content);
}
}
Any help on this would be much appreciated.

You should use a factory:
public interface IExportFactory
{
IExport CreateNewExport(string type);
}
Implementation:
class ExportFactory : IExportFactory
{
private readonly IComponentContext container;
public ExportFactory(IComponentContext container)
{
this.container = container;
}
public IExport CreateNewExport(string type)
{
switch (type)
{
case: "html":
return this.container.Resolve<HTMLformat>();
// etc
}
}
}
Registration:
builder.Register<IExportFactory>(
c=> new ExportFactory(c.Resolve<IComponentContext>()))));
builder.RegisterType<HTMLformat>();
builder.RegisterType<PDFformat>();
Controller:
public class HomeController : Controller
{
IExportFactory factory;
public HomeController(IExportFactory factory)
{
this.factory = factory;
}
public void ExportDocument(string content)
{
this.factory.CreateNew("html").Run(content);
}
}

Related

Dependency Injection in Xamarin.Android

I am working on a Xamarin.Android project developed by another developer. I got to know that they have used Dependancy Injection. There is a class like this
public class RemoteSupportHandler : DataAccessor<FwDataContext>, IRemoteSupportSettingHandler
{
private RemoteSupportSetting[] _cached;
public RemoteSupportHandler(IDatabaseController db, ILogger logger, IPerfLogger perfLogger)
: base(db, logger, perfLogger)
{
}
public async Task<RemoteSupportSetting> GetRemoteSupportDemoVideoUrlAsync()
{
return await WithDataContextAsync(ctx =>
{
return (from row in ctx.RemoteSupportSettings
where row.ParamName == "DEMO_VIDEO"
select new RemoteSupportSetting
{
ParamName = row.ParamName
}).FirstOrDefault();
});
}
}
In another file, they have registered this class with UnityContainer. Now I want to call this GetRemoteSupportDemoVideoUrlAsync() method from my Activity. I know I cannot create an object using this constructor. I have no idea how I should I do this.
Registration Code
public class Registrar : IRegistrar {
protected virtual void OnApplyInitializedRegistrations(IUnityContainer container) {
container.RegisterType<IRemoteSupportSettingHandler, RemoteSupportHandler>(new ContainerControlledLifetimeManager());
}
}
public interface IRegistrar
{
void ApplySessionRegistrations(IUnityContainer container);
void ApplyInitializedRegistrations(IUnityContainer container);
}
UPDATE 2
public abstract class MyApplication : Application, IPlatformApplication {
public IUnityContainer AppUnityContainer => _container;
protected virtual void OnLaunched()
{
IActivityService activityService = new ActivityService(this);
AppUnityContainer.RegisterInstance(activityService);
AppUnityContainer.RegisterType<IRegistrar, PlatformRegistrar>();
}
}

Inject Dependency into Core Module of a ASP Boilerplate project

I have NotificationJob class where I have all the functions related to Notification Feature for my .Net Core application. It has some injected dependencies from Domain services. I am having a problem trying to inject INotificationJob interface of the class into the CoreModule of the project.
I initially tried injecting the interface directly into the CoreModule but failed so I created another module in the same file called NotificationModule where I inject INotificationJob interface. Then I try to link it with the CoreModule using [DependsOn(typeof(oasisCoreModule))] annotation.
Core Module of the project
[DependsOn(
typeof(AbpZeroCoreModule),
typeof(AbpHangfireAspNetCoreModule),
typeof(AbpWebCommonModule)
)]
public class oasisCoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
Configuration.BackgroundJobs.UseHangfire();
Configuration.Auditing.IsEnabledForAnonymousUsers = true;
// Declare entity types
Configuration.Modules.Zero().EntityTypes.Tenant = typeof(Tenant);
Configuration.Modules.Zero().EntityTypes.Role = typeof(Role);
Configuration.Modules.Zero().EntityTypes.User = typeof(User);
oasisLocalizationConfigurer.Configure(Configuration.Localization);
// Enable this line to create a multi-tenant application.
Configuration.MultiTenancy.IsEnabled = oasisConsts.MultiTenancyEnabled;
// Configure roles
AppRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
Configuration.Settings.Providers.Add<AppSettingProvider>();
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(oasisCoreModule).GetAssembly());
}
public override void PostInitialize()
{
IocManager.Resolve<AppTimes>().StartupTime = Clock.Now;
}
}
// This is the custom module that I created in the same file as the core module.
[DependsOn(typeof(oasisCoreModule))]
public class NotificationModule : AbpModule
{
INotificationJob _job;
public NotificationModule(INotificationJob job)
{
_job = job;
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
public override void PostInitialize()
{
_job.Loop();
}
}
INotificationJob Interface I am Injecting into the NotificationModule
public interface INotificationJob: IDomainService
{
void Loop();
void CheckTickets();
void CheckReminders(string email, string ticket);
}
Class Implementation of INotificationJob Interface
public class NotificationJob: DomainService, INotificationJob
{
private readonly ITicketRefManager _ticketRefManager;
private readonly IClientManager _clientManager;
private readonly IEmailManager _emailManager;
public NotificationJob(
ITicketRefManager ticketRefManager,
IClientManager clientManager,
IEmailManager emailManager,
)
{
_ticketRefManager = ticketRefManager;
_clientManager = clientManager;
_emailManager = emailManager;
}
public void Loop()
{
RecurringJob.AddOrUpdate(() => CheckTickets(), Cron.Minutely);
}
}
When I run the solution, I am presented with an error saying as shown:
Are there any other steps that I need to take to complete the Dependency Injection process? Or are the steps that I described flawed?
I'm not sure what you're trying to do with you "interface injecting", but you can try this if I understand correctly what you're trying to do :
Core Module
[...]
public override void PostInitialize()
{
var recurrentJobs = IocManager.Resolve<NotificationJob>();
RecurringJob.RemoveIfExists("JobName");
RecurringJob.AddOrUpdate("JobName", () => recurrentJobs.CheckTickets(), Cron.Minutely);
}
Your class
public class NotificationJob : ISingletonDependency
{
private readonly ITicketRefManager _ticketRefManager;
private readonly IClientManager _clientManager;
private readonly IEmailManager _emailManager;
public NotificationJob(
ITicketRefManager ticketRefManager,
IClientManager clientManager,
IEmailManager emailManager,
)
{
_ticketRefManager = ticketRefManager;
_clientManager = clientManager;
_emailManager = emailManager;
}
public void CheckTickets()
{
//Do something
}
}
Does it helps ?

autofac instance a class in constructor

I have the next problem, i dont understand why this code dont work i think is because i dont injectate the class of constructor by autofac but i dont know how do that, can us help me to do that the better way?
Before I add the generator this work if i comment the generator code in service work.
This is my code:
I have a class Controller that invoke a serv:
public class ZonesController : Controller
{
private IZoneService zoneService;
public ZonesController(IZoneService zoneService)
{
this.zoneService = zoneService;
}
[HttpGet]
//Do work
}
This is the service and interface:
public class ZoneService : IZoneService
{
private readonly IZoneRepository zoneRepository;
private readonly IDtoFactory dtoFactory;
private readonly ZoneGenerator zoneGenerator;
public ZoneService(IZoneRepository zoneRepository,
IDtoFactory dtoFactory,
ZoneGenerator zoneGenerator)
{
this.zoneRepository = zoneRepository;
this.dtoFactory = dtoFactory;
this.zoneGenerator = zoneGenerator;
}
public void Add(ZoneDetailDTO zone)
{
zoneGenerator.Generate(zone);
}
//Do Work
}
public interface IZoneService
{
void Add(ZoneDetailDTO zone);
//Do Methods
}
The generator invoke ohter class, factories:
public class ZoneGenerator
{
private readonly ZoneFactory zoneFactory;
private readonly IZoneRepository zoneRepository;
public ZoneGenerator(ZoneFactory zoneFactory, IZoneRepository zoneRepository)
{
this.zoneFactory = zoneFactory;
this.zoneRepository = zoneRepository;
}
public void Generate(ZoneDetailDTO zoneModel)
{
var zone = zoneFactory.Create(zoneModel);
zoneRepository.Add(zone);
}
}
The Factory:
public class ZoneFactory
{
private readonly ZoneMapFactory zoneMapFactory;
private readonly ZoneScheduleFactory zoneScheduleFactory;
public ZoneFactory(ZoneMapFactory zoneMapFactory,
ZoneScheduleFactory zoneScheduleFactory)
{
this.zoneMapFactory = zoneMapFactory;
this.zoneScheduleFactory = zoneScheduleFactory;
}
public Zone Create(zoneDetailDTO zone)
{
var map = zoneMapFactory.Create(zone.Map.Address, zone.Map.Latitude, zone.Map.Longitude);
var schedule = zoneScheduleFactory.Create(zone.Schedule.StartHour, zone.Schedule.EndHour);
return new Zone(zone.Name,
zone.ProvinceId,
map,
schedule,
zone.Tags);
}
}
And finally my container:
//method in Startup class Asp.Net Core
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ZoneService>().As<IZoneService>();
builder.RegisterType<ZoneRepository>().As<IZoneRepository>();
builder.RegisterType<ProvinceService>().As<IProvinceService>();
builder.RegisterType<ProvinceRepository>().As<IProvinceRepository>();
builder.RegisterType<DtoFactory>().As<IDtoFactory>();
}
}
You have missed to add to your Load method the following:
builder.RegisterType<ZoneGenerator>().AsSelf();
builder.RegisterType<ZoneFactory>().AsSelf();
builder.RegisterType<ZoneMapFactory>().AsSelf();
builder.RegisterType<ZoneScheduleFactory>().AsSelf();

AutoFac - How to register and resolve an object with parameter?

public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
DoSomethingElse object is used by couple of methods in this class but it's not a requirement for all the methods. How do I register and resolve DoSomethingElse?
The problem as I understand it:
public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
You don't want to instantiate the DoSomethingElse type everytime you instantiate the FooController. You also want to provide it with a value at run time.
So this calls for the Factory Pattern:
public interface IDoSomethingElseFactory
{
IDoSomethingElse Create(string value);
}
public class DoSomethingElseFactory : IDoSomethingElseFactory
{
public IDoSomethingElse Create(string value)
{
// Every call to this method will create a new instance
return new DoSomethingElse(value);
}
}
public class FooController : ApiController
{
private IDb db;
private readonly IDoSomethingElseFactory doSomethingElseFactory;
public FooController (
IDb context,
IDoSomethingElseFactory doSomethingElseFactory)
{
db = context;
this.doSomethingElseFactory = doSomethingElseFactory;
}
public void DoSomething(string value)
{
// this will be the point at which a brand new
// instance of `DoSomethingElse` will be created.
var output = doSomethingElseFactory.Create(value);
}
}
Then to register this:
builder.RegisterType<DoSomethingElseFactory>()
.As<IDoSomethingElseFactory>()

Implementing CastleWindsor with Model View Presenter (MVP)

I would like to implement CastleWindsor with the MVP pattern, but I keep getting an 'Object Reference Not Set to an Object reference on the Presenter when the repository is called to obtain some data.
This is how I did it and I am wondering if there is anything wrong, so please let me know if you can:
Presenter:
public class CategoryPresenter
{
ICategoryRepository categoryRepository;
ICategoryView categoryView;
public CategoryPresenter(ICategoryView _categoryView, ICategoryRepository _categoryRepository)
{
categoryView = _categoryView;
categoryRepository = _categoryRepository;
}
//public CategoryPresenter(ICategoryView _categoryView) : this (_categoryView, new CategoryRepository())
//{ }
public CategoryPresenter(ICategoryView _view)
{
categoryView = _view;
}
public IEnumerable<object> GetActiveCategories()
{
return categoryRepository.GetActiveCategories();
}
}
IoC Class:
public static class IoC
{
public static IWindsorContainer windsorContainter { get; set; }
}
IoCConfig Class:
class IoCConfig
{
public static IWindsorContainer RegisterCastleWindsorContainer()
{
IWindsorContainer windsorContainer = new WindsorContainer()
.Install(new RepositoryInstaller())
IoC.windsorContainter = windsorContainer;
return windsorContainer;
}
}
Installer Class:
public class RepositoryInstaller: IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<ICategoryRepository>().ImplementedBy<CategoryRepository>).LifestyleTransient());
}
}
Finally in Global.ascx file I am doing this at App_Start:
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
IoCConfig.RegisterCastleWindsorContainer();
}
With this, the error message is as said above; the error happens at the presenter's method: GetActiveCategories();
As you see at no where in code I invoke the resolve method on the container.
Please let me know if if you have any suggestions.
Thank you.
I have resolved this to the IoC Class
public static T Resolve<T>()
{
try
{
return windsorContainer.Resolve<T>();
}
catch (Exception e)
{
throw e;
}
}
And then add this to the presenter:
ICategoryRepository categoryRepository = IoC.Resolve<ICategoryRepository>();
ICategoryView categoryView = IoC.Resolve<ICategoryView>();

Categories