Search code examples
c#logginginterfacemvvmcross

How Interface is resolved in MvvmCross


In .Core project I have an interface for logging:

 public interface ILogger
{
    void Trace(string format, params object[] args);
    .........
    void Fatal(string format, params object[] args);
}

Which is used in a log service interface:

public interface ILogService
{
    ILogger GetLogger(string name);
    ILogger GetLogger(Type typeName);
    ILogger GetLogger<T>();
}

In .Droid project that interface is implemented:

 public class AndroidLogService : ILogService
{
    public ILogger GetLogger(string name)
    {
        return new AndroidLogger(name);
    }

    public ILogger GetLogger(Type typeName)
    {
        return GetLogger(typeName.Name);
    }

    public ILogger GetLogger<T>()
    {
        return GetLogger(typeof(T));
    }
}

In .Droid Setup.cs file AndroidLogService is registered:

 Mvx.LazyConstructAndRegisterSingleton<ILogService, AndroidLogService>();
 Mvx.LazyConstructAndRegisterSingleton<IFileService, AndroidFileService>();

and finally used in some file in .Droid project:

 private readonly ILogger _logger;

    public AndroidFileService(IContextService contextService, ILogService logService, IEncryptionService encryptionService)
    {
        _logger = logService.GetLogger<AndroidFileService>();
        .......
    }

Finally logs work like this:

_logger.Warn("Failed to retrieve logo. Error: {0}", ex);

My doubts and questions: AndroidFileService is never called with params that described above but from MvvmCross docs I've read that it's called Construction Injection

Ok, I understand this part but one thing is dark for me: Where ILogger implementation exists? I didn't find in the whole solution any part with something like

Mvx.RegisterType<ILogger , SomeLogger>();

How it can be? What a mechanism is used to register ILogger?


Solution

  • I found the answer.

    I went inside AndroidLogService in Setup.cs:

        public class AndroidLogService : ILogService
    {
        public ILogger GetLogger(string name)
        {
            return new AndroidLogger(name);
        }
    
        public ILogger GetLogger(Type typeName)
        {
            return GetLogger(typeName.Name);
        }
    
        public ILogger GetLogger<T>()
        {
            return GetLogger(typeof(T));
        }
    }
    

    Then I went inside AndroidLogger:

    using NLog;
    using ILogger = ....Services.Support.ILogger;//from .Core project
    namespace ....Android.Services.Support//from .Droid project
    {
    public class AndroidLogger : ILogger
    {
        private readonly NLog.ILogger _logger;
    
        public AndroidLogger(string name)
        {
            _logger = LogManager.GetLogger(name);
        }
        .................
    

    where I see that is used NLog which is built-in implementation of ILogger.

    So, when the build was created for android I inserted this snippet in 2 files: one from .Core project and another from .Droid

    _logger = logService.GetLogger<SomeViewModel>();
    String name = logService.GetType().Name;
    _logger.Debug("LogService name = {0} ", name);
    

    which resulted for both cases as LogService name = AndroidLogService.

    Before this check I thought that as .Core project doesn't have any reference to .Droid project, so, there are different implementations for them, but I was wrong: Interface implemented in .Droid/.iOs project also works for .Core project.