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 Microsoft.Extensions.Logging and what is the best way to use it later in the code?
Note: this question is a copy of this question about log4net but now specific to Microsoft.Extensions.Logging.
So, my question is what is the proper way to create implementation that proxies to Microsoft.Extensions.ILogger?
you should create something like:
public sealed class MicrosoftLoggingAdapter : ILogger
{
private readonly Microsoft.Extensions.ILogger adaptee;
public MicrosoftLoggingAdapter (Microsoft.Extensions.ILogger adaptee) =>
this.adaptee = adaptee;
public void Log(LogEntry e) =>
adaptee.Log(ToLevel(e.Severity), 0, e.Message, e.Exception, (s, _) => s);
private static LogLevel ToLevel(LoggingEventType s) =>
s == LoggingEventType.Debug ? LogLevel.Debug :
s == LoggingEventType.Information ? LogLevel.Information :
s == LoggingEventType.Warning ? LogLevel.Warning :
s == LoggingEventType.Error ? LogLevel.Error :
LogLevel.Critical;
}
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 MicrosoftLoggingAdapter. You also need to register Microsoft.Extensions.ILogger, or just give an instance of MS logger to the DI container to inject it to the MicrosoftLoggingAdapter constructor.
If you don't use a DI container, i.e., you use Pure DI, then you do something like this:
var logger = loggerFactory.CreateLogger("Application");
ILogger logging_adapter = new MicrosoftLoggingAdapter(logger);
var myobject = new MyClass(other_dependencies_here, logging_adapter);
Here is my solution. Not too unlike Steven's. But not exactly like it. And mine leans toward dotNetCore, but the same thing can be accomplished in dotnetFW.
DotNetCoreLogger is the concrete of "MY" ILogger. And I inject the "microsoft" ILogger (Microsoft.Extensions.Logging.ILogger) into "My" concrete logger.
There is another SOF answer that "inspired" "my" logging abstraction....and after going from DotNetFramework (classic) to DotNotCore, I am so glad I did a "my" ILogger abstraction.
using System;
namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
public interface ILogger
{
void Log(LogEntry entry);
void Log(string message);
void Log(Exception exception);
}
}
namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
public enum LoggingEventTypeEnum
{
Debug,
Information,
Warning,
Error,
Fatal
};
}
using System;
namespace MyApplication.Infrastructure.Logging.LoggingAbstractBase
{
public class LogEntry
{
public readonly LoggingEventTypeEnum Severity;
public readonly string Message;
public readonly Exception Exception;
public LogEntry(LoggingEventTypeEnum severity, string message, Exception exception = null)
{
if (message == null) throw new ArgumentNullException("message");
if (message == string.Empty) throw new ArgumentException("empty", "message");
this.Severity = severity;
this.Message = message;
this.Exception = exception;
}
}
}
using System;
using Microsoft.Extensions.Logging;
namespace MyApplication.Infrastructure.Logging.LoggingCoreConcrete
{
public class DotNetCoreLogger<T> : MyApplication.Infrastructure.Logging.LoggingAbstractBase.ILogger
{
private readonly ILogger<T> concreteLogger;
public DotNetCoreLogger(Microsoft.Extensions.Logging.ILogger<T> concreteLgr)
{
this.concreteLogger = concreteLgr ?? throw new ArgumentNullException("Microsoft.Extensions.Logging.ILogger is null");
}
public void Log(MyApplication.Infrastructure.Logging.LoggingAbstractBase.LogEntry entry)
{
if (null == entry)
{
throw new ArgumentNullException("LogEntry is null");
}
else
{
switch (entry.Severity)
{
case LoggingAbstractBase.LoggingEventTypeEnum.Debug:
this.concreteLogger.LogDebug(entry.Message);
break;
case LoggingAbstractBase.LoggingEventTypeEnum.Information:
this.concreteLogger.LogInformation(entry.Message);
break;
case LoggingAbstractBase.LoggingEventTypeEnum.Warning:
this.concreteLogger.LogWarning(entry.Message);
break;
case LoggingAbstractBase.LoggingEventTypeEnum.Error:
this.concreteLogger.LogError(entry.Message, entry.Exception);
break;
case LoggingAbstractBase.LoggingEventTypeEnum.Fatal:
this.concreteLogger.LogCritical(entry.Message, entry.Exception);
break;
default:
throw new ArgumentOutOfRangeException(string.Format("LogEntry.Severity out of range. (Severity='{0}')", entry.Severity));
}
}
}
public void Log(string message)
{
this.concreteLogger.LogInformation(message);
}
public void Log(Exception exception)
{
/* "Always pass exception as first parameter" from https://blog.rsuter.com/logging-with-ilogger-recommendations-and-best-practices/ */
/* there is an issue with https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Abstractions/LoggerExtensions.cs
* the default MessageFormatter (for the extension methods) is not doing anything with the "error". this plays out as not getting full exception information when using extension methods. :(
*
* private static string MessageFormatter(FormattedLogValues state, Exception error)
* {
* return state.ToString();
* }
*
* Below code/implementation is purposely NOT using any extension method(s) to bypass the above MessageFormatter mishap.
*
* */
this.concreteLogger.Log(LogLevel.Error, exception, exception.Message);
}
}
}
/* IoC/DI below */
private static System.IServiceProvider BuildDi(Microsoft.Extensions.Configuration.IConfiguration config)
{
//setup our DI
IServiceProvider serviceProvider = new ServiceCollection()
.AddLogging()
.AddSingleton<IConfiguration>(config)
.AddSingleton<MyApplication.Infrastructure.Logging.LoggingAbstractBase.ILogger, MyApplication.Infrastructure.Logging.LoggingCoreConcrete.DotNetCoreLogger<Program>>()
.BuildServiceProvider();
//configure console logging
serviceProvider
.GetService<ILoggerFactory>()
.AddConsole(LogLevel.Debug);
return serviceProvider;
}
Related
I have below unit test C# code,
public class ServiceTest
{
public readonly Service _sut;
private readonly Mock<IServiceClient> _serviceClientMock = new Mock<IServiceClient>();
private readonly Mock<ILogger<Service>> _loggerMock = new Mock<ILogger<Service>>();
public ServiceTest()
{
_sut = new Service(_serviceClientMock.Object, _loggerMock.Object);
}
[Fact]
public void Constructor_throws_Exception()
{
Assert.Throws<ArgumentNullException>(() => new Service(null, null));
}
[Fact]
public async Task Do_Test_For_DoMethod()
{
await _sut.DoMethod();
}
}
I have Constructor_throws_Exception which only covers one argument null exception, but not the other. How to cover both argument null exception plus the catch block for method? Is there a way I can merge with all in a single test? I am using xUnit.
You have to create a unique test for each invalid combination. Could be something like this:
public static IEnumerable<object[]> GetInvalidConstructorArguments()
{
yield return new object[] { new Mock<IServiceClient>().Object, null };
yield return new object[] { null, new Mock<ILogger<Service>>().Object };
}
[Theory]
[MemberData(nameof(GetInvalidConstructorArguments))]
public void ThrowsOnNullArgument(IServiceClient serviceClient, ILogger<Service> logger)
{
Assert.Throws<ArgumentNullException>(() => new Service(serviceClient, logger));
}
Getting a working mock for the ILogger<> is more complicated then it seems in the first spot. The problem is, that all convenient methods are extensions methods, which can't be mocked. Under the hood, all of these methods will call the Log<TState>() method which must be mocked. Thankfully to this answer, this can be done as follows:
public class MyTests
{
[Fact]
public void ExceptionShouldBeWrittenToLog()
{
// Instruct service client to throw exception when being called.
var serviceClient = new Mock<IServiceClient>();
var exception = new InvalidOperationException($"Some message {Guid.NewGuid()}");
serviceClient.Setup(s => s.Do()).Throws(exception);
// Create a strict mock, that shows, if an error log should be created.
var logger = new Mock<ILogger<MyService>>(MockBehavior.Strict);
logger.Setup(l => l.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((o, t) => o.ToString() == exception.Message),
It.IsAny<InvalidOperationException>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()));
// Setup SUT and call method.
var service = new MyService(serviceClient.Object, logger.Object);
service.DoSomething();
// Check if method of logger was being called.
logger.VerifyAll();
}
}
public interface IServiceClient
{
public void Do();
}
public class MyService
{
private readonly IServiceClient serviceClient;
private readonly ILogger<MyService> logger;
public MyService(IServiceClient serviceClient, ILogger<MyService> logger)
{
this.serviceClient = serviceClient;
this.logger = logger;
}
public void DoSomething()
{
try
{
serviceClient.Do();
}
catch (Exception ex)
{
logger.LogError(ex.Message);
}
}
}
I'm trying to make an unit test for a logger in an application.
For example I need to test the method Logger.info("some message"), but this method is static and return void.
Searching on Google I understand that I have to use Moq but am unable to implement that on the UnitTest class.
The Logger constructor does not have an argument and in x.Debug I have an error that says that I can't access
from instance reference.
Is there a way to implement UnitTest without editing the production code?
[TestClass()]
public class LoggerTests
{
[TestMethod()]
public void DebugTest()
{
var mock = new Mock<Logger>();
mock.Setup(x => x.Debug(It.IsAny<string>());
new Logger(mock.Object).AddLog("testing");
mock.VerifyAll;
}
}
Program.cs
private static void ConfigureLogger()
{
Logger.AddLog(new NLogAppender());
Logger.Level = TraceLevel.Verbose;
Logger.Info("Configured Logger");
}
Logger.cs
public class Logger
{
public static readonly List<IAppender> loggings = new List<IAppender>();
public static void AddLog(IAppender appender)
{
loggings.Add(appender);
}
public static TraceLevel Level { get; set; }
static Logger()
{
Level = TraceLevel.Verbose;
}
public static void Info(string message)
{
LogMessage(message);
}
}
NlogAppender.cs
public class NLogAppender : IAppender
{
public NLog.Logger logger;
public NLogAppender()
{
logger = LogManager.GetLogger(nameof(NLogAppender));
}
public void AddLog(string str)
{
}
}
IAppender.cs
public interface IAppender
{
void AddLog(string str);
}
You can't mock a static class, and you shouldn't mock the class/system under test.
Add a mock appender to the logger:
// Arrange
var logString = "test-info"
var appenderMock = new Mock<IAppender>();
appenderMock.Setup(a => a.AddLog(logString));
Logger.AddLog(appenderMock.Object);
// Act
Logger.Info(logString);
// Assert
// TODO: exactly once
appenderMock.VerifyAll();
Note this static class may persist data between tests causing unexpected results, consult your test framework for configuring this.
Apart from that, you usually don't want to roll your own logging infrastructure, there's lots of things you can do wrong and why reinvent the wheel? Plenty of ILogger(<T>) implementations around.
I'm following a c# tutorial on udemy and finding how the code works very confusing. I'll paste the code then explain why
public interface ILogger
{
void LogError(string message);
void LogInfo(string message);
}
public class DbMigrator
{
private readonly ILogger _logger;
public DbMigrator(ILogger logger)
{
_logger = logger;
}
public void Migrate()
{
_logger.LogInfo("Migrationg started at {0}" + DateTime.Now);
// Details of migrating the database
_logger.LogInfo("Migrationg finished at {0}" + DateTime.Now);
}
}
public class FileLogger : ILogger
{
private readonly string _path;
public FileLogger(string path)
{
_path = path;
}
public void LogError(string message)
{
Log(message, "ERROR");
}
public void LogInfo(string message)
{
Log(message, "INFO");
}
private void Log(string message, string messageType)
{
using (var streamWriter = new StreamWriter(_path, true))
{
streamWriter.WriteLine(messageType + ": " + message);
}
}
}
class Program
{
static void Main(string[] args)
{
var dbMigrator = new DbMigrator(new FileLogger("C:\\Projects\\log.txt"));
dbMigrator.Migrate();
}
}
I'm getting confused about how do interfaces work in memory(which I think is called the heap)
since dbmigrator calls migrate()
which is using type of Ilogger when an instance of FileLogger is passed but appears to work without explicitly casting which I'm finding very confusing to how it works.
Hopefully my question makes sense as a lot of these concepts are new to me and I'm struggling with the correct terminology to explain my confusion
Thanks
DbMigrator can call any class that implements the ILogger interface. It just happens you have a FileLogger, but you could also implement a logger that writes to a database, as long as you implement all the functions in the interface.
class MySuperLogger : ILogger
{
void LogError(string message) { /* do something super */ }
void LogInfo(string message) { /* do something super */ }
}
class Program
{
static void Main(string[] args)
{
var dbMigrator = new DbMigrator(new MySuperLogger());
dbMigrator.Migrate();
}
}
See how there is no difference in the dbMigrator code, just a different type of ILogger was created. Everything else is the same.
So I have a marker interface called IMessage.Then I have classes like:
public class MessageA: IMessage
{
}
Then I have message handlers defined as:
internal interface IMessageHandler<in T> where T: IMessage
{
void Handle(T message);
}
public class MessageAHandler : IMessageHandler<MessageA>
{
public void Handle(T message)
{
//Some logic here
}
}
I want to re-route these messages that I get to the corresponding message handlers when I get a new message. Example:
public class MessageReceiver
{
public void ReceiveMessage(IMessage message)
{
//somehow resolve the appropiate message handler here
messageHandler.Handle(message);
}
}
I can accomplish this right now by using factories like below but I need to have a dependency on each a new factory per different type of message. So I'm wondering if there is a way to create a single factory that will be smart enough to resolve the appropiate message handler?
public class MessageReceiver
{
private readonly Func<IMessageHandler<MessageA>> _messageAFactory;
public MessageReceiver(Func<IMessageHandler<MessageA>> messageAFactory)
{
_messageAFactory= messageAFactory;
}
public void ReceiveMessage(IMessage message)
{
if (message is MessageA)
{
var messageHandler = _messageAFactory();
messageHandler.Handle(message as MessageA);
}
// Add more if-statements here for more messages
}
}
Autofac Registration
public class InfrastructureModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//Register the types in the infrastructure assembly
builder.RegisterAssemblyTypes(ThisAssembly).AsImplementedInterfaces()
.InstancePerLifetimeScope();
//Register the message handlers
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(x => x.IsAssignableFrom(typeof(IMessageHandler<IMessage>)))
.InstancePerDependency().AsImplementedInterfaces();
}
}
First I'll make a small implementation for your messages, just a basic handled flag, in order to test
public class MessageA : IMessage
{
public bool Handled
{
get;
private set;
}
public void MarkAsHandled()
{
this.Handled = true;
}
}
public class MessageB : IMessage
{
public bool Handled
{
get;
private set;
}
public void MarkAsHandled()
{
this.Handled = true;
}
}
Now let's implement both handlers as:
public class MessageAHandler : IMessageHandler<MessageA>
{
public void Handle(MessageA message)
{
message.MarkAsHandled();
}
}
public class MessageBHandler : IMessageHandler<MessageB>
{
public void Handle(MessageB message)
{
message.MarkAsHandled();
}
}
As a side note, you might want to mark your IMessageHandler interface as public (I get compiler error if visibility is set as internal).
Now let's add a small handler:
public interface IMessageHandler
{
Type MessageType { get; }
void Handle(IMessage message);
}
public class MessageHandlerAdapter<T> : IMessageHandler where T : IMessage
{
private readonly Func<IMessageHandler<T>> handlerFactory;
public MessageHandlerAdapter(Func<IMessageHandler<T>> handlerFactory)
{
this.handlerFactory = handlerFactory;
}
public void Handle(IMessage message)
{
var handler = handlerFactory();
handler.Handle((T)message);
}
public Type MessageType
{
get { return typeof(T); }
}
}
We can now implement MessageReceiver this way:
public class MessageReceiver
{
private readonly IEnumerable<IMessageHandler> handlers;
public MessageReceiver(IEnumerable<IMessageHandler> handlers)
{
this.handlers = handlers;
}
public void ReceiveMessage(IMessage message)
{
var handler = this.handlers.Where(h => h.MessageType == message.GetType()).FirstOrDefault();
if (handler != null)
{
handler.Handle(message);
}
else
{
//Do something here, no handler found for message type
}
}
}
Now to test that our messages are processed properly, here is a small test:
[TestClass]
public class TestSelector
{
private IContainer container;
[TestMethod]
public void TestMethod()
{
var processor = container.Resolve<MessageReceiver>();
MessageA ma = new MessageA();
MessageB mb = new MessageB();
processor.ReceiveMessage(ma);
processor.ReceiveMessage(mb);
Assert.AreEqual(ma.Handled, true);
Assert.AreEqual(mb.Handled, true);
}
}
And we need to modify registration a bit, if opting for manual registration, we do as follow:
public TestSelector()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<MessageAHandler>().As<IMessageHandler<MessageA>>();
containerBuilder.RegisterType<MessageBHandler>().As<IMessageHandler<MessageB>>();
containerBuilder.RegisterType<MessageHandlerAdapter<MessageA>>().As<IMessageHandler>();
containerBuilder.RegisterType<MessageHandlerAdapter<MessageB>>().As<IMessageHandler>();
containerBuilder.RegisterType<MessageReceiver>();
this.container = containerBuilder.Build();
}
In here, we now need to register one handler and the relevant adapter.
It is also of course possible to perform assembly scan, but this requires a little bit more plumbing, since using:
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(x => x.IsAssignableFrom(typeof(IMessageHandler<IMessage>)))
.InstancePerDependency().AsImplementedInterfaces();
will not work
typeof(MessageAHandler).IsAssignableFrom(typeof(IMessageHandler<IMessage>))
will return false, since MessageAHandler implements IMessageHandler, not IMessageHandler
To do automatic discovery and registration, here is a snippet:
public TestSelector()
{
var containerBuilder = new ContainerBuilder();
Func<Type, Type> GetHandlerInterface = (t) => t.GetInterfaces()
.Where(iface => iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(IMessageHandler<>)).FirstOrDefault();
var handlerTypes = typeof(IMessage).Assembly.GetTypes()
.Where(type => type.IsClass
&& !type.IsAbstract
&& GetHandlerInterface(type) != null);
foreach (Type handlerType in handlerTypes)
{
Type messageType = GetHandlerInterface(handlerType).GetGenericArguments()[0];
var genericHandler = typeof(MessageHandlerAdapter<>).MakeGenericType(messageType);
containerBuilder.RegisterType(handlerType).AsImplementedInterfaces();
containerBuilder.RegisterType(genericHandler).As<IMessageHandler>();
}
containerBuilder.RegisterType<MessageReceiver>();
this.container = containerBuilder.Build();
}
For anyone who is still looking for better solution for auto dispatching to appropriate message handlers registered, there is a nice implementation via MediatR.This is awesome library which can dispatch messages to appropriate registered handlers, and has capability to post messages to multiples handlers.
It is best suited for CQRS scenarios and also for Async Web API, refer CQRS using MediatR . There is a nice support when using DI container like Autofac and StructuredMap, Refer to wiki page of MediatR wiki for full details on DI support.
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.