I've just come from a place where an API controller would have just the Services it needed injected in to it...
[ApiController]
public class SomeController : ControllerBase
{
private IFirstService firstService
private ISecondService secondService
public SomeController(IFirstService firstService, ISecondService secondService)
{
this.firstService = firstService;
this.secondService = secondService;
}
[HttpGet]
public IActionResult SomeMethod()
{
var data = firstService.GetSomething();
return OkObjectResult(data);
}
}
Now I find myself in a shop that does this...
[ApiController]
public class SomeController : ControllerBase
{
private IServiceProvider services;
public SomeController(IServiceProvider services)
{
this.services = services;
}
[HttpGet]
public IActionResult SomeMethod()
{
var service = servies.Get<IFirstService>();
if(service is null)
{
//...
}
var data = firstService.GetSomething();
return OkObjectResult(data);
}
}
Now, I can't really explain why, but this just seems wrong.
Am I just experiencing StuckInMyWaysitis or is this really the bad practice my bones tells me it is? Or, is there, in fact, a more widely accepted way of doing the "right" thing?
Injecting IServiceProvider implements the Service Locator pattern, which is generally considered to be an anti-pattern.
In your first example two services are injected. You can easily tell what the controller depends on. It's easier to tell if a class begins to depend on too many things when we see five, 10, or 20 dependencies injected. When that happens we usually refactor because the number of dependencies indicates that the class is doing too many things.
In the second example we can't tell from the injected dependency (IServiceProvider) what the class depends on. The only way to tell is to look at every use of services throughout the class and see what gets resolved from it. A class could end up depending on many other classes even though we only see one dependency in the constructor.
This also makes unit testing more difficult. In the first example we might have to create fakes or mocks for one or both services. In the second example we have to either mock IServiceProvider to return mocks or create an IServiceCollection, register the mocks with it as service implementations, and then build a ServiceProvider from it. Both make tests more complex.
Some have reasoned that API controllers are an exception, and that it's okay to have them depend on something like a service locator. (MediatR is a common example.) This is an opinion: It's not bad as long as the controller has little or no logic and is only used to route HTTP requests to some higher-level code.
If we use MediatR or some similar abstraction like ICommandHandler<TCommand> then at least we've constrained the class to submitting queries or commands to handlers. It's not as bad as injecting IServiceProvider which allows the class to resolve any registered service.
It's wrong because it means that every time you need a service you have to explicitly request it and then check the instance for null. This is unnecessary code duplication for no benefit.
It also violates the explicit dependencies principle, which Microsoft recommends you use to architect your code.
Almost certainly this was done because somebody couldn't figure out how DI works, or they forgot to register a service and couldn't be a***d to fix it properly, so they just chucked in IServiceProvider instead and that ended up working, and then they cargo-culted it everywhere. In other words, laziness and/or ignorance.
Likely you will come up against resistance when you try to fix this by using explicit dependencies. The trick is to make the person(s) advocating for this mess explain why the mess is better than following good architectural practices, particularly those from Microsoft.
When you've been programming long enough, you learn to trust your gut. If it feels bad, it almost always is.
First, Let us refactor the second code to get rid of some code smells,
[ApiController]
public class SomeController : ControllerBase
{
private IFirstService firstService
private ISecondService secondService
private IServiceProvider services;
public SomeController(IServiceProvider services)
{
this.services = services;
this.firstService= servies.Get<IFirstService>();
this.secondService= servies.Get<ISecondService>();
}
[HttpGet]
public IActionResult SomeMethod()
{
var data = firstService.GetSomething();
return OkObjectResult(data);
}
}
Why?
you automatically get rid of all the checks, and now you can do that in your constructor if needed.
If many methods needed instances all might have duplicate codes like this.
It violates SRP as the methods are doing more than they should be.
Now if we look it is closer to your First code. With one difference, Instantiating service vs Injecting service. There are a few problems with this IMO,
DI Containers are tools, they are not part of our domain. By taking IServiceProvider, we are trying our services to them. Which implies we always need some DI provider.
Secondly this also hides our dependencies, which makes integration
difficult. Constructors are like messengers that clearly tell us
what we need to keep ready beforehand, before we instantiate a
Class. If we hide this information, you may not know if certain
dependency was configured or not without running the application.
With clearly defined dependencies in constructor, we cannot skip
this part.
Also, just like we had duplicate code in our methods, now we have duplicate code in constructor of different services. Each service will be calling these Get methods. So why not do them in one place. And if you consider this and refactor, you automatically reach to your first example.
[ApiController]
public class SomeController : ControllerBase
{
private IFirstService firstService
private ISecondService secondService
public SomeController(IFirstService firstService, ISecondService secondService)
{
this.firstService = firstService;
this.secondService = secondService;
}
}
public class Startup()
{
public void Start()
{
//....
//....
var service1 = servies.Get<IFirstService>();
var service2 = servies.Get<IFirstService>();
SomeController= new Controller(service1,service2);
//or just servies.Get<SomeController>();
}
}
This is how instantiation happen if you use Containers like AutoFac.
Related
I'm building an application that performs actions initiated by a user and one particular class has dependencies on things I can wire up in DI such as an ILogger instance as well as an HttpClient in addition to runtime arguments that identify the user and the instance of the action (mostly to be used while logging to help with debugging).
The trouble I have is that I'm not entirely sure how to inject this class into the other classes that need it as a result of the runtime dependencies.
Here's a simplified example of one of my classes:
public class Dependency : IDependency
{
private readonly HttpClient httpClient;
private readonly ILogger<Dependency> logger;
private readonly RuntimeDeps runtimeDeps
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
RuntimeDeps runtimeDeps)
{
// set private fields
}
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{runtimeDeps.InstanceId} failed. " +
"Initiated by {runtimeDeps.UserName}");
}
}
This feels like it requires a factory to create but then is it best to request the HttpClient and Logger in the factory method or declare it as a dependency of the factory? If the latter, I presume the factory would have to be registered as a transient or as a scoped resource since registering it as a singleton would result in a captive dependency (I think).
Any suggestions on redesigns are also welcome if this is a symptom of a poor design. I'd love to implement Mark Seeman's Pure DI to get some more assistance from the compiler but I don't know if that's possible in Azure functions.
A transient factory with the transient dependencies injected into the constructor and the runtime dependencies as parameters of the Create method will work fine.
DI is baked into the Azure Functions library in the sense that parameters are injected into the trigger methods, but beyond these you should be able to use Pure DI to manage your own dependencies by calling into some composition root helper class from the trigger function which knows how to build your dependency graph in a pure manner.
Instead of requiring runtime data during the construction of a component, it's better to let runtime data flow through method calls on an initialized object graph by either:
passing runtime data through method calls of the API or
retrieving runtime data from specific abstractions that allow resolving runtime data.
I formalized this in 2015 in this blog post, which I referred to in the comments.
After reading your additional comments, I came to the conclusion that in your case option 2 is most suited, as the data you are sending is likely an implementation detail to the component, and should not be part of the public API.
In that case, you can redesign your component as follows:
public class Dependency : IDependency
{
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
IRuntimeDepsProvider provider) ...
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{provider.InstanceId} failed. " +
$"Initiated by {provider.UserName}");
}
}
IRuntimeDepsProvider is an abstraction that hides the retrieval and storage of runtime data. This gives you the ability to postpone the decision to either use a Closure Composition Model or an Ambient Composition Model until the Last Responsible Moment.
Using the IRuntimeDepsProvider abstraction, you can chose to set the incoming runtime values after the object graph is constructed. For instance:
public class MyFunction
{
// Notice the different abstraction here
public MyFunction(
IRuntimeDepsInitializer initializer,
IHandler<Something> handler) ...
public void TheFunction(Guid instanceId, string userName, Something cmd)
{
// Setting the runtime data *after* the object graph is constructed,
initializer.SetData(instanceId, userName);
// but before the graph's public methods are invoked.
handler.Handle(cmd);
}
}
Here, a second abstraction is introduced, namely IRuntimeDepsInitializer. Now you can have one class implementing both interfaces:
public class RuntimeDepsStorage : IRuntimeDepsInitializer, IRuntimeDepsProvider
{
public Guid InstanceId { get; private set; }
public string UserName { get; private set; }
public void SetData(Guid id, string name)
{
InstanceId = id;
UserName = name;
}
}
TIP: Instead of using two interfaces, you can also use only IRuntimeDepsProvider and let MyFunction depend on the concrete RuntimeDepsStorage. Which solution is best depends on the context.
Now the main trick here is to make sure that RuntimeDepsStorage becomes a Scoped dependency, because you want to reuse it throughout a request, but not shared by multiple requests.
When applying Pure DI, this would look like this:
var storage = new RuntimeDepsStorage();
new MyFuncion(
initializer: storage,
handler: new SomethingHandler(
stuffDoer: new Dependency(
httpClient: client, // Did you notice this is a runtime dep as well?
logger: new Logger<Dependency>(),
provider: storage)))
If, on the other hand, you would be using MS.DI as your DI Container, registration would be similar to the following:
services.AddScoped(_ => new RuntimeDepsStorage());
services.AddScoped<IRuntimeDepsProvider>(
c => c.GetRequiredService<RuntimeDepsStorage>());
services.AddScoped<IRuntimeDepsInitializer>(
c => c.GetRequiredService<RuntimeDepsStorage>());
// etc, your usual registrations here
I'm learning dependency injection, because I don't want my BE to look spaghety no more. I have a good understanding of Asp.Net Core and EF Core. I just never learned dependecy injection properly. I'm playing around with an idea. Let's say, that I create an EmailSenderService (and IEmailSenderService with it). I do the same for CustomLogger and WeatherRepository. Here are the implementations:
Program.cs:
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddScoped<ICustomLogger, CustomLogger>();
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IWeatherRepository, WeatherRepository>();
// Add swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
CustomLogger.cs
public interface ICustomLogger
{
public void Log(string logText);
}
public class CustomLogger : ICustomLogger
{
public void Log(string logText) => System.Diagnostics.Debug.WriteLine(logText);
}
EmailSenderService.cs
public interface IEmailSenderService
{
public void SendMail(string email, string text);
}
public class EmailSenderService : IEmailSenderService
{
public void SendMail(string email, string text) => System.Diagnostics.Debug.WriteLine($"TO: {email}, TEXT: {text}");
}
WeatherForecastModel.cs
public struct WeatherForecastModel
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
WeatherRepository.cs
public interface IWeatherRepository
{
public WeatherForecastModel[] GetRandomSample();
}
public class WeatherRepository : IWeatherRepository
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public WeatherForecastModel[] GetRandomSample() =>
Enumerable.Range(1, 5).Select(index => new WeatherForecastModel
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
WeatherForecastController.cs
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ICustomLogger _customLogger;
private readonly IEmailSenderService _emailSenderService;
private readonly IWeatherRepository _weatherRepository;
public WeatherForecastController(ICustomLogger customLogger, IEmailSenderService emailSenderService, IWeatherRepository weatherRepository)
{
_customLogger = customLogger;
_emailSenderService = emailSenderService;
_weatherRepository = weatherRepository;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecastModel> Get()
{
_customLogger.Log("Started function GetWeatherForecast");
WeatherForecastModel[] results = _weatherRepository.GetRandomSample();
_customLogger.Log("Started sending mail.");
_emailSenderService.SendMail("some.mail#domain.com", $"Summary of the first result: {results[0].Summary}");
_customLogger.Log("Ended sending mail.");
_customLogger.Log("Ended function GetWeatherForecast");
return results;
}
}
Now, with the whole implementation, in place, I don't like it. Like visually. I do not want to see logging and email sending logic inside of my controller. This is the fundamentaly issue, I'm trying to solve with this question. I could (I implemented it for testing) inject logger inside the EmailSenderService and inside the WeatherRepository and log there, howerver, I do not like that either. I do not want to see logging inside of my logic. So, I thought about something I called LogAwareEmailSenderService. Here is impelementation:
public class LogAwareEmailSenderService : IEmailSenderService
{
private readonly ICustomLogger _customLogger;
private readonly IEmailSenderService _emailSenderService;
public LogAwareEmailSenderService(ICustomLogger customLogger, IEmailSenderService emailSenderService)
{
_customLogger = customLogger;
_emailSenderService = emailSenderService;
}
public void SendMail(string email, string text)
{
_customLogger.Log($"Started sending email to: {email}, containing text: {text}");
_emailSenderService.SendMail(email, text);
_customLogger.Log($"Done sending email to: {email}, containing text: {text}");
}
}
Basically, what I'm trying to achieve, is: Take my original EmailSenderService, then inject it into my LogAwareEmailSenderService. The idea is, that now, I should be able to inject this LogAwareEmailSenderService into my controller without the need to change my controller at all (just remove my previous logging logic), right? And If I achieve this, I can go on and continue, to make something like LogAndEmailAwareWeatherRepository, that will inject LogAwareEmailSenderService and instead of sending mail and logging function start inside of the controller. I will just call LogAndEmailAwareWeatherRepository, that will log these things, and send the email, resulting in controller only calling the important, _weatherRepository.GetRandomSample() -- This call will do the logging and sending mail, using the previously described abstractions.
However, in the first place, I am unable to inject the EmailSenderService inside the LogAwareEmailSenderService. I want them both to be scoped. I trid this approach (in my Program.cs):
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IEmailSenderService, LogAwareEmailSenderService>();
however I got circular dependency error:
'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService Lifetime: Scoped ImplementationType: DependencyInjectionExample.Services.EmailSenderService.LogAwareEmailSenderService': A circular dependency was detected for the service of type 'DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService'.
DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService(DependencyInjectionExample.Services.EmailSenderService.LogAwareEmailSenderService) -> DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService)'
So, I got some questions:
Am I going about this right? Like, is what I described above, the normal approach to things?
Where should I put my Logging logic? When doing this, I also thought about caching things, meaning, that I would have something like CacheAwareWeatherRepository, that would only care about the caching implementation and then call the WeatherRepository to get data and return them, while caching them.
How to implement my solution?
I still don't understand some parts of dependecy injection, are there any articles/books that helped you personally understand it?
If you've got here, thank you, I know it is long, however I wanted to describe my problem, possible solutions, and questions clearly.
If you have any questions, about anything, please feel free to ask me in comments, or email me (if it's long question) to dibla.tomas#email.cz. I would really like to get to the bottom of this.
PS: This is not about implementation of bussiness logic, or anything like this, this is only for getting data, logging it, caching it and doing abstractions above data access. I implemented this, with idea that you would have one interface and then layers of abstractions. One for getting the actual data (fAb), One for logging the fact (sAb) implementing fAb, One for caching data (tAb) implementing sAb, One for logging the fact of caching (qAb) implementing tAb. And so on.
Am I going about this right? Like, is what I described above, the normal approach to things?
There's not a right/wrong, but what you're describing is an accepted pattern, called the decorator pattern. One service adds behaviors around another one while implementing the same interface.
Where should I put my Logging logic?
Depends on what you mean by "logging logic." The true logic of your logging (opening files and writing to them, e.g.) is already abstracted away behind the logger interface, as it should be.
If you like to have generic messages logged every time a public method is entered or exited, then you can do that with an aspect-oriented Fody Weaver to avoid repetitive code.
The lines of code that decide what to output as a log message, on the other hand, are mostly going to be specific to your implementation. The most useful diagnostic messages are probably going to be ones that need to know contextual information about your specific implementation, and that code needs to be embedded within the implementation code itself. The fact that you "visually don't want to see" calls to the logging service in your controller code is something you should get over. Diagnostic logging is a cross-cutting concern: a responsibility inherent to every class regardless of what their "single responsibility" is supposed to be.
How to implement my solution?
The DI registration method can take a delegate that lets you be more specific about how the type is resolved.
builder.Services.AddScoped<EmailSenderService>(); // allow the next line to work
builder.Services.AddScoped<IEmailSenderService>(p => new LogAwareEmailSenderService(
p.GetRequiredService<ICustomLoggerService>(),
p.GetRequiredService<EmailSenderService>()));
I still don't understand some parts of dependecy injection, are there any articles/books that helped you personally understand it?
Technically not the sort of question we're supposed to be asking on StackOverflow, but I learned from Mark Seeman's Dependency Injection in .NET (affiliate link). It's kind of old now, so library-specific details are outdated, but the principles are enduring.
I thought it might be worth mentioning the Scrutor library which lets you easily specify the decoration setup. For example, you could have:
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.Decorate<IEmailSenderService, LogAwareEmailSenderService>();
Edit: the Decorator pattern is a great way to honour Single Responsibility while enabling the Open/Closed principle: you're able to add new decorators to extend the capabilities of your codebase without updating the existing classes.
However, it comes with the cost of a somewhat more involved setup. The Scrutor library takes care of the decoration so that you don't need to manually code how the services are composed. If you don't have many decorators, or you don't have many levels of decoration, then that advantage might not be useful to you.
The scanning capability is not related to the decorator setup: it's simply another capability that allows one to add classes to the service collection without manually the classes (sort of auto-discovery). You can do this via reflection.
Here's an example of the decorator setup if you also had caching:
builder.Services.AddScoped<IWeatherRepository, WeatherRepository>();
builder.Services.Decorate<IWeatherRepository, DiagnosticsWeatherRepositoryDecorator>();
builder.Services.Decorate<IWeatherRepository, CachedWeatherRepositoryDecorator>();
You could do this manually:
builder.Services.AddScoped<WeatherRepository>();
builder.Services.AddScoped(provider => new DiagnosticsWeatherRepositoryDecorator(provider.GetRequiredService<WeatherRepository>()));
builder.Services.AddScoped<IWeatherRepository>(provider => new CachedWeatherRepositoryDecorator(provider.GetRequiredService<DiagnosticsWeatherRepositoryDecorator>)));
It becomes a bit more involved if the constructors take other parameters. It's completely possible, but really verbose.
I thought I'd also share some advice regarding your 5th question; my experience of dependency injection frameworks is that:
The frameworks are simply a key-value map; if a class needs interface A, then create class B.
Sometimes it's just a key; that happens when you only need to let the framework know that class C exists.
Whenever a class needs to be created, the map of all classes and all interface/class to class mappings are consulted, and whatever the map lists is created.
It seems like you're aware, but these frameworks also manage the lifetime of the objects it creates. For example, a scoped lifetime is linked to the duration of the http request. This means that an IDisposible object created by the framework, will be deposed once the request ends.
In your case:
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IEmailSenderService, LogAwareEmailSenderService>();
The second statement actually overwrites the mapping of the first statement: you can only have one key (in this case IEmailSenderService) in the collection. So when the framework tried to create LogAwareEmailSenderService it saw that LogAwareEmailSenderService needs an IEmailSenderService but the only one it knows about is LogAwareEmailSenderService.
This is why we only list the interface once when we manually tied up the decorated classes. When the Scrutor library is used, it re-maps the types allowing you to list the interface multiple times.
Following this answer I did this :
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
And then on the Simple Injector :
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
This works great if I inject the ILogger on every class constructor I need. My problem is that I have some classes that I cannot use the constructor injection. For this cases I would tipically do :
var logger = SimpleInjectorInitializer.Container.GetInstance<ILogger>();
However the above method does not work, it throws an error on the simple injector class since the c.Consumer is null.
Here is one of the examples I need to resolve ILogger, this class is registered on the webapi startup class.
public class ExceptionWebApiHandlingAttribute : IExceptionFilter
{
public ExceptionWebApiHandlingAttribute()
{
}
}
Is there any alternative ?
Thanks
When working on the application boundary, it is sometimes hard or impossible to use constructor injection. Typical examples are MVC filter attributes or ASP.NET Web Form Page classes that require a default constructor.
A typical solution to these problems is to make such boundary class into a Humble Object, where all interesting logic is extracted from the boundary class into a component. The boundary class should only contain the call to the Service Locator and call one method on the resolved service. This minimizes the amount of untestable code in the application.
In all other cases, constructor injection should be preferred.
The fact however that you resolve an ILogger implies that your boundary class does too much. Instead this ILogger should be a constructor dependency of the component that you extracted from the boundary class to become a Humble Object.
Once you've done this, you won't be resolving ILogger directly anymore and this solves your problem; ILogger has become a dependency of a consumer and this ensures that Simple Injector is able to build the correct Logger<T> on your behalf.
When it comes to applying dependencies to exception filters in Web API (your particular case), a good solution is to create a proxy for your exception filters that will delegate the call to the real filter that gets resolved. This can be a bit of infrastructure and the concept is explained here.
If it is impossible to apply the above advise, for whatever reason, you can always request a Logger<T> directly from the container:
ILogger log = SimpleInjectorInitializer.Container.GetInstance<Logger<MyHumbleObject>>();
I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.
In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.
ObjectFactory.Initialize{
container.For .....
}
Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.
Static method to return container:
public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}
Userservice's contstructor looks like this:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;
public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}
Finally the initialise (this instance in a console app) looks somthing like this:
private static IUserService _userService;
private static IContainer _container;
static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}
So to my questions.
Am I doing anything seriously wrong here
In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.
Is returning the IContainer from the static method the best approach
If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.
Thanks for any advice.
To go through your questions in order:
Am I doing anything seriously wrong here
No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.
In the UserService, should I be passing the IContainer in and using
the object factory to get the instance or should I leave as is.
You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.
Is returning the IContainer from the static method the best approach
Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.
If this was a MVC app, is it best practice to build this once in the
Global.asax or should the controller constructor call the static
method every time.
Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.
Improvements:-
Take advantage of StructureMap's registries:
Instead of referencing the dependencies directly like this:
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserService>().Use<UserService>();
this.For<IStringService>().Use<StringService>();
this.For<IUserRepository>().Use<UserRepository>();
}
}
Then load your registries like this:
container.Configure(c => {
c.IncludeRegistry<WebsiteRegistry>();
c.IncludeRegistry<TaskRegistry>();
});
HTTP Context bound containers:
Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.
I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.
This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.
Auto registering dependencies
Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.
Forgive a genuine but n00b level query, please. I'm doing a new project and starting to bake in the IoC aspect of it. It's the first I've worked on where I was in charge of building up the framework so I'm cutting my teeth with IoC somewhat. I'm taking a hearty recommendation to use Ninject. Cool.
But as I sit down to create my first class that will rely on constructor injection, it strikes me - I still need to use all of these quite custom/3rd party interfaces in the constructors. So How is it that my code is less coupled to log4net if my classes all take a log4net ILog instance in their constructor? I still need a using statement for log4net in each file that wants to log anything.
I thought that was the point - abstraction and de-coupling of your multitudes of classes, and pushing all of the dependencies into one class. It seems to me that every class that wants to log anything is still quite bound to log4net, and to change log4net out for another logger would be tedious all the same. how is this a win?
I'm sure I'm missing something, so help me out? Am I meant to create my own interfaces everywhere I wanted to be truly decoupled and then add adapters for the implementations or something? Only then would it seem to be we've pushed all the dependencies to one area.
If you use IOC, you inject the interfaces into your class, not the implementation, so that is ok. To get around your specific problem, try looking at the common logging framework (http://netcommon.sourceforge.net/) which itself is a wrapper for log4net or a multitude of other logging frameworks.
This couples you to the common logging framework, but it is very widely used, stable and abstracts the specific of logging without you having to do any of that yourself.
When I have used this in the past, I use a post build script to bring the log4net assemblies into the output directory, so the binding happens at runtime only. For testing purposes and as far as your code is concerned, you are talking to the common logging framework via the public interface provided.
I know what are you talking about! you are going to make a kind of generalization to reduce code duplication(I'm hopping). as you are using .net framework, I have to say that it does not support for aspect oriented programming by default to let you behave different in every situation. for example take a look at this piece of code:
public class BlogService : IBlogService
{
private readonly IBlogRepository _blogRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;
public BlogService(
IBlogRepository blogRepository,
IUnitOfWork unitOfWork,
ILogger logger)
{
_blogRepository = blogRepository;
_unitOfWork = unitOfWork;
_logger = logger;
}
public GetAllBlogPostResponse GetAllBlogPost(GetAllBlogPostRequest request)
{
var response = new GetAllBlogPostResponse();
try
{
var blogPosts = _blogRepository.GetAll();
if (blogPosts != null)
{
response.BlogPostViewModel = blogPosts.ConvertToPostListViewModel();
response.Success = true;
response.MessageType = MessageType.Success;
response.Message = ServiceMessages.GeneralServiceSuccessMessageOnRetrieveInformation;
_logger.Log(string.Format(response.Message));
}
else
{
response.MessageType = MessageType.Info;
response.Message = ServiceMessages.GeneralServiceAlarmMessageOnRetrieveInformation;
_logger.Log(string.Format(response.Message));
}
}
catch (Exception exception)
{
response.Success = false;
response.Message = ServiceMessages.GeneralServiceAlarmMessageOnRetrieveInformation;
_logger.Log(string.Format(response.Message));
_logger.Log(exception.Message);
}
return response;
}
I have injected IBlogRepository, IUnitOfWrork and ILogger(Log4net) in every service class of my application. rather than that I have similar response and generic message in every catch statement. once I wanted to make a kinds of generalization and not to re-implement the similar code in every service class but you making generalization in such a condition will be more cost effective and difficult. although it's so important to not duplicate the code in some situations, for example I have this BaseController and derive all of my controller from that:
public class BaseController : Controller
{
private readonly ICookieStorageService _cookieStorageService;
private readonly ILanguageService _languageService;
public BaseController(ICookieStorageService cookieStorageService,ILanguageService languageService)
{
_cookieStorageService = cookieStorageService;
_languageService = languageService;
}
}
so I don't need to create the cookieStorageService and languageService in my controllers each time as I have implemented it in for once.