c# DI Unity Container how to resolve dependent object - c#

We have following implementation of IProduct & ILogger class. Manager classes are being used as communication channel. We have used unity as given below to resolve manager class but it giving following error-
===================unity configuration==========
IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, FileLogger>("File");
container.RegisterType<ILogger, BDLogger>("DB");
container.RegisterType<IProduct, ProductA>("productA");
container.RegisterType<IProduct, ProductB>("productB");
container.RegisterType<ProducManager>(new InjectionConstructor(container.Resolve<IProduct>("productA")));
container.Resolve<ProducManager>("productA");
========================================================
"Resolution of the dependency failed, type = \"usingDI.IProduct\",
name = \"productA\".\r\nException occurred while: while
resolving.\r\nException is: InvalidOperationException - The current
type, usingDI.ILogger, is an interface and cannot be constructed. Are
you missing a type
mapping?\r\n-----------------------------------------------\r\nAt the
time of the exception, the container was:\r\n\r\n Resolving
usingDI.ProductA,productA (mapped from usingDI.IProduct, productA)\r\n
Resolving parameter \"logger\" of constructor
usingDI.ProductA(usingDI.ILogger logger)\r\n Resolving
usingDI.ILogger,(none)\r\n"}"
Please suggest me best way to resolve dependency for manager classes.
public interface IProduct
{
void dosomething();
}
public class ProducManager
{
IProduct _product;
public ProducManager(IProduct product)
{
_product = product;
}
public void DoSomething()
{
_product.dosomething();
}
}
public class ProductA : IProduct
{
ILogger _logger;
public ProductA(ILogger logger)
{
_logger = logger;
}
public void dosomething()
{
try
{
//code
//
}
catch (Exception ex)
{
_logger.WriteLog(ex.Message);
}
}
}
public class ProductB : IProduct
{
ILogger _logger;
public ProductB(ILogger logger)
{
_logger = logger;
}
public void dosomething()
{
try
{
//code
//
}
catch (Exception ex)
{
_logger.WriteLog(ex.Message);
}
}
}
public class LogManager
{
ILogger _logger;
public LogManager(ILogger logger)
{
_logger = logger;
}
public void WriteLog(string exception)
{
_logger.WriteLog(exception);
}
}
public interface ILogger
{
void WriteLog(string exception);
}
public class FileLogger : ILogger
{
public void WriteLog(string exception)
{
}
}
public class BDLogger : ILogger
{
public void WriteLog(string exception)
{
}
}

You need to register a type mapping for your interface ILogger. Otherwise does Unity not now which implementation of ILogger it should use (see your exception).
HereĀ“s an example registering the interface ILogger with a mapping to FileLogger:
_container.RegisterType<ILogger, FileLogger>();
IProduct product = _container.Resolve<ProductA>(); //ILogger is injected to Product

Related

How to pass logger object while creating instance using reflection?

Abstract Class:
public abstract class Rater
{
public Rater()
{
}
public abstract decimal Rate(Policy policy);
}
Child classes:
public class AutoPolicyRater : Rater
{
public readonly ILogger<AutoPolicyRater> _logger;
public AutoPolicyRater(ILogger<AutoPolicyRater> logger)
{
_logger = logger;
}
public override decimal Rate(Policy policy)
{
_logger.Log("Rating AUTO policy...");
_logger.Log("Validating policy.");
if (String.IsNullOrEmpty(policy.Make))
{
_logger.Log("Auto policy must specify Make");
return 0m;
}
if (policy.Make == "BMW")
{
if (policy.Deductible < 500)
{
return 1000m;
}
return 900m;
}
return 0m;
}
}
public class LandPolicyRater : Rater
{
public readonly ILogger<LandPolicyRater> _logger;
public AutoPolicyRater(ILogger<LandPolicyRater> logger)
{
_logger = logger;
}
public override decimal Rate(Policy policy)
{
_logger.Log("Rating LAND policy...");
_logger.Log("Validating policy.");
if (policy.BondAmount == 0 || policy.Valuation == 0)
{
_logger.Log("Land policy must specify Bond Amount and Valuation.");
return 0m;
}
if (policy.BondAmount < 0.8m * policy.Valuation)
{
_logger.Log("Insufficient bond amount.");
return 0m;
}
return (policy.BondAmount * 0.05m);
}
}
Factory class, where I want to dynamically pass the logger object:
public class RaterFactory
{
private readonly IRatingUpdater _ratingUpdater;
public RaterFactory(ILogger logger)
{
}
public Rater Create(Policy policy)
{
try
{
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { ?? });//here I want to pass logger object
}
catch
{
return new UnknownPolicyRater();
}
}
}
As these classes are not controllers, and I want to create object in my factory method, how can I pass logger object and log information to application insight? I would like to pass generic logger object, however, if there is another approach to achieve, I'm ok.
EDIT:
After #fildor's suggestion, I tried below and it is logging information in Application Insight traces.
public class RaterFactory
{
private readonly ILoggerFactory _loggerFactory;
public RaterFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public Rater Create(Policy policy)
{
try
{
string typeString = $"MyCompany.{policy.Type}PolicyRater";
ILogger modelLogger = _loggerFactory.CreateLogger(typeString);
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { modelLogger });
}
catch
{
return new UnknownPolicyRater();
}
}
}
public class AutoPolicyRater : Rater
{
public readonly ILogger _logger;
public AutoPolicyRater(ILogger logger)
{
_logger = logger;
}
//other code
}
As requested: a possible implementation:
public class RaterFactory
{
private readonly ILoggerFactory _loggerFactory;
public RaterFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
public Rater Create(Policy policy)
{
try
{
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { _loggerFactory });
}
catch
{
return new UnknownPolicyRater();
}
}
}
And then ...
public class AutoPolicyRater : Rater
{
private readonly ILogger<AutoPolicyRater> _logger;
public AutoPolicyRater(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AutoPolicyRater>();
}
public override decimal Rate(Policy policy)
{
// ... ommited for brevity
}
}
The RaterFactory class has no need to know in advance all dependencies injected into the instances it creates.
Instead, you can inject IServiceProvider and let ActivatorUtilities resolve the dependencies of the Rater instances that you are creating each time.
This is how it can be done:
public class RaterFactory
{
private readonly IServiceProvider _serviceProvider;
public RaterFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public Rater Create(Policy policy)
{
try
{
// OPTION 1
return (Rater)ActivatorUtilities.CreateInstance(
_serviceProvider,
Type.GetType($"MyCompany.{policy.Type}PolicyRater"));
// OPTION 2
return (Rater)ActivatorUtilities.GetServiceOrCreateInstance(
_serviceProvider,
Type.GetType($"MyCompany.{policy.Type}PolicyRater"));
}
catch
{
return new UnknownPolicyRater();
}
}
}
As shown above, there are two possible options that you should choose according to your needs and constraints.
ActivatorUtilities.CreateInstance: This method creates each time a new instance and does not query the service collection for the target type. This is convenient if you don't know all the possible target types in advance (or you don't want to register them for some reason).
ActivatorUtilities.GetServiceOrCreateInstance: This method looks for the target type into the service collection; if a registration is found, it returns the corresponding instance, otherwise it behaves like ActivatorUtilities.CreateInstance. This means that you can register the target type in the service collection as usual with the most appropriate lifetime (singleton, scoped or transient) for each type. The only downside of this approach is that, if you have some singleton or scoped target types, you have to provide a way to register them in the service collection, which may be tricky in a plugin-like application.
Again, please note that there are no constraints on which dependencies can be injected in the Rater subtypes, because after all the "dirty" work of dependency resolution is done by the ActivatorUtilities class.

Using Azure Function V3, how do I inject existing Ilogger into new class file?

I have created a new Azure Function, V3, CORE 3.1, using VS2019. It uses a basic HTTPTrigger. I have created a new class file and would like to inject the existing Ilogger into it. How can this be achieved? I'm new to this so any help would be appreciated.
I have a Function which writes logs to App Insights and I use ILogger.
You can use ILogger like this with Dependency Injection in your other service/helper classes.
public interface IExampleClass
{
void ExampleMethod();
}
public class ExampleClass : IExampleClass
{
private readonly ILogger<ExampleClass> _logger;
public ExampleClass(ILogger<ExampleClass> logger)
{
_logger = logger;
}
public void ExampleMethod()
{
_logger.LogInformation("Example info log");
}
}
I enable logging in the Startup file and register DI.
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
builder.Services.AddTransient<ExampleClass, IExampleClass>();
}
}
Which can be invoked by the main class.
public class ThisIsAnAzureFunction
{
private readonly IExampleClass _exampleClass;
public ThisIsAnAzureFunction(IExampleClass exampleClass)
{
_exampleClass = exampleClass;
}
[FunctionName("SomeAzureFunctionName")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
{
try
{
//Try some stuff
}
catch (Exception exception)
{
//Log some stuff
log.LogError(exception);
throw;
}
}
}

I am learning on how to implement Dependency Injection [DI] in C#. Is this the valid DI program as an example?

1. Main Method
class Program
{
static void Main(string[] args)
{
ILogger _log = new Logger();
IDataAccess _da = new DataAccess();
BusinessLogic bs = new BusinessLogic(_log,_da);
bs.ProcessData();
Console.ReadLine();
}
}
2. BusinessLogic Class implements IBusinessLogic interface
class BusinessLogic : IBusinessLogic
{
ILogger _log;
IDataAccess _dataAccess;
public BusinessLogic(ILogger log, IDataAccess dataAccess)
{
_log = log;
_dataAccess = dataAccess;
}
public void ProcessData()
{
_log.Log("Start");
Console.WriteLine("process");
_dataAccess.LoadData();
_dataAccess.SaveData("processInfo");
_log.Log("Finish");
}
}
3. Logger Class implements ILogger interface
class Logger : ILogger
{
public void Log(string p)
{
Console.WriteLine(p);
}
}
4. DataAccess Class implements IDataAccess interface
class DataAccess : IDataAccess
{
public void LoadData()
{
Console.WriteLine("Loaddata");
}
public void SaveData(string name)
{
Console.WriteLine("Saving Data");
}
}
4. Interfaces
interface IBusinessLogic
{
void ProcessData();
}
interface ILogger
{
void Log(string p);
}
interface IDataAccess
{
void LoadData();
void SaveData(string name);
}
With respect to the above code i have 3 interfaces for BusinessLogic, Logger and DataAccess for all 3 classes respectively.....
If this is the correct implementation for Dependency Injection then let me know the improvements or suggestions for the code if any.....
OR incase it is NOT correct, suggest me the modifications to achieve the same.
Thanks In Advance!

Installing Windsor Logging Facility into a library

I'm developing a framework where I've put lots of logging throughout. I used Castle Windsor's ILogger through this property pattern:
namespace Framework
{
public class SomeClass
{
private ILogger _logger = NullLogger.Instance;
public ILogger Logger
{
get { return _logger; }
set { _logger = value; }
}
public void DoSomething()
{
Logger.Info("Doing something.");
}
//...
}
}
I also provide an installer from within the framework:
namespace MyFramework
{
public class LoggerInstaller : IWindsorInstaller
{
private readonly string _configPath;
public LoggerInstaller(string configPath)
{
_configPath = configPath;
}
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Log4net, _configPath));
//I've also tried this one:
//container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithConfig(_configPath));
}
}
}
This project is then referenced from other projects. For example, in the test project, I'll construct a test by first installing the logger. I do this with an abstract class that all of my long running tests extend:
namespace Framework.Test
{
public abstract class Log4NetLoggedTest
{
private const string ConfigFilePath = "log4net.config";
protected ILogger Logger { get; set; }
protected IWindsorContainer Container { get; set; }
protected Log4NetLoggedTest()
{
Container = new WindsorContainer();
Container.Install(new LoggerInstaller(ConfigFilePath));
Logger = Container.Resolve<ILogger>();
}
~Log4NetLoggedTest()
{
Container.Dispose();
}
}
}
So that my test looks like this:
namespace Framework.Test
{
[TestFixture]
public class MyLongRunningTest : Log4NetLoggedTest
{
[Test]
[Category("LongRunning")]
public void ModelConvergesForS50()
{
Logger.Info("Starting test...");
var obj = new SomeClass();
obj.DoSomething();
// ...
}
}
}
The test's ILogger Logger gets resolved and set properly, so in this example I get the "Starting test..." but not the "Doing something." The SomeClass's ILogger stays as a NullLogger.
Please help!
You are instantiating SomeObj with 'new' rather than going through the container. If you don't go through the container, it can't inject the dependency
I may be saying something stupid, but, shouldnt be something like:
namespace Framework.Test
{
[TestFixture]
public class MyLongRunningTest : Log4NetLoggedTest
{
[Test]
[Category("LongRunning")]
public void ModelConvergesForS50()
{
Logger.Info("Starting test...");
var obj = new SomeClass();
obj.Logger = Logger;
obj.DoSomething();
// ...
}
}
}
I couldn't see you applying that instance of the logger that you use inside the class anywhere.

Castle Windsor won't inject Logger in a property!

I try to inject log4net in a ILogger property of my service class but the property is always NULL!
I've seen this topic but it doesn't help me!
How can I get Castle Windsor to automatically inject a property?
this is Program.cs
CastleContainer.Instance
.Install(
new RepositoriesInstaller(),
new PersistenceInstaller(),
new LoggerInstaller(),
new FormInstaller(),
new ServiceInstaller()
);
FrmStart form1 = CastleContainer.Resolve<FrmStart>(new {Id="666" });
I use log4net.config external file and this is my installer:
public class LoggerInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
}
#endregion
}
This is the class contains the property I want Windsor to inject:
public partial class FrmStart : Form
{
private EventService EventService;
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public FrmStart(EventService eventService, string Id)
: this()
{
Logger.Debug("xxx");
this.EventService = eventService;
this.id = Id;
}
Note that "eventService" and "Id" in the constructor are correctly injected!
If I try to inject the Logger in the constructor it works and I've the Logger object:
{log4net.Repository.Hierarchy.DefaultLoggerFactory+LoggerImpl}! :-(
I've tried to create a public property for EventService and Windsor can inject it properly! So I think the problem is related only to the ILogger interface.
I prepared a simple full-code example here:
using Castle.Core.Logging;
using Castle.Facilities.Logging;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace IocTest
{
public class LoggerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logger", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
}
}
public class LogicInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly()
.Pick()
.If(t => t.Name.StartsWith("Logic"))
.Configure((c => c.LifeStyle.Transient)));
}
}
class Program
{
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
container.Install(
new LoggerInstaller(),
new LogicInstaller()
);
LogicClass1 logic1 = container.Resolve<LogicClass1>();
LogicClass2 logic2 = container.Resolve<LogicClass2>();
}
}
public class LogicClass1
{
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public LogicClass1()
{
logger.Debug("Here logger is NullLogger!");
}
}
public class LogicClass2
{
public LogicClass2(ILogger logger)
{
logger.Debug("Here logger is properly injected!");
}
}
}
What's wrong?
A problem is where you are checking it:
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public LogicClass1()
{
logger.Debug("Here logger is NullLogger!");
}
The property injection will not happen until after the constructor is run, so checking the property value in the constructor will never show the value you are expecting
I was having the same problem. It was always null.
I managed to solve the problem by injecting the logger in the constructor this way:
public ILogger logger;
public MyController(ILogger logger)
{
this.logger = logger;
logger.Info("Something");
}
You could also initialize your Logger by using:
public ILogger Logger { get; set; }
public MyController()
{
Logger = NullLogger.Instance;
}

Categories