Does dependency injection increase my risk of doing something foolish? - oop

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.

Related

What is the best practice when adding data in one-to-many relationship?

I am developing a website for a beauty salon. There is an admin part of the website, where the esthetician can add a new care. A care is linked to a care category (all cares related to hands, feets, massages, ...). To solve this I wrote this code into the CareRepository in the .NET API :
public async Task<Care?> AddAsync(Care care)
{
// var dbCareCategory = await this._careCategoryRepository.GetByNameAsync(care.CareCategoryName);
if (string.IsNullOrEmpty(care.CareCategoryName) || string.IsNullOrWhiteSpace(care.CareCategoryName))
return null;
var dbCareCategory = await this._instituteDbContext.CareCategories
.Where(careCategory => Equals(careCategory.Name, care.CareCategoryName))
.Include(careCategory => careCategory.Cares)
.FirstOrDefaultAsync();
if (dbCareCategory == null || dbCareCategory.Cares.Contains(care))
return null; // TODO : improve handling
dbCareCategory.Cares.Add(care);
await this._instituteDbContext.SaveChangesAsync();
return care;
}
My problem here is that I am a bit struggling with the best practice to have, because in order to add a care to a category, I have to get the category first. At the first place, I called the CareCategoryRepository to get the care (commented line). But then, EF was not tracking the change, so when I tried to add the care, it was not registered in the database. But once I call the category from the CareRepository, EF tracks the change and saves the Care in the database.
I assume this is because when calling from another repository, it is a different db context that tracks the changes of my entity. Please correct me if my assumption is wrong.
So, I am wondering, what is the best practice in this case ?
Keep doing what I am doing here, there is no issue to be calling the category entities from the care repository.
Change my solution and put the AddCare method into the CareCategoryRepository, because it makes more sense to call the categories entities from the CareCategoryRepository.
Something else ?
This solution works fine, however I feel like it may not be the best way to solve this.
The issue with passing entities around in web applications is that when your controller passes an entity to serve as a model for the view, this goes to the view engine on the server to consume and build the HTML for the view, but what comes back to the controller when a form is posted or an AJAX call is made is not an entity. It is a block of data cast to look like an entity.
A better way to think of it is that your Add method accepts a view model called AddCareViewModel which contains all of the fields and FKs needed to create a new Care entity. Think about the process you would use in that case. You would want to validate that the required fields are present, and that the FKs (CareCategory etc.) are valid, then construct a Care entity with that data. Accepting an "entity" from the client side of the request is trusting the client browser to construct a valid entity without any way to validate it. Never trust anything from the client.
Personally I use the repository pattern to serve as a factory for entities, though this could also be a separate class. I use the Repository since it already has access to everything needed. Factory methods offer a standard way of composing a new entity and ensuring that all required data is provided:
var care = _careRepository.Create(addCareViewModel.CareCategoryId,
/* all other required fields */);
care.OptionalField = addCareViewModel.OptionalField; // copy across optional data.
_context.SaveChanges(); // or ideally committed via a Unit of Work wrapper.
So for instance if a new Care requires a name, a category Id, and several other required fields, the Create method accepts those required fields and validates that they are provided. When it comes to FKs, the repository can load a reference to set the navigation property. (Also ensuring that a valid ID was given at the same time)
I don't recommend using a Generic Repository pattern with EF. (I.e. Repository()) Arguably the only reason to use a Repository pattern at all with EF would be to facilitate unit testing. Your code will be a lot simpler to understand/maintain, and almost certainly perform faster without a Repository. The DbContext already serves all of those needs and as a Unit of Work. When using a Repository to serve as a point of abstraction for enabling unit testing, instead of Generic, or per-entity repositories, I would suggest defining repositories like you would a Controller, with effectively a one-to-one responsibility.
If I have a CareController then I'd have a CareRepository that served all needs of the CareController. (Not just Care entities) The alternative is that the CareController would need several repository references, and each Repository would now potentially serve several controllers meaning it would have several reasons to change. Scoping a repository to serve the needs of a controller gives it only one reason to change. Sure, several repositories would potentially have methods to retrieve the same entity, but only one repository/controller should be typically responsible for creating/updating entities. (Plus repositories can always reference one another if you really want to see something as simple as Read methods implemented only once)
If using multiple repositories, the next thing to check is to ensure that the DbContext instance used is always scoped to the Web Request, and not something like Transient.
For instance if I have a CareRepository with a Create method that calls a CareCategoryRepository to get a CareCategory reference:
public Care Create(string name, int careCategoryId)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameOf(name));
var care = new Care { Name = name };
var careCategory = _careCategoryRepository.GetById(careCategoryId);
care.CareCategory = careCategory;
_context.Cares.Add(care);
}
We would want to ensure that the DbContext reference (_context) in all of our repositories, and our controller/UnitOfWork if the controller is going to signal the commit with SaveChanges, are pointing at the exact same single reference. This applies whether repositories call each other or a controller fetches data from multiple repositories.

Autofac Multitenant Database Configuration

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...

Facade in Object Oriented Programming

In OOP, should a Facade be an object or just a class? Which is better?
Most of the examples in Wikipedia creates Facade as an object which should be instantiated before use.
CarFacade cf = new CarFacade();
cf.start();
Can it be designed to be like this instead?
CarFacade.start();
UPDATE
Can a Facade facilitate a singleton?
A facade
represents a high level API for a complex subsystem (module).
reduces client code dependencies.
This means that your client code only uses the facade and does
not have a lot of dependencies to classes behind that facade.
It is better to use an instance of an interface, because
you can replace it for tests. E.g. mock the subsystem the facade represents.
you can replace it at runtime.
When you use a static methods, your client code is bound to that method implementations at compile-time. This is usually the opposite of the open/close principle.
I said "usually the opposite", because there are examples when static methods are used, but the system is still open for extension. E.g.
ServiceLoader
The static load methods only scan the classpath and lookup service implementations. Thus adding classes and META-INF/services descriptions to the classpath will add other available services without changing the ServiceLoader's code.
Spring's AuthenticationFacade for example uses a ThreadLocal internally. This makes it possible to replace the behavior of the AuthenticationFacade. Thus it is open for extension too.
Finally I think it is better to use an instance and interface like I would use for most of the other classes.
It's two fold. You can use it as a static method. Say for instance in spring security I use AuthenticationFacade to access currently logged in user Principal details like so. AuthenticationFacade.getName()
There are other instances, in which mostly people create an instance of Facade and use it. In my opinion neither approach is superior over the other. Rather it depends on your context.
Finally Facade can use Singleton pattern to make sure that it creates only one instance and provides a global point of access to it.
This question is highly subjective. The only reason I am responding is because I reviewed some of my own code and found where I had written a Façade in one application as a singleton and written almost the same Façade in a different application requiring an instance. I'm going to discuss why I chose each of those routes in their respective applications so that I can evaluate if I made the correct choice.
A façade vs the open/close principle is already explained by #Rene Link. In my personal experience, you have to think of it this way: Does the object hold the state of itself?
Let's say I have a façade that wraps the Azure Storage API for .NET (https://learn.microsoft.com/en-us/azure/storage/common/storage-samples-dotnet)
This facade holds information about how to authenticate against the storage API so that it the client can do something like this:
Azure.Authenticate(username, password);
Azure.CreateFile("My New Text File", "\\FILELOCATION");
As you can see in this example, I have not created an instance and i'm using static methods, therefore following the singleton pattern. While this makes for code that is more concise, I now have an issue if I need to authenticate to a given path with a different credential than the one already provided, I would have to do something like this:
Azure.Authenticate(username, password)
Azure.CreateFile("My New Text File", "\\FILELOCATION");
Azure.Authenticate(username2, password2);
Azure.CreateFile("My Restrictied Text File", "\\RESTRTICTEDFILELOCATION");
While this would work, it can be hard to determine why authentication failed when I call Azure.ReadFile, as I have no idea what username and password may have been passed into the singleton from thread4 on form2 (which is no where to found) This is a prime example of where you should be using an instance. It would make much more since to do something like this:
Using (AzureFacade myAzure = Azure.Authenticate(username, password))
{
Azure.CreateFile("My New Text File", "\\FILELOCATION"); // I will always know the username and password.
}
With that said, what happens if the developer needs to create a file in Azure in a method that has no idea what the username and password to Azure may be. A good example of this would be an application that periodically connects to Azure and performs some multi-threaded tasks. In said application, the user setups a connection string to azure and all mulit-threaded tasks are performed using that connection string. Therefore, there is no need to create an instance for each thread (as the state of the object will always be the same) However, in order to maintain thread safety, you don't want to share the same instance across all the threads. This is where a singleton, thread-safe pattern may come into play. (Spring's AuthenticationFacade according to #Rene Link) So that I could do something like this (psudocode)
Thread[] allTask = // Create 5 threads
Azure.Authenticate(username, password) // Authenticate for all 5 threads.
allTask.start(myfunction)
void myFunction()
{
Azure.CreateFile("x");
}
Therefore, the choice between an instance of a façade v. a singleton façade is completely dependent on the intended application of the facade, however both can definitely exist.

service.AddScoped() vs service.AddDbContext()

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.

Where to put methods that interact with multiple classes

I have a class called Contact and one called Account
and I have a method called public static Account GetAccount(Contact c) {...}
Where is the best place to put this method? What design patterns should I be looking at?
A) With the Contact class
B) With the Account class
C) Have the method accessible in both classes
D) Somewhere else?
There are probably many good answers to your question. I'll take a stab at an answer, but it will have my personal biases baked in it.
In OOP, you generally don't see globally accessible) functions, disconnected from, but available to all classes. (Static methods might be globally available, but they are still tied to a particular class). To follow up on dkatzel's answer, a common pattern is in OOP is instance manager. You have a class or instance that provides access to a a database, file store, REST service, or some other place where Contact or Account objects are saved for future use.
You might be using a persistence framework with your Python project. Maybe something like this: https://docs.djangoproject.com/en/dev/topics/db/managers/
Some persistence frameworks create handy methods instance methods like Contact.getAccount() -- send the getAccount message to a contact and the method return the associated Account object. ...Or developers can add these sorts of convenience methods themselves.
Another kind of convenience method can live on the static side of a class. For example, the Account class could have a static getAccountForContact() method that returns a particular account for a given Contact object. This method would access the instance manager and use the information in the contact object to look up the correct account.
Usually you would not add a static method to the Contact class called getAccountForContact(). Instead, you would create an instance method on Contact called getAccount(). This method could then call Account.getAccountForContact() and pass "self" in as the parameter. (Or talk to an instance manager directly).
My guiding principle is typically DRY - do not repeat yourself. I pick the option that eliminates the most copy-and-paste code.
If you define your method in this way, it's not really connected with either of your classes. You can as well put it in a Util class:
public class AccountUtil{
public static Account getAccount(Contact c){ ... }
// you can put other methods here, e.g.
public static Contact getContact(Account a){ ... }
}
This follows the pattern of grouping static functions in utility classes like Math in Java / C#.
If you would like to bound the function to a class in a clear way, consider designing your class like this:
public class Contact{
public Account getAccount(){ ... } // returns the Account of this Contact
// other methods
}
In OOP it is generally recommended that you avoid using global functions when possible. If you want a static function anyways, I'd put it in a separate class.
It depends on how the lookup from Contact to Account happens but I would vote for putting it in a new class that uses the Repository pattern.
Repository repo = ...
Account account = repo.getAccount(contact);
That way you can have multiple Repository implemtations that look up the info from a database, or an HTTP request or internal mapping etc. and you don't have to modify the code that uses the repositories.
My vote is for a new class, especially if the function returns an existing account object. That is, if you have a collection of instances of Contact and a collection of instances of Account and this function maps one to the other, use a new class to encapsulate this mapping.
Otherwise, it probably makes sense as a method on Contact if GetAccount returns a new account filled in from a template. This would hold if GetAccount is something like a factory method for the Account class, or if the Account class is just a record type (instances of which have lifetimes which are bound to instances of Contact).
The only way I see this making sense as part of Account is if it makes sense as a constructor.