Correct way to use Autofac with Factory Pattern? - c#

IN a Winforms project, I have set up Autofac and Factory Pattern and it looks like it's working as expected. However, I'm still not sure whether the following is best practice.
The factory class is:
public static class Client
{
public static readonly IRequestFactory RequestFactory = new RequestFactory();
}
public class Configuration
{
public IContainer Container { get; private set; }
public Configuration()
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Request"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
Container = builder.Build();
}
}
public class RequestFactory : IRequestFactory, IDisposable
{
private ILifetimeScope scope;
public RequestFactory()
{
scope = Client.Configuration.Container.BeginLifetimeScope();
}
public T Get<T>()
{
return scope.Resolve<T>();
}
public void Dispose()
{
if (scope != null)
{
scope.Dispose();
}
}
}
Then, classes in separate assemblies have the IRequestFactory as a ctor parameter.
Is the above the correct way to implement factor pattern with Autofac or is there a better way?

Related

getting an error when dependency injection in console app with autofac

This question previously asked actually
Using Autofac to inject a dependency into the Main entry point in a console app
Correct use of Autofac in C# console application
Just want to call the non-static method from my main static method in the console app
So I followed the above articles, built in this way
namespace SampleConsoleApp
{
[ExcludeFromCodeCoverage]
public class Program
{
private ISampleService _oSampleService;
private static IContainer CompositionRoot()
{
var builder = new ContainerBuilder();
builder.RegisterType<SampleInitialize>();
builder.RegisterType<SampleService>().As<ISampleService>();
return builder.Build();
}
public static void Main(string[] args)
{
CompositionRoot().Resolve<SampleInitialize>().Run_Auto();
}
}
}
namespace SampleConsoleApp
{
public class SampleInitialize
{
private ISampleService _oSampleService;
public SampleInitialize(ISampleService oSampleService)
{
_oSampleService = oSampleService;
}
public void Run_Auto()
{
var _list = _oSampleService.GetList();
}
}
}
namespace SampleConsoleApp
{
public class SampleService : ISampleService
{
public SampleService(IContext context)
: base(context)
{
_context = context;
}
public List<String> GetList()
{
var _list = new List<String>();
....
return _list;
}
}
}
namespace SampleConsoleApp
{
public interface ISampleService
{
List<String> GetList();
}
}
but I'm getting an error once this launch as following
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'SampleConsoleApp.SampleInitialize' can be invoked with the available
services and parameters:\r\nCannot resolve parameter
'SampleConsoleApp.SampleService.ISampleService oSampleService' of
constructor 'Void .ctor(SampleConsoleApp.ISampleService)'.
As mentioned from #hocho you need to register IContext.
private static IContainer CompositionRoot()
{
var builder = new ContainerBuilder();
builder.RegisterType<SampleInitialize>();
builder.RegisterType<SampleService>().As<ISampleService>();
builder.RegisterType<SampleDbContext>().As<IContext>();
return builder.Build();
}
Afterwards you need to register everything needed by SampleDbContext constructor as well.

Autofac: Type 'MyController' does not have a default constructor

I have a Web Api app that consumes another REST Api client. I wrapped the REST API client into a service.
myproj/services/PostDataService.cs
public interface IPostDataService
{
Task<IList<Post>> GetAllPosts();
}
public class PostDataService : IPostDataService
{
private static IDataAPI NewDataAPIClient()
{
var client = new DataAPI(new Uri(ConfigurationManager.AppSettings["dataapi.url"]));
return client;
}
public async Task<IList<Post>> GetAllPosts()
{
using (var client = NewDataAPIClient())
{
var result = await client.Post.GetAllWithOperationResponseAsync();
return (IList<Post>) result.Response.Content;
}
}
}
....
I am using AutoFac and injecting the service in the controller
myproj/controllers/PostController.cs
public class PostController : ApiController
{
private readonly IPostDataService _postDataService;
public PostController(IPostDataService postDataService)
{
_postDataService = postDataService;
}
public async Task<IEnumerable<Post>> Get()
{
return await _postDataService.GetAllPosts();
}
}
But I am getting this error.
An error occurred when trying to create a controller of type
'PostController'. Make sure that the controller has a parameterless
public constructor.
Here is my Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ContainerConfig.Configure();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
public static class ContainerConfig
{
private static IContainer _container;
public static IContainer GetContainer()
{
if (_container != null)
return _container;
var builder = new ContainerBuilder();
builder.RegisterType<PostDataService>()
.AsSelf()
.InstancePerLifetimeScope()
.AsImplementedInterfaces();
_container = builder.Build();
return _container;
}
public static IContainer Configure()
{
var container = GetContainer();
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
return container;
}
Can someone spot what I am missing here?
Thanks
I'm missing
builder.RegisterApiControllers(typeof(PostController).Assembly).
Apparently, the controller also needs to be registered.

How to reuse an InstancePerRequest instance create in composition root using Autofac

I have an Asp.NET MVC5 application in which I registre my types using Autofac in Startup class in this way:
public class Startup
{
public void Configuration(IAppBuilder app)
{
IContainer container = null;
var builder = new ContainerBuilder();
// Register Services
builder.RegisterType<SalesRepository>().As<ISalesRepository>().InstancePerRequest();
builder.RegisterType<SalesService>().As<ISalesService>().InstancePerRequest();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IHandle<>))
.AsImplementedInterfaces()
.InstancePerRequest();
builder.Register<IAppEvents>(_ => new AppEvents(container)).InstancePerRequest();
// Register MVC Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
These are my services (this is a simplified scenario, only for demonstration).
The SalesService class receives a ISalesRepository interface as dependency . In addition I have an AppEvents class where I want to resolve IHandle types:
public interface ISalesRepository { }
public class SalesRepository : ISalesRepository
{
public SalesRepository() { }
}
public interface ISalesService { }
public class SalesService : ISalesService
{
ISalesRepository _repo;
public SalesService(ISalesRepository repo)
{
_repo = repo;
}
}
public interface IHandle<T>
{
void Handle();
}
public class SalesActionHandle : IHandle<string>
{
ISalesRepository _repo;
public SalesActionHandle(ISalesRepository repo)
{
_repo = repo;
}
public void Handle() { }
}
public interface IAppEvents
{
void Raise<T>();
}
public class AppEvents : IAppEvents
{
private readonly IContainer _container;
public AppEvents(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public void Raise<T>()
{
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>(); // Runtime error here
foreach (var handler in handlers)
handler.Handle();
}
}
And this is my only (simplified) controller:
public class HomeController : Controller
{
ISalesService _service;
IAppEvents _events;
public HomeController(ISalesService service, IAppEvents events)
{
_service = service;
_events= events;
}
public ActionResult Index()
{
_events.Raise<string>();
return View();
}
}
The problem I have is that I get an error at this line when it is executed:
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>();
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I resolve it by doing this:
public void Raise<T>()
{
using (var scope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var handlers = scope.Resolve<IEnumerable<IHandle<T>>>();
foreach (var handler in handlers)
handler.Handle();
}
}
But in this case, when IHandle is resolved (with SalesActionHandle instance), a new instance of SalesRepository is passed as parameter in SalesActionHandle constructor. What I want is to "reuse" the same instance that SalesService is using (it was created when ISalesService was resolved. I want the same SalesRepository instance for the request)
Is there any way to achieve this behaviour?
The sample code is avaible in Github: https://github.com/josmonver/AutofacTest
You may want to use
AutofacDependencyResolver.Current.RequestLifetimeScope
to match your current request scope, but not to create a new request scope.

Convert unity to autofac

I am trying to convert an example piece of code I found on caching with a repository. The only problem is it's using unity for its DI and I don't have any understanding how it works.
public interface IUnitOfWork : IDisposable
{
IRepository<Blog> BlogRepository { get; }
Task<int> SaveChangesAsync();
}
public class UnitOfWork : IUnitOfWork
{
private IDataStoreContext dataStoreContext;
private readonly IUnityContainer container;
public IRepository<Blog> BlogRepository
{
get
{
// TODO : Use unity containers to generate the UnitOfwork so that to make surethat
// datacontext is a single instance in that instance of uow
return new GenericRepository<Blog>(
this.container.Resolve<ICacheStrategy<Blog>>(),
new SqlDataStoreStrategy<Blog>(this.dataStoreContext));
}
}
public UnitOfWork(IDataStoreContext dataStoreContext, IUnityContainer container)
{
this.dataStoreContext = dataStoreContext;
this.container = container;
}
public async Task<int> SaveChangesAsync()
{
return await this.dataStoreContext.SaveChangesAsync();
}
public void Dispose()
{
this.dataStoreContext.Dispose();
}
}
Can anyone point me in the right direction on how I should write this as an autofac statement?
I have only really ever need to use basic autofac e.g.
var builder = new ContainerBuilder();
// Create the container and use the default application services as a fallback
AutofacRegistration.Populate(builder, services);
builder.Register(c => new Logger())
.As<ILogger>()
.InstancePerLifetimeScope();

How do I specify which registration of an interface to use with a particular mvc controller?

I have two implementations of an interface that in plain old c# would be instantiated like so:
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
var oven = useCache
? new CachedCookieOven(new CookieOven())
: new CookieOven();
var controller = new CookieController(oven); // MVC Controller
here is the interface and classes:
public interface ICookieOven {
IEnumerable<Cookie> Bake();
}
public class CookieOven : ICookieOven {
public IEnumerable<Cookie> Bake() {
var list = new List<Cookie>();
// bake cookies and return them
return list;
}
}
public class CachedCookieOven : ICookieOven {
readonly ICookieOven _oven;
public CachedCookieOven(ICookieOven oven) { _oven = oven; }
public IEnumerable<Cookie> Bake() {
var cookies = GetFromPlate();
return cookies ?? _oven.Bake();
}
}
My MVC controller has the following constructor
public class CookieController : Controller {
readonly ICookieOven _oven;
public CookieController(ICookieOven oven) { _oven = oven; }
public ActionResult ViewCookies() {
var bakedCookies = _oven.Bake();
return View(bakedCookies);
}
}
The Bootstrapper class that is created says in the comments that I don't need to register my mvc controller classes
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
}
}
In Unity I have registered both instances. There may be a better way and if so tell me.
public static class Bootstrapper {
// ...
private static IUnityContainer BuildUnityContainer() {
var container = new UnityContainer();
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
// register
container.RegisterType<ICookieOven, CookieOven>("oven");
if (useCache) {
container.RegisterType<ICookieOven, CachedCookieOven>("cachedOven",
new InjectionConstructor(container.Resolve<ICookieOven>("oven"));
}
}
}
How do I ensure that the correct instance of ICookieOven gets sent to the constructor of the CookieController mvc controller?
Registering types in Unity without a name makes that the default type. If you want to register more than one type, you have to provide a name. The following is the correct way to register my types in the Bootstrapper class:
public static void RegisterTypes(IUnityContainer container)
{
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
if (useCache) {
// named, this is not the default
container.RegisterType<ICookieOven,CookieOven>("oven");
// this one is not named and is the default
container.RegisterType<ICookieOven,CachedCookieOven>(new InjectionConstructor(
container.Resolve<ICookieOven>("oven"));
} else {
// notice it is not named, it is the default
container.RegisterType<ICookieOven,CookieOven>();
}
}
You want to create an object but which one depends on a value only known at runtime. What you need is a factory (couple of examples here).
To implement this, one approach could be like this: your controller could depend on a IOvenFactory, injected in controller's constructor. When you need the oven you can call _ovenFactory.Create().
In an IOvenFactory implementation, you could have the logic of how to create, depending on the configuration value.

Categories

Resources