When using IDataProtectionProvider in a Web API, the IoC container is configured with AddDataProtection (services.AddDataProtection();) and enables the use of DI to retrieve a IDataProtectionProviderin a service as such:
private readonly IDataProtectionProvider _dataProtectionProvider;
public CipherService(IDataProtectionProvider dataProtectionProvider)
{
_dataProtectionProvider = dataProtectionProvider;
}
If I would like to test my CipherService (in my case using Xunit), I will not be able to make this work without using DI, so my question is;
Q: How can I use DI or otherwise make IDataProtectionProvider in a test project?
Here how I did it using Moq framework:
Mock<IDataProtector> mockDataProtector = new Mock<IDataProtector>();
mockDataProtector.Setup(sut => sut.Protect(It.IsAny<byte[]>())).Returns(Encoding.UTF8.GetBytes("protectedText"));
mockDataProtector.Setup(sut => sut.Unprotect(It.IsAny<byte[]>())).Returns(Encoding.UTF8.GetBytes("originalText"));
Mock<IDataProtectionProvider> mockDataProtectionProvider = new Mock<IDataProtectionProvider>();
mockDataProtectionProvider.Setup(s => s.CreateProtector(It.IsAny<string>())).Returns(mockDataProtector.Object);
And where I need to pass in the IDataProtectionProvider, I use:
mockDataProtectionProvider.Object
For an integration test scenario, where you want a real DataProtectionProvider, you can use the following MSDN Documentation article.
Hope this helps.
EphemeralDataProtectionProvider can be used in a unit testing scenario as it generates a random secret for each instance.
Example:
var dataProtectionProvider = new EphemeralDataProtectionProvider();
var service = new CipherService(dataProtectionProvider);
// test as usual
This was specifically provided by Microsoft for your exact use-case.
There are scenarios where an application needs a throwaway IDataProtectionProvider. For example, the developer might just be experimenting in a one-off console application, or the application itself is transient (it's scripted or a unit test project). To support these scenarios the Microsoft.AspNetCore.DataProtection package includes a type EphemeralDataProtectionProvider. This type provides a basic implementation of IDataProtectionProvider whose key repository is held solely in-memory and isn't written out to any backing store.
Related
I am trying to get a better understanding of integration testing. By default, a lot of example utilize IClassFixture<T> for integration testing (e.g. being https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2#basic-tests-with-the-default-webapplicationfactory).
That works great for testing things like - is the page loading, is the form being displayed, am I getting the correct http status code etc. But when testing an API, you'll want some seed data to exist. In order to get seed data into your testing, typical go-to is EF in-memory database. This is achieved via a custom web application factory where you can create a scope, request the appropriate service (i.e. dbcontext), and seed it (e.g. being https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-2.2#customize-webapplicationfactory).
I have an integration test project that is working and fully functional. But the nuances of how it works is still confusing to me.
Am I correct in assuming that when you create a CustomWebApplicationFactory, essentially you are creating a custom "Program.cs" (i.e. the typical entry point into the application) where you are free to add in additional testing services/filters as needed?
Below is my custom web application factory that I am using for my integration testing. My API has basic authentication for most endpoints so I added a global filter to bypass that. But what I am doing below is essentially the same in my Program.cs in my actual API (the only difference being I don't add the fake user and global anonymous filter). So I am lead to believe that my above point stands true. Is this a correct assumption?
Another point I wanted to verify is that in an actual unit test, I can replace a service with a mock. Is this possible in an integration test where I can swap out the DI instance for a requested service to be a test service instead?
E.g. my app has a IUploadFileToAzure service. Instead of using UploadFileToAzure as the DI instance, can I replace that implementation with a TestUploadFileToAzure service in my integration test?
Registering a service multiple times takes the last registration of the service so I was wondering if that can be used as a workaround for my above point. Is this even recommended? I understand it defeats the purpose of testing a service but wanted to verify if that was possible. I tried testing this locally and it did not work.
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<Startup>
{
protected override IWebHostBuilder CreateWebHostBuilder()
{
return WebHost
.CreateDefaultBuilder<Startup>(new string[0])
.ConfigureServices(services =>
{
services.AddSingleton<IStartupFilter, AddCustomMiddlewareStartupFilter>();
});
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder
.UseEnvironment("Development")
.ConfigureServices(services =>
{
services.AddMvc(opt =>
{
//add a global anonymous filter
opt.Filters.Add(new AllowAnonymousFilter());
//add a filter for adding a fake claimsprincipal so that the user service
//correctly identifies the user
opt.Filters.Add(new FakeClaimsPrincipalFilter(true, false));
});
services.AddEntityFrameworkInMemoryDatabase();
// Create a new service provider.
var provider = services
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
// Add a database context using an in-memory
// database for testing.
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("TestDb");
options.UseInternalServiceProvider(provider);
});
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var apiDb = scopedServices.GetRequiredService<AppDbContext>();
// Ensure the database is created.
apiDb.Database.EnsureCreated();
}
});
}
}
Am I correct in assuming that when you create a
CustomWebApplicationFactory, essentially you are creating a custom
"Program.cs" (i.e. the typical entry point into the application) where
you are free to add in additional testing services/filters as needed?
Yes, you are right. For Program.cs it will create the real host server. For CustomWebApplicationFactory, it will create TestServer for the integration tests.
my app has a IUploadFileToAzure service. Instead of using
UploadFileToAzure as the DI instance, can I replace that
implementation with a TestUploadFileToAzure service in my integration
test?
For replacing exsting service, you could try ConfigureTestServices and you could refer Inject mock services
Here's my scenario:
I Have a single app, but I need to switch the database connection by route.
Example:
switch(route)
{
case(URL/A):
{
USE DATABASE 1
}
case(URL/B):
{
USE DATABASE 2
}
DEFAULT:
USE DATABASE DEFAULT
}
Is it possible?
Since you're using ASP.NET MVC, your routes depends on your controllers. Then you can imagine having ControllerA using DatabaseA and ControllerB using DatabaseB.
To use multiple database connections, you need a connection string for each one of them.
I would use the following pieces of code to inject instances of DbContextOptionsBuilder inside of Startup.ConfigureServices()
var ContextAOptionsBuilder = new DbContextOptionsBuilder<ContextA>();
var ContextBOptionsBuilder = new DbContextOptionsBuilder<ContextB>();
Then you can configure your builders this way (depending on your parameters)
ContextAOptionsBuilder.UseSqlServer(Configuration.GetConnectionString("ContextAConnectionString"), builder =>
{
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(30), null);
});
ContextAOptionsBuilder.EnableSensitiveDataLogging();
Then you can inject them as singletons this way :
services.AddSingleton(typeof(DbContextOptionsBuilder<ContextA>),ContextAOptionsBuilder);
You can use a BaseController, whose constructor parameters can access to services this way :
public BaseController(IConfiguration configuration, IMemoryCache memoryCache,
IHttpContextAccessor contextAccessor,
DbContextOptionsBuilder<ContextA> ContextAOptionsBuilder,
DbContextOptionsBuilder<ContextB> ContextBOptionsBuilder){}
Of course, ControllerA and ControllerB being heir classes of BaseController, you can access desired builder quite simply.
public ControllerA(IConfiguration configuration,
IMemoryCache cache,
IHttpContextAccessor contextAccessor,
DbContextOptionsBuilder<ContextA> ContextAOptionsBuilder,
DbContextOptionsBuilder<ContextB> ContextBOptionsBuilder)
:base(configuration, cache, contextAccessor, ContextAOptionsBuilder,ContextBOptionsBuilder)
{
//Create your DbContext using the builder
}
This way you can use one, the other, or both database to build your context
A simpler way would have been injecting your configuration file and building your context from it's content but ppumkin's comment suggested it's a bad idea to do this at a controller level.
This solution is working for me in an ASP.NET Core MVC application, I am still learning the framework but maybe my answer gave you precisions about multiple DbContexts.
You can create 3 connection string also 3 data access Classes. First of your class uses for example DropCreateDatabaseIfModelChanges others use CreateDatabaseIfNotExists. When you call first class your database creates when you need others there will no need recreate it.
Register your context (as scoped, per request) and use factory method for dynamically creating context with specified connection string based on current route (which should be available from HttpContext or something similar). If the databases schemas are same and just data is different this should work easily. I can't provide a snippet for you because it's mostly depends on what DI framework you have.
In the documentation for dependency injection I notice the following line.
The MVC framework will automatically look at the service provider to
register our dependency in the Controller.
They then provide a basic example with constructor injection, not their example but in essence this.
public class Example
{
private IFooFactory foo;
public Example(IFooFactory foo) => this.foo = foo;
public void SampleUse()
{
using(var context = foo.Create())
context.DoSomething();
}
}
If you have a console application, by default it will not look at the service provider to register your dependency with the concrete implementation. Is there a way to simulate that? Otherwise the console application will require you to do something along these lines:
public static Main(string[] args)
{
// Stuff to prepare the application and build service provider.
var service = serviceProvider.GetService<IFooFactory>();
using(var context = service.Create())
context.DoSomething();
// OR
var fooFactory = serviceProvider.GetService<IFooFactory>();
new Example(fooFactory).SampleUse();
}
Which creates the problem of having to pass IFooFactory or pulling things into the main that you may wanted separated for structure. How can I make the console application look at the provider when a new class is created with a defined interface?
You have to create everything manually as the framework is not there to automagically do it for you.
var services = new ServiceCollection();
services.AddTransient<IFooFactory, FooFactory>();
services.AddTransient<Example>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
Example example = serviceProvider.GetService<Example>();
example.SampleUse();
While not ideal, it is usually the way shown in most examples where DI is configured manually.
When you inspect the framework DI integration, behind the scenes it does the exact same thing during startup.
You could probably write your own code to inspect available types, but that is a very broad task to tackle on your own.
Reference Dependency injection in ASP.NET Core
Default service container replacement
The built-in service container is meant to serve the needs of the
framework and most consumer apps. We recommend using the built-in
container unless you need a specific feature that it doesn't support.
Some of the features supported in 3rd party containers not found in
the built-in container:
Property injection
Injection based on name
Child containers
Custom lifetime management
Func<T> support for lazy initialization
Currently I Have configured Identityserver4 as separated project + My WebAPI and store in DB Credentials in IdentityServer.
Now i have problem how to make CRUD(In my frontend API) to IdentityServer(I want from my API add Clients to IdentityServer)
How to make property?
From IdentityServer4.EntityFramework and IdentityServer4.EntityFramework.Storage, you have access to IConfigurationDbContext (once you've added the required services in ConfigureServices using e.g. AddConfigurationStore). Because this is registered as part of the Dependency Injection system, you can take a dependency on it in one of your controllers. e.g.:
public class ClientsController : ControllerBase
{
private readonly IConfigurationDbContext _configurationDbContext;
public ClientsController(IConfigurationDbContext configurationDbContext)
{
_configurationDbContext = configurationDbContext;
}
// ...
}
IConfigurationDbContext is an abstraction of a standard DbContext, with the following DbSet<T> properties:
Clients
IdentityResources
ApiResources
It also includes both SaveChanges and SaveChangesAsync - Everything one might expect from a DbContext. Because of all of this, you can CRUD each of these entities just like any other Entity Framework Core driven database.
One final thing to note is that there are both Models (in IdentityServer4.Storage) and Entities (in IdentityServer4.EntityFramework.Storage). There are also a few extension methods for mapping between these (e.g. ClientMappers.ToEntity).
Given all of this, you can create a Model inside of your controller (or perhaps somewhere much better encapsulated than directly there). Here's a basic example for creating a new Client:
var clientModel = new Client
{
ClientId = "",
ClientName = "",
// ...
};
_configurationDbContext.Clients.Add(clientModel.ToEntity());
await _configurationDbContext.SaveChangesAsync();
The Client class here comes from IdentityServer4.Models and is then converted to an Entity using a ToEntity extension method I hinted at above. Working with a Model and converting to an Entity is simpler than trying to manipulate an Entity directly - If you're interested, you can see the mapping that takes place here.
This works in the same way for ApiResources, IdentityResources, etc. Use the source code links I've provided if you want to find out more about those specifically, but the information I've provided here should have you covered.
In order to use IdentityServer4 and IdentityServer4.EntityFramework in your API project, you can just add the two references to your API project. After that, you can configure the DI in the same way (using AddIdentityServer in ConfigureServices), but you don't need to add the middleware (using UseIdentityServer in Configure). You can even just use AddIdentityServer().AddConfigurationStore(...) to set up the relevant services, as you don't need a signing key, etc.
One way you can do this is by bootstrapping the ID4 Quickstart (tutorial located here):
http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html
Other option is to use their quickstart seeds located here to speed this up:
https://github.com/IdentityServer/IdentityServer4.Samples
Now if you want to implement restfull login there are constraints around it (i wanted to find out as well) check out this question:
IdentityServer 4 Restfull Login/Logout
I am writing some integration tests. I am using Dependency Injection with Windsor Castle.
I would like to resolve the test class using an inversion of control container. I do not think that resolve all my dependencies inside the test class is the solution for my case.
I would like to do what I have done inside the web api project. I implemented IHttpControllerActivator, which is an extension point to fully control controller's life-cycle. That is, we can define how a controller is instantiated.
I would like to do the same for the tests. But I do not understand which is the interface I have to implement. Can anyone help me?
I think I just need to know which is the corresponding IHttpControllerActivator for unit test.
EDIT
I have a web api project to test. The web api project resolves all the dependencies with WindsorCastle. Now I need to test the web api. This is what I am doing:
public voi MyTest_Ok()
{
//Arrange
var myController = new MyWebApiController();
var result = await myController.DoWork();
//Asserts
}
Obviously it does not work because I am not using castle windsor to resolve the controller and so I do not resolve any dependency from web api controller to bottom.
I think I could replace this line
var myController = new MyWebApiController();
with something like this
var myController = windsorContainer.Resolve<MyWebApiController>();
But this solution I think is wrong. I think it's better to resolve dependencies as happen inside the controller:
public class MyWebApiController : ApiController()
{
public InjectedDependency dep { get; set; }
public DoWork()
{
dep.DoWork();
}
}
I can do this because I have implemented a custom IHttpControllerActivator.
Answer is: your test framework does. As I know none of the common test frameworks allows you take control over creating your test classes.
More info about this here as well:
A .NET Unit Test without a parameterless constructor, to facilitate dependency injection
NUnit provide ParameterizedTestFixture -https://github.com/nunit/docs/wiki/TestFixtureData
So in theory as a dirty workaround you would be able to inject some dependencies trough constructor by this, but it wasn't designed for this purpose.
In general you have to go for service locator.