In Azure Functions (v3 on NetCore3.1) using SimpleInjector 5.3, I've followed the guidance here using IHttpClientFactory instead of a typed client that depends on a MS DI-constructed HttpClient, but SimpleInjector can't resolve the IHttpClientFactory either.
public class FooClient
{
private IHttpClientFactory _clientFactory;
private FooClientConfig _config;
public FooClient(IHttpClientFactory clientFactory, FooClientConfig config)
{
_clientFactory = clientFactory;
_config = config;
}
}
public class Startup : FunctionsStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
var container = new Container();
container.RegisterInstance<FooClientConfig>(new FooClientConfig() { ApiKey = Configuration.GetValue<string>("FooApiKey") });
container.Register<FooClient>();
services.AddSimpleInjector(container);
}
}
public class FooCommandHandler
{
private readonly FooClient _fooClient;
public FooCommandHandler (FooClient client)
{
_fooClient = fooClient;
}
}
I then use the container to activate a Command/Query mediator but the container can't find an IHttpClientFactory to use for the FooClient.
SimpleInjector.ActivationException: 'The configuration is invalid. Creating the instance for type FooClient failed. The constructor of type FooClient contains the parameter with name 'clientFactory' and type IHttpClientFactory, but IHttpClientFactory is not registered. For IHttpClientFactory to be resolved, it must be registered in the container. Verification was triggered because Container.Options.EnableAutoVerification was enabled. To prevent the container from being verified on first resolve, set Container.Options.EnableAutoVerification to false.'
I guess my question is, where am I supposed to setup the Auto-cross-wiring for simpleinjector? I thought the call to services.AddSimpleInjector(container); would make the MS DI registered IHttpClientFactory available to the container and thus to the registrations therein.
Following the integration guide that Steven has put together over at the SimpleInjector docs VERY CAREFULLY, and using IHttpClientFactory instead of any typed clients I was finally able to get this to work - it is not pretty though.
I suggest that if you're using anything other than the Http factory pattern in the old Azure Functions ecosystem (non-isolated) you'll be fine. It's the cross-wiring of certain services like HttpClient under the hood that makes this a total mess. Hope this helps anyone else facing the same issue.
Related
I am writing a dotnet standard library class that will contain an HttpClient that calls a web api method. I want the input/output classes available for ease of use to the caller. The projects consuming the package will be framework apps (4.7)
As far as I can tell the "correct" way to do that is to have a extension method taking an IServiceCollection which registers my client according to some known "defaults" and allows clients to pass in options.
I guess I'm wondering how that would get utilized in a framework app properly? So after I configure the service collection pipeline to know how to do things properly... How does the framework app ever get a ServiceCollection? Do i just make a static class that news up a ServiceCollection and stores the reference? Again to make that as easy as possible would I just include a static factory method in the library class to do that for the consumer? Something like this?
public sealed class DependencyInjectionHelper
{
private static readonly Lazy<DependencyInjectionHelper> _instance = new Lazy<DependencyInjectionHelper>();
public static DependencyInjectionHelper Instance => _instance.Value;
public readonly IServiceCollection ServiceCollection;
public readonly ServiceProvider ServiceProvider;
private DependencyInjectionHelper()
{
ServiceCollection = new ServiceCollection();
ServiceProvider = ServiceCollection.BuildServiceProvider();
}
public MyHttpClient GetClient()
{
return ServiceProvider.GetService<MyHttpClient>();
}
}
public static IServiceCollection AddMyClient(this IServiceCollection services, Action<MyClientOptions, IServiceProvider> configureOptions)
{
services.AddOptions();
services.AddLogging();
services.AddHttpClient<IMyClient, MyClient>().ConfigureHttpClient(client =>
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//configure baseaddress from options here somehow
client.BaseAddress = new Uri("https://someurl:5001/");
if (!AppContext.TryGetSwitch("System.Net.Http.UseSocketsHttpHandler", out var enabled) || !enabled)
{
//https://www.nimaara.com/beware-of-the-net-httpclient/
var servicePoint = ServicePointManager.FindServicePoint(client.BaseAddress);
int desiredLeaseTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;
if (servicePoint.ConnectionLeaseTimeout != desiredLeaseTimeout)
{
servicePoint.ConnectionLeaseTimeout = desiredLeaseTimeout;
}
}
});
return services;
}
Guess i'm looking for examples in the proper pattern to accomplish this. I understand dependency injection all the way through is probably the best way... but I can't just change monolithic apps to have it. So i want something flexible enough to be used if you have dependency injection, but super simple to consume out of the box.
While running the .Net Core 2.0 API endpoint getting below error.
A suitable constructor for type 'RestDataService' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.
public partial class RestDataService : IRestDataService
{
private static HttpClient _client;
private static AppConfiguration _configuration;
private const short MaxRetryAttempts = 3;
private const short TimeSpanToWait = 2;
public RestDataService(AppConfiguration configuration)
{
_client = configuration.HttpClient;
_configuration = configuration;
}
........
And my startup class is something like this :
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var config = new AppConfiguration
{
Environment = Configuration["environment"],
};
services.AddMvc().AddJsonOptions(o => o.SerializerSettings.NullValueHandling = NullValueHandling.Include);
services.AddMemoryCache();
services.AddCors();
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddSingleton(Configuration);
services.AddSingleton(config);
services.AddLogging();
services.AddTransient<IRestDataService, RestDataService>();
services.AddHttpClient<IRestDataService, RestDataService>()
.AddPolicyHandler(request => request.Method == HttpMethod.Get ? retryPolicy : noOp);
Any suggestions, to get rid of this? constructor is already public and all the parameters are registered in startup file
I received the error "A suitable constructor for type '<type>' could not be located." after accidentally generating a protected constructor instead of public constructor. Marking it back to public fixed it.
For AddHttpClient, you need to provide HttpClient parameter for RestDataService. And, you need to register AppConfiguration.
RestDataService
public class RestDataService: IRestDataService
{
private static HttpClient _client;
private static AppConfiguration _configuration;
private const short MaxRetryAttempts = 3;
private const short TimeSpanToWait = 2;
public RestDataService(AppConfiguration configuration
, HttpClient client)
{
_client = configuration.HttpClient;
_configuration = configuration;
}
}
Startup.cs
var config = new AppConfiguration
{
Environment = Configuration["environment"],
};
services.AddSingleton(typeof(AppConfiguration), config);
services.AddHttpClient<IRestDataService, RestDataService>();
I just ran across this issue because I was accidentally registering HttpClient to an interface.
public void ConfigureServices(IServiceCollection services) {
// !! Wrong, this is done automatically by AddHttpClient<IMyService, MyService>()
services.AddTransient<IMyService, MyService>();
// !! There is no suitable constructor for IMyService, since it is an interface.
services.AddHttpClient<IMyService>();
// Instead, let AddHttpClient manage your service's lifetime,
// and tell it the implementation.
// It is registered with a Transient lifetime as described below.
services.AddHttpClient<IMyService, MyService>();
}
Important context, from source: https://www.stevejgordon.co.uk/ihttpclientfactory-patterns-using-typed-clients-from-singleton-services
When defining typed clients in your ConfigureServices method, the typed service is registered with transient scope. This means that a new instance is created by the DI container every time one is needed. The reason this occurs is that a HttpClient instance is injected into the typed client instance. That HttpClient instance is intended to be short lived so that the HttpClientFactory can ensure that the underlying handlers (and connections) are released and recycled.
You have to define which concrete class of interface you want to use for IRestDataService. So, define like this.
services.AddTransient<IRestDataService, RestDataService>();
Remove static keyword before AppConfiguration.
private readonly AppConfiguration _configuration;
In my case I got this problem when inattentively duplicating row with DI service registration to register new service but accidentally missed that this is .AddHttpClient() method instead of .AddTransient() or .AddScoped()
This doesn't directly answer the question, but is related.
For anyone using ActivatorUtilities.CreateInstance<T>(IServiceProvider, params object[] parameters) it's worth mentioning that every parameter must be in the parameters of the class you are creating. I.e.
public class Example
{
public Example(AppConfiguration configuration)
{
...
}
}
_ = ActivatorUtilities.CreateInstance<Example>(_serviceProvider, new HttpClient())
This will fail as the Example class doesn't have a constructor that has a HttpClient paramter
I had forgotten to add a RequestDelegate next parameter to my middleware constructor. Without this, I would get an exception with the message "A suitable constructor for type [Type] could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor" upon calling IApplicationBuilder.UseMiddleware. My constructor was already public, and my services were all registered. I just needed to add RequestDelegate next to my parameters.
I'm trying to understand dependency injection in ASP.NET MVC CORE.
All examples are the same, they show to register HttpContextAccessor
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
Then the class that wants to access it:
public class UserService : IUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public bool IsUserLoggedIn()
{
var context = _httpContextAccessor.HttpContext;
return context.User.Identities.Any(x => x.IsAuthenticated);
}
}
But then, when i actually want to create an instance of UserService, it asks for the httpContextAccessor object in constructor, where do i get that from?
When using dependency injection, you are not supposed to actually create any service yourself. To consume your UserService, you should just inject that somewhere as well.
Typically, the flow in ASP.NET Core for your application code starts in a controller. So if you want to use the UserService inside of a controller action, you should inject it into the controller:
public class ExampleController : Controller
{
private readonly IUserService _userService;
public ExampleController(IUserService userService)
{
_userService = userService;
}
public IActionResult Index()
{
var isLoggedIn = _userService.IsUserLoggedIn();
// …
return View();
}
}
So you don’t create an instance yourself using new but instead you rely on the dependency injection system to provide you with an instance.
You just need to make sure to register the service inside of the ConfigureServices:
services.AddTransient<IUserService, UserService>();
This principle holds regardless of where you are within your application. Since the entry point is always being created by the system, you are always inside of a dependency injection context, so you can just depend on things which have dependencies themselves (which again could have more dependencies etc).
I would strongly suggest you to read the chapter on dependency injection of the documentation, as it covers the idea very well. It also explains what the different lifetimes mean.
in DI, you normally dont need to create Instance by yourself. Instead you need to register your implemented services to the DI service container and then call it inside your constructor.
This way you eliminates the need for manual instance creation.
services.AddScoped<IMyService, MyService>();
then
class MyConsumerClass
{
private readonly IMyService _myService;
MyConsumerclass(IMyService myService)
{
_myService = myService;
}
}
In this way, you don't need to care about what services is needed to be initialized (parameterized) into your constructor.
I have implemented an adapter that implement IServiceProvider and returned it from the ConfigureServices method in the Startup. class:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var kernel = new StandardKernel();
var container = new NinjectComponentContainer(kernel);
// ...
return ServiceProviderFactory.Create(container, services);
}
However, my implementation doesn't seem to be used everywhere. I even tried to override the IHttpContextAccessor to return a modified HttpContext:
public HttpContext HttpContext {
get
{
var result = _httpContextAccessor.HttpContext;
result.RequestServices = _serviceProvider;
return result;
}
set => _httpContextAccessor.HttpContext = value;
}
To test whether I could get to my implementation I used a filter in order to see what the HttpContext.RequestServices would return:
public class AuthorizationTestAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var service = context.HttpContext.RequestServices.GetService(typeof(IAccessConfiguration));
}
}
The type returned by context.HttpContext.RequestServices is:
My main issue was trying to get registered components resolved in the constructor of a filter but it always seems to fail saying the component is not registered. However it does seem to work when using the TypeFilter attribute:
[TypeFilter(typeof(RequiresSessionAttribute))]
However, my attribute does inherit from TypeFilter:
public class RequiresSessionAttribute : TypeFilterAttribute
{
public RequiresSessionAttribute() : base(typeof(RequiresSession))
{
Arguments = new object[] { };
}
private class RequiresSession : IAuthorizationFilter
{
private readonly IAccessConfiguration _configuration;
private readonly IDatabaseContextFactory _databaseContextFactory;
private readonly ISessionQuery _sessionQuery;
public RequiresSession(IAccessConfiguration configuration,
IDatabaseContextFactory databaseContextFactory, ISessionQuery sessionQuery)
{
Guard.AgainstNull(configuration, nameof(configuration));
Guard.AgainstNull(databaseContextFactory, nameof(databaseContextFactory));
Guard.AgainstNull(sessionQuery, nameof(sessionQuery));
_configuration = configuration;
_databaseContextFactory = databaseContextFactory;
_sessionQuery = sessionQuery;
}
I did come across this question but there is no definitive answer.
Any ideas on how to correctly provider a custom implementation of the IServiceProvider interface that will be used throughout the solution?
Even though Microsoft states that it is possible to replace the built-in container it appears as though it is not quite this simple, or even possible.
As stated by Steven in his very first comment, if you choose to use your container of choice, you should run them side-by-side.
The guidance from Microsoft suggests changing the ConfigureServices in the Startup class from this:
public void ConfigureServices(IServiceCollection services)
{
// registrations into services
}
to the following:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var container = new YourContainer(); // Castle, Ninject, etc.
// registrations into container
return new YourContainerAdapter(container);
}
However, there are a number of issues with this since there are already framework registrations in services that we do not necessarily know how to re-register in our own container. Well, there is a descriptor so if our container supports all the various methods then it is actually possible to re-register all the components. The various DI containers have different mechanisms when it comes to registration and service resolution. Some of them have a very hard distinction between the two making it quite tricky at times to accommodate a "common" solution.
My initial idea was to provide an adapter that accepts both my own container as well as the services collection from which I would then get the built-in service provider by calling services.BuildServiceProvider(). In this way I could attempt to resolve from the built-in provider and then, if the resolving bit failed, attempt to resolve from my own container. However, it turns out that the .net core implementation does in fact not use the returned IServiceProvder instance.
The only way I could get this to work was to wire up my own container and use it to resolve my controllers. That could be done by providing an implementation of the IControllerActivator interface.
In this particular implementation I was fiddling with Ninject although I typically prefer Castle but the same applies to any DI container:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
}
public class ControllerActivator : IControllerActivator
{
private readonly IKernel _kernel;
public ControllerActivator(IKernel kernel)
{
Guard.AgainstNull(kernel, nameof(kernel));
_kernel = kernel;
}
public object Create(ControllerContext context)
{
return _kernel.Get(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
_kernel.Release(controller);
}
}
In order to register the controller types I did my DI wiring in the Configure method since I have access to the IApplicationBuilder which can be used to get to the controller types:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
{
var kernel = app.ApplicationServices.GetService<IKernel>();
// kernel registrations
var applicationPartManager = app.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var controllerFeature = new ControllerFeature();
applicationPartManager.PopulateFeature(controllerFeature);
foreach (var type in controllerFeature.Controllers.Select(t => t.AsType()))
{
kernel.Bind(type).ToSelf().InTransientScope();
}
applicationLifetime.ApplicationStopping.Register(OnShutdown);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(
options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()
);
app.UseMvc();
}
This worked swimmingly for the controllers but resolving "filters" was still a problem given that they use the IFilterFactory on the filter itself to implement a factory method:
public IFilterMetadata CreateInstance (IServiceProvider serviceProvider);
Here we can see that the IServiceProvider implementation is provided in order to resolve any depedencies. This applies when using the TypeFilterAttribute or when defining new filters that inherit from TypeFilterAttribute as I have in my question.
This mechanism is actually a very good example of the difference between "Inversion of Control" and "Dependency Injection". The control lies with the framework (inversion) and we have to provide the relevant implementations. The only issue here is that we are not able to hook in properly since our provided IServiceProvider instance is not passed to the CreateInstance method which then results in a failure when attempting to create an instance of the filter. There are going to be a number of ways to fix this design but we'll leave that to Microsoft.
In order to get my filters working I decided to go the "cross-wiring" route as alluded to by Steven by simply registering the depedencies required by my filters in the services collection also:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IKernel>(new StandardKernel());
services.AddSingleton<IControllerActivator, ControllerActivator>();
services.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>();
services.AddSingleton<IDatabaseGateway, DatabaseGateway>();
services.AddSingleton<IDatabaseContextCache, ContextDatabaseContextCache>();
// and so on
}
Since I do not have many dependencies in my filter it works out OK. This does mean that we have "duplicate" registrations that we need to be careful of depending on how the instances are used.
I guess another option may be to forego your DI container of choice and use only the built-in container.
I am trying to understand the UserManagerFactory middleware explained here per request lifetime management for usermanager.
I created this class which I am calling from the Startup Configuration method
public class CustomUserManagerProvider
{
public static CustomUserStore<CustomUser> CreateCustomUserStore()
{
return new CustomUserStore<CustomUser>(/*Need to inject dependencies here*/);
}
public static CustomUserManager CreateCustomUserManager(IdentityFactoryOptions<CustomUserManager> options,
IOwinContext context)
{
return new CustomUserManager(context.Get<CustomUserStore<CustomUser>>());
}
}
And the Startup Configuration
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(CustomUserManagerProvider.CreateCustomUserStore);
app.CreatePerOwinContext<IngramUserManager>(CustomUserManagerProvider.CreateCustomUserManager);
////....Other things
}
Now, My CustomUserStore has some dependencies which I want to inject in the constructor.
The composition root of the IOC container knows how to resolve these dependencies.
How do I make the CustomUserManagerProvider DI container aware(If that makes sense)...
Although this works
public static CustomUserStore<CustomUser> CreateCustomUserStore()
{
var dependency = DependencyResolver.Current.GetService<ISomeDependency>();
return new CustomUserStore<CustomUser>(dependency);
}
But, I was trying to avoid the service locator (anti)pattern. Is this my only option, Is this even right??
I am using Ninject.
Cant I just create a UserManager in requestScope in the composition root and inject into the controllers, wont that be the same thing?
In a web app, is CreatePerOwinContext same as creating InRequestScope?
Yes, you can inject the UserManager into your controllers a different way if you like, there's nothing that requires using the CreatePerOwinContext/IdentityFactoryMiddleware.