Web API - Inject dependency at ServiceContainer using Unity - c#

I am using ExceptionLogger to handle all the global exception. My inheriting class requires dependencies to be injected for Nlog to invoke.
public class NLogExceptionLogger : ExceptionLogger
{
private readonly ILoggingService _loggingService;
public NLogExceptionLogger(ILoggingService<NLogExceptionLogger> loggingService)
{
_loggingService = loggingService;
}
public override void Log(ExceptionLoggerContext context)
{
_loggingService.FirstLevelServiceLog(context.Exception.StackTrace);
}
}
LoggingService Class:
public class LoggingService<T> : ILoggingService<T>
{
private readonly ILogger _logger;
public LoggingService()
{
string currentClassName = typeof(T).Name;
_logger = LogManager.GetLogger(currentClassName);
}
public void FirstLevelServiceLog(string log)
{
_logger.Log(LogLevel.Debug, log);
}
}
My Unity Code:
public static UnityContainer RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType(typeof(ILoggingService<>), typeof(LoggingService<>))
}
I am registering ExceptionLogger globally by doing: (On this line i am getting an error)
config.Services.Add(typeof(IExceptionLogger), typeof(NLogExceptionLogger));
//Register Dependency Container
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.RegisterComponents());
I am getting following error at runtime:
System.ArgumentException: 'The type RuntimeType must derive from IExceptionLogger.'
My assumption is i am not properly registering the dependency for NLogExceptionLogger.
Any idea on how to resolve dependency while registering the service?

When adding service to ServicesContainer you add the type with the service instance.
Assuming dependency resolver has already been setup, that can be used to resolve the instance if it has dependencies.
var logger = config.DependencyResolver.GetService(typeof(NLogExceptionLogger));
config.Services.Add(typeof(IExceptionLogger), logger);
There is also a difference between exceptions loggers and exception handlers.
I suggest reviewing the following reference link to determine which one is appropriate for your needs.
Reference Global Error Handling in ASP.NET Web API 2

Related

How to properly use NLog in ASP.NET CORE application with Autofac as a dependency container?

In my ASP.NET CORE application I use Autofac as a dependency container and NLog for logging.
I register NLog in Autofac like:
builder.Register(x =>
{
var config = x.Resolve<IConfigurationRoot>();
return new NLogLogger(config);
}).As<ILogger>();
Class NlogLogger looks like:
public class NLogLogger : IT.CORE.LoggingCore.ILogger
{
private NLog.ILogger logger;
public NLogLogger(IConfigurationRoot configuration)
{
logger = LogManager.Setup()
.LoadConfigurationFromSection(configuration)
.GetCurrentClassLogger();
}
public void Debug(Exception exception)
{
logger.Debug(exception);
}
// the rest of the login methods
...
}
In application I inject via constructor ILogger and use appropriate method for logging.
In NLog documentation we can see:
How do you register and use NLog in your projects as a static private field in each class or resolve it from DI Container ?

Inject different loggers for controllers in ASP.NET MVC

I have defined services in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DbConnection");
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
services.AddControllersWithViews();
services.AddScoped<IAdsService, AdsService>();
services.AddScoped<ILogger, ConsoleLogger>();
services.AddScoped<ILogger, FileLogger>();
services.AddScoped<IAdsRepository, AdsRepository>();
}
This is my implementation of Logger:
public class ConsoleLogger: ILogger
{
public void Log(LogData data) => Console.WriteLine(data.ToString());
}
public class FileLogger : ILogger
{
private string Path = "logs";
public void Log(LogData data)
{
if (!Directory.Exists(Path))
{
DirectoryInfo di = Directory.CreateDirectory(Path);
}
File.AppendAllText(Path + "/logs.txt", data.ToString());
}
}
I want to use different loggers for different controllers:
e.g.
private readonly ILogger _logger;
private readonly IAdsService _adsService;
public AdController(IAdsService adsService, ILogger logger)
{
_adsService = adsService;
_logger = logger;
}
However it only takes FileLogger - how to specify my controller to use ConsoleLogger in Startup?
What you are looking for is a feature called context-based injection, which is something that is not easily implemented with MS.DI. That's not to say it's impossible, but depending on your needs, it might require a lot of configuration.
One way to achieve this, though, it by configuring any component that requires an alternative logger explicitly using a lambda using the ActivatorUtilities class. Here's an example:
private static void AddServices(IServiceCollection services)
{
// The default logger
services.AddScoped<ILogger, FileLogger>();
// Additional 'alternative' loggers
services.AddScoped<ConsoleLogger>();
// Configure a component that requires an alternative logger
services.AddTransient<AdController>(c =>
ActivatorUtilities.CreateInstance<AdController>(c,
c.GetRequiredService<ConsoleLogger>()));
}
In this example:
FileLogger is registered as ILogger allowing any 'normal' component that depends on ILogger to get injected with FileLogger.
ConsoleLogger is registered as itself, allowing it to be requested als alternative logger
AdController is registered using the ActivatorUtilities so that ActivatorUtilities is responsible for creating a new AdController where a resolved ConsoleLogger is supplied to ActivatorUtilities. This allows ActivatorUtilities to supply ConsoleLogger to the first constructor parameter that is assignable from ConsoleLogger. This basically means that ConsoleLogger is supplied to the ILogger argument of AdController.
To test this code, try this:
public interface IAdsService { }
public class AdsService : IAdsService { }
public interface ILogger { }
public class ConsoleLogger : ILogger { }
public class FileLogger : ILogger { }
public class AdController
{
public AdController(IAdsService adsService, ILogger logger) => this.Logger = logger;
public ILogger Logger { get; }
}
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddTransient<IAdsService, AdsService>();
AddServices(services);
var provider = services.BuildServiceProvider();
using (var scope = provider.CreateScope())
{
var controller =
scope.ServiceProvider.GetRequiredService<AdController>();
Console.WriteLine(controller.Logger.GetType().Name);
}
}
}
There are several downsides to this approach, the most important being that this solution might not scale well. There is no good way to take a more convention-based approach where you say "use ConsoleLogger for any component that follows the following definition X". You must specify each component that uses an alternative logger explicitly.
If these limitations cause maintainability issues, try using a different DI Container that natively supports this feature.

web api self host custom ioc inject data to controllers

I have a property in my web api self hosted app that I would like to inject to my controllers, which is loaded via reflection using my custom IoC framework, here is my startup code:
public CustomClass StuffInstance { get; set; }
// This method is required by Katana:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var webApiConfiguration = ConfigureWebApi();
// Use the extension method provided by the WebApi.Owin library:
app.UseWebApi(webApiConfiguration);
}
my controllers are mostly scaffolded and some like:
// PUT: api/EventTypeDescriptions/5
[ResponseType(typeof(void))]
public IHttpActionResult PutStuff(int id, int something)
{
//do stuff
//here i would like to use StuffInstance like a singleton
return StatusCode(HttpStatusCode.NoContent);
}
how can a inject StuffInstance to my controllers? this information would be relevant to anyone making an IoC framework btw
I found the information to inject instances to my controllers in this link:
http://www.asp.net/web-api/overview/advanced/dependency-injection
basically i implemented a dependency resolver for my custom IoC Library
in case someone has the same problem, here is the code, maybe for other IoC frameworks it needs more work
public class CustomIocDependencyResolver : IDependencyResolver
{
private readonly CustomIoc container;
public ComponentLoaderWebApiDependencyResolver(CustomIoc container)
{
this.container = container;
}
IDependencyScope IDependencyResolver.BeginScope()
{
return new CustomIocDependencyResolver(container);
}
Object IDependencyScope.GetService(Type serviceType)
{
return container.GetInstance(serviceType);
}
IEnumerable<Object> IDependencyScope.GetServices(Type serviceType)
{
return container.GetAllInstances(serviceType);
}
public void Dispose()
{
}
}
now my katana Configuration looks like:
// This method is required by Katana:
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = ConfigureWebApi();
config.DependencyResolver = CustomIocDependencyResolver(container);
// Use the extension method provided by the WebApi.Owin library:
app.UseWebApi(config);
}
being container the instance of my custom IoC
Since you mentioned AutoFac as a potential candidate, I recommend you follow their tutorial on WebAPI integration. You'll need to define an interface on CustomClass so that you can properly inject it.
You'll need to inject your instance that you've created (since you want to treat it as a singleton) by registering it as an instance component.
public interface ICustomClass {}
public class CustomClass : ICustomClass {}
public CustomClass _stuffInstance = new CustomClass();
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(_stuffInstance).As<ICustomClass>();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
Then, in each controller's constructor, inject your instance that's been bound to the appropriate interface.
public class CustomController : ApiController
{
private readonly ICustomClass _customClass;
public CustomController(ICustomClass customClass)
{
_customClass = customClass;
}
}
With ASP.NET Core 6 you can now register a service provider:
builder.Services.AddScoped<ICustomClass, CustomClass>(sp => new CustomClass()/* or your already existing instance */);
builder.Services.AddSingleton<ICustomClass>(sp => new CustomClass()/* or your already existing singleton instance */);
it will be injected to your controllers:
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private readonly ICustomClass _customClass;
private readonly ILogger _logger;
public MyController(ICustomClass customClass, ILogger<MyController> logger)
{
_customClass = customClass;
_logger = logger;
}

using a Handler in Web API and having Unity resolve per request

I am using Unity as my IoC framework and I am creating a type based on the value in the header of each request in a handler:
var container = new UnityContainer();
container.RegisterType<IFoo,Foo>(new InjectionConstructor(valuefromHeader));
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityDependencyResolver(container);
The problem is that the handler's SendAsync means that the global container is getting overwritten by different requests and the controllers that use IFoo in their constructor are getting the wrong values.
1) Can I make the SendAsync sync?
2) If not, how do I create different instances for each request and have the IoC container resolve safely?
I have looked at the following articles without success:
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
http://www.strathweb.com/2012/11/asp-net-web-api-and-dependencies-in-request-scope/
http://benfoster.io/blog/per-request-dependencies-in-aspnet-web-api-using-structuremap
Thanks in advance.
I agree with #Steven's approach, but that doesn't answer your more general question of how to resolve per request.
I would recommend you change to using the UnityHierarchicalDependencyResolver and then anything you register with HierarchicalLifetimeManager will be resolved per request.
Change this...
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityDependencyResolver(container);
to this...
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityHierarchicalDependencyResolver(container);
The problem you are having is caused by you mixing runtime values with design time dependencies. In general, the services you resolve from the container should not depend on runtime values in their constructor. You shouldn't do this, because components tend to live much longer than runtime values and injecting runtime values into components, makes it much harder to diagnose and verify the container's configuration.
Instead, hide that value behind a service that can provide consumers with that instance when required. For instance:
public interface IHeaderValueProvider
{
HeaderValue GetCurrentValue();
}
You can create an implementation that can be easily registered and injected into any component that needs that value. Anytime after the construction phase, those components can call the GetCurrentValue() method on the injected IHeaderValueProvider dependency.
I managed to resolve per request by declaring my custom UnityResolver's class within the WebApiConfig class. The UnityResolver class uses the HttpConfiguration class assuming you're using an OWIN context.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var _container = new UnityContainer();
DependencyConfiguration.ConfigureContainer(_container);
config.DependencyResolver = new UnityResolver(_container);
}
The ConfigureContainer class is simply a class where I declare my IOC dependencies as shown below:
private static void RegisterReleaseEnv(IUnityContainer container)
{
//Repository Registration
container
.RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());
}
It is very important that you use the HierarchicalLifetimeManager lifetime manager so that you get a new instance per request.
The UnityResolver class then looks like this:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
I hope this helps.
For more information: http://www.asp.net/web-api/overview/advanced/dependency-injection

Resolving or injecting dependency in global.asax using autofac

I need to execute some one-time code on start of my application in the global.asax. I've already got autofac up and running with numerous registrations but the problem is that I can't figure out how to resolve or inject a dependency into SecurityConfig.RegisterActivities() that's inside my global.asax.
I tried manually resolving the dependency myself in global.asax using the autofac container but it threw the exception "No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested."
How do I get this dependency into that class?
protected void Application_Start()
{
var builder = new ContainerBuilder();
DependencyRegistrar dr = new DependencyRegistrar();
dr.Register(builder);
new SecurityConfig().RegisterActivities(); // this needs injecting into or resolving of IServiceManager instance
}
public class DependencyRegistrar
{
public virtual IContainer Register(ContainerBuilder builder)
{
builder.RegisterType<ServiceManager>().As<IServiceManager>().InstancePerHttpRequest();
builder.RegisterType<SecurityConfig>().AsSelf().PropertiesAutowired().InstancePerDependency();
}
}
public class SecurityConfig
{
public void RegisterActivities()
{
ServiceManager.DoSomething();
}
public IServiceManager ServiceManager { get; set; }
}
This allowed me to resolve my dependencies finally.
using(var scope = container.BeginLifetimeScope("AutofacWebRequest"))
{
scope.Resolve<SecurityConfig>().RegisterActivities();
}

Categories

Resources