Inject object using MEF with information about destination object - c#

I am looking for a way to inject a logging object which wraps a log4net logger into various objects using MEF. The problem I currently have is that the logging object requires the type of the object it is a member of. I could get round this problem by setting the type property on the logging object within the constructor of the containing object, however this leaves the onus of setting the type on the developer, and there is no compile time restriction I can think of to enforce this.
I there a way to specify that when the logging object is generated by MEF and injected, its constructor parameter is set to the type of the target class of the injection?
My logger implements an interface
public interface ILogger
{
Type Type { get; }
}
An Example of the concrete implementation of this is
[Export(typeof(Ilogger))]
public class SimpleLogger : ILogger
{
public SimpleLogger(Type typeOfObjectToLogFor)
{
this.Type = typeOfObjectToLogFor
}
public Type Type { get; }
public void Info(string message)
{
//log the messsage including the type information
}
}
and it is currently consumed not using MEF as:
public class ExampleObject
{
private readonly ILogger logger = new SimpleLogger(typeof(ExampleObject));
public ExampleObject(){}
public void MethodThatLogs()
{
logger.Info("MethodThatLogs called");
}
}
and what I would like to do is inject it using constructor injection:
public class ExampleObject
{
private readonly ILogger logger;
[ImportingConstructor]
public ExampleObject(Ilogger injectedLogger)
{
logger = injectedLogger;
}
public void MethodThatLogs()
{
logger?.Info("MethodThatLogs called");
}
}
I could do all this with lazy evaluated reflection, but it feels like something that should be possible from a decent DI container, and hopefully that means that MEF will support it, cam anyone help?

By default, specifying an [Export] attribute, you're setting the PartCreationPolicy to Shared, which means that the container will create a singleton for your export - your logger.
But I suggest you to export not a class but a factory method that will accept one argument and create the logger for you.
class LoggerFactory
{
[Export("GetLogger")]
public ILogger GetLogger(Type type)
{
return new SimpleLogger(type);
}
}
class ExampleObject
{
private readonly ILogger logger;
[ImportingConstructor]
public ExampleObject([Import(ContractName = "GetLogger", AllowDefault = true)]Func<Type, ILogger> loggerCreator)
{
logger = loggerCreator?.Invoke(this.GetType());
}
}

Related

Simple Injector Parameter appended to Factory

For brevity, I'll use some short and generalized naming conventions. If I have:
public class Factory : IFactory
{
private readonly string dbConnection;
public Factory(string dbConnection)
{
this.dbConnection= dbConnection;
}
public IDataContext Create() => new DataContext(dbConnection);
}
The Factory class has a field, which is being set by the Constructor. How does Simple Injector support the passing of that parameter? If you implement:
public class Service
{
private IFactory Factory { get; }
public Service(IFactory factory)
{
Factory = factory;
}
public void Save()
{
using(var context = Factory.Create())
context.Insert(...);
}
}
The parameter is never actually passed to or through the Factory when it is initialized or instantiated. When you register the dependencies, it doesn't look it is possible:
ContainerFactory.Register<IFactory, Factory>(Lifestyle.Transient);
I was looking into the IEventHandler interface, that is apart of Simple Injector which looks like it would address this issue, but is that how you're supposed to pass a parameter in this instance?
container.RegisterSingleton<IFactory>(new Factory("constr"));

Ninject pass constructor argument typeof class that implements the interface

I am attempting to use Ninject with my application logging wrapper.
Here is the wrapper:
public class NLogLogger : ILogger
{
private readonly Logger _logger;
public NLogLogger(Type t)
{
_logger = LogManager.GetLogger(t.Name);
}
}
As you can see I am passing the type into the loggers constrctor, so I would use it like the following:
public class EntityObject
{
public ILogger Logger { get; set; }
public EntityObject()
{
Logger = new NLogLogger(typeof(EntityObject));
}
}
Now I cannot seem to find out how to do something similar with using Ninject.
Here is my binding module:
public class LoggerModule : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<NLogLogger>();
}
}
Now obviously I get an exception thrown because it cannot inject the type into the constructor. Any ideas how I can do this?
Error activating Type
No matching bindings are available, and the type is not self-bindable.
Activation path:
4) Injection of dependency Type into parameter t of constructor of type NLogLogger
3) Injection of dependency ILogger into parameter logger of constructor of type NzbGetSettingsService
2) Injection of dependency ISettingsService{NzbGetSettingsDto} into parameter nzbGetService of constructor of type DashboardController
1) Request for DashboardController
Assuming that your classes look like this:
public class EntityObject
{
public ILogger Logger { get; set; } //it is better by the way to convert this into a private field
public EntityObject(ILogger logger)
{
Logger = logger;
}
}
You would need to register your NLogLogger like this:
Bind<ILogger>().To<NLogLogger>()
.WithConstructorArgument(
typeof(Type),
x => x.Request.ParentContext.Plan.Type);

Inject a component property into another component's constructor parameter with Autofac

With Autofac IoC container, say one has the following scenario:
public interface IHaveASpecialProperty
{
SpecialType SpecialProperty { get; }
}
public class HaveASpecialPropertyImpl : IHaveASpecialProperty
{
// implementation
}
public class SomeComponent
{
public SomeComponent(SpecialType special)
{
_special = special;
// rest of construction
}
private readonly SpecialType _special;
// implementation: do something with _special
}
// in composition root:
containerBuilder.RegisterType<HaveASpecialPropertyImpl>
.As<IHaveASpecialProperty>();
containerBuilder.RegisterType<>(SomeComponent);
Is there a way to register, within Autofac container, the HaveASpecialPropertyImpl type to act as a kind of provider/ factory of SpecialType instances?
What I currently have is this classic approach:
public class SomeComponent
{
public SomeComponent(IHaveASpecialProperty specialProvider)
{
_special = specialProvider.SpecialProperty;
// rest of construction
}
private readonly SpecialType _special;
// implementation: do something with _special
}
The rationale is basically related to the Law of Demeter: specialProvider is used only to grab a SpecialType instance, which instead is the actual dependency needed and used by SomeComponent, so it seems reasonable to just inject that SpecialType instance, without concerning SomeComponent on where that instance comes from.
PS: I've read about Delegate Factories, not sure if that's the (only?) way to go.
You can register a delegate :
builder.Register(c => c.Resolve<IHaveASpecialProperty>().SpecialProperty)
.As<ISpecialType>();
Using this registration, each time you will resolve a ISpecialType Autofac will resolve a IHaveASpecialProperty and return the SpecialProperty property value as ISpecialType.

Static factories - good practice?

I've got a static log manager class that should return instances of a desired logger based on a parameter.
public static class LogManager {
private static ILoggerFactory Factory { ... }
public static ILogger GetLogger(string name) {
return Factory.Create(name);
}
}
Since the concrete implementation of ILoggerFactory must be set (initialization), I'm wondering if I should only keep a reference on the type of the implementation and return a new instance everytime the factory is requested - or if it's okay to keep a static reference of an instance of the implementation.
Version 1
private static Type _factoryType;
public static void SetFactory<TFactory>()
where TFactory : ILoggerFactory, new()
{
_factoryType = typeof(TFactory);
}
private static Factory {
get { return (ILoggerFactory)Activator.CreateInstance(_factoryType);
}
public static ILogger GetLogger(string name) {
return Factory.Create(name);
}
Version 2
private static ILoggerFactory _loggerFactory;
public static void SetFactory<TFactory>()
where TFactory : ILoggerFactory, new()
{
_loggerFactory = (ILoggerFactory)Activator.CreateInstance<TFactory();
}
public static ILogger GetLogger(string name) {
return _loggerFactory.Create(name);
}
Arguably, main difference appear to be in the lazy loading: v1 will create logger type when GetLogger is called, whereas v2 will create logger during SetFactory. There is not much of a difference otherwise. It is OK to keep a reference as a private static field to either the type of a logger or the factory itself.
However, if this is production code, I'd get rid of this log manager and factories altogether. Instead I'd use logging framework, like nlog or log4net directly. This simplifies code and makes it more maintainable. Building abstraction in this case is over-engineering.

C# derived class type needed in base for logging using NLog

We're using NLog for logging in an C# MVC3 web application. All of our controllers extend a custom base "ApplicationController" that gives us access to a constantly needed methodes and s members.
I'd like all controllers to have access to the Logger via this base class, but want the detail of knowing what derived class the log statements originated in.
Our application controller looks like this:
public abstract class ApplicationController : Controller
{
protected Logger _logger;
protected virtual Logger Logger
{
get { return _logger ?? (_logger = LogManager.GetCurrentClassLogger()); }
}
protected ApplicationController()
{
Context = new Entities();
}
If a derived controller doesn't override the Logger than all statements will show they originated from the Application controller. Currently, I've got essentially the same Logger statement in all derived controllers. For example:
public class PropertyController : ApplicationController
{
private readonly DatatapeService _datatapeService;
private readonly PropertyService _propertyService;
protected override Logger Logger
{
get { return _logger ?? (_logger = LogManager.GetCurrentClassLogger()); }
}
Obviously this is poor implementation practice.
How can I dry this up? Specifically, what is my understanding of C#
lacking to accomplish exactly this specific task?
Is there a logging pattern that I should be following where I'm not exposing the
logging class (NLog) directly?
TIA!
I am unfamiliar with NLog but in Log4Net the syntax
LogManager.GetLogger(this.GetType()) will accomplish what you want. GetTypereturns the leaf type in your inheritance hierarchy, even if called in the base ApplicationController class, when the logger is first created (ie: on first access to the Logger property) it will instantiate it with type PropertyController
NLog API is slightly different than Log4net. You need to use
Logger = LogManager.GetLogger(GetType().Name);
if you only pass the type, LogManager will expect a logger type (i.e. a custom logger)
The How to create Logger for sub classes page of the NLog wiki now suggests the following pattern:
class BaseClass
{
protected BaseClass()
{
Log = LogManager.GetLogger(GetType().ToString());
}
protected Logger Log { get; private set; }
}
class ExactClass : BaseClass
{
public ExactClass() : base() { }
...
}
Just check nLog wiki here
In most cases you will have one logger per class, so it makes
sense to give logger the same name as the current class.
Makes sense to do it like this
public abstract class ApplicationController : Controller
{
protected Logger _logger;
protected virtual Logger Logger(string className)
{
return LogManager.GetLogger(className);
}
}
public class PropertyController : ApplicationController
{
private readonly DatatapeService _datatapeService;
private readonly PropertyService _propertyService;
protected override Logger Logger()
{
return base.Logger("PropertyController ");
}
}

Categories