I am still fairly new to Autofac and Nlog and I need some help in understanding what is taking place in my Autofac LoggingModule for Nlog. It works as expected thanks to following the injecting-nlog-with-autofacs-registergeneric. But rather than just copy paste, I would like to make sure I understand what is occurring in each method (Load & AttachToComponentRegistration). If you could review my thoughts and further clarify anything I have incorrect (quite a bit I am sure), I would greatly appreciate it. Thank you in advance!
- Database Target using Nlog
- Dependency Injection using Autofac
- ASP.NET MVC web app for learning
- Dvd Libary app (DvdAdd, DvdEdit, DvdDelete, DvdList)
LoggingModule
public class LoggingModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder
.Register((c, p) => new LogService(p.TypedAs<Type>()))
.AsImplementedInterfaces();
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing +=
(sender, args) =>
{
var forType = args.Component.Activator.LimitType;
var logParameter = new ResolvedParameter(
(p, c) => p.ParameterType == typeof(ILog),
(p, c) => c.Resolve<ILog>(TypedParameter.From(forType)));
args.Parameters = args.Parameters.Union(new[] { logParameter });
};
}
}
My understanding of the code within Load()
c - The parameter c, provided to the expression, is the component context(an IComponentContext object) in which the component is being created. The context in which a service can be accessed or a component's dependencies resolved.
p - An IEnumerable with the incoming parameter set
AsImplementedInterfaces - Autofac allows its users to register the types explicitly or implicitly. While "As" is used for explicit registrations, "AsImplementedInterfaces" and "AsSelf" are used for implicit ones. In other words, the container automatically registers the implementation against all the interfaces it implements.
Thoughts: The Load method code registers a new LogService class (which represents "c") with the type of logger (which represents "p") as the constructor parameter for the LogService class
Questions:
- Are my thoughts above correct?
- Should it be SingleInstance or should it / will it only live as long as the calling classes scope? (I am thinking about my Unit Of Work)
My understanding of the code within AttachToComponentRegistration()
AttachToComponentRegistration method - Override to attach module-specific functionality to a component registration.
AttachToComponentRegistration Parameters:
- IComponentRegistry componentRegistry - Provides component registrations according to the services they provide.
- IComponentRegistration registration - Describes a logical component within the container.
registration.Preparing - Fired when a new instance is required. The instance can be provided in order to skip the regular activator, by setting the Instance property in the provided event arguments.
var forType = args.Component.Activator.LimitType;
args = Autofac.Core.PreparingEventArgs - Fired before the activation process to allow parameters to be changed or an alternative instance to be provided.
Component = PreparingEventArgs.Component Property - Gets the component providing the instance being activated
Activator = IComponentRegistration.Activator Property - Gets the activator used to create instances.
LimitType = IInstanceActivator.LimitType Property - Gets the most specific type that the component instances are known to be castable to.
Thoughts on forType
- As I understand it, this variable holds the Name
and FullName
of the calling class from where the logging service is being called?
Questions:
- Are my thoughts
forType
correct?
var logParameter = new ResolvedParameter(
(p, c) => p.ParameterType == typeof(ILog),
(p, c) => c.Resolve<ILog>(TypedParameter.From(forType)));
ResolvedParameter - can be used as a way to supply values dynamically retrieved from the container, e.g. by resolving a service by name.
Thoughts on logParameter
- This is where I start to get lost. So does, it check that the Parameter is of Type ILog and if so it will then resolve it with the constructor parameter and pass in forType
variable?
Questions:
- Are my thoughts on
logParameter
above correct?
args.Parameters = args.Parameters.Union(new[] { logParameter });
args.Parameters = PreparingEventArgs.Parameters Property - Gets or sets the parameters supplied to the activator.
args.Parameters.Union = Produces the set union of two sequences by using the default equality comparer. Returns an System.Collections.Generic.IEnumerable`1 that contains the elements from both input sequences, excluding duplicates.
Thoughts on args.Parameters
- I really do not know at this point other than to guess that it returns a collection of Parameters and removes duplicates?
Questions:
- Could you help talk me through what is going on in
args.Parameters
?
logParameter Debugger Image Nlog Database Table Image
LogService class
public class LogService : ILog
{
private readonly ILogger _log;
public LogService(Type type)
{
_log = LogManager.GetLogger(type.FullName);
}
public void Debug(string message, params object[] args)
{
Log(LogLevel.Debug, message, args);
}
public void Info(string message, params object[] args)
{
Log(LogLevel.Info, message, args);
}
public void Warn(string message, params object[] args)
{
Log(LogLevel.Warn, message, args);
}
public void Error(string message, params object[] args)
{
Log(LogLevel.Error, message, args);
}
public void Error(Exception ex)
{
Log(LogLevel.Error, null, null, ex);
}
public void Error(Exception ex, string message, params object[] args)
{
Log(LogLevel.Error, message, args, ex);
}
public void Fatal(Exception ex, string message, params object[] args)
{
Log(LogLevel.Fatal, message, args, ex);
}
private void Log(LogLevel level, string message, object[] args)
{
_log.Log(typeof(LogService), new LogEventInfo(level, _log.Name, null, message, args));
}
private void Log(LogLevel level, string message, object[] args, Exception ex)
{
_log.Log(typeof(LogService), new LogEventInfo(level, _log.Name, null, message, args, ex));
}
}
ILog interface
public interface ILog
{
void Debug(string message, params object[] args);
void Info(string message, params object[] args);
void Warn(string message, params object[] args);
void Error(string message, params object[] args);
void Error(Exception ex);
void Error(Exception ex, string message, params object[] args);
void Fatal(Exception ex, string message, params object[] args);
}