I currently have a web app on .NET 6 with integration tests using WebApplicationFactory.
Here is a simplified version of my Program.cs file:
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var configuration = builder.Configuration;
services.AddAuthentication()
.AddJwtBearer(o =>
{
var configs = configuration.GetRequiredSection("authOptions");
// using configs here
});
For most services I need to mock, I can remove them from the service descriptor. However, this would not work for services like adding authentication from what I have seen. Basically, I am looking for a way to mock the configurations for integration testing.
The AddJwtBearer also has no access to the IServiceProvider and thus cannot use the injectable IConfiguration. I would like to account for all such features that need to use the configuration from builder.Configuration.
I am trying something like this:
public class CustomWebApplicationFactory: WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration(configBuilder =>
{
// remove all configs or at least user secrets from config builder
// add mocked configurations
});
}
}
I would like to remove the configuration so as to make sure in future if I add a configuration I forget to mock, the integration test would throw an exception instead of using the user secrets.
I suggest the following approach if you would like to clear any existing default configuration providers and then add your custom configuration.
public class CustomWebApplicationFactory: WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration(configBuilder =>
{
//clears all the default configuration providers
configBuilder.Sources.Clear();
//Add your custom configuration from Json file or memory
});
}
}
You can find more examples here.
Hope this helps.
Related
When configuring OpenIddict encryption keys (both for signing and validating signed "access tokens"), this is done in the Startup of the application (public void ConfigureServices(IServiceCollection services) {...}), where the services (DI) are still being registered.
So, assuming that the asymmetric keys I want to use to sign/validate the tokens are stored on Azure Key Vault, and in the context of following the good practices and principles (like SOLID) to use Dependency Injection to implement a client to access my Azure Key Vault (instead of a static helper class that can just be called in the Startup, as done in this example), my question is...
Is there a way to configure OpenIddict Encryption Keys using Dependency Injection, maybe using a function or handler that would be run after the setup is done?
Example of configuring OpenIddict Server:
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenIddict()
// [...]
.AddServer(options =>
{
// [...]
var key = new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsaKey);
options.AddSigningKey(key);
// [...]
});
}
Example of configuring a Resource API with OpenIddict validation:
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenIddict()
.AddValidation(options =>
{
// [...]
var key = new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsaKey);
options.AddEncryptionKey(key);
// [...]
});
}
The only way of using DI I found is not recommended at all, which would be registering the services I need first, and manually calling services.BuildServiceProvider() to have a ServiceProvider to resolve the type I need and its dependencies, example:
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenIddict()
// [...]
.AddServer(options =>
{
// [...]
ServiceProvider serviceProvider = services.BuildServiceProvider();
var azureKeyVaultClient = serviceProvider.GetService<IAzureKeyVaultClient>();
var rsaKey = azureKeyVaultClient.GetKey(myKeyName).ToRSA();
var key = new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsaKey);
options.AddSigningKey(key);
// [...]
});
}
But, as you can see below, besides the fact it is a very odd approach, it's also not recommended because "Calling 'BuiIdServiceProvider' from application code results in an additional copy of singleton services being created.".
So, does anyone know how I can use DI when configuring OpenIddict keys?
I'm trying to figure out how to fix an issue I have going on with Swagger displaying on our STAGE and PROD servers. I believe my issue is the fact that we have Load Balancer that uses HTTPS to get to but once you get there all the sites are served over HTTP. I believe that is the reason I'm getting
Can't read from server. It may not have the appropriate access-control-origin settings.
So I found the following on Swagger and I'm thinking I just need to set my Schema to HTTP but I'm not 100% sure where to make this change? Do I add it to the SwaggerConfig.cs file?
https://swagger.io/docs/specification/2-0/api-host-and-base-path/
This is what I have in my SwaggerConfig.cs file:
public class SwaggerConfig
{
//public static void Register(HttpConfiguration config)
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.ApiKey("Api-Token")
.Description("API Key for accessing secure APIs")
.Name("Api-Token")
.In("header");
c.SingleApiVersion("v1", "WorkdayAPI");
c.IncludeXmlComments(string.Format(#"{0}\bin\WorkdayApi.XML",
System.AppDomain.CurrentDomain.BaseDirectory));
// If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option.
c.PrettyPrint();
})
.EnableSwaggerUi(c =>
{
// If your API supports ApiKey, you can override the default values.
// "apiKeyIn" can either be "query" or "header
c.EnableApiKeySupport("Api-Token", "header");
});
}
}
I would like to use ASP.NET Core's default DI container to setup DI for my Service Fabric project.
//This is what I've got so far, and it works great
ServiceRuntime.RegisterServiceAsync(
"MyServiceType",
context => new MyService(context, new MyMonitor()
).GetAwaiter().GetResult();
//This is how I use it
public MyService(StatefulServiceContext context, IMonitor myMonitor)
: base(context)
{
this._myMonitor = myMonitor;
}
How would I set up DI, if MyMonitor class has a dependency on a ConfigProvider class, like this:
public MyMonitor(IConfigProvider configProvider)
{
this._configProvider = configProvider;
}
I think this question will give you some light: Why does ServiceRuntime.RegisterServiceAsync return before the serviceFactory func completes?
Technically, the ServiceRuntime.RegisterServiceAsync() is a dependency registration, it requires you to pass the serviceTypeName and the factory method responsible for creating the services Func<StatelessServiceContext, StatelessService> serviceFactory
The factory method receives the context and returns a service (Stateful or stateless).
For DI, you should register all dependencies in advance and call resolve services to create the constructor, something like:
var provider = new ServiceCollection()
.AddLogging()
.AddSingleton<IFooService, FooService>()
.AddSingleton<IMonitor, MyMonitor>()
.BuildServiceProvider();
ServiceRuntime.RegisterServiceAsync("MyServiceType",
context => new MyService(context, provider.GetService<IMonitor>());
}).GetAwaiter().GetResult();
PS:
Never Register the context (StatelessServiceContext\StatefulServiceContext) in the DI, in a shared process approach, multiple partitions might be hosted on same process and will have multiple contexts.
This code snippet is not tested, I've used in the past, don't have access to validate if matches the same code, but is very close to the approach used, might need some tweaks.
Hi #OscarCabreraRodríguez
I am working on the project that simplifies development of Service Fabric Reliable Services and it has great built-in support for dependency injection scenarios.
You can find general information project page, wiki and specific information about dependency injection here.
The idea is that project abstracts you from working with Service instance directly instead providing you with a set of more concrete objects.
Here is a simple example for ASP.NET Core application:
public static void Main(string[] args)
{
new HostBuilder()
.DefineStatefulService(
serviceBuilder =>
{
serviceBuilder
.UseServiceType("ServiceType")
.DefineAspNetCoreListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpoint("ServiceEndpoint")
.UseUniqueServiceUrlIntegration()
.ConfigureWebHost(
webHostBuilder =>
{
webHostBuilder
.ConfigureServices(
services =>
{
// You can configure as usual.
services.AddTransient<IMyService, MyService>();
})
.UseStartup<Startup>();
});
});
})
.Build()
.Run();
[Route("api")]
public class ApiController : Controller
{
public ApiController(IMyService service) { }
[HttpGet]
[Route("value")]
public string GetValue()
{
return $"Value from {nameof(ApiController)}";
}
}
Hope I understand your use case correctly and this information is relevant.
I must integrate Oauth with Autofac. But something goes wrong. I think I understand why, but I don't know how to solve it. I let you see my code.
My Autofac Config
{
builder.RegisterType<CustomAuthorizationServerProvider>()
.PropertiesAutowired()
.SingleInstance();
builder.RegisterType<MyBusinessObj>()
.As<IMyBusinessObj>()
.InstancePerRequest()
.PropertiesAutowired();
//IMySessionObj is a prop inside MyBusinessObj
builder.RegisterType<MySessionObj>()
.As<IMySessionObj>()
.InstancePerRequest()
.PropertiesAutowired();
//IMyUnitOfWorkObjis a prop inside MyBusinessObj
builder.RegisterType<MyUnitOfWorkObj>()
.As<IMyUnitOfWorkObj>()
.InstancePerRequest();
...
}
Startup.cs
I have the classic configuration plus the resolution of my authorizationServerProvider.. As you can see, I resolve it in the container... because it is a singleton.
app.UseAutofacMiddleware(_container);
app.UseAutofacWebApi(config);
var oauthServerOptions = new OAuthAuthorizationServerOptions
{
...,
Provider = _container.Resolve<CustomAuthorizationServerProvider>()
};
app.UseOAuthAuthorizationServer(oauthServerOptions);
app.UseWebApi(config);
CustomAuthorizationServerProvider.cs
This is how I have implemented my CustomAuthorizationServerProvider.
public class CustomAuthorizationServerProvider: OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
var autofacLifetimeScope = OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);
var myBusinessObj = autofacLifetimeScope.Resolve<IMyBusinessObj>();
var xxx = myBusinessObj.DoWork();
...
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var myBusinessObj = autofacLifetimeScope.Resolve<IMyBusinessObj>();
var xxx = myBusinessObj.DoWork();
...
context.Validated(ticket);
}
}
Here I solve my IMyBusinessObj in a lifetimescope, not in the container. This object is responsible (indirectly) to connect to db, access the session, access the cache and so on... so it cannot be a singleton.
I need it would have a lifetime per request.
So here the problems.. Two problems there are in my configuration.
I have a InstancePerRequest object inside a SingleInstance object. I cannot do that. Troubleshooting Per-Request Dependencies
I effectively cannot have a InstancePerRequest object when I configure oauth in the startup... because in that context does not exist a request yet.
So.. I have understood which are my problems.
Any idea or tips?
Thank you
I was having a very similar issue if not the same. I was able to resolve it by doing the following:
1. Do not resolve IOAuthAuthorizationServerProvider directly from the container. Instead, use IDependencyResolver. In your example:
var oauthServerOptions = new OAuthAuthorizationServerOptions
{
...,
Provider = (IOAuthAuthorizationServerProvider)resolver.GetService(typeof(IOAuthAuthorizationServerProvider)),
};
This requires that you have correctly configured HttpConfiguration.DependencyResolver:
HttpConfiguration config = new HttpConfiguration();
... // Configure unrelated
var builder = new ContainerBuilder();
... // set Autofac registrations
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// THIS is where you configure OAuthAuthorizationServerOptions, using IDependencyResolver to resolve IOAuthorizationServerProvider instead of IContainer
ConfigureAuth(app, config.DependencyResolver);
2. I was using dynamic assembly scanning to configure certain Autofac module registrations. I inadvertently was scanning for classes ending with "Provider" and registering them as RequestPerInstance(). This was a problem for me, as it was re-registering my IOAuthAuthorizationServerProvider as a per-request instance, which is unable to be resolved during Startup() code.
Problem code which I replaced with individual registrations:
builder.RegisterAssemblyTypes(executingAssembly)
.Where(t => t.Name.EndsWith("Provider"))
.AsImplementedInterfaces()
.InstancePerRequest();
3. Check properties of MySessionObj, and see what dependencies Autofac is resolving (if any). Make sure that you are explicitly registering dependencies as InstancePerRequest().
By using OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext);, you are resolving dependencies to the "AutoFacWebRequest" lifetime scope, and not the root scope. As a result, my understanding is dependencies resolved to this lifetime scope should be disposed after the request has finished and shouldn't cause future problems with your application.
4. I am not sure what properties are being autowired for your CustomAuthorizationServerProvider object, but assuming you did not post a complete code sample for this class, I would try removing PropertiesAutowired() from it's Autofac registration and inside the object continue to use OwinContextExtensions.GetAutofacLifetimeScope(context.OwinContext); to resolve these other properties if possible.
Could you provide specific detail about what the error or error message you are observing is?
The definition of my interface is as follows:
public interface IApplicationSettings
{
string LoggerName { get; }
string NumberOfResultsPerPage { get; }
string EmailAddress { get; }
string Credential { get; }
}
The implementation of this interface is given below:
public class WebConfigApplicationSettings : IApplicationSettings
{
public string LoggerName
{
get { return ConfigurationManager.AppSettings["LoggerName"]; }
}
public string NumberOfResultsPerPage
{
get { return ConfigurationManager.AppSettings["NumberOfResultsPerPage"]; }
}
public string EmailAddress
{
get { return ConfigurationManager.AppSettings["EmailAddress"]; }
}
public string Credential
{
get { return ConfigurationManager.AppSettings["Credential"]; }
}
}
I also created a factory class to obtain the instance of the concrete implementation of WebConfigSettings as follows:
public class ApplicationSettingsFactory
{
private static IApplicationSettings _applicationSettings;
public static void InitializeApplicationSettingsFactory(
IApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
public static IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
Then I resolved dependency as follows:
public class DefaultRegistry : Registry {
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
}
}
Now when i running my application it throw me following exception:
Exception has been thrown by the target of an invocation.
and the Inner Exception is
No default Instance is registered and cannot be automatically determined for type 'Shoppingcart.Infrastructure.Configuration.IApplicationSettings'\r\n\r\nThere is no configuration specified for Shoppingcart.Infrastructure.Configuration.IApplicationSettings\r\n\r\n1.) Container.GetInstance(Shoppingcart.Infrastructure.Configuration.IApplicationSettings)\r\n
I am using StructureMap for MVC5
The reason your code isn't working is because when you call ObjectFactory.GetInstance<IApplicationSettings>(), your registry hasn't been registered and thus, StructureMap's configuration is incomplete.
I believe what you're trying to do is the following (tested and works):
public class ApplicationSettingsFactory
{
public ApplicationSettingsFactory(WebConfigApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
private static IApplicationSettings _applicationSettings;
public IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
With your registry configured like this:
public DefaultRegistry() {
Scan(scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
this.For<IApplicationSettings>().Use(ctx => ctx.GetInstance<ApplicationSettingsFactory>().GetApplicationSettings());
}
I can't really tell you why your registration fails in StructureMap, but if you allow me, I would like to feedback on your design.
Your design and code violates a few basic principles:
You are violating the Interface Segregation Princple (ISP).
The ISP describes that interfaces should be narrow (role interfaces) and should not contain more members than a consumer uses. You however defined an application wide IApplicationSettings interface and your intention is to inject into any consumer that needs some configuration settings. Changes are really slim however that there is a consumer that actually needs all settings. This forces the consumer to depend on all members, it makes the API more complex, while it just needs one.
You are violating the Open/Closed Principle (OCP).
The OCP describes that it should be possible to add new features without making changes to existing classes in the code base. You will however find yourself updating the IApplicationSettings interface and its implementations (you will probably have a fake/mock implementation as well) every time a new setting is added.
Configuration values aren't read at startup, which makes it harder to verify the application's configuration.
When a consumer makes a call to a property of your IApplicationSettings abstraction, you are forwarding the call to the ConfigurationManager.AppSettings. This means that if the value isn't available or incorrectly formatted, the application will fail at runtime. Since some of your configuration values will only be used in certain cases, this forces you to test every such case after you deployed the application to find out whether the system is configured correctly.
Solution
The solution to these problems is actually quite simple:
Load configuration values at start-up.
Inject configuration values directly into a component that needs that exact value.
Loading the configuration values directly at start-up, allows the application to fail fast in case of a configuration error, and prevents the configuration from being read over and over again needlessly.
Injecting configuration values directly into a component, prevents that component from having to depend on an ever-changing interface. It makes it really clear what a component is depending upon, and bakes this information in during application start-up.
This doesn't mean though that you can't use some sort of ApplicationSettings DTO. Such DTO is exactly what I use in my applications. This basically looks as follows:
public static Container Bootstrap() {
return Bootstrap(new ApplicationSettings
{
LoggerName = ConfigurationManager.AppSettings["LoggerName"],
NumberOfResultsPerPage = int.Parse(
ConfigurationManager.AppSettings["NumberOfResultsPerPage"]),
EmailAddress = new MailAddres(
ConfigurationManager.AppSettings["EmailAddress"]),
Credential = ConfigurationManager.AppSettings["Credential"],
});
}
public static Container Bootstrap(ApplicationSettings settings) {
var container = new Container();
container.RegisterSingle<ILogger>(
new SmtpLogger(settings.LoggerName, settings.EmailAddress));
container.RegisterSingle<IPagingProvider>(
new PagingProvider(settings.NumberOfResultsPerPage));
// Etc
return container;
}
In the code above you'll see that the creation of the ApplicationSettings DTO is split from the configuration of the container. This way I can test my DI configuration inside an integration test, where the start-up projects configuration file is not available.
Also note that I supply the configuration values directly to the constructors of components that require it.
You might be skeptic, because it might seem to pollute your DI configuration, because you have dozens of objects that require to be set with the same configuration value. For instance, your application might have dozens of repositories and each repository needs a connection string.
But my experience is that is you have many components that need the same configuration value; you are missing an abstraction. But don't create an IConnectionStringSettings class, because that would recreate the same problem again and in this case you aren't really making an abstraction. Instead, abstract the behavior that uses this configuration value! In the case of the connection string, create an IConnectionFactory or IDbContextFactory abstraction that allows creation of SqlConnection's or DbContext classes. This completely hides the fact that there is a connection string from any consumer, and allows them to call connectionFactory.CreateConnection() instead of having to fiddle around with the connection and the connection string.
My experience is that makes the application code much cleaner, and improves the verifiability of the application.
Thanks every one for responses. I found my solution. The solution is instead of using Default Registry I created another class for resolve the dependencies. Inside the class I used
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
instead of
IContainer Initialize() {
return new Container(c => c.AddRegistry<ControllerRegistry>());
}
Then inside ControllerRegistry I resolved dependencies as follows:
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
Then I called that class inside Global.asax as follows:
Bootstrap.ConfigureDependencies();
Finally inside Global.asax I resolved dependency for Factory class as follows:
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
My entire code is given below:
Bootstrap class (newly created)
public class Bootstrap
{
public static void ConfigureDependencies()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
}
public class ControllerRegistry : Registry
{
public ControllerRegistry()
{
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
}
}
}
Global.asax
Bootstrap.ConfigureDependencies();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());