I have used singleton pattern a using static property, constructor
public class MyClass
{
private readonly MemoryCacheManager _cacheManager;
private static readonly Lazy<MyClass> _Lazy = new Lazy<MyClass>(() => new MyClass());
public static MyClass Language { get { return _Lazy.Value; } }
private MyClass()
{
_cacheManager = new MemoryCacheManager();
LoadCacheData();
}
// Rest of class
}
I have tried like following using Autofac in global.asax:
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterType<MemoryCacheManager>().SingleInstance();
}
And inside MyClass constructor:
private MyClass(MemoryCacheManager cache)
{
_cacheManager = cache;
LoadCacheData();
}
public string Translate(string language)
{
var translation = _cacheManager.GetValueFromCache();
}
And I want to call this method in Index.cshtml
Previously I did it directly like this:
<h4>#MyClass.Language.Translate("Welcome", Model.Language)</h4>
As I had Language as follow in MyClass:
public static Localizer Language { get { return _Lazy.Value; } }
But now I do not have this property.
How can I call Translate method in Index.cshtml as I do not have static property like previous.
You just need to register MyClass as a SingleInstance with your container:
var builder = new ContainerBuilder();
builder.RegisterType<MyClass>().As<IMyClass>().SingleInstance();
Then inject where ever you need:
public AnotherClass(IMyClass myClass)
{
_myClass = myClass;
}
Although it's probably the cache you want a single instance of. In that case:
builder.RegisterType<MemoryCacheManager>().SingleInstance();
And then:
public MyClass(MemoryCacheManager cache)
{
_cacheManager = cache;
LoadCacheData();
}
EDIT:
The first thing you need to do is set the DependencyResolver in your Application_Start class (you'll need to get the Autofac MVC Integration NuGet package for this):
protected void Application_Start()
{
this.RegisterAutoFac();
// Rest of method
}
private void RegisterAutoFac()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<MyClass>().As<IMyClass>();
builder.RegisterType<MyCache>().As<IMyCache>().SingleInstance();
var container = builder.Build();
// Setup the dependency resolver
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
Then you need to inject MyClass into the constructor of your controller:
public class TestController : Controller
{
private readonly IMyClass _myClass;
public TestController(IMyClass myClass)
{
_myClass = myClass;
}
// Rest of the controller
}
Then when your creating model for you get the data you need from MyClass:
public ActionResult Index()
{
var model = new ExampleModel
{
WelcomeMessage = _myClass.Translate("Welcome")
};
return View(model);
}
And in your view:
<h4>#Model.WelcomeMessage</h4>
Related
I have been working on converting my tightly coupled method into one that can be unit tested and have sought some advice on here. I now have my method passing its unit test thanks to some advice - however I now find that I cant call the method from my application. I used to access my GetAllProductsFromCSV() method from the controller with the following:
public ActionResult Index()
{
var products = new ProductsCSV();
List<ProductItem> allProducts = products.GetAllProductsFromCSV();
foreach (var product in allProducts)
{
if (string.IsNullOrEmpty(product.ImagePath))
{
product.ImagePath = "blank.jpg";
}
}
return View(allProducts);
}
The Method was as follows:
public class ProductsCSV
{
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = HttpContext.Current.Server.MapPath(#"~/CSV/products.csv");
String[] csvData = File.ReadAllLines(productFilePath);
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
}
I have now made the following changes in the ProductCSV class:
public class ProductsCSV
{
private readonly IProductsCsvReader reader;
public ProductsCSV(IProductsCsvReader reader = null)
{
this.reader = reader;
}
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = #"~/CSV/products.csv";
var csvData = reader.ReadAllLines(productFilePath);
var result = parseProducts(csvData);
return result;
}
private List<ProductItem> parseProducts(String[] csvData)
{
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
Along with the following class & Interface:
public class DefaultProductsCsvReader : IProductsCsvReader
{
public string[] ReadAllLines(string virtualPath)
{
var productFilePath = HostingEnvironment.MapPath(virtualPath);
String[] csvData = File.ReadAllLines(productFilePath);
return csvData;
}
}
public interface IProductsCsvReader
{
string[] ReadAllLines(string virtualPath);
}
As I said, the Unit-Test on method GetAllProductsFromCSV completes successfully now however when I try accessing the method from my controller I get a NullReferenceException on the reader.ReadAllLines call within GetAllProductsFromCSV. It makes sense to me that when I attempt to create an instance of ProductsCSV from within the controller - I am not passing in any parameters... The constructor for the class however requests a IProductsCsvReader. What I cant figure out is how do I actually make the call to the method now? I hope that is clear??
First lets update ProductsCSV to have a backing interface
public interface IProductsCSV {
List<ProductItem> GetAllProductsFromCSV();
}
public class ProductsCSV : IProductsCSV {
//...other code removed for brevity
}
The controller wound now depend on the abstraction introduced above, decoupling it from the concrete implementation from the original controller. Though a simplified example, this allows the controller to be easier to maintain and unit-test in isolation.
public class ProductsController : Controller {
private readonly IProductsCSV products;
public ProductsController(IProductsCSV products) {
this.products = products;
}
public ActionResult Index() {
List<ProductItem> allProducts = products.GetAllProductsFromCSV();
foreach (var product in allProducts) {
if (string.IsNullOrEmpty(product.ImagePath)) {
product.ImagePath = "blank.jpg";
}
}
return View(allProducts);
}
}
Note how the action matched exactly what you had before except for how the products is created.
Finally now that the controller has been refactored for dependency inversion, the framework needs to be configured to be able to inject the dependencies into the the controller when requested.
You can eventually use your library of choice but for this example I am using what they used in documentation
ASP.NET MVC 4 Dependency Injection
Never mind the version. The implementation is transferable.
In the documentation above they used Unity for their IoC container. There are many container libraries available so search for the one you prefer and use that.
public static class BootStrapper {
private static IUnityContainer BuildUnityContainer() {
var container = new UnityContainer();
//Register types with Unity
container.RegisterType<IProductsCSV , ProductsCSV>();
container.RegisterType<IProductsCsvReader, DefaultProductsCsvReader>();
return container;
}
public static void Initialise() {
//create container
var container = BuildUnityContainer();
//grab the current resolver
IDependencyResolver resolver = DependencyResolver.Current;
//create the new resolver that will be used to replace the current one
IDependencyResolver newResolver = new UnityDependencyResolver(container, resolver);
//assign the new resolver.
DependencyResolver.SetResolver(newResolver);
}
}
public class UnityDependencyResolver : IDependencyResolver {
private IUnityContainer container;
private IDependencyResolver resolver;
public UnityDependencyResolver(IUnityContainer container, IDependencyResolver resolver) {
this.container = container;
this.resolver = resolver;
}
public object GetService(Type serviceType) {
try {
return this.container.Resolve(serviceType);
} catch {
return this.resolver.GetService(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType) {
try {
return this.container.ResolveAll(serviceType);
} catch {
return this.resolver.GetServices(serviceType);
}
}
}
You would call the above bootstrapper in your start up code.
For example
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Bootstrapper.Initialise(); //<-- configure DI
AppConfig.Configure();
}
So now when ever the framework has to create the ProductsController it will know how to initialize and inject the controller's dependencies.
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();
I'm wiring up Autofac dependency injection within my ASP.NET MVC 5 web application using OWIN middleware (so using startup.cs instead of global.asax), and trying to use property injection to set a public variable within a Controller.
I'm playing around with property injection to have Autofac automatically set the Test property in the LoginController.
public interface ITest
{
string TestMethod();
}
public class Test : ITest
{
public string TestMethod()
{
return "Hello world!";
}
}
public class LoginController : Controller
{
public ITest Test { get; set; }
public LoginController()
{
var aaa = Test.TestMethod();
// Do other stuff...
}
}
Here's what my startup.cs looks like. I have been playing around, so some of this code might not be needed (or causing my issue?).
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterType<Test>().As<ITest>().SingleInstance();
builder.Register(c => new Test()).As<ITest>().InstancePerDependency();
builder.RegisterType<ITest>().PropertiesAutowired();
builder.RegisterType<LoginController>().PropertiesAutowired();
builder.RegisterModelBinderProvider();
builder.RegisterFilterProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// Some other stuff...
}
}
So, the 'Test' public property is always null, and therefore breaks on runtime.
Any ideas what could be my issue? Thanks advance for your help! :)
So, the 'Test' public property is always null, and therefore breaks on runtime.
It's not always null. It's null in the constructor because Autofac (actually ALL code) cannot set properties until the constructor is finished.
public class LoginController : Controller
{
public ITest Test { get; set; }
public LoginController()
{
// Test is null, will always be null here
var aaa = Test.TestMethod();
}
}
A super dummied down version of autofac does something like:
var controller = new LoginController();
controller.Test = new Test();
If you need to execute code after the property is set you could do something hacky like the following (but really you should just be using constructor injection):
public class LoginController : Controller
{
private ITest _test;
public ITest Test
{
get { return _test; }
set
{
var initialize = (_test == null);
_test = value;
if (initialize)
{
Initialize();
}
}
}
public LoginController()
{
}
private void Initialize()
{
var aaa = Test.TestMethod();
}
}
Again the more logical way would be to just do:
public class LoginController : Controller
{
private readonly ITest _test;
public LoginController(ITest test)
{
_test = test;
var aaa = _test.TestMethod();
// Do other stuff...
}
}
If you did this:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>("Logging");
container.RegisterType<IService, CachingService>("Caching");
var services = container.ResolveAll<IService>();
foreach (var service in services)
Console.WriteLine(service);
Console.ReadKey();
}
}
interface IService { }
class DataService : IService { }
class LoggingService : IService { }
class CachingService : IService { }
The output you would get would include only the named mappings and would not include the default DataService mapping. The output of this program would be:
MoreUnityPractice.LoggingService
MoreUnityPractice.CachingService
Why did they decide not to get the default, unnamed mapping/registration with ResolveAll?
It was done this way so that you can have a Composite.
An example Composite IService
public class CompositeDataService : IService
{
public readonly IService[] services;
public CompositeDataService(IService[] services)
{
this.services = services;
}
}
And a demonstration test
[Fact]
public void Test()
{
var container = new UnityContainer();
container.RegisterType<IService, CompositeDataService>();
container.RegisterType<IService, LoggingService>("Logging");
container.RegisterType<IService, CachingService>("Caching");
var service = container.Resolve<IService>();
Assert.IsType<CompositeDataService>(service);
Assert.Equal(2, ((CompositeDataService)service).services.Count());
}
It is officially documented here
The two overloads of this method [ResolveAll] accept either an interface or a type name, and they return an instance of IEnumerable that contains references to all registered objects of that type that are not default mappings. The list returned by the ResolveAll method contains only named instance registrations. The ResolveAll method is useful if you have registered multiple object or interface types using the same type but different names
Here is some code to work around it (Note: I haven't run the code)
using System;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
public class Remember : UnityContainerExtension
{
protected override void Initialize()
{
this.Context.Registering += this.OnRegistering;
this.Context.RegisteringInstance += this.OnRegisteringInstance;
}
private void OnRegisteringInstance(object sender, RegisterInstanceEventArgs e)
{
if(string.IsNullOrEmpty(e.Name))
{
string uniqueName = Guid.NewGuid().ToString();
this.Context.RegisterNamedType(e.RegisteredType, uniqueName);
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.RegisteredType)),
new NamedTypeBuildKey(e.RegisteredType, uniqueName));
}
}
private void OnRegistering(object sender, RegisterEventArgs e)
{
if (e.TypeFrom != null && string.IsNullOrEmpty(e.Name))
{
string uniqueName = Guid.NewGuid().ToString();
this.Context.RegisterNamedType(e.TypeFrom, uniqueName);
if (e.TypeFrom.IsGenericTypeDefinition && e.TypeTo.IsGenericTypeDefinition)
{
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
new NamedTypeBuildKey(e.TypeFrom, uniqueName));
}
else
{
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
new NamedTypeBuildKey(e.TypeFrom, uniqueName));
}
}
}
}
With an example
[TestMethod]
public void CanResolveMultipeDefaultMappingsUsingResolveAll()
{
var container = new UnityContainer().AddNewExtension<Remember>();
container.RegisterType<IFoo, One>();
container.RegisterType<IFoo, Two>();
container.RegisterType<IFoo, Three>();
IFoo[] foos = container.ResolveAll<IFoo>().OrderBy(f => f.GetType().Name).ToArray();
Assert.AreEqual(3, foos.Length);
Assert.IsInstanceOfType(foos[0], typeof(One));
Assert.IsInstanceOfType(foos[1], typeof(Three));
Assert.IsInstanceOfType(foos[2], typeof(Two));
}
public interface ILog
{
void Write(string msg);
}
public class MyLog : ILog
{
public void Write(string msg)
{
Console.WriteLine(msg);
}
}
public interface ICanLog
{
ILog Log { get; set; }
}
public interface IMyClass
{
void Test();
}
public class MyClass : IMyClass, ICanLog
{
public ILog Log { get; set; }
public void Test()
{
Log.Write("Test");
}
}
I am using Autofac with Castle DynamicProxy,
and try to let MyClass Test Method output "BEGIN"/"END" automatic.
public class MyLogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("BEGIN");
invocation.Proceed();
Console.WriteLine("END");
}
}
The following is test code:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MyLog>().As<ILog>();
builder.Register(c =>
{
ProxyGenerator g = new ProxyGenerator();
object proxy = g.CreateClassProxy(typeof(MyClass), new MyLogInterceptor());
ICanLog proxyICanLog = (ICanLog)proxy;
proxyICanLog.Log = c.Resolve<ILog>();
return proxy;
}).As<IMyClass>();
using (var container = builder.Build())
{
objectContext.Container = container;
IMyClass myclass = container.Resolve<IMyClass>();
myclass.Test();
}
But result no output "BEGIN"/"END", why ?
and if I create AutoLogModule that try build Log Property Instance automatic
public class AutoLogModule : Autofac.Module
{
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
var type = registration.Activator.LimitType;
if (HasPropertyDependencyOnClass(type))
{
registration.Activated += InjectClassViaProperty;
}
}
private bool HasPropertyDependencyOnClass(Type type)
{
return type.GetProperties().Any(property => property.CanWrite && property.PropertyType==typeof(ILog));
}
private void InjectClassViaProperty(object sender, ActivatedEventArgs<object> evt)
{
var type = evt.Instance.GetType();
var propertyInfo = type.GetProperties().First(x => x.CanWrite && x.PropertyType==typeof(ILog));
ILog log = new MyLog();
propertyInfo.SetValue(evt.Instance, log, null);
}
}
The following is test code:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MyLog>().As<ILog>();
builder.RegisterModule(new AutoLogModule());
builder.Register(c =>
{
ProxyGenerator g = new ProxyGenerator();
object proxy = g.CreateClassProxy(typeof(MyClass), new MyLogInterceptor());
//ICanLog proxyICanLog = (ICanLog)proxy;
//proxyICanLog.Log = c.Resolve<ILog>();
return proxy;
}).As<IMyClass>();
using (var container = builder.Build())
{
objectContext.Container = container;
IMyClass myclass = container.Resolve<IMyClass>();
myclass.Test();
}
The result is Test Method throw
"Object reference not set to an instance of an object."
in Log.Write("Test")
How to write this feature?
I know this is a rather old post but as I was trying to accomplish the same thing with Autofac and I found the documentation that helped me to achieve it. I will answer just in case it helps someone else.
In my case I'm using Autofac 4.92 and and extra package for DynamicProxy called Autofac.Extras.DynamicProxy 4.5.0 as the documentations sates.
I see a difference where you register your Interceptors. Even though what you are doing is what I would have done initially; is not what Autofac Documentation currently says about how to Register Interceptors:
builder.RegisterType<MyClass>().As<IMyClass>().EnableInterfaceInterceptors();
// Typed registration
builder.Register(c => new MyLogInterceptor ();
Lastly, you need to Associate Interceptors with Types to be Intercepted:
[Intercept(typeof(MyLogInterceptor))]
public class MyClass : IMyClass, ICanLog
{
public ILog Log { get; set; }
public void Test()
{
Log.Write("Test");
}
}
I hope this answer may help. In any case, the Autofac documentation explains step by step how to do it just in case my code may mistakenly skip some relevant part.