I am interested in learning more about how people implement registration using dependency injection platforms. Although the links below and my examples relate to log4net and Unity, I will not necessarily use them. For dependency injection / IOC, I will probably use MEF, as this is the standard the rest of the project dwells on (large).
I am very new to / ioc dependency injection and quite new to C # and .NET (I wrote very little production code in C # /. NET after 10 years or so of VC6 and VB6). I have done a lot of research on the various logging solutions that are there, so I think I have a decent pen for their feature sets. I'm just not familiar enough with the real mechanics of getting one dependent injection (or maybe more "correct"), getting an abstracted version of one dependent injection).
I saw other posts related to registration and / or dependency, for example: attachment and dependency logging interfaces
Logging Protocols
What does the Wrapper Log4Net class look like?
again about the configuration of log4net and Unity IOC
My question is not particularly relevant to "How do I implement the xxx registration platform using the ioc yyy tool?" Rather, I'm interested in how people handled the completion of the registration platform (how often, but not always recommended) and configuration (i.e. app.config). For example, using log4net as an example, I could configure (in app.config) several registrars, and then get these registrars (without dependency injection) in a standard way to use the code as follows:
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Alternatively, if my registrar is not named for the class, but rather for the functional area, I could do this:
private static readonly ILog logger = LogManager.GetLogger("Login"); private static readonly ILog logger = LogManager.GetLogger("Query"); private static readonly ILog logger = LogManager.GetLogger("Report");
So, I think my “requirements” would be something like this:
I would like to isolate the source of my product from a direct dependence on the registration platform.
I would like to be able to resolve a specific instance of a named instance of a log (perhaps sharing the same instance among all requests of the same named instance) directly or indirectly using some kind of dependency injection, possibly using MEF.
I don’t know if I will call it a strict requirement, but I need the opportunity to get a named logger (different from the class registrar) on demand. For example, I can create a registrar for my class based on the class name, but one method requires special hard diagnostics, which I would like to control separately. In other words, I may need one class to “depend” on two separate log instances.
Let's start with number 1. I read a number of articles, primarily here in stackoverflow, about whether to wrap an idea. See the Best Practices link above and go to jeffrey hantin for one look at why log4net is poorly ported. If you made a wrapper (and if you could wrap it efficiently), would you stick strictly for the purpose of injecting / removing a direct dependency? Or will you also try to divert some or all of the information about log4net app.config?
Suppose I want to use System.Diagnostics, I would probably want to implement interface-based logic (perhaps even using the "common" ILogger / ILog interface), possibly based on TraceSource, so I can inject it. Do you add an interface, say, through TraceSource, and just use the information about the application. System.infigostics.config how ??
Something like that:
public class MyLogger : ILogger { private TraceSource ts; public MyLogger(string name) { ts = new TraceSource(name); } public void ILogger.Log(string msg) { ts.TraceEvent(msg); } }
And use it as follows:
private static readonly ILogger logger = new MyLogger("stackoverflow"); logger.Info("Hello world!")
Moving by number 2 ... How to allow a specific instance of the name log? Should I just use the app.config information for the registration platform that I choose (i.e. Allow registrars based on the naming scheme in app.config)? So, in the case of log4net, perhaps I prefer to “enter” the LogManager (note that I know this is not possible, since it is a static object)? I could wrap the LogManager (name it MyLogManager), give it an ILogManager interface, and then enable the MyLogManager.ILogManager interface. My other objects may have a dependency (Import in MEF parlance) on ILogManager (Export from assembly where it is implemented). Now I can have these objects:
public class MyClass { private ILogger logger; public MyClass([Import(typeof(ILogManager))] logManager) { logger = logManager.GetLogger("MyClass"); } }
When ILogManager is called, it will directly delegate log8net LogManager. Alternatively, can a wrapped LogManager take the ILogger instances it receives based on app.config and add them to the (??) MEF container by name. Later, when a logger with the same name is requested, a wrapped LogManager is requested for that name. If an ILogger is located there, it is allowed to do so. If this is possible with MEF, are there any benefits to this?
In this case, indeed, only the ILogManager is “injected”, and it can issue instances of ILogger as log4net normally does. How does this type of injection (essentially from a factory) compare to introducing named log instances? This makes it easier to use the app.config file for log4net (or another registration platform).
I know that I can get named instances from the MEF container as follows:
var container = new CompositionContainer(<catalogs and other stuff>); ILogger logger = container.GetExportedValue<ILogger>("ThisLogger");
But how do I get named instances in a container? I know about an attribute-based model where I can have different implementations of ILogger, each of which is called (via the MEF attribute), but that doesn't really help me. Is there a way to create something like app.config (or a section in it) that will list the registrars (all the same implementations) by name and what MEF can read? Could / should there be a central "manager" (for example, MyLogManager) that resolves log names through the base app.config, and then inserts the allowed logger into the MEF container? This way, it will be available to someone else with access to the same MEF container (although without MyLogManager knowing how to use the log4net app.config information, it seems that the container will not be able to directly resolve any named logs).
This has been a fairly long time. Hope this will be consistent. Feel free to share any specific information about how you depend on, implement the registration platform (we are most likely looking at log4net, NLog or something (hopefully subtle) based on System.Diagnostics) in your application.
Did you enter "manager" and did it return instances of the magazine?
Have you added your own configuration information to your own configuration section or to your configuration platform DI configuration in order to simplify / possibly directly import the registrar instances (i.e. make your dependencies on ILogger, not ILogManager).
How about having a static or global container that has an ILogManager interface in it or a set of named instances of ILogger. Thus, instead of typing in the usual sense (via the constructor, property, or member data), the dependency on logging is explicitly resolved on demand. This is a good or bad way to inject addiction.
I mark this as a wiki community, since it doesn't seem like a question with a specific answer. If someone feels different, feel free to change them.
Thanks for any help!