How can I instantiate Services in MVC - c#

I have an ASP.Net MVC 5 project using an Onion Architecture where I have repositories and services and I use Services from my controller. In my controller, I need to use the IGenericService variables I created, but how can I instantiate these variables? The problem being that my Service needs a IRepository for its constructor, and in turn IRepositoryneeds to be initialized too.
What I tried was AddSingleton(IGenericService<MyClass>, GenericService<MyClass>) in the method ConfigureServices(IServiceCollection services) in the Startup.cs file but it doesn't seem to help.
Edit As suggested my #Nkosi I am trying to resolve dependencies and followed this tutorial to do so : http://scottdorman.github.io/2016/03/17/integrating-asp.net-core-dependency-injection-in-mvc-4/ . My problem now is that I get an invalid operation exception :
Unable to resolve service for type 'Repository.PrincipalServerContext' while attempting to activate 'WebExploitv2.Controllers.NavigationController'
My startup.cs looks like this now:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
ConfigureAuth(app);
ConfigureServices(services);
var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());
DependencyResolver.SetResolver(resolver);
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllerAsServices(typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t)
|| t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
services.AddSingleton<IGenericRepository<Web_Documents>, GenericRepository<Web_Documents>>();
services.AddSingleton<IGenericService<Web_Documents>, GenericService<Web_Documents>>();
services.AddSingleton<IGenericRepository<Web_Categories>, GenericRepository<Web_Categories>>();
services.AddSingleton<IGenericService<Web_Categories>, GenericService<Web_Categories>>();
services.AddSingleton<IGenericService<Web_User_joint_Profils>, GenericService<Web_User_joint_Profils>>();
services.AddSingleton<IGenericRepository<Web_User_joint_Profils>, GenericRepository<Web_User_joint_Profils>>();
services.AddSingleton<IGenericRepository<Web_Group_joint_Profils>, GenericRepository<Web_Group_joint_Profils>>();
services.AddSingleton<IGenericService<Web_Group_joint_Profils>, GenericService<Web_Group_joint_Profils>>();
services.AddSingleton<IMenuService, MenuService>();
services.AddSingleton<IMenuRepository, MenuRepository>();
}
}
I also added a DefaultDependencyResolver class :
public class DefaultDependencyResolver : IDependencyResolver
{
protected IServiceProvider serviceProvider;
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public object GetService(Type serviceType)
{
return this.serviceProvider.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
}
Next I have the ServiceProviderExtension class:
public static class ServiceProviderExtensions
{
public static IServiceCollection AddControllerAsServices(this IServiceCollection services, IEnumerable<Type> controllerTypes)
{
foreach(var type in controllerTypes)
{
services.AddTransient(type);
}
return services;
}
}
Finally in my controller, I have Interfaces of GenericService which allows me to access Repository and in turn access my DB. I use the followed interfaces for instantiation
private IGenericService<Web_User_joint_Profils> _userProfileService;
private IGenericService<Web_Group_joint_Profils> _groupProfileService;
private IGenericService<Web_Categories> _categoryService;
PrincipalServerContext context;
private NavigationController(PrincipalServerContext context, IGenericService<Web_User_joint_Profils> userProfileService, IGenericService<Web_Group_joint_Profils> groupProfileService, IGenericService<Web_Categories> categoryService)
{
_context = context;
_userProfileService = userProfileService;
_groupProfileService = groupProfileService;
_categoryService = categoryService;
}
Note that My GenericService takes POCOs as generics in order to know where to look in Database. So for each of these in Startup.ConfigureServices(IServiceCollection services) I added an AddSingleton method to register these services and repositories with the DI container.
Any ideas why I get this exception?

I wouldn't call services inside a startup.
Instance your IGenericService as a private readonly, then create the constructor to call in startup.cs or where ever you decide to use it.
private readonly IGenericService _genericService = new GenericService();
public IGenericService GenericService
{
get{ return _genericService; }
set{ _genericService = value; }
}
Now you call your classes like:
GenericService.Method();

It is rather simple, using IServiceCollection instance that is being passed to ConfigureServices method by the run time you do:
services.AddSingleton<IAbstraction, ConcreteImplementation>();
or, for a transient lifetime scope:
services.AddTransient<IAbstraction, ConcreteImplementation>();
or, in your case:
services.AddSingleton<IGenericService<MyClass>, GenericService<MyClass>>();

Related

MVC5 Web API and Dependency Injection

Trying to do some DI on Web API 2 without third-party tools.
So, from some examples I've got custom dependency resolver (why there's no integrated one? Strange, even Microsoft.Extensions.DependencyInjection provides nothing):
public class DependencyResolver : IDependencyResolver
{
protected IServiceProvider _serviceProvider;
public DependencyResolver(IServiceProvider serviceProvider)
{
this._serviceProvider = serviceProvider;
}
public IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{
}
public object GetService(Type serviceType)
{
return this._serviceProvider.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this._serviceProvider.GetServices(serviceType);
}
public void AddService()
{
}
}
then created this class:
public class ServiceConfig
{
public static void Register(HttpConfiguration config)
{
var services = new ServiceCollection();
services.AddScoped<IMyService, MyServiceClient>();
var resolver = new DependencyResolver(services.BuildServiceProvider());
config.DependencyResolver = resolver;
}
}
and registered it:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configure(ServiceConfig.Register);
}
But when I'm trying to use it:
public class TestController : ApiController
{
private IMyService _myService = null;
public TestController(IMyService myService)
{
_myService = myService;
}
public void Get()
{
_myService.DoWork();
}
}
I'm getting error:
An error occurred when trying to create a controller of type 'TestController'. Make sure that the controller has a parameterless public constructor.
How to cook this one in right way?
What you see happening is related to this problem. In short, Web API will call its default IHttpControllerActivator implementation to request a new controller instance. That instance will call into your DependencyResolver.GetService method. That method will forward the call to MS.DI's GetService method. However, since you didn't register your controllers into the MS.DI container, it will return null. This will cause the default IHttpControllerActivator to try to create the controller using reflection, but this requires a default constructor. Since the controller doesn't have one, this results in the rather cryptic exception message.
The quick solution, therefore, is to register your controllers, e.g.:
services.AddTransient<TestController>();
This, however, will only partly solve your problem because your IDependencyResolver implementation is broken. It is broken in an ugly way, because it might seem to work at first, but will result in memory leaks, because you always resolve from the root container, instead of resolving from a scope. This will cause your resolved controller instances (and other disposable transient components) to stay referenced for the lifetime of your application.
To fix this, you should change your IDependencyResolver implementation to the following:
public class DependencyResolver : IDependencyResolver
{
private readonly IServiceProvider provider;
private readonly IServiceScope scope;
public DependencyResolver(ServiceProvider provider) => this.provider = provider;
internal DependencyResolver(IServiceScope scope)
{
this.provider = scope.ServiceProvider;
this.scope = scope;
}
public IDependencyScope BeginScope() =>
new DependencyResolver(provider.CreateScope());
public object GetService(Type serviceType) => provider.GetService(serviceType);
public IEnumerable<object> GetServices(Type type) => provider.GetServices(type);
public void Dispose() => scope?.Dispose();
}
This implementation will ensure a new IServiceScope is created on each web request and services are always resolved from a request; not from the root IServiceProvider.
Although this will fix your problems, another implementation might still be benificial.
The IDependencyResolver contract is problematic, because it is forced to return null when a call to GetService doesn't result in the correct resolution of a registration. This means that you will end up with these annoying "Make sure that the controller has a parameterless public constructor" errors when you forget to register your controllers.
It is, therefore, much easier to create a custom IHttpControllerActivator instead. In that case you can call GetRequiredService which will never return null:
public class MsDiHttpControllerActivator : IHttpControllerActivator
{
private readonly ServiceProvider provider;
public MsDiHttpControllerActivator(ServiceProvider provider) =>
this.provider = provider;
public IHttpController Create(
HttpRequestMessage request, HttpControllerDescriptor d, Type controllerType)
{
IServiceScope scope = this.provider.CreateScope();
request.RegisterForDispose(scope); // disposes scope when request ends
return (IHttpController)scope.ServiceProvider.GetRequiredService(controllerType);
}
}
This MsDiHttpControllerActivator implementation can be added to the Web API pipeline as follows:
GlobalConfiguration.Configuration.Services
.Replace(typeof(IHttpControllerActivator),
new MsDiHttpControllerActivator(services.BuildServiceProvider(true)));
This removes the need to have an IDependencyResolver implementation. You still need to register your controllers, though:
services.AddTransient<TestController>();
Also note that I changed this:
services.BuildServiceProvider()
To this:
services.BuildServiceProvider(true)
This is a really important change; it protects you (for some part) against Captive Dependencies, which are one of the major problems when using DI Containers. For some obscure reason, the BuildServiceProvider() overload defaults to false, which means it will not validate your scopes.

How can I inject dependencies into a custom ILogger in asp.net core 2.0?

In asp.net core 1.1 I could inject the IServiceProvider into the logger provider and resolve my logger when CreateLogger was called, but it all changed in asp.net core 2.0
My ILogger implementation needs dependencies injected.
How can I achieve this?
ASP.NET core provides possibility to replace built-in DI container with custom one (see this article for details). You could use this possibility to obtain instance of IServiceProvider earlier for logging bootstrapping while still using standard .Net core DI container.
To do this you should change return value of Startup.ConfigureServices(IServiceCollection services) method from void to IServiceProvider. You can use this possibility to build instance of IServiceProvider in ConfigureServices, use it for logging bootstrapping and then return from the method.
Sample code:
public interface ISomeDependency
{
}
public class SomeDependency : ISomeDependency
{
}
public class CustomLogger : ILogger
{
public CustomLogger(ISomeDependency dependency)
{
}
// ...
}
public class CustomLoggerProvider : ILoggerProvider
{
private readonly IServiceProvider serviceProvider;
public CustomLoggerProvider(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public ILogger CreateLogger(string categoryName)
{
return serviceProvider.GetRequiredService<ILogger>();
}
// ...
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return ConfigureLogging(services);
}
private IServiceProvider ConfigureLogging(IServiceCollection services)
{
services.AddTransient<ISomeDependency, SomeDependency>();
services.AddSingleton<ILogger, CustomLogger>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new CustomLoggerProvider(serviceProvider));
return serviceProvider;
}
// ...
}
Starting of with that dependency thing you need in various places
public class SomeDependency : ISomeDependency
{
}
An extension file so we can configure logging on the ServiceCollection as per MSDN
Pretty standard stuff you can find on various sources
public static class ApplicationLoggerFactoryExtensions
{
public static ILoggingBuilder CustomLogger(this ILoggingBuilder builder)
{
builder.Services.AddSingleton<ILoggerProvider, CustomLoggerProvider>();
//Be careful here. Singleton may not be OK for multi tenant applications - You can try and use Transient instead.
return builder;
}
}
The logger provider is the part that gets called AFTER services are built when you are working in your business code and need to log stuff.
So in the context of application the DI is built and available here. And it probably makes sense now why ILoggerProvider exists now.
public class CustomLoggerProvider : ILoggerProvider
{
private ISomeDependency someDependency;
public CustomLoggerProvider(ISomeDependency someDependency)
{
this.someDependency = someDependency;
}
public ILogger CreateLogger(string categoryName)
{
return new CustomeLogger(someDependency);
}
}
The concrete custom logger pretty simple stuff
public class CustomLogger : ILogger
{
public CustomLogger(ISomeDependency dependency)
{
}
}
And in the place where you are configuring your ServiceCollection.. as in the OP's question in Startup.cs
private void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISomeDependency, SomeDependency>();
//services.AddSingleton<ILogger, CustomLogger>(); <== NO
var loggerFactory = new LoggerFactory(); //??? newer DotNet gives you LoggerFactory in startup this may be unnecessary.
//Add some console printer
services.AddLogging(configure => configure.AddConsole())
.Configure<LoggerFilterOptions>(options => options.MinLevel = LogLevel.Trace);
//Add our custom logger
services.AddLogging(configure => configure.CustomLogger()); // <== our extension helping out!
}
So just a note for usage of ILogger
✘ DO NOT - Do not add any ILogger to your services
The whole point of LoggerFactory and LoggerProvider configuration is to simplify using ILogger
public MyBusinessService(ILogger<BusinessServiceClass> log)
{
log.Information("Please tell all registered loggers I am logging!);
}
In my example it will print out message to console if available and the CustomLogger that took a Dependency we injected. If you register more.. it will go to all of them
If you are configuring logging in program.cs you can create a function to configure logging and get an instance of logging provider like this:
private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
{
loggingBuilder.AddConfiguration(context.Configuration.GetSection("Logging"));
loggingBuilder.AddDebug();
loggingBuilder.AddConsole();
var serviceProvider = loggingBuilder.Services.BuildServiceProvider();
loggingBuilder.AddProvider(new DoxErrorLoggerProvider(serviceProvider, null));
}
Then in BuildWebHost you will configure logging as follows:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(ConfigureApplicationLogging)
.UseNLog()
.UseStartup<Startup>()
.Build();

Unable to resolve service for type while attempting to activate

In my ASP.NET Core application, I get the following error:
InvalidOperationException: Unable to resolve service for type 'Cities.Models.IRepository' while attempting to activate 'Cities.Controllers.HomeController'.
I the HomeController I am trying to pass the Cities getter to the view like so:
public class HomeController : Controller
{
private readonly IRepository repository;
public HomeController(IRepository repo) => repository = repo;
public IActionResult Index() => View(repository.Cities);
}
I have one file Repository.cs that contains an interface and its implementation like so:
public interface IRepository
{
IEnumerable<City> Cities { get; }
void AddCity(City newCity);
}
public class MemoryRepository : IRepository
{
private readonly List<City> cities = new List<City>();
public IEnumerable<City> Cities => cities;
public void AddCity(City newCity) => cities.Add(newCity);
}
My Startup class contains the default-generated code from the template. I have made any changes:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
For the Dependency Injection framework to resolve IRepository, it must first be registered with the container. For example, in ConfigureServices, add the following:
services.AddScoped<IRepository, MemoryRepository>();
For .NET 6+, which uses the new hosting model by default, add the following in Program.cs instead:
builder.Services.AddScoped<IRepository, MemoryRepository>();
AddScoped is just one example of a service lifetime:
For web applications, a scoped lifetime indicates that services are created once per client request (connection).
See the docs for more information on Dependency Injection in ASP.NET Core.
We are getting this error in Entity frame work core database first approach. I followed below steps and error got resolved
Step 1: Check Your context class constructor should be like this
public partial class ZPHSContext : DbContext
{
public ZPHSContext(DbContextOptions<ZPHSContext> dbContextOptions)
: base(dbContextOptions)
{
}
}
Step 2: In Startup file
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<ZPHSContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("BloggingDatabase")));
}
Step 3: Connection string in appsettings
"ConnectionStrings": {
"BloggingDatabase": "Server=****;Database=ZPHSS;Trusted_Connection=True;"
}
Step 4: Remove default code in OnConfiguring method in context class
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}
Other answers are CORRECT, however I was spinning up a new asp.net core 2.1.x project and got this error.
Ended up being a typo by ME.
So in my Controller instead of Correctly using the Interface like this
public HomeController(IApplicationRepository applicationRepository)
{
_applicationRepository = applicationRepository;
}
My typo had me using ApplicationRepository instead of its interface IApplicationRepository
Notice below, and so with NO ERRORS spotting the missing "I" was fun :/
public HomeController(IApplicationRepository applicationRepository)
{
_applicationRepository = applicationRepository;
}
Thus the controller was not resolving the DI...
A method like this needs to be added to your Startup:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//...
// Add application services.
services.AddTransient<IRepository, MemoryRepository>();
//..
}
Services should be registered before used.
UPDATE:
If you do not want to use DI on your application, just create and instance of MemoryRepository on the constructor of HomeController, like this:
public class HomeController : Controller
{
private IRepository repository;
public HomeController()
{
repository = new MemoryRepository();
}
public IActionResult Index()
{
return View(repository.Cities);
}
}
You have to add your implementation to DI (Dependeny Injection) section. For .Net Core Mvc, it would be like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseInMemoryDatabase()
);
services.AddScoped<IRepository, MemoRepostory>();
}
This may not be helpful for your code sample but in my case the same error was a result of a circular dependency.
you have to register your repository like this
services.AddSingleton<IRepository, MemoryRepository>();
In my case, I was trying to access context through constructor. like here;
private readonly Context _context;
public ImageController(Context context)
{
_context = context;
}
But When I tried to access the context just by creating an instance of class, it worked like here;
Context c = new Context();
For me I am using visual studio 2022 and .NET 6
the solution was add the following line in the Program.cs file :
builder.Services.AddSingleton<IHISInterface<UserDetails>, UserDetailsRepository>();
There is one more possibility that, You might have sent wrong variable in the place while writing this HTTPPOST last part code
mine is
var categoryMap = _mapper.Map(categoryCreate);
if(!_categoryRepository.CreateCategory(categoryMap))
{
ModelState.AddModelError("", "Something went wrong while saving");
return StatusCode(500, ModelState);
}
return Ok("Successfully created");
in the if condition I passed the category as parameter instead of categoryMap
so please cross check

Does .net core dependency injection support Lazy<T>

I am trying to use the generic Lazy class to instantiate a costly class with .net core dependency injection extension. I have registered the IRepo type, but I'm not sure what the registration of the Lazy class would look like or if it is even supported. As a workaround I have used this method http://mark-dot-net.blogspot.com/2009/08/lazy-loading-of-dependencies-in-unity.html
config:
public void ConfigureService(IServiceCollection services)
{
services.AddTransient<IRepo, Repo>();
//register lazy
}
controller:
public class ValuesController : Controller
{
private Lazy<IRepo> _repo;
public ValuesController (Lazy<IRepo> repo)
{
_repo = repo;
}
[HttpGet()]
public IActionResult Get()
{
//Do something cheap
if(something)
return Ok(something);
else
return Ok(repo.Value.Get());
}
}
Here's another approach which supports generic registration of Lazy<T> so that any type can be resolved lazily.
services.AddTransient(typeof(Lazy<>), typeof(Lazier<>));
internal class Lazier<T> : Lazy<T> where T : class
{
public Lazier(IServiceProvider provider)
: base(() => provider.GetRequiredService<T>())
{
}
}
You only need to add a registration for a factory method that creates the Lazy<IRepo> object.
public void ConfigureService(IServiceCollection services)
{
services.AddTransient<IRepo, Repo>();
services.AddTransient<Lazy<IRepo>>(provider => new Lazy<IRepo>(provider.GetService<IRepo>));
}
Services that are to be fetched in Lazy will be re-introduced by the factory registration method with the new Lazy of the intended service type and provided for its implementation using serviceProvider.GetRequiredService.
services.AddTransient<IRepo, Repo>()
.AddTransient(serviceProvider => new Lazy<IRepo>(() => serviceProvider.GetRequiredService<IRepo>()));
To my opinion, the code below should do the work(.net core 3.1)
services.AddTransient<IRepo, Repo>();
services.AddTransient(typeof(Lazy<>), typeof(Lazy<>));
To register services as lazy
services.AddScoped<Lazy<AService>>();
services.AddScoped<Lazy<BService>>();
Or by creating an extension
static class LazyServiceCollection
{
public static void AddLazyScoped<T>(this IServiceCollection services)
{
services.AddScoped<Lazy<T>>();
}
}
...
services.AddLazyScoped<AService>();
services.AddLazyScoped<BService>();
And use it
[ApiController, Route("lazy")]
public class LazyController : ControllerBase
{
private readonly Lazy<AService> _aService;
private readonly Lazy<BService> _bService;
public LazyController(Lazy<AService> aService, Lazy<BService> bService)
{
_aService = aService;
_bService = bService;
}
[HttpGet("a")]
public ActionResult GetA()
{
_aService.Value.DoWork();
return new OkResult();
}
[HttpGet("b")]
public ActionResult GetB()
{
_bService.Value.DoWork();
return new OkResult();
}
}
Result
Init AService
AService Work
I use this form, I hope resolve your problem, this code for Scoped and Transient Life-Cycle you can write for other Life-Cycle look like this.
My Dot-Net-Core vertion is 6
public static class Lazier
{
public static IServiceCollection AddScopedLazier<T>(this IServiceCollection services)
{
return services.AddScoped(provider => new Lazy<T>(provider.GetService<T>));
}
public static IServiceCollection AddTransientLazier<T>(this IServiceCollection services)
{
return services.AddTransient(provider => new Lazy<T>(provider.GetService<T>));
}
}
Usage for Scoped Life-Cycle:
services.AddScoped<ISideDal, EfSideDal>().AddScopedLazier<ISideDal>();
Usage for Transient Life-Cycle:
services.AddTransient<ISideDal, EfSideDal>().AddTransientLazier<ISideDal>();
A bit late to the party here, but to throw another solution on to the pile... I wanted to selectively allow Lazy instantiation of services, so I created this extension method:
public static IServiceCollection AllowLazy(this IServiceCollection services)
{
var lastRegistration = services.Last();
var lazyServiceType = typeof(Lazy<>).MakeGenericType(
lastRegistration.ServiceType);
services.Add(new ServiceDescriptor(
lazyServiceType,
serviceLocator => Activator.CreateInstance(
lazyServiceType,
() => serviceLocator.GetRequiredService(
lastRegistration.ImplementationType ??
lastRegistration.ServiceType
))!,
lastRegistration.Lifetime
));
return services;
}
That way you can just tack .AllowLazy() on to your registration without having to re-specify the types or the scope -
public void ConfigureService(IServiceCollection services)
{
services.AddTransient<IRepo, Repo>().AllowLazy();
}

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;
}

Categories

Resources