In an AzureFunction, I register some services as scoped and some other as Singleton.
It turned out that a dependency of a Singleton was a Scoped service (a bad thing) and at runtime I get this kind of exception.
I would like to be able to write an unit test to check the same thing as the runtime but I did not manage to succeed. Anyone can help me ?
What I tried:
// Arrange
var functionStartup = new MyFunctionStartup();
var serviceCollection = new ServiceCollection();
var functionHostBuilder = A.Fake<IFunctionsHostBuilder>();
A.CallTo(() => functionHostBuilder.Services).Returns(serviceCollection);
// Act
// doing in fact under the hood:
// services.AddSingleton<ISingleton, Singleton>();
// services.AddScoped<IScopedDependencyOfSingleton, ScopedDependencyOfSingleton>();
functionStartup.Configure(functionHostBuilder);
// Assert
var provider = serviceCollection.BuildServiceProvider();
var singleton = provider.GetService<ISingleton>();
You can get an underlying DryIoc IContainer from the service provider and Validate for the captive dependency in a singleton:
var container = provider.GetRequiredService<IContainer>();
var errors = container.Validate(ServiceInfo.Of<ISingleton>());
if (errors.Count > 0)
{
// handle errors
}
Here is the documentation for Validate.
Related
I have cases, where I want to configure services based on objects which are registered in the dependency injection container.
For example I have the following registration for WS Federation:
authenticationBuilder.AddWsFederation((options) =>{
options.MetadataAddress = "...";
options.Wtrealm = "...";
options.[...]=...
});
My goal in the above case is to use a configuration object, which is available via the DI container to configure the WsFederation-middleware.
It looks to me that IPostConfigureOptions<> is the way to go, but until now, I have not found a way to accomplish this.
How can this be done, or is it not possible?
See https://andrewlock.net/simplifying-dependency-injection-for-iconfigureoptions-with-the-configureoptions-helper/ for the I(Post)ConfigureOptions<T> way, but I find that way too cumbersome.
I generally use this pattern:
// Get my custom config section
var fooSettingsSection = configuration.GetSection("Foo");
// Parse it to my custom section's settings class
var fooSettings = fooSettingsSection.Get<FooSettings>()
?? throw new ArgumentException("Foo not configured");
// Register it for services who ask for an IOptions<FooSettings>
services.Configure<FooSettings>(fooSettings);
// Use the settings instance
services.AddSomeOtherService(options => {
ServiceFoo = fooSettings.ServiceFoo;
})
A little more explicit, but you have all your configuration and DI code in one place.
Of course this bypasses the I(Post)ConfigureOptions<T> entirely, so if there's other code that uses those interfaces to modify the FooSettings afterwards, my code won't notice it as it's reading directly from the configuration file. Given I control FooSettings and its users, that's no problem for me.
This should be the approach if you do want to use that interface:
First, register your custom config section that you want to pull the settings from:
var fooSettingsSection = configuration.GetSection("Foo");
services.Configure<FooSettings>(fooSettingsSection);
Then, create an options configurer:
public class ConfigureWSFedFromFooSettingsOptions
: IPostConfigureOptions<Microsoft.AspNetCore.Authentication.WsFederation.WsFederationOptions>
{
private readonly FooSettings _fooSettings;
public ConfigureWSFedFromFooSettingsOptions(IOptions<FooSettings> fooSettings)
{
_fooSettings = fooSettings.Value;
}
public void Configure(WsFederationOptions options)
{
options.MetadataAddress = _fooSettings.WsFedMetadataAddress;
options.Wtrealm = _fooSettings.WsFedWtRealm;
}
}
And finally link the stuff together:
services.AddTransient<IPostConfigureOptions<WsFederationOptions>, ConfigureWSFedFromFooSettingsOptions>();
The configurer will get your IOptions<FooSettings> injected, instantiated from the appsettings, and then be used to further configure the WsFederationOptions.
In my project I am trying to get a user based on it's email adress every second with the UserManager but when I do this I get the following error Cannot access a disposed object Object name: 'UserManager1, but this is when I do it inside of a Timer(). If I just do it once there is no problem, how can I fix this? This timer is inside a class that is being called by a SignalR Hub.
Code:
Timer = new System.Threading.Timer(async (e) =>
{
IEnumerable<Conversation> conversations = await _conversationsRepo.GetAllConversationsForUserEmailAsync(userMail);
List<TwilioConversation> twilioConversations = new List<TwilioConversation>();
foreach (Conversation conversation in conversations)
{
TwilioConversation twilioConversation = await _twilioService.GetConversation(conversation.TwilioConversationID);
twilioConversation.Messages = await _twilioService.GetMessagesForConversationAsync(conversation.TwilioConversationID);
twilioConversation.ParticipantNames = new List<string>();
List<TwilioParticipant> participants = await _twilioService.GetParticipantsForConversationAsync(conversation.TwilioConversationID);
foreach (TwilioParticipant participant in participants)
{
User user = await _userManager.FindByEmailAsync(participant.Email);
twilioConversation.ParticipantNames.Add(user.Name);
}
twilioConversations.Add(twilioConversation);
}
}, null, startTimeSpan, periodTimeSpan);
UserManager along with quite a few other types is a service that has a scoped lifetime. This means that they are only valid within the lifetime of a single request.
That also means that holding on to an instance for longer is not a safe thing to do. In this particular example, UserManager depends on the UserStore which has a dependency on a database connection – and those will definitely be closed when the request has been completed.
If you need to run something outside of the context of a request, for example in a background thread, or in your case in some timed execution, then you should create a service scope yourself and retrieve a fresh instance of the dependency you rely on.
To do that, inject a IServiceScopeFactory and then use that to create the scope within your timer code. This also applies to all other scoped dependencies, e.g. your repository which likely requires a database connection as well:
Timer = new System.Threading.Timer(async (e) =>
{
using (var scope = serviceScopeFactory.CreateScope())
{
var conversationsRepo = scope.ServiceProvider.GetService<ConversionsRepository>();
var userManager = scope.ServiceProvider.GetService<UserManager<User>>();
// do stuff
}
}, null, startTimeSpan, periodTimeSpan);
My question is similar to question about DI for NserviceBus Handler for testing (Handler).
As a solution, you can use constructor injection by using the following syntax:
Test.Handler<YourMessageHandler>(bus => new YourMessageHandler(dep1, dep2))
I couldn't find a way to use the same approach for Saga testing.
There is a support for property injecting, which would look something like this:
var saga = Test.Saga<MySaga>()
.WithExternalDependencies(DependenciesSetUp);
private void DependenciesSetUp(MySaga saga)
{
saga.M2IntegrationService = M2IntegrationService.Object;
saga.ProcessLogService = ProcessLogService.Object;
saga.Log = Log.Object;
}
However, this approach requires making my dependencies public properties. And I want to try to avoid it.
Is there a way to use construction dependency injection for Saga testing?
You can work around this like:
Have a saga that has a constructor with parameters (in addition to a default empty constructor, which is required).
This is how your test can look like:
Test.Initialize();
var injected = new InjectedDependency() {Id = Guid.NewGuid(), SomeText = "Text"};
var testingSaga = new MySaga(injected);
var saga = Test.Saga(testingSaga);
saga.WhenReceivesMessageFrom("enter code here")
Will this work for you?
Yes it is also supported:
var saga = new MySaga(new MyFirstDep(), new MySecondDep());
Test.Saga(saga)
.ExpectSend<ProcessOrder>(m => m.Total == 500)
.ExpectTimeoutToBeSetIn<SubmitOrder>((state, span) => span == TimeSpan.FromDays(7))
.When(s => s.Handle(new SubmitOrder
{
Total = 500
}));
I am using Autofac 3.5.2 on Mono and when I try to register a generic collection and then resolve it I get the right instance where 1 element of the right type has already been added. To explain it in code:
class Fake {}
var builder = new ContainerBuilder();
builder.RegisterType<Fake>();
bilder.RegisterGeneric(typeof(List<>));
var scope = builder.Build();
var list = scope.Resolve<List<Fake>>();
Console.WriteLine(list.Count); // => prints 1!
Is this to be expected? Why? How can I avoid that?
Autofac has built-in support for collection and will by default try to use the constructor with the most available arguments when it resolves a service.
Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container
> http://autofac.readthedocs.org/en/latest/register/registration.html#register-by-type
List<T> contains a constructor which take a IEnumerable<T>.
When Autofac resolve List<Fake> it will choose the constructor with IEnumerable<T>, then resolve IEnumerable<T> which will resolve all available instance of T.
If you have more than one Fake registered, Autofac will resolve all of them when you resolve. For example :
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>));
var scope = builder.Build();
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 2!
You can specify which constructor to use when you register List<T>
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>)).UsingConstructor(Type.EmptyTypes);
var scope = builder.Build();
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 0!
Or you can ignore default behavior by using the ContainerBuildOptions.ExcludeDefaultModules parameter in the Build method
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterGeneric(typeof(List<>));
var scope = builder.Build(ContainerBuildOptions.ExcludeDefaultModules);
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 0!
I won't recommend removing default behaviors unless you really know what you do.
Suppose I have a dependency that is registered as HttpRequestScoped so there is only one instance per request. How could I resolve a dependency of the same type outside of an HttpRequest?
For example:
// Global.asax.cs Registration
builder.Register(c => new MyDataContext(connString)).As<IDatabase>().HttpRequestScoped();
_containerProvider = new ContainerProvider(builder.Build());
// This event handler gets fired outside of a request
// when a cached item is removed from the cache.
public void CacheItemRemoved(string k, object v, CacheItemRemovedReason r)
{
// I'm trying to resolve like so, but this doesn't work...
var dataContext = _containerProvider.ApplicationContainer.Resolve<IDatabase>();
// Do stuff with data context.
}
The above code throws a DependencyResolutionException when it executes the CacheItemRemoved handler:
No scope matching the expression 'value(Autofac.Builder.RegistrationBuilder`3+<>c__DisplayClass0[MyApp.Core.Data.MyDataContext,Autofac.Builder.SimpleActivatorData,Autofac.Builder.SingleRegistrationStyle]).lifetimeScopeTag.Equals(scope.Tag)' is visible from the scope in which the instance was requested.
InstancePerLifetimeScope(), rather than HttpRequestScoped(), will give the result you need.
There is a caveat though - if IDatabase requires disposal, or depends on something that requires disposal, this won't happen if you resolve it from the ApplicationContainer. Better to do:
using (var cacheRemovalScope =
_containerProvider.ApplicationContainer.BeginLifetimeScope())
{
var dataContext = cacheRemovalScope.Resolve<IDatabase>();
// Do what y' gotta do...
}