I have a solution that has WebAPI, BL and DAL layers in separate projects interfaces included, the projects are targeting .Net 4.8, I am trying to implement Dependency Injection for the first time.
I haven't used any external IoC packages StructureMap, Autofac, etc and really the only injection I'm doing is between the layers.
I have been following this previous stackoverflow question
However, I have become stuck.
This is my startup.cs:
using TA.Services.WebAPI.Providers;
using System.Web.Http.Dependencies;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using System.Web.Mvc;
using TA.Services.BL.BusinessLogic;
using TA.Services.BL.Interface;
[assembly: OwinStartup(typeof(TA.Services.WebAPI.Startup))]
namespace TA.Services.WebAPI
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
ConfigureServices(services);
var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());
HttpConfiguration config = new HttpConfiguration();
config.DependencyResolver = resolver;
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t)
|| t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class DefaultDependencyResolver : System.Web.Mvc.IDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
{
protected IServiceProvider serviceProvider;
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IDependencyScope BeginScope()
{
return new DefaultDependencyResolver(this.serviceProvider.CreateScope().ServiceProvider);
}
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 static class ServiceProviderExtensions
{
public static IServiceCollection AddControllersAsServices(this IServiceCollection services,
IEnumerable<Type> controllerTypes)
{
foreach (var type in controllerTypes)
{
services.AddTransient(type);
}
return services;
}
}
}
I have only altered one of my simple controllers to inject it's appropriate BL interface and tested via the front-end, but it gets a 'Make sure that the controller has a parameterless public constructor'
So other than startup and the controller I haven't touched anything else.
Questions:
1: Can anyone see if there is anything missing from what I've done?
2: I can see through debug, that the controllers I have are populating the services via ConfigureServices(). Do I need to do anything extra to link them up with their dependencies?
[UPDATE 1 of 2]: Controller: Basically just changed out the constructor so it has a parameter.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TA.Services.BL.BusinessLogic;
using TA.Services.BL.Interface;
using TA.Services.DTO.DTO;
using TA.Services.WebAPI.Providers;
using Syncfusion.EJ2.Base;
using Newtonsoft.Json;
using TA.Services.WebAPI.Helpers;
namespace TA.Services.WebAPI.Controllers
{
[WebApiConfig.CamelCaseControllerConfig]
public class AuditsController : ApiController
{
private readonly IAuditsBL _auditsBL;
/*
public AuditsController()
{
_auditsBL = new AuditsBL();
}
*/
public AuditsController(IAuditsBL auditsBL)
{
_auditsBL = auditsBL;
}
...
}
}
[UPDATE 2 of 2]:
Made a change to ConfigureServices adding singleton to the services
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
.Where(t => typeof(IController).IsAssignableFrom(t)
|| t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
//Added this
services.AddSingleton<IAuditsBL, AuditsBL>();
}
When I run the app I'm getting services populated like:
and when I run the front-end and navigate to where the AuditController gets called I get the following in devtools: