Logging using AOP in .NET Core 2.1 - c#

I want to implement AOP for the logging in my .NET Core 2.1 solution. I've never used it before and I've been looking online and cant seem to see any examples of people using it with Core 2. Does anyone know how i would go about this?
For example what packages to use for AOP and have any example code to get me started? Im using the built in DI with .net core so i dont need to worry about that part.

Microsoft DI does not offer advances scenarios such as interceptor or decorators(there is a workaround for decorators using Microsoft DI: https://medium.com/#willie.tetlow/net-core-dependency-injection-decorator-workaround-664cd3ec1246).
You can implement AOP by using Autofac (https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html) or Simple injector with dynamic proxy. Both have a really good documentation. Simple injector doesn't have an out of the box solution for interception because of their design rules but you can add an extension for it (http://simpleinjector.readthedocs.io/en/latest/aop.html).
Here is a basic AOP scenario from the official SI documentation:(http://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html) :
//Add registration to the composition root
container.InterceptWith<MonitoringInterceptor>(serviceType => serviceType.Name.EndsWith("Repository"));`
// Here is an example of an interceptor implementation.
// NOTE: Interceptors must implement the IInterceptor interface:
private class MonitoringInterceptor : IInterceptor {
private readonly ILogger logger;
public MonitoringInterceptor(ILogger logger) {
this.logger = logger;
}
public void Intercept(IInvocation invocation) {
var watch = Stopwatch.StartNew();
// Calls the decorated instance.
invocation.Proceed();
var decoratedType = invocation.InvocationTarget.GetType();
this.logger.Log(string.Format("{0} executed in {1} ms.",
decoratedType.Name, watch.ElapsedMilliseconds));
}
}

Disclaimer: I am the producer of this solution
Microsoft does not provide an AOP solution out the box for Net Core. However, I have produced a 3rd party project which may help. It works directly with Net Core and plugs in via the ServiceCollection registration in your application.
What Microsoft does provide is a library called System.Runtime.DispatchProxy which can be used to create proxy objects for your classes. However, this proxy isnt particularly useful or feature rich on its own and would require a lot of extra code to get something that is on a level with Castle Proxy (the well known Dynamic Proxy library)
With that in mind, I have created a library which wraps the DispatchProxy into code that can be easily injected during the ServiceCollection configuration in the application startup. The trick is to have a way to create attributes AND a paired interceptor that can be applied to your methods. The attribute is then read during the Proxy wrapping and the relevant Interceptor is called.
This is an example Interceptor Attribute
public class ConsoleLogAttribute : MethodInterceptorAttribute
{
}
This is an example Interceptor class
public class ConsoleLogInterceptor : MethodInterceptor
{
public override void BeforeInvoke(IInterceptionContext interceptionContext)
{
Console.WriteLine($"Method executing: {interceptionContext.CurrentMethod.Name}");
}
public override void AfterInvoke(IInterceptionContext interceptionContext, object methodResult)
{
Console.WriteLine($"Method executed: {interceptionContext.CurrentMethod.Name}");
}
}
This is how it would be applied to your method
[ConsoleLog]
public void TestMethod()
{
}
And then finally, this is how it would be added to your ServiceCollection configuration (assuming that the class you wanted to Proxy was called [TestClass]:
public void ConfigureServices(IServiceCollection services)
{
// Configure Simple Proxy
services.EnableSimpleProxy(p => p.AddInterceptor<ConsoleLogAttribute, ConsoleLogInterceptor>());
// Configure your services using the Extension Methods
services.AddTransientWithProxy<ITestClass, TestClass>();
}
Take a look at this GitHub project: https://github.com/f135ta/SimpleProxy

Related

When do we need IOptions?

I am learning DI in .Net Core and I do not get the idea about the benefit of using IOptions.
Why do we need IOptions if we can do without it?
With IOptions
interface IService
{
void Print(string str);
}
class Service : IService
{
readonly ServiceOption options;
public Service(IOptions<ServiceOption> options) => this.options = options.Value;
void Print(string str) => Console.WriteLine($"{str} with color : {options.Color}");
}
class ServiceOption
{
public bool Color { get; set; }
}
class Program
{
static void Main()
{
using (ServiceProvider sp = RegisterServices())
{
//
}
}
static ServiceProvider RegisterServices()
{
IServiceCollection isc = new ServiceCollection();
isc.Configure<ServiceOption>(_ => _.Color = true);
isc.AddTransient<IService, Service>();
return isc.BuildServiceProvider();
}
}
Without IOptions
interface IService
{
void Print(string str);
}
class Service : IService
{
readonly ServiceOption options;
public Service(ServiceOption options) => this.options = options;
public void Print(string str) => Console.WriteLine($"{str} with color : {options.Color}");
}
class ServiceOption
{
public bool Color { get; set; }
}
class Program
{
static void Main()
{
using (ServiceProvider sp = RegisterServices())
{
//
}
}
static ServiceProvider RegisterServices()
{
IServiceCollection isc = new ServiceCollection();
isc.AddSingleton(_ => new ServiceOption { Color = true });
isc.AddTransient<IService, Service>();
return isc.BuildServiceProvider();
}
}
In .Net core, it is recommended that all your configurations should be strongly typed based on their use cases. This will help you to achieve separate of concerns.
Practically, you can achieve the same thing without using IOptions as you stated.
So, if I go back one step and if we have a look at all the available options in .net core configuration:
1. Raw Configuration[path:key]
You can directly access IConfiguration instance and provide path of JSON key in the accessor part, and the configuration value would be returned.
This is not good approach because there is no strong typing here while reading the configuration.
2. IOptions binding to a Config Section
You can use IOptions implementation (which you already know).
This is better because you can have a single class with all related configurations. The IOptions interface provides you additional benefits.
As far as I understood, this IOptions interface decouples your configuration from the actors who are reading the configuration and thereby you can use some additional services from .net core framework.
Please refer MSDN article for details about the benefits.
You can also refer to the twitter conversation at this blog. In that blog, Rick also explains that he could not find any practical case on how this approach is different from the 3rd approach below - as generally the configurations are not dynamic and they are done only once before the application startup.
3. Configuration.Bind() to bind to a Config Section
You can use .Bind call to bind a configuration section to a POCO class. You get strongly typed object. Here if multiple actors are using the configurations, they will not get additional services provided by IOptions interface.
I know this is not exactly pointing out the difference. But I am sure this will bring little more clarity on deciding your preference.
Short answer: yes, you can do without it and access your setting directly from ConfigurationManager.AppSettings, like in this answer.
Slightly longer answer: especially when you want to test your (Console) Application, it might be nice to inject services and settings.
ASP.NET Core comes with DI included and it will be set up in your Startup.cs. DI can be used in Console Applications, but it might be hard(er) to set it up, as the default application has no plumbing for it. I wrote a small blog on how to setup DI with IOptions configuration for .NET Core Console Applications.
By itself IOptions<TOptions> doesn't add anything, in your examples. However, it allows you to use the OptionsBuilder API, should you need any of its features:
Configuring your Options objects using other services;
Validate your Options object;
Add post-configuration to your Options object.
From my experience, all of these use cases are quite exotic, though. For the basic use case, where you want to bind a section of your IConfiguration to an Options object, you can just inject the Options object directly, as per your second example. Not using the IOptions<T> interface has the benefit of being less cumbersome to unit test - you don't need to mock it.
However, if you want your Options values to automatically update at runtime as the configuration sources change, you will need to make use of a wrapper interface. But IOptions<T> itself doesn't do that - you'll need to use either IOptionsSnapshot<T> or IOptionsMonitor<T> for that.

Share Microsoft.Extensions.DependencyInjection.ServiceProvider configuration between projects

I have a solution that has the following projects
Acme.Core
Acme.Domain
Acme.Repositories
Acme.Services
Acme.Web
In the past I've used Unity for DI in full framework projects. I was able to register concrete objects to interface mappings in executable projects (web apps, console app, test apps).
I'm trying to implement the same approach with .NET Core. I wanted to first try using the Microsoft.Extensions.DependencyInjection library. Within the ASP.NET Core application it works great. Unfortunately I've run into an issue when I try to share/reference that instance with the registions to other projects, such as a .NET Standard library.
My idea was to inject the ServiceProvider into the constructor of the service:
public class AddressService : BaseService, IAddressService
{
private readonly IServiceProvider _serviceProvider;
public AddressService(IServiceProvider serviceProvider, string userOrProcessName)
{
_serviceProvider = serviceProvider;
}
public IReadOnlyList<IState> GetAllStates()
{
_serviceProvider.GetService<IAddressRepository>();
// other logic removed
}
}
I tried the following inside the Startup.ConfigureServices():
services.AddTransient<IAddressService>(s => new AddressService(HttpContext.RequestServices, Environment.UserName));
The issue I ran into is that I cannot reference HttpContext.RequestServices outside of a Controller. I haven't been able to figure another way of passing the ServiceProvider instance.
My questions:
How do pass a reference for the current ServiceProvider?
Is there a better design to accomplish my goal sharing the configuration of Microsoft.Extensions.DependencyInjection in multiple libraries?
Prevent injecting IServiceProvider into your application components; that leads to the Service Locator anti-pattern.
Instead, you should build up application components solely using Constructor Injection. This means that your AddressService should require IAddressRepository as constructor argument, not IServiceProvider. For instance:
public class AddressService : IAddressService
{
private readonly IAddressRepository repo;
public AddressService(IAddressRepository repo, IUserContext userContext)
{
this.repo = repo;
}
public IReadOnlyList<IState> GetAllStates()
{
// other logic removed
}
}
Also try to prevent injecting primites into your constructors. It's not a bad practice per se, but it does complicate object graph construction. Instead, either wrap the value into a class, in case its a configuration value, or hide it behind an abstraction (as shown above) in case it's a runtime value.
Both practices simplify both your application code and the Composition Root.
For instance, this will be the result of the previous AddressService redesign:
services.AddTransient<IAddressRepository, SqlAddressRepository>();
services.AddTransient<IAddressService, AddressService>();
services.AddScoped<IUserContext, UserContext>();
services.AddHttpContextAccessor();
Here, UserContext could be defined as follows:
public class UserContext : IUserContext
{
private readonly IHttpContextAccessor accessor;
public UserContext(IHttpContextAccessor accessor) => this.accessor = accessor;
public string UserName => this.accessor.HttpContext.User.Identity.Name;
}
In order to share configuration across multiple projects, you can put the configuration into a shared assembly, and register (not resolve) them in there. Many dependency injection libraries offer that functionality. e.g.
in Autofac you create a module (https://autofaccn.readthedocs.io/en/latest/configuration/modules.html) that takes a container builder to configure:
protected override void Load(ContainerBuilder builder) { ... }
SimpleInjector provides packages: https://simpleinjector.readthedocs.io/en/latest/howto.html#package-registrations
Unity can support something similar: Can I register my types in modules in Unity like I can in Autofac?
Ninject has a similar module feature: What is the intention of Ninject modules?
A similar feature has be created for Microsoft.Extensions.DependencyInjection: https://github.com/aruss/DotNetCore_ModularApplication
At a high level, you create a method that receives the DI container and adds your registrations to that container. If your DI framework doesn't provide hooks you need to manually call the method yourself, but the general concept doesn't change.
Splitting registrations into modules allows you to easily group similar sets of functionality while maintaining the flexibility of incorporating different sets of functionality into different projects. You could of course create a single shared assembly that registered the union of all dependencies for all projects, but that would carry around unnecessary baggage and result in a less reusable implementation.
The key point as Steven points out is that you configure the container and let it inject the dependencies rather than looking from the inside out for the dependencies.

.NET Core 2.0 Modular Dependency Injection

I am trying to build a library that has core and extensions packages like Entity Framework and its database providers.
What I am trying to do is when I register that library with dependency injection, I want to give specific implementation as a parameter.
Think EF. In order to use sql provider on EF we need to register it with SQL provider passed as option parameter like the following.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["ConnectionString"]);
});
I would like to build similar structure. Lets say my framework will provide film producer. It will have producer.core package for framework related classes and two extensions package called Producer.Extensions.Hollywood and Producer.Extensions.Bollywood.
If I want to use Hollywood provider, I need to install core package and Hollywood extension package. On registration it should look like
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});
I could not find even a keyword that will point me a direction. I tried to read entity framework's source code but it is too complicated for my case.
Is there anyone who could point me a direction?
Thanks in advance.
I'm not sure if I completely understand your requirements, but DI and extensions are an easy thing in .net core.
Let's say you want this in your Startup.cs
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});
To implements this, create your library and add a static extension class
public static class FilmProducerServiceExtensions
{
public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<ProducerOptions> options)
{
// Create your delegate
var producerOptions = new ProducerOptions();
options(producerOptions);
// Do additional service initialization
return services;
}
}
where your ProducerOptions implementation might look like
public class ProducerOptions
{
public void UseHollywoodProducer()
{
// Initialize hollywood
}
public void UseBollywoodProducer()
{
// Initialize bollywood
}
}
If you wish to use the passed ProducerOptions in your service, there are two ways to do it. Either use dependency injection again, or directly access the service by using service provider in your extension method
var serviceProvider = services.BuildServiceProvider()
IYourService service = sp.GetService<IYourService>();
And now you have the original Use piece of initialization working.
Hope it helps.
Edit:
To clarify. To inject your options in the service, you can use
services.Configure(ProducerOptions);
in your extension method, and pass to your service constructor via
public YourService(IOptions<ProducerOptions>)
You can then simplify or complicate your options as much as you want.
A useful link for this kind of extensions might be the CORS repository for .net core: https://github.com/aspnet/CORS
Edit after comments:
I think I've got it now. You want packages to extend and implement specific options, kind of like what serilog does with different sinks. Piece of cake.
Scrap the ProducerOptions implementation.
Lets say you have a base package with initial empty structures (BaseProducer library) and an interface
public interface IProducerOptions
{
// base method signatures
}
Your service extension now becomes
public static class FilmProducerServiceExtensions
{
public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<IProducerOptions> options)
{
// Do additional service initialization
return services;
}
}
Now you create a new package with specific "Hollywood producer" options and you want to extend the base option set
public static class HollyWoodExtensions
{
public static void UseHollywoodProducer(this IProducerOptions options)
{
// Add implementation
}
}
Create as many packages and IProducerOptions extensions as you like, and the added methods will start appearing in your Startup.cs
services.AddFilmProducer(options =>
{
options.UseHollywoodProducer();
});

Can't inject a delegate using ASP.NET Core DI

Say I've a MVC Core Controller like this:
public class SomeController
{
public SomeController(IConfiguration appConfig, Func<string> someDelegate)
{
}
}
Also, I'm using AutoFac to resolve injections. Object injections are working flawlessly while adding a delegate injection produces an ASP.NET Core exception which tells that Func<string> can't be injected because there's no component to inject with such type.
When I try to manually resolve SomeController using AutoFac I get the desired behavior.
Is there any way to support this scenario without using AutoFac to resolve controllers?
Controllers are not resolved via DI by default, they are constructed in the DefaultControllerFactory or so.
Update
Microsoft.Extensions.DependencyInjection doesn't support named components, discovery, auto registrations, decorators etc.
It's meant to be simple out of the box IoC and provide the base for DI for basic applications and offer easy way for 3rd party IoC containers (with advanced features such as auto discovery, decorators etc.) to be integrated (basically all they need is process the information in IServiceCollection and return their own implementation of IServiceProvider from Configure method).
Tag helpers, controllers and view components are different in this aspect as they have their own activators (the default one use activation utilities, which at some point further down the pipeline use the service provider). For that reasons AddControllersAsServices exists, because it replaces DefaultControllerActivator (which uses ActivationUtilities, see DefaultControllerActivator.cs) with ServiceBasedActivator (which uses IServiceProvider, see ServiceBasedControllerActivator).
Also see this related answer for details on how to resolve controllers, tag helpers and view components via DI.
var builder = services
.AddMvc()
.AddControllersAsServices() // this one for your case
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I was just run into this issue myself so I thought I would share for future reference as I had one case where I wanted to resolve a delegate but including an additional library seemed like overkill.
Given the following defintions:
public interface ISomething { /*...*/ };
public interface ISomeService { /*...*/ }
public class SomeService : ISomeService { /*...*/ }
public class Something
{
public Something(ISomeService service, string key) { /*...*/ }
}
// I prefer using a delegate for readability but you
// don't have to use one
public delegate ISomething CreateSomething(string key);
The delegate can be registered like this:
var builder = services
.AddSingleton<ISomeService, SomeService>()
.AddTrasient<CreateSomething>(provider => key => new Something(provider.GetRequiredService<ISomeService>(), key));

Dependency injection resolving by name

How can I inject different implementation of object for a specific class?
For example, in Unity, I can define two implementations of IRepository
container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository");
container.RegisterType<IRepository, BaseRepository>();
and call the needed implementation
public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository)
As #Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:
Create a repository resolver:
public interface IRepositoryResolver
{
IRepository GetRepositoryByName(string name);
}
public class RepositoryResolver : IRepositoryResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IRepository GetRepositoryByName(string name)
{
if(name == "TestSuiteRepository")
return _serviceProvider.GetService<TestSuiteRepositor>();
//... other condition
else
return _serviceProvider.GetService<BaseRepositor>();
}
}
Register needed services in ConfigureServices.cs
services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>();
Finally use it in any class:
public class BaselineManager
{
private readonly IRepository _repository;
public BaselineManager(IRepositoryResolver repositoryResolver)
{
_repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
}
}
In addition to #adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.
UPDATE Now it's available as nuget package.
In order to register your services you'll need to add following code to your Startup class:
services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddByName<IService>()
.Add<ServiceA>("key1")
.Add<ServiceB>("key2")
.Add<ServiceC>("key3")
.Build();
Then you can use it via IServiceByNameFactory interface:
public AccountController(IServiceByNameFactory<IService> factory) {
_service = factory.GetByName("key2");
}
Or you can use factory registration to keep the client code clean (which I prefer)
_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));
Full code of the extension is in github.
You can't with the built-in ASP.NET Core IoC container.
This is by design. The built-in container is intentionally kept simple and easily extensible, so you can plug third-party containers in if you need more features.
You have to use a third-party container to do this, like Autofac (see docs).
public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)
After having read the official documentation for dependency injection, I don't think you can do it in this way.
But the question I have is: do you need these two implementations at the same time? Because if you don't, you can create multiple environments through environment variables and have specific functionality in the Startup class based on the current environment, or even create multiple Startup{EnvironmentName} classes.
When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.
I also wrote an article about injecting dependencies from a JSON file so you don't have to recompile the entire application every time you want to switch between implementations. Basically, you keep a JSON array with services like this:
"services": [
{
"serviceType": "ITest",
"implementationType": "Test",
"lifetime": "Transient"
}
]
Then you can modify the desired implementation in this file and not have to recompile or change environment variables.
Hope this helps!
First up, this is probably still a bad idea. What you're trying to achieve is a separation between how the dependencies are used and how they are defined. But you want to work with the dependency injection framework, instead of against it. Avoiding the poor discover-ability of the service locator anti-pattern. Why not use generics in a similar way to ILogger<T> / IOptions<T>?
public BaselineManager(RepositoryMapping<BaselineManager> repository){
_repository = repository.Repository;
}
public class RepositoryMapping<T>{
private IServiceProvider _provider;
private Type _implementationType;
public RepositoryMapping(IServiceProvider provider, Type implementationType){
_provider = provider;
_implementationType = implementationType;
}
public IRepository Repository => (IRepository)_provider.GetService(_implementationType);
}
public static IServiceCollection MapRepository<T,R>(this IServiceCollection services) where R : IRepository =>
services.AddTransient(p => new RepositoryMapping<T>(p, typeof(R)));
services.AddScoped<BaselineManager>();
services.MapRepository<BaselineManager, BaseRepository>();
Since .net core 3, a validation error should be raised if you have failed to define a mapping.

Categories