I have a section in appsettings.json which contains a list of libraries and their dependencies, and how to configure them in different execution environments.I'd like to be able to validate that the library collection includes all the dependencies.
That's easy enough to do with a little recursion. But I can't figure out how to override the configuration binding process so that I can do the validation.
The only way I've come up with is to create a raw collection of the libraries, based on appconfig.json, and then create a service which validates the collection and makes it available. Something like:
public class RawLibraries : List<Library>
{
}
public class LibraryResolver
{
public LibraryResolver( IOptions<RawLibraries> rawLibs, ILogger logger )
{
// validate rawLibs and log errors
}
// ...implementation
}
services.Configure<RawLibraries>(Configuration.GetSection("Libraries"));
services.AddSingleton<LibraryResolver, LibraryResolver>();
But this seems convoluted. Thoughts on a better approach?
Why not to follow the authors and write your own extension method with additional validation?
Take a look here. This is the source code of services.Configure<> method:
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extension methods for adding options services to the DI container.
/// </summary>
public static class OptionsServiceCollectionExtensions
{
...
/// <summary>
/// Registers an action used to configure a particular type of options.
/// </summary>
/// <typeparam name="TOptions">The options type to be configured.</typeparam>
/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> to add the services to.</param>
/// <param name="configureOptions">The action used to configure the options.</param>
/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> so that additional calls can be chained.</returns>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class
{
if (services == null)
throw new ArgumentNullException("services");
if (configureOptions == null)
throw new ArgumentNullException("configureOptions");
services.AddSingleton<IConfigureOptions<TOptions>>((IConfigureOptions<TOptions>) new ConfigureOptions<TOptions>(configureOptions));
return services;
}
}
}
As you can see Configure<TOptions> method is an extension method. Simply write your own let say ConfigureAndValidate<TOptions>() extension method which will do proper validation before services.AddSingleton... line.
Related
The UserService constructor has two parameters, a IUnitOfWork and a IUserRepository:
public UserService(IUnitOfWork unitofWork, IUserRepository userRepository)
{ ... }
I am using named registrations to differentiate between multiple instances of IUnitOfWork, so when registering the UserService with the Unity container, I need to explicitly specify the parameters using an InjectionConstructor:
container.RegisterType<IUserService, UserService>(
new InjectionConstructor(
new ResolvedParameter<IUnitOfWork>("someContext"),
new ResolvedParameter<IUserRepository>()
)
);
Is it possible for new ResolvedParameter<IUserRepository>() to be omitted? I would like Unity to implicitly deduce this parameter since there is no need for a named registration. The code would look like this:
container.RegisterType<IUserService, UserService>(
new InjectionConstructor(
new ResolvedParameter<IUnitOfWork>("someContext")
)
);
This would be done is any case when I don't need to use the InjectionConstructor.
Based on InjectionConstructor, I came up with this RequiredInjectionConstructor. It allows you to specify any set of arguments and it will attempt to find a constructor which is required to have (at a minimum) the passed set of injection parameters. If there are multiple constructors that meet this criteria, it chooses the constructor with the least number of parameters. The remaining constructor parameters are assumed to be unnamed resolved parameters.
I haven't performed a full suite of unit tests on it yet, so let me know if you encounter any issues.
/// <summary>
/// A class that holds the collection of minimum required
/// parameters for a constructor, so that the container can
/// be configured to call this constructor.
/// </summary>
public class RequiredInjectionConstructor : InjectionMember
{
private readonly List<InjectionParameterValue> _requiredParameterValues;
/// <summary>
/// Create a new instance of <see cref="RequiredInjectionConstructor"/> that looks
/// for a constructor with a minimum of the given required set of parameters.
/// </summary>
/// <param name="requiredParameterValues">The values for the parameters, that will
/// be converted to <see cref="InjectionParameterValue"/> objects.</param>
public RequiredInjectionConstructor(params object[] requiredParameterValues)
{
_requiredParameterValues = InjectionParameterValue.ToParameters(requiredParameterValues).ToList();
}
/// <summary>
/// Add policies to the <paramref name="policies"/> to configure the
/// container to call this constructor with the required parameter values.
/// </summary>
/// <param name="serviceType">Interface registered, ignored in this implementation.</param>
/// <param name="implementationType">Type to register.</param>
/// <param name="name">Name used to resolve the type object.</param>
/// <param name="policies">Policy list to add policies to.</param>
public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
{
ConstructorInfo ctor = FindConstructor(implementationType, _requiredParameterValues);
IEnumerable<InjectionParameterValue> selectedConstructorParameterValues = GetSelectedConstructorParameterValues(ctor, _requiredParameterValues);
policies.Set<IConstructorSelectorPolicy>(
new SpecifiedConstructorSelectorPolicy(ctor, selectedConstructorParameterValues.ToArray()),
new NamedTypeBuildKey(implementationType, name));
}
private static ConstructorInfo FindConstructor(Type typeToCreate, IEnumerable<InjectionParameterValue> requiredInjectionParameters)
{
var typeToCreateReflector = new ReflectionHelper(typeToCreate);
var matchedConstructors = typeToCreateReflector.InstanceConstructors.
Where(ctor =>
{
var constructorParameterTypes = ctor.GetParameters().Select(info => info.ParameterType);
return requiredInjectionParameters.All(required => constructorParameterTypes.Any(required.MatchesType));
});
if (matchedConstructors.Any())
{
// Prefer the constructor that has the least number of arguments.
// Other preference models could be implemented here.
return matchedConstructors.OrderBy(ctor =>
ctor.GetParameters().Count()).
FirstOrDefault();
}
string signature = string.Join(", ", requiredInjectionParameters.Select(required => required.ParameterTypeName).ToArray());
throw new InvalidOperationException(
string.Format("Unable to find a constructor with the minimum required parameters. Type: {0}, RequiredParameters: {1}",
typeToCreate.FullName,
signature));
}
private static IEnumerable<InjectionParameterValue> GetSelectedConstructorParameterValues(ConstructorInfo ctor, IEnumerable<InjectionParameterValue> requiredInjectionParameters)
{
var injectionParameterValues = new List<InjectionParameterValue>();
foreach (var parameter in ctor.GetParameters())
{
var existingInjectionParameter = requiredInjectionParameters.FirstOrDefault(required => required.MatchesType(parameter.ParameterType));
injectionParameterValues.Add(existingInjectionParameter ?? new ResolvedParameter(parameter.ParameterType));
}
return injectionParameterValues;
}
}
Would you be willing to decorate your constructor with the DependencyAttribute from Unity? This solution is straight forward, built-in, and lets you pick and chose named dependency. But it does 'dirty' your constructor with Unity goo.
public UserService(
[Dependency("someContext")]IUnitOfWork unitofWork,
IUserRepository userRepository)
{ ... }
Another solution would be to write a custom BuilderStrategy and UnityContainerExtension. This could be done with a bit more work.
I am developing an application and I started to use as my base some code from an example by John Papa. Looking on the web I found this same code and it appears in an answer to a question on
Stackoverflow. Here is the question:
How to de-attach an entity from a Context in Entity Framework?
It's in the answer that was given by: SynerCoder
One part of the answer suggests the following class that is used to provide a repository from a dictionary of cached repositories. Can someone help me out and tell me is there really
an advantage in doing this. I understand the code but can't see the point of keeping repositories in a dictionary. Would it not be the case that every new web request would see an
empty dictionary and have to get / make a new repository anyway.
Data/Helpers/IRepositoryProvider.cs
using System;
using System.Collections.Generic;
using System.Data.Entity;
using Data.Contracts;
namespace Data.Helpers
{
/// <summary>
/// A maker of Repositories.
/// </summary>
/// <remarks>
/// An instance of this class contains repository factory functions for different types.
/// Each factory function takes an EF <see cref="DbContext"/> and returns
/// a repository bound to that DbContext.
/// <para>
/// Designed to be a "Singleton", configured at web application start with
/// all of the factory functions needed to create any type of repository.
/// Should be thread-safe to use because it is configured at app start,
/// before any request for a factory, and should be immutable thereafter.
/// </para>
/// </remarks>
public class RepositoryFactories
{
/// <summary>
/// Return the runtime repository factory functions,
/// each one is a factory for a repository of a particular type.
/// </summary>
/// <remarks>
/// MODIFY THIS METHOD TO ADD CUSTOM FACTORY FUNCTIONS
/// </remarks>
private IDictionary<Type, Func<DbContext, object>> GetFactories()
{
return new Dictionary<Type, Func<DbContext, object>>
{
//If you have an custom implementation of an IRepository<T>
//{typeof(IArticleRepository), dbContext => new ArticleRepository(dbContext)}
};
}
/// <summary>
/// Constructor that initializes with runtime repository factories
/// </summary>
public RepositoryFactories()
{
_repositoryFactories = GetFactories();
}
/// <summary>
/// Constructor that initializes with an arbitrary collection of factories
/// </summary>
/// <param name="factories">
/// The repository factory functions for this instance.
/// </param>
/// <remarks>
/// This ctor is primarily useful for testing this class
/// </remarks>
public RepositoryFactories(IDictionary<Type, Func<DbContext, object>> factories)
{
_repositoryFactories = factories;
}
/// <summary>
/// Get the repository factory function for the type.
/// </summary>
/// <typeparam name="T">Type serving as the repository factory lookup key.</typeparam>
/// <returns>The repository function if found, else null.</returns>
/// <remarks>
/// The type parameter, T, is typically the repository type
/// but could be any type (e.g., an entity type)
/// </remarks>
public Func<DbContext, object> GetRepositoryFactory<T>()
{
Func<DbContext, object> factory;
_repositoryFactories.TryGetValue(typeof(T), out factory);
return factory;
}
/// <summary>
/// Get the factory for <see cref="IRepository{T}"/> where T is an entity type.
/// </summary>
/// <typeparam name="T">The root type of the repository, typically an entity type.</typeparam>
/// <returns>
/// A factory that creates the <see cref="IRepository{T}"/>, given an EF <see cref="DbContext"/>.
/// </returns>
/// <remarks>
/// Looks first for a custom factory in <see cref="_repositoryFactories"/>.
/// If not, falls back to the <see cref="DefaultEntityRepositoryFactory{T}"/>.
/// You can substitute an alternative factory for the default one by adding
/// a repository factory for type "T" to <see cref="_repositoryFactories"/>.
/// </remarks>
public Func<DbContext, object> GetRepositoryFactoryForEntityType<T>() where T : class
{
return GetRepositoryFactory<T>() ?? DefaultEntityRepositoryFactory<T>();
}
/// <summary>
/// Default factory for a <see cref="IRepository{T}"/> where T is an entity.
/// </summary>
/// <typeparam name="T">Type of the repository's root entity</typeparam>
protected virtual Func<DbContext, object> DefaultEntityRepositoryFactory<T>() where T : class
{
return dbContext => new EFRepository<T>(dbContext);
}
/// <summary>
/// Get the dictionary of repository factory functions.
/// </summary>
/// <remarks>
/// A dictionary key is a System.Type, typically a repository type.
/// A value is a repository factory function
/// that takes a <see cref="DbContext"/> argument and returns
/// a repository object. Caller must know how to cast it.
/// </remarks>
private readonly IDictionary<Type, Func<DbContext, object>> _repositoryFactories;
}
}
Here's the code that calls the factory:
using System;
using Data.Contracts;
using Data.Helpers;
using Models;
namespace Data
{
/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();
repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}
// Repositories
public IRepository<Event> Events { get { return GetStandardRepo<Event>(); } }
public IRepository<Candidate> Candidates { get { return GetStandardRepo<Candidate>(); } }
/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}
protected void CreateDbContext()
{
DbContext = new UnicornsContext();
// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;
// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;
// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}
protected IRepositoryProvider RepositoryProvider { get; set; }
private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}
private UnicornsContext DbContext { get; set; }
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}
#endregion
}
}
It seems to me that the factory makes things more complicated that they need be. Am I correct and should I do this a simpler way such as with something like:
private IRepository<xx> = new GenericRepository<xx>(dbContext);
One more point. In my application I am using Unity. So would it be even easier to just specify the needed repositories in the constructor and have Unity create the repositories for me. If I did this then is there a way I could pass around the dbContext so it could be used by Unity when creating the repository? Has anyone used Unity to create repositories like this?
OK. Here's my best shot:
The point of keeping repositories in a cache is to ensure that the repository is only initiated once per request. The repository cache is in the RepositoryProvider class and is exposed to the UnitOfWork by the GetRepositoryForEntityType method. So the advantage is that the unit of work is not concerned with caching or creation of repositories.
The RepositoryProvider class is instantiated once per unit of work. (NB - it is desirable to create the repositories new for every request). The RepositoryProvider keeps the repositories in a dictionary using the type as a key. This is fine when using the generic repository base which has a Type parameter. But what if you have created a custom repository? In this example the creation of repositories by type is handed off to the RepositoryFactories class via the MakeRepository method. The advantage is that creating repositories is separated from caching.
The RepositoryFactories class knows when to make a custom repository because it contains a dictionary that uses Type as a key and a function as a value. The function is the constructor for a custom repository. If there's a value in the dictionary then use that constructor otherwise just use the generic base constructor.
All this means that as you add entities you do not have to modify any of these classes unless you create a custom repository. And when you do that all you have to do is add an entry to the dictionary in RepositoryFactories
I have successfully created a working custom STS using the project templates for the passive and active cases that came with the most recent WIF SDK (for .NET 4.0). Everything works as desired.
I am now trying to upgrade my web applications and services to .NET 4.5, including my custom STS. I have been able to map all of the namespaces/classes from Microsoft.IdentityModel.xxx to the new namespaces/classes built into the framework with 1 exception - WSTrustServiceHostFactory.
That class no longer seems to exist, and I cannot figure out how to replace the functionality it provided. Namely, from this link:
http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.protocols.wstrust.wstrustservicehostfactory
<%#ServiceHostLanguage="C#"Debug="true"Service="XXX.XXX.MyActiveSTSConfiguration"Factory="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceHostFactory"%>
My passive STS is currently working after upgrading to 4.5. I need to find an appropriate/recommended method of instantiating an active SecurityTokenService using the 4.5 framework (ideally, using web.config for most configuration as in the SDK project templates). Any suggestions are appreciated.
This turned out to be pretty simple once I figured a few things out.
Service host markup:
<%# ServiceHost Language="C#" Debug="true" Service="XXX.XXX.MyActiveSTSConfiguration" Factory="XXX.XXX.CustomWSTrustServiceHostFactory" %>
Here's my custom factory class implementation. The key is that since you can no longer use WSTrustServiceFactory to create a WSTrustServiceHost for you, you have to explicitly create one yourself in the CreateServiceHost method overrides.
public class CustomWSTrustServiceHostFactory
: ServiceHostFactory {
/// <summary>
/// Initializes a new instance of the <see cref="CustomWSTrustServiceHostFactory"/> class.
/// </summary>
public CustomWSTrustServiceHostFactory()
: base() { }
/// <summary>
/// Creates and configures a <see cref="WSTrustServiceHost"/> with a specific base address.
/// </summary>
/// <param name="serviceType">Specifies the type of service to host (ignored).</param>
/// <param name="baseAddresses">The <see cref="T:Uri"/> array that contains the base addresses for the service.</param>
/// <returns>A <see cref="WSTrustServiceHost"/> with a specific base address.</returns>
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) {
var config = new PortalActiveSTSConfiguration();
var host = new WSTrustServiceHost(config, baseAddresses);
//var host = base.CreateServiceHost(serviceType, baseAddresses);
var serviceBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
serviceBehavior.AddressFilterMode = AddressFilterMode.Any;
return host;
}
/// <summary>
/// Creates and configures a <see cref="WSTrustServiceHost"/> with a specific base address.
/// </summary>
/// <param name="constructorString">The constructor string (ignored).</param>
/// <param name="baseAddresses">The <see cref="T:Uri"/> array that contains the base addresses for the service.</param>
/// <returns></returns>
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) {
var config = new PortalActiveSTSConfiguration();
var host = new WSTrustServiceHost(config, baseAddresses);
//var host = base.CreateServiceHost(constructorString, baseAddresses);
var serviceBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
serviceBehavior.AddressFilterMode = AddressFilterMode.Any;
return host;
}
}
Custom service configuration class implementation (basically what came with the WIF 4.0 STS template):
public class MyActiveSTSConfiguration
: SecurityTokenServiceConfiguration {
public MyActiveSTSConfiguration()
: base(
WebConfigurationManager.AppSettings[ISSUER_NAME],
new X509SigningCredentials(
CertificateUtil.GetCertificate(
StoreName.My, StoreLocation.LocalMachine, X509FindType.FindByThumbprint,
WebConfigurationManager.AppSettings[SIGNING_CERTIFICATE_THUMBPRINT],
true)
)
) {
this.SecurityTokenService = typeof(MyActiveSTS);
}
}
Looked for a method on the MvcContrib.TestHelper.RouteTestingExtensions class named ShouldNotMap. There is ShouldBeIgnored, but I don't want to test an IgnoreRoute invocation. I want to test that a specific incoming route should not be mapped to any resource.
Is there a way to do this using MvcContrib TestHelper?
Update
Just tried this, and it seems to work. Is this the correct way?
"~/do/not/map/this".Route().ShouldBeNull();
I think you are looking for the following:
"~/do/not/map/this".ShouldBeIgnored();
Behind the scenes this asserts that the route is processed by StopRoutingHandler.
I was looking for the same thing. I ended up adding the following extension methods to implement ShouldBeNull and the even shorter ShouldNotMap:
In RouteTestingExtensions.cs:
/// <summary>
/// Verifies that no corresponding route is defined.
/// </summary>
/// <param name="relativeUrl"></param>
public static void ShouldNotMap(this string relativeUrl)
{
RouteData routeData = relativeUrl.Route();
routeData.ShouldBeNull(string.Format("URL '{0}' shouldn't map.", relativeUrl));
}
/// <summary>
/// Verifies that the <see cref="RouteData">routeData</see> is null.
/// </summary>
public static void ShouldNotMap(this RouteData routeData)
{
routeData.ShouldBeNull("URL should not map.");
}
In GeneralTestExtensions.cs :
///<summary>
/// Asserts that the object should be null.
///</summary>
///<param name="actual"></param>
///<param name="message"></param>
///<exception cref="AssertFailedException"></exception>
public static void ShouldBeNull(this object actual, string message)
{
if (actual != null)
{
throw new AssertFailedException(message);
}
}
I am wondering what is the best way to use NLog with Managed Extensibility Framework (MEF)?
I have an application that support plugins using MEF architecture (Import and Exports etc)
I want to add logging capability to my application.
As a logging component I want to use NLog.
What would you recommend?
1. Create a wrapper for NLog, i.e. additional plugin that configures NLog and exports functions like void Log(string level, string message) that other plugins importing
2. Every plugin should have it is own instance of NLog configured and used. (They all would write to the same file actually).
This is an interesting approach, however, it seems to suffer from the drawback that all loggers that are injected (or the one singleton that is injected) will be the same instance (or will have the same name, the name being the name of the NLogLoggingService class. That means that you cannot very easily control the granularity of logging (i.e. turn logging to "Info" level in one class and "Warn" in another class). Also, if you opt to use the call site formatting tokens, you will always get the call site of the call the the NLog logger rather than the call site in your application code.
Here is an abbreviated version of the logger that was linked:
[Export(Services.Logging.LoggingService, typeof(ILoggingService))]
class NLogLoggingService : ILoggingService
{
Logger log; public NLogLoggingService()
{
log = LogManager.GetCurrentClassLogger();
}
public void Debug(object message)
{
log.Debug(message);
}
public void DebugWithFormat(string format, params object[] args)
{
if (args.Length == 0)
{
log.Debug(format);
}
else
{
Debug(string.Format(format, args));
}
}
public bool IsDebugEnabled
{
get
{
return log.IsDebugEnabled;
}
}
}
In the constructor LogManager.GetCurrentClassLogger() is used to get the NLog logger. GetCurrentClassLogger will return a NLog logger that is "named" based on the "current" type, which, in this case, is NLogLoggingService. So, to configure NLog in the app.config file, you will configure based on the that the logger is named "SoapBox.Core.NLogLoggingService". Commonly, in code that uses NLog (or log4net) directly, each class gets its own uniquely named logger like this:
namespace MyNamespace
{
public class MyClass1
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass1.DoSomeWork");
}
}
public class MyClass2
{
private static readonly Logger logger LogManager.GetCurrentClassLogger();
public void DoSomeWork()
{
logger.Info("Logging from inside MyClass2.DoSomeWork");
}
}
}
Now the logging for MyClass1 and MyClass2 is individually controllable. You can configure different levels for each class, send them to different targets, or turn one or both off altogether. Alternatively, due to the concept of logger hierarchies in both log4net and NLog, you could control the logging in both class simultaneously by configuring a "logger" for the namespace (MyNamespace in this case), or any "ancestor" namespace. If there is not a logger configured for the fully qualified typename, then the logging framework essentially moves up the hierarchy by considering the name a dot delimited string and removing the last chunk and checking to see if that logger is configured. So, in this case, we are requesting loggers for MyNamespace.MyClass1 and MyNamespace.MyClass2. I could configure the app.config file to have MyNamespace log at the "info" and write to a file target (appender in log4net-speak). If I did that, then both loggers that I requested via their fully qualified names would inherit the MyNamespace configuration.
With the suggested way of injecting NLog via MEF, you will only have one logger instance, so you cannot configure each class to log differently. Also, as I mentioned earlier, if you opt to log call site information, you will always get "SoapBox.Core.NLogLoggingService" for the class and "Debug" (or DebugWithFormat, or Info, or InfoWithFormat, etc) for the method.
This seems to be an issue with successfully injecting loggers from log4net and NLog. You can see the question that I asked about this very issue a couple of months ago.
Ultimately I was able to figure out how some dependency injection frameworks can successfully inject log4net and NLog loggers that are specific to the class being created (i.e. if the DI framework is instantiating MyClass, which in turn depends on an ILogger interface, then MyClass will get a logger that is essentially equivalent to what would have happened if MyClass requested the logger itself via the LogManager.GetCurrentClassLogger api). Generally "resolvers" in DI/IoC frameworks are given the current context (containing, among other information, the type of the object currently being created). With that type available, it becomes a simple matter of having a logging framework-specific resolver receive that type and pass it along to the logging framework to create a logger appropriate for that type.
In order to get the most out of NLog's (and log4net's) capabilities you would really like to be able to tell MEF that your class is dependendent on "ILogger", but also that the instance of "ILogger" that gets injected into your class should depend on the Type of your class.
I don't know how easy it will be to achieve that with MEF. Alternatively, you could wrap NLog's static LogManager in a ILogManager and inject that. That would deviate from the normal "inject ILogger" paradigm.
To summarize: If you inject NLog via MEF this way, you will indeed be able to log with NLog, but you will only ever have one named logger (SoapBox.Core.NLogLoggingService). This means that you will not be able control with any degree of granularity - either for levels/on/off or for output (NLog Target/log4net Appender)
I don't have a good answer for what to do as far as injecting NLog via MEF AND keeping the granularity/flexibility that "raw" NLog gives you.
I can say that we have decided to use Common.Logging for .NET to abstract the logging framework but we decided NOT to inject logging. Instead, we will just use a static LogManager (as provided by Common.Logging) to hand out loggers.
I think Option 1 is better.
You can take a look at how the open source framework SoapBox Core imports a reference to an ILoggingService using MEF. It also provides a default implementation of the logging service based on NLog, but you could easily swap it out for log4Net, for example.
For reference:
the ILoggingService interface
the Logging Service that wraps NLog and exports itself using MEF
SoapBox Core is LGPL'd, so you might be able to use (this part) in your application.
I have been fighting with this problem a while now.
Really improtant was the Callsite (FullyQualified Namespace) within the logfiles.
First, i tryed to get the right logger out of the Stacktrace:
[MethodImpl(MethodImplOptions.NoInlining)]
private static NLog.Logger GetLogger()
{
var stackTrace = new StackTrace(false);
StackFrame[] frames = stackTrace.GetFrames();
if (null == frames) throw new ArgumentException("Stack frame array is null.");
StackFrame stackFrame;
switch (frames.Length)
{
case 0:
throw new ArgumentException("Length of stack frames is 0.");
case 1:
case 2:
stackFrame = frames[frames.Length - 1];
break;
default:
stackFrame = stackTrace.GetFrame(2);
break;
}
Type declaringType = stackFrame.GetMethod()
.DeclaringType;
return declaringType == null ? LogManager.GetCurrentClassLogger() : LogManager.GetLogger(declaringType.FullName);
}
But sadly, the Stacktrace with MEF is very long and i cannot clearly identify the correct caller for the Requester of the ILogger.
So, instead of injecting the ILogger Interface via Constructor Injection, i have created a ILogFactory Interface, that can get injected via Constructor Injection and call then the Create Method on the Factory
public interface ILogFactory
{
#region Public Methods and Operators
/// <summary>
/// Creates a logger with the Callsite of the given Type
/// </summary>
/// <example>
/// factory.Create(GetType());
/// </example>
/// <param name="type">The type.</param>
/// <returns></returns>
ILogger Create(Type type);
#endregion
}
And implemented it:
using System;
using System.ComponentModel.Composition;
[Export(typeof(ILogFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class LogFactory : ILogFactory
{
#region Public Methods and Operators
public ILogger Create(Type type)
{
var logger = new Logger().CreateLogger(type);
return logger;
}
#endregion
}
With the ILogger:
public interface ILogger
{
#region Public Properties
bool IsDebugEnabled { get; }
bool IsErrorEnabled { get; }
bool IsFatalEnabled { get; }
bool IsInfoEnabled { get; }
bool IsTraceEnabled { get; }
bool IsWarnEnabled { get; }
#endregion
#region Public Methods and Operators
void Debug(Exception exception);
void Debug(string format, params object[] args);
void Debug(Exception exception, string format, params object[] args);
void Error(Exception exception);
void Error(string format, params object[] args);
void Error(Exception exception, string format, params object[] args);
void Fatal(Exception exception);
void Fatal(string format, params object[] args);
void Fatal(Exception exception, string format, params object[] args);
void Info(Exception exception);
void Info(string format, params object[] args);
void Info(Exception exception, string format, params object[] args);
void Trace(Exception exception);
void Trace(string format, params object[] args);
void Trace(Exception exception, string format, params object[] args);
void Warn(Exception exception);
void Warn(string format, params object[] args);
void Warn(Exception exception, string format, params object[] args);
#endregion
}
and Implementation of:
using System;
using NLog;
using NLog.Config;
/// <summary>
/// The logging service.
/// </summary>
public class Logger : NLog.Logger, ILogger
{
#region Fields
private string _loggerName;
#endregion
#region Public Methods and Operators
/// <summary>
/// The get logging service.
/// </summary>
/// <returns>
/// The <see cref="ILogger" />.
/// </returns>
public ILogger CreateLogger(Type type)
{
if (type == null) throw new ArgumentNullException("type");
_loggerName = type.FullName;
var logger = (ILogger)LogManager.GetLogger(_loggerName, typeof(Logger));
return logger;
}
To use it... just inject the ILogFactory and calle the Create Method in a Mefed Importing Constructor:
[ImportingConstructor]
public MyConstructor(
ILogFactory logFactory)
{
_logger = logFactory.Create(GetType());
}
hope this helps
If you create a new ExportProvider and cast the ImportDefinition being passed in to a ICompositionElement. You can get the type that the logger is being injected into.
Here is the ExportProvider
public class LoggerExportProvider : ExportProvider
{
private readonly ExportDefinition _loggerExportDefinition;
private readonly Func<string, ILogger> _loggerFactory;
/// <summary>
/// Initializes a new instance of the <see cref="LoggerExportProvider"/> class.
/// </summary>
/// <param name="loggerFactory">The logger factory function.</param>
public LoggerExportProvider(Func<string, ILogger> loggerFactory)
{
_loggerFactory = loggerFactory;
_loggerExportDefinition = new ExportDefinition(typeof (ILogger).FullName, new Dictionary<string, object> {{"ExportTypeIdentity", typeof (ILogger).FullName}});
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
{
IList<Export> exports = new List<Export>();
var compositionElement = definition as ICompositionElement;
if (compositionElement == null || compositionElement.Origin == null)
return exports;
var constraint = definition.Constraint.Compile();
if (constraint(_loggerExportDefinition))
exports.Add(new Export(_loggerExportDefinition, () => _loggerFactory(compositionElement.Origin.DisplayName)));
return exports;
}
}
This is setup in such a way that it will work with any logging framework as you need to pass in a function that will return an ILogger (the Ilogger is our own, you'll have to create your own interface or just make it specific to Nlog). The string being passed to the function is the full class name that the type is being injected too. (compositionElement.Origin.DisplayName)
An example of bootstrapping MEF with this would look like this:
public class Example
{
[Import]
public ILogger Logger { get; set;}
public Example()
{
var aggregatecatalogue = new AggregateCatalog();
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(typeof (ILogger).Assembly));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(GetType().Assembly));
var container = new CompositionContainer(aggregatecatalogue, new LoggerExportProvider(s => new MockLogger(s)));
container.ComposeParts(this);
}
}
The code above was copied from a unit test, so I'm just add specific assemblies instead of parsing a directory. The MockLogger is an implementation of the ILogger interface that takes the logging class name (or injecting type) as a parameter to it's constructor.
This doesn't require parsing any stack traces and pulls the information that is otherwise sitting there directly out of MEF.