How to replace ServiceLocator in Startup class - c#

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.

Related

ASP.NET Core 3.0: Disable ASP0000 Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices' [duplicate]

In my asp.net core 2.0 web app, I've got a custom ISecurityTokenValidator which validates tokens.
It depends on a repository to do a db lookup - the repository itself is setup as a scoped dependency:
services.AddScoped<IMyRepository>(MyRepository);
Now the funkiness comes about because of the way the ISecurityTokenValidator is setup.
It's added in ConfigureServices:
.AddJwtBearer(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
})
This is how it looks:
public class MyTokenValidator : ISecurityTokenValidator
{
private readonly IServiceProvider _serviceProvider;
public MyTokenValidator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public bool CanReadToken(string securityToken) => true;
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
var serviceScopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
var myRepository = scope.ServiceProvider.GetService<IMyRepository>();
var principalFactory = scope.ServiceProvider.GetService<IUserClaimsPrincipalFactory<User>>();
// Use the repo....
}
}
}
Now, because the IsecurityTokenProvider is only instantiated once, it's effectively a singleton. When I use the service provider to ask for a IMyRepository I was finding that I was always received the same object - there is no new scope as far as it was concerned, because it's in a singleton class.
To get round that, you'll see in the code above Ive had to manually force a new scope every time the token validator is called. Is this really the only way to resolve this, it seems like I'm hacking around to make it work here...
Old question but the best way I have found to solve this problem is to use IPostConfigureOptions<JwtBearerOptions> to configure SecurityTokenValidators.
First register the JWT bearer and options
services.AddAuthentication(options =>
{
...
}).AddJwtBearer(AuthenticateScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
...
};
});
Then register a custom implementation of IPostConfigureOptions<JwtBearerOptions>
services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();
And register a custom implementation of ISecurityTokenValidator
services.AddSingleton<MyCustomSecurityTokenValidator>();
CustomJwtBearerOptionsPostConfigureOptions could look something like:
public class CustomJwtBearerOptionsPostConfigureOptions : IPostConfigureOptions<JwtBearerOptions>
{
private readonly MyCustomSecurityTokenValidator _tokenValidator; //example dependancy
public CustomJwtBearerOptionsPostConfigureOptions(MyCustomSecurityTokenValidator tokenValidator)
{
_tokenValidator = tokenValidator;
}
public void PostConfigure(string name, JwtBearerOptions options)
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(_tokenValidator);
}
}
Now options.SecurityTokenValidators is configured by CustomJwtBearerOptionsPostConfigureOptions which is instantiated by dependency injection and can pass on the relevant decencies.

Unity DI not working in DI - default controller constructor called instead

I am trying to get Unity Container Dependency Injection working on a self-hosted owin app. I have added the Unity nuget package to my project, and have set up my UnityConfig class as follows:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDBContext,UniversalCoatingsDbContext>();
container.RegisterType<IUserRepository,UserRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Then, I set up my controller like this:
public class UserController : ApiController
{
private IUserRepository userRepo;
public UserController() {
Console.WriteLine("User controller default constructor");
}
//dependency injected value
public UserController(IUserRepository repo)
{
this.userRepo = repo;
Console.WriteLine("DI enabled constructor");
}
[HttpPost]
public JsonResult<MessageResponse> Register(UnhashedUser unhashed_user)
{
MessageResponse response = new MessageResponse();
if(ModelState.IsValid)
{
response = userRepo.createUser(unhashed_user);
}
else
{
response.message = "Invalid Request sent.";
}
return Json(response);
}
}
The UnityConfig.RegisterComponents() method is called at the end of my Startup class's Configuration() method (after all the middleware is setup). When I access this controller's URL, the parameterless constructor is always called, and thus the instance of IUserRepository is never resolved.
Am I missing some sort of configuration pattern? Any info greatly appreciated.
I modified my UnityConfig class to expose the container as a static variable. And then,
I added this to my startup class:
//set up dependency injection
UnityConfig.RegisterComponents();
config.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(UnityConfig.container);
app.UseWebApi(config);

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

Dependency Injection (using SimpleInjector) and OAuthAuthorizationServerProvider

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
}

Dependency injection not working with Owin self-hosted Web Api 2 and Autofac

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.

Categories

Resources