Let's say I want to implement different DbContexts (MySql, MsSql), but make an app completely unaware of it.
So with "AddScoped" (or any other) method I can register things like:
<AppDbContextContract, AppDbContextMySql>
<AppDbContextContract, AppDbContextMsSql>
Or even hide each of it behind factories.
But with AddDbContext() I can't even see an obvious way to put the implementation I need instead of abstract AppDbContextContract.
What is the use of AddDbContext() method aside of providing an easy way to add a DB context in a basic application? Should I prefer "general" DI methods over it?
.AddDbContext also allows you to configure it at the same time. Configuration can't work with the abstract type, since you have to pass a IDbContextOptionsBuilder<T> into your DbContext, where T is your concrete implementation.
However, you can use both together if you want to inject the abstract class.
services.AddDbContext<AppDbContextMySql>( /* configure it */);
services.AddDbContext<AppDbContextSqlServer>( /* configure it */);
services.AddScoped<AppDbContextContract>(p => p.GetRequiredService<AppDbContextMySql>());
services.AddScoped<AppDbContextContract>(p => p.GetRequiredService<AppDbContextSqlServer>());
Not using .AddDbContext you'd need to write
var dbOptionsA = new DbContextOptionsBuilder<AppDbContextMySql>();
dbOptionsA.UseMySql(...);
services.AddSingleton(dbOptionsA);
var dbOptionsB = new DbContextOptionsBuilder<AppDbContextSqlServer>();
dbOptionsB.UseSqlServer(...);
services.AddSingleton(dbOptionsB);
services.AddScoped<AppDbContextContract,AppDbContextMySql>();
services.AddScoped<AppDbContextContract,AppDbContextSqlServer>();
Not so pretty, eh?
But if the configuration happens from outside, then yes. You could only have a single AppDbContextContract, which accepts a IDbContextOptions<AppDbContextContract> and configure this in a library. You'd still have to register IDbContextOptions<AppDbContextContract> during startup somewhere.
Related
The SignalR documentation has a part where it explains how to use .NET's DI to inject the IHubContext into a controller/middleware, but is there any way to get a reference to/instance of a Hub from just any plain class? Does it have to specifically be a service or whatever else the DI requires in order to make this work?
To give a very contrived (and possibly wrong) example: Say we have a TestHub and a static List<Whatever>. Whenever a client connects to TestHub, we create a new Whatever and add it to the static list. Each Whatever does one thing: asynchronously waits a random amount of time, and then somehow calls TestHub to send a message to all clients.
Now, this might completely be an architectural issue, seeing as the static List can just as well be a Singleton service that can use DI, but the idea is that the List doesn't govern when the messages are sent, instead the Whatever objects do that, with the random wait abstracting some nondeterministic logic.
If this scenario makes any sense, how can the Whatever call the TestHub?
If it doesn't, please let me know what I'm getting wrong. I'm very new to this, so I'm not really sure if the use case makes much sense in general.
Thanks in advance.
Nope, no statics allowed. Put the class in DI and inject the IHubContext is the way to go! You can also consider using a background service.
PS: Of course, you can create your own static but that's not a route I would recommend.
I'm currently making a library that interacts with a particular API that requires an oAuth OIDC connection/token and I'd like to make something that makes that particular part easier for users of this library so they don't need all this custom code.
What is this currently called and is there an example of code?
I ask because from trying to get this work, the documentation is ALL OVER THE PLACE. It looks like this particular process has undergone significant changes multiple times as things went on from before netcore to netcore2 and now netcore31.
Both AddAuthentication and AddOpenIdConnect are extension methods.
An extension method allows you to "add" methods to a type without having to modify the type directly - the methods aren't actually added to the type, but we can call them as if they had been. This is useful in situations where you'd like to extend the behaviour of a class created by a third party but don't have access to the source code.
As for what the particular pattern in question is, whilst there is no canonical name, it's merely a way of encapsulating the configuration of services and dependencies for your application.
AddAuthentication is an extension method of IServiceCollection, which is services type. AddAuthentication has a return type of AuthenticationBuilder, and AddOpenIdConnect is an extension method for AuthenticationBuilder. This is the implementation of AddOpenIdConnect, but as you're looking to encapsulate the configuration, you could probably do something like this:
public static class OpenIdConnectExtensions
{
public static AuthenticationBuilder ConfigureOpendIdConnect(
this AuthenticationBuilder builder)
{
return builder.AddOpenIdConnect(options =>
{
options.SignInScheme = IdentityConstants.ExternalScheme;
// Do whatever else you need.
});
}
}
And call it as follows:
services
.AddAuthentication()
.ConfigureOpendIdConnect()
Middleware, on the other hand, is code that executes as part of a pipeline in order to process requests and responses. The middleware sits in the middle of receiving requests and sending responses, hence the name. This allows you do things such as always adding certain headers to responses without that logic being split across your application. As you correctly mentioned, you see these being applied via calls such as app.UseXyz().
I have a base abstract context which has a couple hundred shared objects, and then 2 "implementation" contexts which both inherit from the base and are designed to be used by different tenants in a .net core application. A tenant object is injected into the constructor for OnConfiguring to pick up which connection string to use.
public abstract class BaseContext : DbContext
{
protected readonly AppTenant Tenant;
protected BaseContext (AppTenant tenant)
{
Tenant = tenant;
}
}
public TenantOneContext : BaseContext
{
public TenantOneContext(AppTenant tenant)
: base(tenant)
{
}
}
In startup.cs, I register the DbContexts like this:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
Then using the autofac container and th Multitenant package, I register tenant specific contexts like this:
IContainer container = builder.Build();
MultitenantContainer mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);
mtc.ConfigureTenant("1", config =>
{
config.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
});
mtc.ConfigureTenant("2", config =>
{
config.RegisterType<TenantTwoContext>().AsSelf().As<BaseContext>();
});
Startup.ApplicationContainer = mtc;
return new AutofacServiceProvider(mtc);
My service layers are designed around the BaseContext being injected for reuse where possible, and then services which require specific functionality use the TenantContexts.
public BusinessService
{
private readonly BaseContext _baseContext;
public BusinessService(BaseContext context)
{
_baseContext = context;
}
}
In the above service at runtime, I get an exception "No constructors on type 'BaseContext' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'". I'm not sure why this is broken....the AppTenant is definitely created as I can inject it other places successfully. I can make it work if I add an extra registration:
builder.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
I don't understand why the above registration is required for the tenant container registrations to work. This seems broken to me; in structuremap (Saaskit) I was able to do this without adding an extra registration, and I assumed using the built in AddDbContext registrations would take care of creating a default registration for the containers to overwrite. Am I missing something here or is this possibly a bug in the multitenat functionality of autofac?
UPDATE:
Here is fully runable repo of the question: https://github.com/danjohnso/testapp
Why is line 66 of Startup.cs needed if I have lines 53/54 and lines 82-90?
As I expected your problem has nothing to do with multitenancy as such. You've implemented it almost entirely correctly, and you're right, you do not need that additional registration, and, btw, these two (below) too because you register them in tenant's scopes a bit later:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
So, you've made only one very small but very important mistake in TenantIdentitifcationStrategy implementation. Let's walk through how you create container - this is mainly for other people who may run into this problem as well. I'll mention only relevant parts.
First, TenantIdentitifcationStrategy gets registered in a container along with other stuff. Since there's no explicit specification of lifetime scope it is registered as InstancePerDependency() by default - but that does not really matter as you'll see. Next, "standard" IContainer gets created by autofac's buider.Build(). Next step in this process is to create MultitenantContainer, which takes an instance of ITenantIdentitifcationStrategy. This means that MultitenantContainer and its captive dependency - ITenantIdentitifcationStrategy - will be singletons regardless of how ITenantIdentitifcationStrategy is registered in container. In your case it gets resolved from that standard "root" container in order to manage its dependencies - well, this is what autofac is for anyways. Everything is fine with this approach in general, but this is where your problem actually begins. When autofac resolves this instance it does exactly what it is expected to do - injects all the dependencies into TenantIdentitifcationStrategy's constructor including IHttpContextAccessor. So, right there in the constructor you grab an instance of IHttpContext from that context accessor and store it for using in tenant resolution process - and this is a fatal mistake: there's no http request at this time, and since TenantIdentitifcationStrategy is a singleton it means that there will not ever be one for it! So, it gets null request context for the whole application lifespan. This effectively means that TenantIdentitifcationStrategy will not be able to resolve tenant identifier based on http requests - because it does not actually analyze them. Consequently, MultitenantContainer will not be able to resolve any tenant-specific services.
Now when the problem is clear, its solution is obvious and trivial - just move fetching of request context context = _httpContextAccessor.HttpContext to TryIdentifyTenant() method. It gets called in the proper context and will be able to access request context and analyze it.
PS. This digging has been highly educational for me since I had absolutely no idea about autofac's multi-tenant concept, so thank you very much for such an interesting question! :)
PPS. And one more thing: this question is just a perfect example of how important well prepared example is. You provided very good example. Without it no one would be able to figure out what the problem is since the most important part of it was not presented in the question - and sometimes you just don't know where this part actually is...
I have a simple REST client that works well. In my application code I do something like this:
restClient = new RestClient(configurationData)
restClient.get('/person/1') //Get Person
restClient.get('/equipment/auto/3') //Get an Auto
restClient.get('/house/7') //Get a House
That works well but things are getting more complicated and I would like to divorce the application code from the specific resource locations.
I'd like to be able to write a wrapper around the service, which will store the resource locations and not require me to put them in my application code. I would expect my code to start looking more like this:
restClient = new RestClient(configurationData)
restClient.getPerson(1) //Get Person
restClient.getAuto(3) //Get an Auto
restClient.getHouse(7) //Get a House
I started adding these wrappers inside of my RestClient class but it got very bloated very fast, and it felt that the abstraction should be at a higher level. Mixing Resource-specifics with my client also felt wrong.
So, instead I subclassed RestClient, and each resource has its own class. The problem is that now I have to instantiate a new client for every different resource type:
personRestClient = new PersonRestClient(configurationData)
personRestClient.get(1);
autoRestClient = new AutoRestClient(configurationData)
autoRestClient.get(3);
housesRestClient = new HousesRestClient(configurationData)
housesRestClient.get(7);
But now I've created a new Client class for each Resource and I am fairly certain that is a very bad thing to do. It's also a pain because I have to tie my connection configuration data to each one, when this should only happen once.
Is there a good example or pattern I should be following when I want to write abstractions for my Resources? My base RestClient works fine but I dislike having to put the server-side API locations in my application code. But I also don't want to have to instantiate one specialized client class for each Resource I want to interact with.
I am in a similar situation, and have what I consider to be a good implementation with the appropriate abstractions. Whether my solution is the best practice or not, I cannot guarantee it, but it is fairly lightweight. Here is how I have it architected:
My UI layer needs to make calls into my REST service, so I created an abstraction called ServiceManagers.Interfaces.IAccountManager. The interface has methods called GetAccounts(Int64 userId).
Then I created a Rest.AccountManager that implemented this Interface, and injected that into my AccountController. The Rest.AccountManager is what wraps the REST specifics (URL, get/post/put..., parameters, etc).
So, now my UI code only has to call accountManager.GetAccounts(userId). You can create an all-encompassing interface so that you only have a Get, but I feel that is less expressive. It is ok to have many different interfaces for each component(ie: PersonManager, HouseManager, AutoManager), because each are a separate concern returning different data. Do not be afraid of having a lot of interfaces and classes, as long as your names are expressive.
In my example, my UI has a different manager for each controller, and the calls made fit each controller appropriately (ie. GetAccounts for AccountController, GetPeople for PeopleController).
Also, as to the root configuration data, you can just use a configurationCreationFactory class or something. That way all implementations have the appropriate configuration with the core logic in one location.
This can be a hard thing to explain, and I know I did not do a perfect job, but hopefully this helps a little. I will try to go back through and clean it up later, especially if you do not get my point :)
I am thinking something like this, again some way of mapping your end points to the client. You can have the mapping as an xml or a properties file which can be loaded and cached during the app start. The file should have key value pairs
PERSON_ENDPOINT=/person/
AUTO_ENDPOINT=/equipment/auto/...
The client should pass this key to the factory may be ClientFactory which has this xml cache and retrieves the end point from the cached file. The parameters can be passed to the factory as custom object or a map. The factory gives back the complete end point say "/person/1" which you can pass to your client. This way you dont need to have different classes for the client. If you dont like the xml or a file you can have it as a static map with key value pairs. If its an xml or file you dont need a code change every time that is the advantage.
Hope this helps you.
I'm trying to embrace widespread dependency injection/IoC. As I read more and more about the benefits I can certainly appreciate them, however I am concerned that in some cases that embracing the dependency injection pattern might lead me to create flexibility at the expense of being able to limit risk by encapsulating controls on what the system is capable of doing and what mistakes I or another programmer on the project are capable of making. I suspect I'm missing something in the pattern that addresses my concerns and am hoping someone can point it out.
Here's a simplified example of what concerns me. Suppose I have a method NotifyAdmins on a Notification class and that I use this method to distribute very sensitive information to users that have been defined as administrators in the application. The information might be distributed by fax, email, IM, etc. based on user-defined settings. This method needs to retrieve a list of administrators. Historically, I would encapsulate building the set of administrators in the method with a call to an AdminSet class, or a call to a UserSet class that asks for a set of user objects that are administrators, or even via direct call(s) to the database. Then, I can call the method Notification.NotifyAdmins without fear of accidentally sending sensitive information to non-administrators.
I believe dependency injection calls for me to take an admin list as a parameter (in one form or another). This does facilitate testing, however, what's to prevent me from making a foolish mistake in calling code and passing in a set of NonAdmins? If I don't inject the set, I can only accidentally email the wrong people with mistakes in one or two fixed places. If I do inject the set aren't I exposed to making this mistake everywhere I call the method and inject the set of administrators? Am I doing something wrong? Are there facilities in the IoC frameworks that allow you to specify these kinds of constraints but still use dependency injection?
Thanks.
You need to reverse your thinking.
If you have a service/class that is supposed to mail out private information to admins only, instead of passing a list of admins to this service, instead you pass another service from which the class can retrieve the list of admins.
Yes, you still have the possibility of making a mistake, but this code:
AdminProvider provider = new AdminProvider();
Notification notify = new Notification(provider);
notify.Execute();
is harder to get wrong than this:
String[] admins = new String[] { "joenormal#hotmail.com" };
Notification notify = new Notification(admins);
notify.Execute();
In the first case, the methods and classes involved would clearly be named in such a way that it would be easy to spot a mistake.
Internally in your Execute method, the code might look like this:
List<String> admins = _AdminProvider.GetAdmins();
...
If, for some reason, the code looks like this:
List<String> admins = _AdminProvider.GetAllUserEmails();
then you have a problem, but that should be easy to spot.
No, dependency injection does not require you to pass the admin list as a parameter. I think you are slightly misunderstanding it. However, in your example, it would involve you injecting the AdminSet instance that your Notification class uses to build its admin list. This would then enable you to mock out this object to test the Notification class in isolation.
Dependencies are generally injected at the time a class is instantiated, using one of these methods: constructor injection (passing dependent class instances in the class's constructor), property injecion (setting the dependent class instances as properties) or something else (e.g. making all injectable objects implement a particular interface that allows the IOC container to call a single method that injects its dependencies. They are not generally injected into each method call as you suggest.
Other good answers have already been given, but I'd like to add this:
You can be both open for extensibility (following the Open/Closed Principle) and still protect sensitive assets. One good way is by using the Specification pattern.
In this case, you could pass in a completely arbitrary list of users, but then filter those users by an AdminSpecification so that only Administrators recieve the notification.
Perhaps your Notification class would have an API similar to this:
public class Notification
{
private readonly string message;
public Notification(string message)
{
this.message = message;
this.AdminSpecification = new AdminSpecification();
}
public ISpecification AdminSpecification { get; set; }
public void SendTo(IEnumerable users)
{
foreach(var u in users.Where(this.AdminSpecification.IsSatisfiedBy))
{
this.Notify(u);
}
}
// more members
}
You can still override the filtering behavior for testing-purposes by assigning a differet Specification, but the default value is secure, so you would be less likely to make mistakes with this API.
For even better protection, you could wrap this whole implementation behind a Facade interface.