SOLID principles dictate that:
abstracts belong to upper / political strata ( DIP )
This means that our application code should not depend directly on the framework code, even if it is an abstraction. Instead, we must define the role interfaces that are intended to be used by our application.
Thus, instead of depending on the abstraction of Microsoft.Framework.Logging.ILogger , which might or may not correspond to our specific needs of the application, SOLID principles direct us to the abstractions (ports) that belong to this application and use adapter implementations, which connect to the code infrastructure. Here is an example of how your own ILogger abstraction might look.
When the application code depends on your own abstraction, you need an adapter implementation that can redirect the call to the implementation provided by the framework:
public sealed class MsLoggerAdapter : MyApp.ILogger { private readonly Func<Microsoft.Framework.Logging.ILogger> factory; public MsLoggerAdapter(Func<Microsoft.Framework.Logging.ILogger> factory) { this.factory = factory; } public void Log(LogEntry entry) { var logger = this.factory(); LogLevel level = ToLogLevel(entry.Severity); logger.Log(level, 0, entry.Message, entry.Exception, (msg, ex) => ex != null ? ex.Message : msg.ToString()); } private static LogLevel ToLogLevel(LoggingEventType severity) { ... } }
This adapter can be registered in the application container as follows:
container.RegisterSingleton<MyApp.ILogger>(new MsLoggerAdapter( app.ApplicationServices.GetRequiredService<Microsoft.Framework.Logging.ILogger>));
GREAT WARNING . Do not make direct copies of the frame abstraction. This will almost never lead to good results. You must specify the abstractions that are defined in terms of your application. It may also mean that the adapter is becoming more complex and requires several infrastructure components to fulfill its contract, but it leads to a cleaner and more convenient application code.
But if using SOLID is too much trouble for you, and you just want to directly depend on external components, you can always cross-link the necessary dependencies in the application container as follows:
container.Register<Microsoft.Framework.Logging.ILogger>( app.ApplicationServices.GetRequiredService<Microsoft.Framework.Logging.ILogger>);
It's just as simple, but note that in order for your application to be clean and maintainable, it is much better to define specific application abstractions that are consistent with SOLID principles. Also note that even if you do, you will only need some of these cross-wire dependencies. Therefore, it is better to keep the application container as separate as possible from the vNext configuration system.
Using middleware here is a completely different problem. In middleware, you enter runtime data ( next delegate) into the component ( CustomMiddleware class). This gives you double grief, because it complicates the registration and elimination of the component and prevents it from being checked and diagnosed by the container. Instead, you should move the next delegate from the constructor and to the Invoke delegate as follows:
public class CustomMiddleware { private IPersonService _personService; public CustomMiddleware(IPersonService personService) { _personService = personService; } public async Task Invoke(HttpContext context, RequestDelegate next) { } }
Now you can connect the middleware to the pipeline as follows:
app.Use(async (context, next) => { await container.GetInstance<CustomMiddleware>().Invoke(context, next); });
But do not forget that you can always create your middleware manually as follows:
var frameworkServices = app.ApplicationServices; app.Use(async (context, next) => { var mw = new CustomMiddleware( container.GetInstance<IPersonService>(), container.GetInstance<IApplicationSomething>(), frameworkServices.GetRequiredService<ILogger>(), frameworkServices.GetRequiredService<AspNetSomething>()); await mw.Invoke(context, next); });
Not surprisingly, ASP.NET calls its own ApplicationServices because it uses your own application container; rather than an embedded configuration system.