New to Dependency Injection, so this is probably a simple matter, but i have tried and cant figure it out, i am using Simple Injector.
I have a WebApi that uses SimpleInjector perfectly fine, now i would like to implement security using OAuth.
To do this i started to follow this tutorial, which is very helpful, but doesnt use Dependancy Injection
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
I have my global.asax file looking like this, to setup dependancy injection (working perfect)
protected void Application_Start()
{
SimpleInjectorConfig.Register();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
I have created a Startup.Auth.cs file to configure OAuth
public class Startup
{
public void Configuration(IAppBuilder app)
{
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new MyAuthorizationServerProvider() // here is the problem
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Now as i commented above, MyAuthorizationServerProvider is the problem. it takes a parameter of IUserService which i usually inject. I do not want to empty constructor because my IUserService also injects a repository. Here is the file
public class ApiAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private IUserService _service;
public ApiAuthorizationServerProvider (IUserService service)
{
_service = service;
}
public override async Task ValidateClientAuthentication(
OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin",
new[] { "*" });
IUserService service = Startup.Container.GetInstance<IUserService>();
User user = _service.Query(e => e.Email.Equals(context.UserName) &&
e.Password.Equals(context.Password)).FirstOrDefault();
if (user == null)
{
context.SetError("invalid_grant",
"The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
How can i get this working with Dependency Injection? This must happen quite a lot and must be able to do something to handle it. I am sure its something simple, but i am still learning.
I took some time to find out if it would be possible to register OAuthAuthorizationServerOptions in the Owin pipeling using the app.Use() method directly, instead of app.UseOAuthAuthorizationServer() which is just an extension method over app.Use(). app.Use() has an overload where you could register a delegate which you could use to construct the OAuthAuthorizationServerOptions.
Unfortunately this effort hit a dead end, because it seems that even if we'd use a delegate for the construction, this will be most likely only called once by the Owin pipeline which leads to the same result, namely a singleton instance of the OAuthAuthorizationServerOptions and thus all dependencies of this class will be singleton as well.
So the only solution to keep things working as they should be, is to pull a new instance of your UserService every time the GrantResourceOwnerCredentials() method is called.
But to follow the Simple Injector design principles it would be bad design to keep a dependency on the container in the ApiAuthorizationServerProvider class, like the original code shows.
A better way to do this would be to use a factory for the UserService class instead of directly pulling it from the container. The next code shows an example of how you could do this:
First of all, clean out the Application_Start() method in your global.asax file and place all your startup code in the Owin Startup() method. The code of the Startup() method:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = SimpleInjectorConfig.Register();
GlobalConfiguration.Configure(WebApiConfig.Register);
Func<IUserService> userServiceFactory = () =>
container.GetInstance<IUserService>();
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new ApiAuthorizationServerProvider(userServiceFactory)
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Notice how I changed the signature of the SimpleInjectorConfig.Register() function by returning the completly configured Simple Injector container to the caller so it can be used directly.
Now change the constructor of your ApiAuthorizationServerProvider class, so the factory method can be injected:
public class ApiAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private Func<IUserService> userServiceFactory;
public ApiAuthorizationServerProvider(Func<IUserService> userServiceFactory)
{
this.userServiceFactory = userServiceFactory;
}
// other code deleted for brevity...
private IUserService userService
{
get
{
return this.userServiceFactory.Invoke();
}
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
// other code deleted for brevity...
// Just use the service like this
User user = this.userService.Query(e => e.Email.Equals(context.UserName) &&
e.Password.Equals(context.Password)).FirstOrDefault();
// other code deleted for brevity...
}
}
This way you get a new UserService everytime the GrantResourceOwnerCredentials() method is called and the complete dependency graph behind the UserService class will follow the lifetimes you defined in your Simple Injector configuration, while you depend on the container only in the composition root of the application.
When you start with Dependency Injection, Owin is probably not the most friendly API to start with.
I noticed this part in your code:
IUserService service = Startup.Container.GetInstance<IUserService>();
You are probably doing this as a workaround before you find out how to use the constructor. But I think that's your answer right there. The OAuthAuthorizationServerProvider is a singleton, so your IUserService will be a singleton also and all the dependencies of this class will be singleton as well.
You mentioned you use a repository in your user service. Your probably don't want this repository to be singleton as I suppose this repository will use a DbContext of some kind.
So the intermediate answer could be the solution you made already. Maybe there is a more elegant solution if you do some research on what the UseOAuthAuthorizationServer method does exactly. The source code of Katana can be found here: Katana source code
For the registration of the other asp.net identity classes the link in the comment of DSR will give you a good starting point.
Firstly, this is a late answer. I just wrote this down in case somebody else come across the similar issue and somehow get linked to this page (like me) in the future.
The previous answer is reasonable, but will not solve the problem if the service is actually registered per Web API request, which I believe is what people usually do if they want to use dependency injection for identity framework object like UserManager.
The problem is when GrantResourceOwnerCredentials get called (usually when people hit the 'token' endpoint), simple injector won't start a api request life cycle. To solve this, all you need to do is start one.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//......
using (Startup.Container.BeginExecutionContextScope())
{
var userService= Startup.Container.GetInstance<IUserService>();
// do your things with userService..
}
//.....
}
With BeginExecutionContextScope, simple injector will start a new context scope. However, remember it need to be disposed explicitly.
As long as you are registering the dependency resolver for your webapi in your App_Start SimpleInjectorConfig.Register();
Like this
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
And if you are using the recommended AsyncScopedLifestyle
Then you can use the dependency resolver to get a new instance of your services like this
using (var scope = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
var _userService = scope.GetService(typeof(IUserService)) as IUserService;
//your code to use the service
}
Related
I'm having some trouble with the whole dependency injection with/through reflection.
The scenario is as following;
User authenticates via AzureAD through our identity server
If user is not in local database, save the user together with some other information
I keep restructuring my logic and I still can't make the puzzle work.
Currently this is my chain:
OWIN Startup:
I'm specifying a method to run after the OnTokenValidated event has triggered: ProfileEvents.ValidatedToken
services.AddAuthentication()
.AddOpenIdConnect("oidc", o =>
{
o.ClientId = $"{configuration["Globals:AzureApplication:AppId"]}";
o.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
o.Authority = $"https://login.microsoftonline.com/{configuration["Globals:AzureApplication:TenantId"]}";
o.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
o.Events = new OpenIdConnectEvents()
{
OnTokenValidated = ProfileEvents.ValidatedToken
};
});
DatabaseContext is added like this:
public void ConfigureServices(IServiceCollection services)
{
.... // other stuff
services.Configure<Config.ConnectionStrings>(configuration.GetSection("ConnectionStrings"));
services.AddDbContext<ModelContext>(options => options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
}
The my ValidatedToken method looks like this:
internal static class ProfileEvents
{
internal static Task ValidatedToken(TokenValidatedContext context)
{
var dbContext = new ProfileDAL();
dbContext.SaveToDb(context.Principal);
return Task.FromResult(0);
}
}
And finally my ProfileDAL looks like this:
public class ProfileDAL
{
internal async Task SaveToDb(ClaimsPrincipal principal)
{
var nameClaim = principal.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn");
var emailClaim = principal.FindFirstValue("email");
// TODO: Save user..
}
}
Now which way I turn I either have to use and pass IOptions through the chain so that ModelContext can override "OnConfiguring" to actually get the connection string or I have to pass the context.
Is there really no way to access either the connection string outside of the DI?
For me I feel like something like this would solve all of my current issues:
public partial class ModelContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer( ** Magic way to access connection string in appsettings ** );
}
}
When you speak of 'passing down the chain`, that shouldn't be necessary. If we're using a dependency injection container then we don't have to pass a dependency to one class, have that pass a dependency to another class, and so on. In fact, that's part of what we're avoiding by using the container.
We don't have to do that because each class is receiving its dependencies as abstractions (usually interfaces.) That means that one class can't pass something to its dependencies because it doesn't even know what that dependency needs.
Rather than passing something along from one class to another as if in a chain, each individual class is resolved with just the dependency it needs. None of the classes in the chain are responsible for supplying constructor arguments to their dependencies.
That becomes more difficult when we use static classes like ProfileEvents. You can't inject ProfileDAL into it because it's static. Then, because ProfileDAL isn't getting "newed" - new ProfileDAL() - there's no way to inject its dependencies.
That in turn means that you won't use constructor injection with ProfileDAL, and you'll look for other ways to create and pass in its dependencies. But use of the DI container should prevent that. All the way down the dependency graph everything is following the same pattern, where each class gets its dependencies in its constructor without knowing or caring what dependencies those classes have.
One of my dependencies (DbContext) is registered using the WebApiRequestLifestyle scope.
Now, my background job uses IoC and depends on the service that was registered above using the WebApiRequestLifestyle. I'm wondering how this works when Hangfire calls the method i registered for the background job. Will the DbContext be treated like a transistent object since the web api is not involved?
Any guidance would be great!
Here is my initialize code that occurs during start up:
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
var container = SimpleInjectorWebApiInitializer.Initialize(httpConfig);
var config = (IConfigurationProvider)httpConfig.DependencyResolver
.GetService(typeof(IConfigurationProvider));
ConfigureJwt(app, config);
ConfigureWebApi(app, httpConfig, config);
ConfigureHangfire(app, container);
}
private void ConfigureHangfire(IAppBuilder app, Container container)
{
Hangfire.GlobalConfiguration.Configuration
.UseSqlServerStorage("Hangfire");
Hangfire.GlobalConfiguration.Configuration
.UseActivator(new SimpleInjectorJobActivator(container));
app.UseHangfireDashboard();
app.UseHangfireServer();
}
public static Container Initialize(HttpConfiguration config)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterWebApiControllers(config);
container.RegisterMvcIntegratedFilterProvider();
container.Register<Mailer>(Lifestyle.Scoped);
container.Register<PortalContext>(Lifestyle.Scoped);
container.RegisterSingleton<TemplateProvider, TemplateProvider>();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
return container;
}
Here is my code that kicks off the background job:
public class MailNotificationHandler : IAsyncNotificationHandler<FeedbackCreated>
{
private readonly Mailer mailer;
public MailNotificationHandler(Mailer mailer)
{
this.mailer = mailer;
}
public Task Handle(FeedbackCreated notification)
{
BackgroundJob.Enqueue<Mailer>(x => x.SendFeedbackToSender(notification.FeedbackId));
BackgroundJob.Enqueue<Mailer>(x => x.SendFeedbackToManagement(notification.FeedbackId));
return Task.FromResult(0);
}
}
Finally here is the code that runs on the background thread:
public class Mailer
{
private readonly PortalContext dbContext;
private readonly TemplateProvider templateProvider;
public Mailer(PortalContext dbContext, TemplateProvider templateProvider)
{
this.dbContext = dbContext;
this.templateProvider = templateProvider;
}
public void SendFeedbackToSender(int feedbackId)
{
Feedback feedback = dbContext.Feedbacks.Find(feedbackId);
Send(TemplateType.FeedbackSender, new { Name = feedback.CreateUserId });
}
public void SendFeedbackToManagement(int feedbackId)
{
Feedback feedback = dbContext.Feedbacks.Find(feedbackId);
Send(TemplateType.FeedbackManagement, new { Name = feedback.CreateUserId });
}
public void Send(TemplateType templateType, object model)
{
MailMessage msg = templateProvider.Get(templateType, model).ToMailMessage();
using (var client = new SmtpClient())
{
client.Send(msg);
}
}
}
I'm wondering how this works when Hangfire calls the method i registered for the background job. Will the DbContext be treated like a transistent object since the web api is not involved?
As the design decisions describe, Simple Injector will never allow you to resolve an instance outside an active scope. So that DbContext will neither be resolved as transient or singleton; Simple Injector will throw an exception when there's no scope.
Every application type requires its own type of scoped lifestyle. Web API requires the AsyncScopedLifestyle (in previous versions WebApiRequestLifestyle), WCF an WcfOperationLifestyle and MVC the WebRequestLifestyle. For Windows Services you will typically use an AsyncScopedLifestyle.
If your Hangfire jobs run in a Windows Service, you will have to use either a ThreadScopedLifestyle or the AsyncScopedLifestyle. Those scopes require explicit starting.
When running the jobs on a background thread in a web (or Web API) application, there is no access to the required context and this means that Simple Injector will throw an exception if you try to do so.
You however are using the Hangfire.SimpleInjector integration library. This library implements a custom JobActivator implementation called SimpleInjectorJobActivator and this implementation will create start a Scope for you on the background thread. Hangfire will actually resolve your Mailer within the context of this execution context scope. So the Mailer constructor argument in your MailNotificationHandler is actually never used; Hangfire will resolve this type for you.
The WebApiRequestLifestyle and AsyncScopedLifestyle are interchangeable; the WebApiRequestLifestyle uses an execution context scope in the background and the SimpleInjectorWebApiDependencyResolver actually starts an execution context scope. So the funny thing is that your WebApiRequestLifestyle can be used for background operations as well (although it can be a bit confusing). So your solution works and works correctly.
When running in MVC, however, this will not work, and in that case you would have to create a Hybrid lifestyle, for instance:
var container = new Container();
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
new AsyncScopedLifestyle(),
new WebRequestLifestyle());
You can register your DbContext as follows:
container.Register<DbContext>(() => new DbContext(...), Lifestyle.Scoped);
Here's some feedback on your application's design, if you don't mind.
Prevent letting application code, such as your MailNotificationHandler, from taking a direct dependency on an external library such as Hangfire. This is a direct violation of the Dependency Inversion Principle and makes your application code very hard to test and maintain. Instead, let solely your Composition Root (the place where you wire your dependencies) take a dependency on Hangfire. In your case, the solution is really straightforward and I would even say pleasant, and it would look as follows:
public interface IMailer
{
void SendFeedbackToSender(int feedbackId);
void SendFeedbackToManagement(int feedbackId);
}
public class MailNotificationHandler : IAsyncNotificationHandler<FeedbackCreated>
{
private readonly IMailer mailer;
public MailNotificationHandler(IMailer mailer)
{
this.mailer = mailer;
}
public Task Handle(FeedbackCreated notification)
{
this.mailer.SendFeedbackToSender(notification.FeedbackId));
this.mailer.SendFeedbackToManagement(notification.FeedbackId));
return Task.FromResult(0);
}
}
Here we added a new IMailer abstraction and made the MailNotificationHandler dependent on this new abstraction; unaware of the existence of any background processing. Now close to the part where you configure your services, define an IMailer proxy that forwards the calls to Hangfire:
// Part of your composition root
private sealed class HangfireBackgroundMailer : IMailer
{
public void SendFeedbackToSender(int feedbackId) {
BackgroundJob.Enqueue<Mailer>(m => m.SendFeedbackToSender(feedbackId));
}
public void SendFeedbackToManagement(int feedbackId) {
BackgroundJob.Enqueue<Mailer>(m => m.SendFeedbackToManagement(feedbackId));
}
}
This requires the following registrations:
container.Register<IMailer, HangfireBackgroundMailer>(Lifestyle.Singleton);
container.Register<Mailer>(Lifestyle.Transient);
Here we map the new HangfireBackgroundMailer to the IMailer abstraction. This ensures that the BackgroundMailer is injected into your MailNotificationHandler, while the Mailer class is resolved by Hangfire when the background thread is started. The registration of the Mailer is optional, but advisable, since it has become a root object, and since it has dependencies, we want Simple Injector to be aware of this type to allow it to verify and diagnose this registration.
I hope you agree that from perspective of the MailNotificationHandler, the application is much cleaner now.
Within my Web API I have linked Autofac as IoC container, and I do it like this:
Domain level
public class Autofac
{
protected ContainerBuilder Builder { get; set; }
public Autofac()
{
this.Builder = new ContainerBuilder();
}
public virtual IContainer Register()
{
// Register dependencies
SetUpRegistration(this.Builder);
// Build registration.
var container = this.Builder.Build();
// End
return container;
}
private static void SetUpRegistration(ContainerBuilder builder)
{
// === DATALAYER === //
// MyRepository
builder.RegisterType<MyRepository>()
.As<IMyRepository>()
.InstancePerLifetimeScope();
// === DOMAIN === //
// MyManager
builder.RegisterType<MyManager>()
.As<IMyManager>()
.InstancePerLifetimeScope();
}
}
Web API
public class Autofac : Domain.IoC.Autofac
{
public IContainer Register(HttpConfiguration config)
{
// Register your Web API controllers.
base.Builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
base.Builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
// Complete registration and get container instance.
var container = base.Register();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Done.
return container;
}
}
As you see it inherits from the base class from Domain and sets up Web API specific config.
Usage
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new IoC.Autofac().Register(GlobalConfiguration.Configuration);
}
Which is at global.asax, as you know.
The question
This works fine for Web API, but I haven't got a clue what I need to do to register all this within a UnitTest project context.
The idea is that I would create a similar implementation to the Autofac class at Web API level, but than with mocks (completely ignoring the base class from Domain).
Any pointers?
Personally I never see the need (and I struggle to comprehend how viable or helpful it would be) to setup my IoC container directly within a unit test.
As a unit test is used to test a logical piece of code that can be quickly built, easily ran and doesn't require much (I'd advocate no) tear-down. It should not require all of your application to be be setup for the test to run.
Remember that your unit test is simply testing the flow of data through the system i.e that your DomainManager is actually going to call a IRepository when you expect that it should. Then you would have separate test classes for all your repositories to determine that they would correctly add to the database etc.
I'm not sure how you use the DBContext class but as an example of a wrapper this is what it would sort of look like.
interface IDBSetWrapper
{
object Add(object entity);
}
interface IDBContextWrapper
{
...
IDBSet Set(Type entityType);
...
}
class DBContextWrapper : IDBContextWrapper
{
private readonly DBContext context;
public DBContextWrapper()
{
context = new DBContext();
}
...
public IDBSet Set(Type entityType)
{
var dbSet = context.Set(entityType);
return new DBSetWrapper(dbSet);
}
...
}
It's not much but I hope that it demonstrates what I mean about a thin wrapper. Basically the wrapper is the DBContext and will contain an instance of it within the class, the actual DBContext will be called when you request the wrapper to do anything.
I have shown what would happen when returning another object (in this case a DBSet), this will also be wrapped in a separate object with an interface. This is so that you can mock the returns from this class easily.
You can add this new wrapper into your IoC a little better now as it provides an interface.
One thing to note is that you won't be able to and probably wouldn't wish to test the wrapper class, there would be very little point as I see it. But previously I've seen colleagues do an integration test on these sort of classes.
I'm using Owin (OAuth), ASP.NET WebApi2 and Unity together with custom Authorization server provider (SimpleAuthorizationServerProvider) based on OAuthAuthorizationServerProvider, but with my implementation of Unit of work and Repository pattern.
My problem is resolving dependencies in Startup class, I mean Startup class needs SimpleAuthorizationServerProvider and SimpleAuthorizationServerProvider needs IUserOrchestration and IUnitOfWorkFactory. Dependencies in SimpleAuthorizationServerProvider are fine, problem is in Startup class, because Startup class has to have constructor without parameters and property injection not working - dependencies are inject too late.
Only working solution is based on ServiceLocator and honestly, it's bad idea.
I need find another working solution...
public class Startup
{
private SimpleAuthorizationServerProvider _simpleProvider;
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
// Create instance for Unity container - let's try to run!
var container = new UnityContainer();
config.DependencyResolver = new UnityResolver(container);
// Include project classes to IoC container
new CommonUnityConfiguration().Configurate(container);
new RepositoryUnityConfiguration().Configurate(container);
new OrchestrationUnityConfiguration().Configurate(container);
new ServerUnityConfiguration().Configurate(container);
// HERE COMES PROBLEMATIC LINE
_simpleProvider = container.Resolve<SimpleAuthorizationServerProvider>(); // Ugh! ServiceLocator - not pretty, but how can I replace it? :(
ConfigureOAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); // enable CORS
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = _simpleProvider
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
and implementation of SimpleAuthorizationServerProvider:
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private readonly IUserOrchestration _userOrchestration;
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
public SimpleAuthorizationServerProvider(IUserOrchestration userOrchestration, IUnitOfWorkFactory unitOfWorkFactory)
{
_userOrchestration = userOrchestration;
_unitOfWorkFactory = unitOfWorkFactory;
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (IUnitOfWork uow = _unitOfWorkFactory.Create())
{
var user = _userOrchestration.FindUser(context.UserName);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
I don't see a Service Locator there, rather, this looks like a Composition Root.
Although it is disputable whether or not the Composition Root is a place to resolve dependencies and use them or only configure them, I wonder where actually you use the resolved instance - in the code snippet the instance is resolved and never used (!?).
You could possibly refactor this to split it into two classes of different responsibilities - have a clean Composition Root where you only configure and other initialization classes where you actually use the configuration. Or rather, decide which of the two you want your startup class should be.
I'm finding my feet with Web Api 2, Owin and Autofac and need some guidance, please.
Overview
I have an Owin self-hosted Web Api that uses Autofac for IoC and dependency injection. The project is a console app acting like a service, meaning it can be stopped and started. I have an Authentication controller with two constructors: one parameter-less and the other injects a repository.
Problem
When I run the service and call the api, my parameter-less constructor is called and my repository never gets injected (_repository = null).
Research
I've done a fair bit of research and found some helpful projects on Github, which I replicated to the tee but I'm missing a big part of the puzzle. This was helpful but didn't solve my problem. I read this question on Stack Overflow and Dane Sparza had a nice demo project but I couldn't find a clear solution. The problem is not the self-hosting but the dependency injection.
My code (thinned out for explanation)
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
var connectioninfo = ConnectionInfo.FromAppConfig("mongodb");
var builder = new ContainerBuilder(); // Create the container builder.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the Web API controllers.
builder.Register(c => new Logger()).As<ILogger>().InstancePerRequest(); // Register a logger service to be used by the controller and middleware.
builder.RegisterType<AuthenticationRepository>().As<IAuthenticationRepository>().WithParameter(new NamedParameter("connectionInfo", connectioninfo)).InstancePerRequest();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container); // Create an assign a dependency resolver for Web API to use.
GlobalConfiguration.Configuration.DependencyResolver = resolver; // Configure Web API with the dependency resolver
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
app.UseAutofacWebApi(config); // Make sure the Autofac lifetime scope is passed to Web API.
}
Program.cs
static void Main(string[] args)
{
var service = new ApiService(typeof(Program), args);
var baseAddress = "http://localhost:9000/";
IDisposable _server = null;
service.Run(
delegate()
{
_server = WebApp.Start<Startup>(url: baseAddress);
},
delegate()
{
if (_server != null)
{
_server.Dispose();
}
}
);
}
ApiController
public class AuthenticationController : ApiController
{
private IAuthenticationRepository _repository;
public AuthenticationController() { }
public AuthenticationController(IAuthenticationRepository repository)
{
_repository = repository;
}
[AllowAnonymous]
public IHttpActionResult Authenticate(string name, string password)
{
if (_repository == null)
return BadRequest("User repository is null.");
var valid = _repository.AuthenticateUser(name, password);
return Ok(valid);
}
}
You should be using the HttpConfiguration with which you're bootstrapping OWIN everywhere.
So, this:
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Should become:
config.DependencyResolver = resolver;
Other than that, everything looks good. Api controllers are registered, although you're not giving them a scope. Not sure if in Autofac scoping defaults to per-request for controllers or if it has the notion of per-request scoping at all (I know that LightInject has it).
Looking around, I think you followed the example on the Google Code repo for Autofac, which indeed uses GlobalConfiguration. Instead, if you look at the GitHub example, it is a bit different. Try to make the changes according to this. Including this:
// This should be the first middleware added to the IAppBuilder.
app.UseAutofacMiddleware(container);
2016 update
What I said above still applies, but something extra from Autofac's docs (thanks Brad):
A common error in OWIN integration is use of the
GlobalConfiguration.Configuration. In OWIN you create the
configuration from scratch. You should not reference
GlobalConfiguration.Configuration anywhere when using the OWIN
integration.