How exactly IAppBuilder.CreatePerOwinContext<T> should be used? - c#

I'm confused on how the OWIN CreatePerOwinContext method is to be used. As far as I can see it's a poor mans DI mechanism. Yet, I fail to see how to use it.
We can register a type/implementation at the Startup sequence like:
app.CreatePerOwinContext<IUserService>(() => {
return new UserService() as IUserService;
});
Then how do we resolve to that later on. Documentation says it can be retrieved via Get method. But Get<T> expects a string parameter, which is the key to that entry in the Enviornment IDictionary? How can I know the key in this case?
IUserService userService = context.Get<IUserService>(???);

You can use typeof to get the key parameter:
HttpContext.GetOwinContext().Get<ApplicationDbContext>(typeof(ApplicationDbContext).ToString());
Also, Microsoft.AspNet.Identity.Owin assembly contains the parameterless version of Get<T>() method, so you can use it if you already have ASP.NET Identity in your project.

I have a more correct answer after running into this myself, trying to implement the code within this stackoverflow answer: https://stackoverflow.com/a/31918218
So given this initialization code within the conventional Configure method:
static void Configuration(IAppBuilder app)
{
//https://stackoverflow.com/a/31918218
app.CreatePerOwinContext<AppBuilderProvider>(() => new AppBuilderProvider(app));
ConfigureAuth(app); //note implementation for this is typically in separate partial class file ~/App_Start/Startup.Auth.cs
}
One can retrieve the instance created by this code:
public ActionResult SomeAction()
{
//https://stackoverflow.com/a/31918218
var app = HttpContext.GetOwinContext().Get<AppBuilderProvider>("AspNet.Identity.Owin:" + typeof(AppBuilderProvider).AssemblyQualifiedName).Get();
var protector = Microsoft.Owin.Security.DataProtection.AppBuilderExtensions.CreateDataProtector(app, typeof(Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1");
var tdf = new Microsoft.Owin.Security.DataHandler.TicketDataFormat(protector);
var ticket = new AuthenticationTicket(ci, null);
var accessToken = tdf.Protect(ticket);
//you now have an access token that can be used.
}

Related

Access IHost across application classes globally

Below is an example code for CreateHostBuilder.
Asp.net core host takes care of resolving dependency through constructor and middleware.
If we want to resolve it for our custom classes which does not get invoked through controller or the main method, how can we get the instance of the host across applications.
Is it a good way to store it as a static variable Or there is some better way to do that?
public class Program
{
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
try
{
var serviceContext = services.GetRequiredService<MyScopedService>();
// Use the context here
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred.");
}
}
await host.RunAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Old question, but never answered....
I've found this necessary normally when working with code that has been converted to newer versions of .net and I need the services in an existing static class. What I've done in the past is expose the host created by builder as a public static property of the program class. For some projects, IHost doesn't work. Eg, a recent AWS Lambda project has a local entry point and lambda entry point, one is IHost and one is IWebHost, and those two don't share a common interfaces. So I added a static "IServiceProvider Services" property to the Startup class and set it to app.ApplicationServices in the Configure routine so that other classes could access that. This is specifically recommended by Microsoft as "Avoid static access to services. For example, avoid capturing IApplicationBuilder.ApplicationServices as a static field or property for use elsewhere." (https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines)
Another option I've used is to add a static method to your classes that can be called right after host startup to inject the host into the class. Right after IHost.Build, I added a routine called something like "InjectHost" that had a call for each class I wanted to inject into.
Lately, I've started getting fancy. I wrote the following startup code and a custom attribute do do my own injection. Technically, the custom attribute isn't even necessary. It's a nod toward optimization, but mostly it's there to make it explicit that certain classes will be injected so that the new code doesn't have a chance to screw with any other DI workarounds previous developers may have put in.
public static class StaticDI {
///<summary>Add app.UseStaticDI to your "Configure" method to enable the dependency injection into static classes.</summary>
public static IApplicationBuilder UseStaticDI(this IApplicationBuilder app) {
var services = app.ApplicationServices;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies) {
//The attribute isn't technically required, I'm just hoping it speeds up startup. If you don't want to
//use it, just remove the .Where.
var types = assembly.GetTypes().Where(x => x.IsDefined(typeof(StaticDIAttribute)));
foreach(var type in types) {
var fields = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
foreach (var field in fields) {
var diObject = services.GetService(field.FieldType);
if (diObject != null) {
field.SetValue(null, diObject);
}
}
}
}
return app;
}
}
///<summary>Add this to static classes to enable dependency injection</summary>
public class StaticDIAttribute:Attribute {
}
Just call "app.UseStaticDI" from your configure method to do the injection.
But in general, always keep in mind that the point of DI is to not use static, it replaces your statics. So the "proper" response is to convert everything to instance classes, based on an interface, preferably with a new static class to house your "AddBlahServices" extension method.

Mock service for xUnit

I have an application that currently works as designed, but I am trying to setup integration testing with xUnit before I expand upon it. At the moment the test will only use the original service when performing the test and I don't see why.
This the is the test:
using IStoreRepository = Repositories.V3.Interfaces.IStoreRepository;
public class StoreTests : IClassFixture<WebApplicationFactory<Startup>> {
private readonly ITestOutputHelper _output;
private readonly WebApplicationFactory<Startup> _factory;
private readonly string _url;
public StoreTests(ITestOutputHelper output, WebApplicationFactory<Startup> factory) {
_output = output;
_factory = factory;
_url = "/api/store";
}
[Theory]
[InlineData("GET", "FAKE123")]
public async Task StoreByCode(string method, string code = null) {
// var client = _factory.CreateClient();
var client = _factory.WithWebHostBuilder(builder => {
builder.ConfigureTestServices(services => {
services.AddScoped<IStoreRepository, StoreRepositoryTest>();
});
}).CreateClient();
var request = new HttpRequestMessage(new HttpMethod(method), $"{_url}/{code}");
string readAsStringAsync;
_output.WriteLine($"Request Uri: {request.RequestUri}");
using (var response = await client.SendAsync(request)) {
response.EnsureSuccessStatusCode();
readAsStringAsync = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode) {
_output.WriteLine($"Not successful ({response.StatusCode}): {readAsStringAsync}");
}
}
var stores = JsonConvert.DeserializeObject<List<Store>>(readAsStringAsync);
Assert.True(stores.Any());
}
}
However when I conduct the test the break point in the real Repository, StoreRepository that is registered in Startup.cs is the one that is hit, not the break point in StoreRepositoryTest. I setup my factory to override the dependency, but it's ignoring it. What can I do to correct this.
For reference, I have been using this source: https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2
Update
Not sure if this question should be deleted or not but it ended up being a really silly mistake. I updated the code above to include a using alias. It turned out I was registering and overriding the V1 interface instead of V3. When I implemented the Mock class I didn't realize I was implementing the old service. So the good news is the above code is a working example of how to mock using Microsoft's documentation.
I have seen this before. You probably created an interface in a different namespace.
Typically, this happens when you have a version 1 interface for a web service, and then you decide to add new functionality. You then create a version 2 interface with exactly the same name.
Put a break point on services.AddScoped<IStoreRepository, StoreRepositoryTest>() and debug that. Inspect the results and scroll to the bottom where your services are being added; You’ll get a clear view of what’s being added.
1) You can try using CustomWebApplicationFactory class and in ConfigureWebHost(IWebHostBuilder builder) method, add builder.ConfigureServices(//define dependencies).
Refer msdn link
2) Alternatively, you can define your own TestStartup class inheriting from Startup class and use it.

Passing an Instance of an Object to a Method that takes an Action<> as Parameter

In Dot Net Core convention for configuring services is as follows.
Method that Requires Action<> As Parameter
public static IServiceCollection AddAsResourceServer(this IServiceCollection services, Action<AuthMiddlewareOptions> action = null)
{
if(action != null)
{
AuthMiddlewareOptions authOptions = new AuthMiddlewareOptions();
action.Invoke(authOptions);
}
...
return services
}
This allows us to configure our service in startup as follows.
Startup ConfigureServices Method
services.AddAsResourceServer((a) =>
{
a.Audience = "Long Audience";
a.Issuer = "provider.com/oauthprovider";
});
This is really cool! I like this pattern. It works very well for allowing anyone to overwrite base configuration options.
However this seems very cumbersome when you already have an instance of the object. How would I create an instance of an object, convert it to an action, and pass that to the .AddAsResourceServer method?
I have tried:
Action<AuthMiddleWareOptions> auth = new Action<AuthMiddleWareOptions>()
/// The above way still requires a "target" in constructor so it doesnt work.
///so i still need to pass each
///property into it.
My consumers of the service may have just created an instance of AuthMiddleWareOptions and populated through appsettings!
They may have done something like this.
AuthMiddlewareOptions myoptions = new AuthMddlewareOptions();
Configuration.Bind("AuthMiddlewareOptions", myoptions);
Now that they have 'myoptions'. Is there a quick way to use that with the Action Parameter. Maybe like this?
AuthMiddlewareOptions myoptions = new AuthMddlewareOptions();
Configuration.Bind("AuthMiddlewareOptions", myoptions);
services.AddAsResourceServer((a) => SpecialThing(myoptions));
You can simply bind your configuration to the options instance provided by the method.
services.AddAsResourceServer(options =>
{
Configuration.Bind("AuthMiddlewareOptions", options);
});
You may register multiple configuration delegates for a single option class:
services.Configure<AuthMiddlewareOptions>(Configuration.GetSection("AuthMiddlewareOptions"));
services.AddAsResourceServer(options => SpecialThing(options));
And AddAsResourceServer should call services.Configure, as well:
public static IServiceCollection AddAsResourceServer(this IServiceCollection services, Action<AuthMiddlewareOptions> action = null)
{
if (action != null)
services.Configure(action);
// ...
return services;
}
Having this setup, AuthMiddlewareOptions is populated from the configuration section "AuthMiddlewareOptions", then the customization delegate (SpecialThing) has a chance to change the options filled at the previous step.
It's important that the order matters! If you swap the two lines, SpecialThing's changes will be overwritten by the values coming from the configuration.
You need to do it the other way arround.
I use for example the AddAuthorization since I do not find your method:
services.AddAuthorization(c =>
{
c.DefaultPolicy = null;
});
This can be configured using the following method:
public static void Config(AuthorizationOptions configure, IConfiguration configuration)
{
configure.DefaultPolicy = null;
//Configuration.Bind("AuthMiddlewareOptions", myoptions);
}
That way you can do:
services.AddAuthorization(c => Config(c, Configuration));
The problem is, that in these Action<T> methods you get the object T, which is already instantiated. So you need to copy the custom created object to it. With above we change the API, so it is configured on the correct object.
I tried many patterns, it wasn't until I hovered over a in the method to realize that it wasnt of type Action<AuthMiddlewareOptions>, but it was in fact AuthMiddleWareOptions. so this very simple assignment worked!
services.AddAsResourceServer(a => a = myoptions);
Quick answer to your question "Passing an Instance of an Object to a Method that takes an Action<> as Parameter" is "no, you can't"
But as a workaround, you could simply make a deepclone of your object, to swap the properties of the "inner" options.
Something like this :
static class Copy
{
public static void ObjectToAnother<T>(T source, T target)
{
foreach (var sourceProp in source.GetType().GetProperties())
{
var targetProp = target.GetType().GetProperty(sourceProp.Name);
targetProp.SetValue(target, sourceProp.GetValue(source, null), null);
}
}
}
And you could use that like this :
var obj = new Obj();
Foo.Bar((a) =>
{
Copy.ObjectToAnother(a, obj);
});
It should work

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
}

How to implement DI for an attribute in WebApi?

I refactored an attribute, which implements Basic Http Authentication in the Web api, to have DI as follows:
public class BasicHttpAuthAttribute : ActionFilterAttribute
{
private readonly ILoginManager _manager;
public BasicHttpAuthAttribute(ILoginManager manager)
{
this._manager = manager;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Content = new StringContent("Missing Auth-Token");
}
else
{
var authToken = actionContext.Request.Headers.Authorization.Parameter;
var decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
string userName = decodedToken.Substring(0, decodedToken.IndexOf(":"));
string password = decodedToken.Substring(decodedToken.IndexOf(":") + 1);
UserInfo user;
if (_manager.LoginPasswordMatch(userName, password, out user))
{
var apiUser = new ApiUser(user.UserID);
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(apiUser), new string[]{});
base.OnActionExecuting(actionContext);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Content = new StringContent("Invalid username or password");
}
}
}
}
Before the refactoring, I was creating an instance of the LoginManager (which itself did not have DI so I could create an instance using a ctor) inside OnActionExecuting. The problem after refactoring is that the build fails because when I apply the filter to a WebApi method, it is expecting an argument there.
How do I implement DI in this case as the LoginManager itself takes a ILoginRepository in its constructor? Is it even possible?
It's not easy to do because the way attributes are treated in Web API is a bit different than what you might expect. First of all they are created at various point in time, and secondly they are cached.
With that said, rather than injection through a constructor, the easiest way is to achieve DI is to call the DI framework of your choice at processing time, and retrieving the dependency then, i.e. inside your onActionExecuting:
var s = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IService));
The easiest option is to make it so your constructor does not require the parameter, but use a different form of injection instead. Exactly how you do that depends on what DI container you're using. With Unity, for example, you can just create a default constructor. Create another public method (I usually call it Initialize to be clear) and decorate it with the [InjectionMethod] attribute. Then, inside your constructor, just call container.BuildUp(this); That basically allows MVC to call the default constructor like it wants, but your InjectionMethod is always automatically called as a part of the construction process.
There are similar ways to do the same thing with other DI containers, but without knowing what you're using the Unit example is the easiest to explain.
You don't control the instantiation of the BasicHttpAuthAttribute so you can't use proper DI.
You can use a ServiceLocator in your attribute's constructor to give you the required dependencies or you can use the BuildUp functionality some containers provide for existing objects.
Unity does this to support BuildUp for 3rd party objects that you don't create yourself.
For your attribute that would mean to create a public writable property of type ILoginManager and tell the container to inject your manager into that property.
You don't have to pollute your attribute with the usage of the DependencyAttribute btw. Register your attribute type with the container and provide an InjectionProperty("NameOfThePropertyToInject") as a parameter for that registration.

Categories

Resources