StructureMap override default Logger instance - c#

I have 2 projects
App (WindosForms used only as UI for starting components )
Components
Components has all interfaces and default implementation that I inject through StructureMap (Registry).
In this project i introduce a interface for Logging and default implementation for all classes (Log2Cnsole) and register with StructureMap.
What i need is that if some one wants to use his own UI app and remove default one I want that user of component DLL can override the default Log2Console with his, only if hi implement his (example LogToDB override Log2Console if he implement interface in his own project and register through StructureMap).
Sorry for my bad English.

The way to do this is offer a default constructor that calls another constructor with a specific implementation:
public interface ILogger
{
void Log(string text);
}
public class ConsoleLogger
{
public void Log(string text) { Console.WriteLine(text); }
}
public class TraceWriter
{
private ILogger log;
// Default behaviour
public TraceWriter () :
this(new ConsoleLogger()) { }
// User specified implementation
public TraceWriter ( ILogger logger )
{
this.log = logger;
}
}

Related

Is there a way to implement an adapter or interface without changing a class that uses it in this situation?

I'm trying to learn and understand interfaces, adapters, and dependency injection and how they can be used to achieve abstraction.
TLDR: How to change the way function\class uses the interface without changing said class\function's code?
I would also like it if you could point out errors in my thinking.
The Example:
Let's say I need to develop a logging mechanism (implement an ILogger interface) for some class (MoneyAdder) that I'm not allowed to modify. I also need to implement usage (please give me a correct term for this) of some other loggers via an adapter so we could choose the best way.
class MoneyAdder
{
private ILogger logger;
private Customer customer;
public MoneyAdder(ILogger logger, Customer customer)
{
this.logger = logger;
}
public void AddMoney(int amount)
{
logger.log("Doing work!");
customer.balance+=amount;
logger.log("I'm done!");
}
}
This is what I did at first:
public interface ILogger
{
void log(string str);
}
public class MyLogger : ILogger
{
public void log(string str)
{
Console.WriteLine($"LOG - {str}");
}
}
In this case, I have complete control over the interface definition, the class that implements it, and is able to use the log string that is given any way I want.
We know that OtherLogger requires a string and it's length to write a log. To use it I wrote an adapter like this:
public class OtherLogger
{
//We know it needs a string and its length for some reason.
public void log2(string str, int i);
}
public class OtherLoggerAdapter : ILogger
{
private OtherLogger ol = new OtherLogger();
public void log(string str)
{
ol.log2(str, str.Length);
}
}
This way I adapt the other dll to my interface. When the adapter is called I, in turn, call the different method name. I'm also able to provide an int it needs because it's computable from the input.
Now I need to add another logger that needs a log string and an assembly from which it was referenced. I'm able to provide it as well. It is not computable from the log string, but I'm able to give it any common information, like the environment variables or the program name because it is common for the program, MoneyAdder class, and StrangeLoggerAdapter.
public class StrangeLogger
{
public void logS(string str, System.Reflection.Assembly assembly);
}
public class StrangeLoggerAdapter : ILogger
{
private StrangeLogger sl = new StrangeLogger();
public void log(string str)
{
sl.logS(str, System.Reflection.Assembly.GetExecutingAssembly());
}
}
The final logger is an old mechanism that was used before. It was directly referenced and called inside MoneyAdder's other methods. (Tightly coupled, is this the correct term?). The logging method definition is as follows:
public class OldLogger
{
public void log(string str, string customerName);
}
It needs a customer name, but it is neither computable from the log string, nor it can be accessed from any adapter I can write. The only way to use it is to "inject" a customer name into a logger like this:
public interface ILogger
{
void log(string str);
void injectCustomer(string customerName);
}
And then to implement it in an adapter like this:
public class OldLoggerAdapter
{
private string customerName;
private OldLogger ol = new OldLogger();
public void injectCustomer(string customerName)
{
this.customerName = customerName;
}
public void log(string str)
{
ol.log(str, this.customerName);
}
}
However, to use the implementation I still need to modify (which I'm not allowed to do) either the MoneyAdder class or AddMoney method to use the injection function.
class MoneyAdder
{
private ILogger logger;
private Customer customer;
public MoneyAdder(ILogger logger, Customer customer)
{
this.logger = logger;
this.logger.injectCustomer(customer.Name);
}
public void AddMoney(int amount)
{
logger.log("Doing work!");
customer.balance+=amount;
logger.log("I'm done!");
}
}
The question:
To implement a logging function I can only use the information, that is either provided to the function via a method or can be computed from that information, or is global to the entire program.
There is no way to directly provide or inject information without modifying the calling function.
Or is there?
Is there a way, using some System\Reflexion\DI\IOC magic, to write something like:
Hey, MoneyAdder, It's an OldLogger that is currently used as ILogger. Whenever you call log(string str) you should actually call my method log(string str, string customerName). I know for sure you have a private property Customer that has a Customer.Name, use that in my log method as a "customerName".

How to pass CallingMemberName to custom logging provider

Using ASP.NET Core and implementing my own console logging provider with ILogging and ILoggingProvider as I want to pass the name of the calling function to the logger as part of the log record as well as date/time stamp.
The best way to retrieve the name of the calling function is to use [CallerMemberName] attribute in the function parameters, however as I'm trying to keep to the standard logging pattern and inheriting the ILogger interface I can't work out how to overload any of the Log method calls to use an additional function parameter to add the CallerMemberName attribute.
Here is the code in Main:
public class Program
{
static ILogger Logger { get; } = ApplicationLogging.CreateLogger<Program>();
public static void Main(string[] args)
{
ApplicationLogging.Logger.AddMyLogger();
Program.Logger.LogInformation("Test log");
...
}
}
Here is my custom logging provider
// Setup logging for all classes to use
public static class ApplicationLogging
{
public static ILoggerFactory Logger { get; } = new LoggerFactory();
public static ILogger CreateLogger<T>() =>
Logger.CreateLogger<T>();
}
public static class MyLoggerProviderExtensions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory loggerFactory)
{
loggerFactory.AddProvider(new MyLoggerProvider());
return loggerFactory;
}
}
public class MyLoggerProvider : ILoggerProvider
{
public MyLoggerProvider()
{
}
public ILogger CreateLogger(string categoryName)
{
return new MyLogger();
}
public void Dispose()
{
}
void IDisposable.Dispose()
{
throw new NotImplementedException();
}
}
public class MyLogger : ILogger
{
public MyLogger()
{
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Console.WriteLine("{0,-12} {1,-20} {2}", DateTime.Now.ToString("HH:mm:ss.fff"), " [NEED_CALLING_METHOD_NAME_HERE]", state);
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
If I add CallerMemberName to the Log method call then I'm not implementing as per the interface and it won't compile (as expected). I tried adding a class scoped variable and to set up the calling member name when instantiating the logger but that won't capture correct calling member.
I'm fairly new to C# so I might be missing the best way to do this - the way I see it I have to overload the Log function to add the [CallerMemberName] attribute but the standard logging call semantics (eg. LogCritical) won't use my overloaded function.
Of course I could just ditch my custom logging provider and write my own logging function which would be simpler but won't leverage the logging infrastructure provided by Microsoft. I know I can use Reflection but I'd prefer not to take the extra CPU hit as this software will run on very low end hardware.
In the Log function:
public void Log()
{
var stackTrace = new System.Diagnostics.StackTrace(1); // skip one frame as this is the Log function frame
var name = stackTrace.GetFrame(0).GetMethod().Name;
}
EDIT:
If you want to avoid reflection maybe:
using (_logger.BeginScope("name of method"))
{
// log the stuff
}
Not sure about .Net Core but in normal .Net you could add this by using Aspect Oriented Programming to multiple methods fairly easy.

Implementation and usage of logger wrapper for log4net

This question is related to Steven’s answer - here. He proposed a very good logger wrapper. I will paste his code below:
public interface ILogger
{
void Log(LogEntry entry);
}
public static class LoggerExtensions
{
public static void Log(this ILogger logger, string message)
{
logger.Log(new LogEntry(LoggingEventType.Information,
message, null));
}
public static void Log(this ILogger logger, Exception exception)
{
logger.Log(new LogEntry(LoggingEventType.Error,
exception.Message, exception));
}
// More methods here.
}
So, my question is what is the proper way to create implementation that proxies to log4net? Should I just add another Log extension method with type parameter and then create a switch inside? Use different log4net method in case of LoggingEventType ?
And second question, what is the best way to use it later in the code?
Because he wrote:
(…) you can easily create an ILogger implementation (…) and configure
your DI container to inject it in classes that have a ILogger in their
constructor.
Does that mean that every class that will log sth (so basically every), should have ILogger in its constructor?
So, my question is what is the proper way to create implementation that proxies to log4net?
you should create something like:
public class Log4netAdapter : ILogger
{
private readonly log4net.ILog m_Adaptee;
public Log4netAdapter(log4net.ILog adaptee)
{
m_Adaptee = adaptee;
}
public void Log(LogEntry entry)
{
//Here invoke m_Adaptee
if(entry.Severity == LoggingEventType.Debug)
m_Adaptee.Debug(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Information)
m_Adaptee.Info(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Warning)
m_Adaptee.Warn(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Error)
m_Adaptee.Error(entry.Message, entry.Exception);
else
m_Adaptee.Fatal(entry.Message, entry.Exception);
}
}
Does that mean that every class that will log sth (so basically every), should have ILogger in its constructor?
As I understand from Stevens answer: Yes, you should do this.
what is the best way to use it later in the code?
If you are using a DI container, then just use the DI container to map ILogger to Log4netAdapter. You also need to register log4net.ILog, or just give an instance of log4net logger to the DI container to inject it to the Log4netAdapter constructor.
If you don't use a DI container, i.e., you use Pure DI, then you do something like this:
ILog log = log4net.LogManager.GetLogger("MyClass");
ILogger logging_adapter = new Log4netAdapter(log);
var myobject = new MyClass(other_dependencies_here, logging_adapter);

Castle Windsor: How to specify different implementations for different properties of the same type [duplicate]

While registering components in Castle Windsor, how do we bind specific implementation of an interface to a component that has a dependency on that interface. I know in advance which implementation needs to be used by the component.
For example i created a sample console application based on code from several blogs and tutorials.
Following is the code.
public interface IReport
{
void LogReport();
}
public interface ILogger
{
string Log();
}
public class FileLogger : ILogger
{
public string Log()
{
return "Logged data to a file";
}
}
public class DatabaseLogger : ILogger
{
public string Log()
{
return "Logged data to a database";
}
}
public class McAfeeService : IReport
{
private readonly ILogger _logger;
public McAfeeService(ILogger logger)
{
this._logger = logger;
}
public void LogReport()
{
string getLogResult = this._logger.Log();
Console.WriteLine("McAfee Scan has " + getLogResult);
}
}
public class NortonService : IReport
{
private readonly ILogger _logger;
public NortonService(ILogger logger)
{
this._logger = logger;
}
public void LogReport()
{
string getLogResult = this._logger.Log();
Console.WriteLine("Norton Scan has " + getLogResult);
}
}
class Program
{
private static IWindsorContainer container;
static void Main(string[] args)
{
// Register components
container = new WindsorContainer();
container.Register(Component.For<IReport>().ImplementedBy<NortonService>());
container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>());
IReport service = container.Resolve<IReport>();
service.LogReport();
Console.ReadLine();
}
}
I would like NortonService to always use a Filelogger and McAfeeService to use a Database Logger.
In the above program i am unable to bind NortonService to FileLogger.
How to do it?
The above answers lead me to inline dependencies and the feature service override
Here is the registration code:
container.Register(Component.For<IReport>().ImplementedBy<NortonService>().Named("nortonService"));
container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>());
container.Register(Component.For<ILogger>().ImplementedBy<DatabaseLogger>());
container.Register(
Component.For<IReport>().ImplementedBy<McAfeeService>().Named("mcafeeService")
.DependsOn(Dependency.OnComponent<ILogger, DatabaseLogger>())
);
IReport mcafeescan = container.Resolve<IReport>("mcafeeService");
mcafeescan.LogReport();
IReport nortonscan = container.Resolve<IReport>("nortonService");
nortonscan.LogReport();
Output:
McAfee Scan has Logged data to a database
Norton Scan has Logged data to a file
I had a problem very like this, two implementation of one interface and two implementation of another interface. I wanted to force usage of particular implementations of those interfaces.
My class structure looked like this -
I looked at the naming convention, but didn't really like it. Instead I used the following -
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IMessageLoader>().ImplementedBy<MessageLoaderDatabase>()
,Component.For<IMessageLoader>().ImplementedBy<MessageLoaderFile>()
,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceDatabase>()
.DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderDatabase>())
,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceFile>()
.DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderFile>())
,Component.For<MessageOfTheDayController>().LifestyleTransient()
.DependsOn(Dependency.OnComponent<IMessageOfTheDayService, MessageOfTheDayServiceFile>())
);
Full info about this approach is here. In the source code provided with that post I show two other ways of achieving the same result.
If you want to do it at runtime, This can be acheived through IHandlerSelector. Write a class that implements IHandlerSelector. It provides a method SelectHandler which will let you define the condition for binding conditionally at runtime. A Handler in this case is a component in Windsor that participates in instance construction. Refer here for more details.
My answer maybe not the best one, you can use naming method to resolve multi implementation:
container.Register(Component.For(typeof(ILogger))
.ImplementedBy(typeof(FileLogger))
.Named("FileLoggerIoC")
.LifestylePerWebRequest() ,
Component.For(typeof(ILogger))
.ImplementedBy(typeof(DatabaseLogger))
.Named("DatabaseLoggerIoC")
.LifestylePerWebRequest());
In your calling functions, you need to resolve it by name :-
var fileLog = container.Resolve("FileLoggerIoC", typeof(ILogger));
var DbLog = container.Resolve("DatabaseLoggerIoC", typeof(ILogger));
Mine method maybe not the best one as people don't like service locator to get the components, you can use this as temporary solution.

How to Inject Log4Net ILog implementations using Unity 2.0

Ultimately this has to do with setting up log4Net but generically the problem is not logging specific.
Generically what I am trying to figure out is how to do, in Microsoft Unity 2.0, something equivalent to what one gets with the Castle.Facilities.Logging.LoggingFacility. Namely the ability to declare a dependency on a logger and have the logger initialized with the Type of the object into which it is being injected.
In the spirit of a test is worth a thousand words, here is what I need:
class Logger_IOC_Tests
{
//[Test]
public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
{
var container = new UnityContainer();
/* Configuration Magic probably involiving registering either
* a custom IDependencyResolverPolicy or BuilderStrategy
* goes here...
*/
container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());
var user = container.Resolve<LoggerUser>();
Assert.True(user.Logger.GetUserType() == user.GetType());
}
}
interface ILogger
{
Type GetUserType();
}
class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
public Type GetUserType()
{
return _type;
}
}
class LoggerUser
{
public readonly ILogger Logger;
public LoggerUser(ILogger logger)
{
Logger = logger;
}
}
I don't know if this what you are looking for, but I saw it a few months ago and was reminded of it when I saw your question. I have not used Unity, so I can't really compare what you have posted with what is at the link. Hopefully it will be useful to you:
http://davidkeaveny.blogspot.com/2011/03/unity-and-log4net.html
I've been trying to achieve the same result of being able to insert correctly configured ILog instances into a dependency using constructor injection with Unity.
In the end, I wrote my own "log4net" unity extension to do exactly this (in part inspired by a blog post that another answerer, Kenneth Baltrinic, wrote).
This allows you to register the extension once with Unity:
var container = new UnityContainer();
container.AddNewExtension<Log4NetExtension>();
and then have the correct ILog logger instance passed in:
public class MyClass
{
private readonly ILog logger;
public MyClass(ILog logger)
{
this.logger = logger;
}
}
The extension can be found here:
https://github.com/roblevine/UnityLoggingExtensions
More info here: http://blog.roblevine.co.uk/net/using-log4net-with-unity/
EDIT this is now available as a NuGet package
After hours of digging around in the Unity source code, I came up with the following solution. However, I would prefer to find a way to set the appropriate dependency resolver based on the type being resolved rather than overriding the default constructor selector policy. For one, because I previously overrode the default constructor selector for other purposes. For another, this solution only handles dependencies that are injected via constructor. For full coverage one would have to override the default property and method selectors as well I presume. For myself, I only need constructors.
class Logger_IOC_Tests
{
[Test]
public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
{
var container = new UnityContainer();
container.AddNewExtension<LoggingExtension>();
container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());
var user = container.Resolve<LoggerUser>();
Assert.True(user.Logger.GetUserType() == user.GetType());
}
}
class LoggingExtension : UnityContainerExtension
{
protected override void Initialize()
{
Context.Policies.SetDefault(typeof(IConstructorSelectorPolicy), new LoggingConstructorSelectorPolicy());
}
}
public class LoggingConstructorSelectorPolicy : DefaultUnityConstructorSelectorPolicy
{
protected override IDependencyResolverPolicy CreateResolver(ParameterInfo parameter)
{
return parameter.ParameterType == typeof(ILogger)
? new LoggerResolverPolicy(parameter.Member.DeclaringType)
: base.CreateResolver(parameter);
}
}
class LoggerResolverPolicy : IDependencyResolverPolicy
{
private readonly Type _dependantType;
public LoggerResolverPolicy(Type dependantType)
{
_dependantType = dependantType;
}
public object Resolve(IBuilderContext context)
{
return new Logger(_dependantType);
}
}
The above extension works well but more configuration information is needed for MVC5 users. Here are the steps using unity.
Add the following line to the top of your startup.cs class above the namespace.
[assembly: log4net.Config.XmlConfigurator(ConfigFile ="Web.config", Watch = true)]
In your global.asax application_startup method add the following information:
log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
The rest of the configuration to the unity container should be as is:
container.AddNewExtension<Log4NetExtension>();
Ensure you have an appender added to your web.config. That should be about it to get this working correctly. Good Luck
With Unity 5 and above, you can now use Unity's own Log4Net extension from https://github.com/unitycontainer/log4net.
All you have to do is install the Nuget and add the extension to your container:
container.AddNewExtension<Log4NetExtension>();
And it will work automatically with any classes that use ILog as a dependency.
You can use the following code to inject Log4Net
log4net.Config.BasicConfigurator.Configure();
container.RegisterType<ILog>(new InjectionFactory(x => LogManager.GetLogger(typeof(Program))));
typeof(Program) is used since I'm registering in program class. Use can use the class name or this keyword
Then you can inject ILog into the class
public class MyClass
{
private readonly ILog logger;
public MyClass(ILog logger)
{
this.logger = logger;
}
}

Categories

Resources