This question is similar to my previous question about Razor Components, but instead, this question is about Razor Pages, which requires a different interception point.
I am making an ASP.NET Core application using the Pure DI approach explained in the book Dependency Injection Principles, Practices, and Patterns (DIPP&P). Part of my application has a web API controller. To implement Pure DI with my controller, I was easily able to follow section 7.3.1 "Creating a custom controller activator" from DIPP&P to create a controller activator class, similar to the example found in DIPP&P. This was done by implementing IControllerActivator and composing my composition root within the create method.
My application will also feature Razor Pages. I would like to continue using the Pure DI approach but I cannot find any examples on how to do this. My assumption is I need to create a RazorPageActivator class, which implements IRazorPageActivator and add my composition root to the Activate method. However, after reviewing the RazorPageActivator class found in the ASP.NET Core GitHub, it looks very complex and I fear if I intercept it (or override it?) by making my own class that implements IRazorPageActivator things will break and I'll be in a mess.
My question is how does one go about implementing Pure DI with Razor Pages, if possible?
With Razor Pages, the IPageModelActivatorProvider functions as your Composition Root's Composer. Here's an example based on the default Visual Studio (2019) Razor Pages project template.
Let's start with the custom IPageModelActivatorProvider, which acts as your Composer, which is part of your Composition Root:
public class CommercePageModelActivatorProvider
: IPageModelActivatorProvider, IDisposable
{
// Singletons
private readonly ILoggerFactory loggerFactory;
public CommercePageModelActivatorProvider(ILoggerFactory loggerFactory) =>
this.loggerFactory = loggerFactory;
public Func<PageContext, object> CreateActivator(
CompiledPageActionDescriptor desc) =>
c => this.CreatePageModelType(c, desc.ModelTypeInfo.AsType());
public Action<PageContext, object> CreateReleaser(
CompiledPageActionDescriptor desc) =>
(c, pm) => (pm as IDisposable)?.Dispose();
private object CreatePageModelType(PageContext c, Type pageModelType)
{
// Create Scoped components
var context = new CommerceContext().TrackDisposable(c);
// Create Transient components
switch (pageModelType.Name)
{
case nameof(IndexModel):
return new IndexModel(this.Logger<IndexModel>(), context);
case nameof(PrivacyModel):
return new PrivacyModel(this.Logger<PrivacyModel>());
default: throw new NotImplementedException(pageModelType.FullName);
}
}
public void Dispose() { /* Release Singletons here, if needed */ }
private ILogger<T> Logger<T>() => this.loggerFactory.CreateLogger<T>();
}
Notice a few things with this implementation:
The structure of this class is very similar to the one's given in the book's code samples.
It implements IDisposable to allow disposing of its own created singletons. In this case, no singletons are created in its constructor, so nothing needs to be disposed. The ILoggerFactory is "externally owned"; it is created by the framework, and will be disposed (if needed) by the framework.
The class uses a custom TrackDisposable extension method (shown later on) that allows tracking scoped and transient dependencies. The TrackDisposable method will add those instances to the request and allows the framework to dispose them when the request ends.
This is why the CreateReleaser method only disposes the Page itself. The disposing of all other created components is done by the framework when you track them for disposal. You can also choose to track the Page itself; in that case you can leave the CreateReleaser delegate empty.
There is a handy Logger<T>() method that simplifies the creation of ILogger<T> implementations. Those come from the framework and are created by the ILoggerFactory.
Here's the TrackDisposable extension method:
public static class DisposableExtensions
{
public static T TrackDisposable<T>(this T instance, PageContext c)
where T : IDisposable
{
c.HttpContext.Response.RegisterForDispose(instance);
return instance;
}
}
The last missing piece of infrastructure required is the registration of your CommercePageModelActivatorProvider into the framework's DI Container. This is done inside the Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Register your custom component activator here
services.AddSingleton<
IPageModelActivatorProvider, CommercePageModelActivatorProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
Related
Scenario
I am trying to change my existing HttpClient to IHttpClientFactory. When I verified the existing code, its using using{...} statement which causes issues and it is mentioned here. So I thought of implementing singleton Http client and reached another blog related to this and it is here.
From all these, I understood that the best one is IHttpClientFactory introduced in .NET Core.
Implementation Plan
As this application is in ASP.NET MVC 4 and does not use DI, I have to do something to use without the DI framework. Based on my search, got answers from StackOverflow and planned to implement the same way. Meanwhile, I also got another project, which already removed all the dependencies and is ready to use in earlier projects without doing all things. The repo is HttpClientFactoryLite.
Question
Now I can use HttpClientFactoryLite by initializing this class? The description also mentioned it can be used along with the existing DI framework so that ClientFactory can be registered as a singleton. Please find the wordings from the readme
using HttpClientFactoryLite;
var httpClientFactory = new HttpClientFactory(); //bliss
If you are using dependency injection, make sure that IHttpClientFactory is registered as a singleton.
In my scenario, I don't have any DI framework added. So I am going to initialize the factory wherever I needed. Here I am confused that in 2 things
Is it necessary to make a singleton class for HttpClientFactoryLite?
How is this HttpClientFactory class disposed? Is there a need to dispose of it as part of the controller or same using statement etc?
Based on the answer from this, Microsoft.Extensions.Http provides the HttpClientFactory only, not the new optimized HttpClient. This is only available in .NET Core 2.1. So any difference in implementing IHttpClientFactory?
Please advise
ASP.NET 3.1:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<IHttpClientFactory, HttpClientFactory>();
}
ASP.NET will automatically pass the correct singleton to controllers which demand an IHttpClientFactory in their constructor.
Poormans variation without DI-Container:
public static class Singleton<TInterface>
{
private static TInterface instance;
public static TInterface Instance
{
get => instance;
private set => instance ??= value;
}
public static void Add<TConcrete>() where TConcrete : TInterface, new()
=> Instance = new TConcrete();
public static void Add<TConcrete>(TConcrete instance) where TConcrete : TInterface
=> Instance = instance;
// put dispose logic if necessary
}
Usage:
// Application Entrypoint
Singleton<IHttpClientFactory>.Add<HttpClientFactory>();
// Class/Controller Property
private readonly IHttpClientFactory httpClientFactory
= Singleton<IHttpClientFactory>.Instance;
Until now, I have used the Unity IOC container to resolve dependencies, which works just fine. With the Unity DI, I normally resolve instances in the following way:
Public class TestClass {
public TestClass()
{
var instance = IOC.resolve<InterfaceClassToResolve>();
}
}
This works great, but seeing that .net core now provides me with an out of the box DI container, I would much rather like to use that - There is just one problem compared to the Unity IOC, namely that it is injected as a constructor argument, and not resolved like the example above.
In most cases, I figured that it forces me to chain my dependencies throughout multiple classes, instead of just resolving my dependency in the classes that actually needs them.
I have been looking at ways to solve this, and as far as I can see, the only option is to do something like this:
Public class TestClass {
public TestClass(IServiceProvider serviceProvider)
{
var instance = serviceProvider.GetService<InterfaceClassToResolve>();
}
}
And then we are back to square one again...
Therefore, am I missing some of the functionality behind the .net core IOC, or is there some secret sauce to why most examples wants me use the .net core IOC via constructor arguments?
You can use DI without constructors like:
On the ConfigureServices
services.AddSingleton<YourClass>()
Then inject it like this:
private YourClass YourClass
{
get
{
return this.serviceProvider.GetRequiredService<YourClass>();
}
}
As already commented, Service Locator pattern is not the best method and considered an anti-pattern.
I understand the necessity, though, of finding a way to easily convert existing code to the out-of-the-box DI system without going mad.
I therefore suggest you to do something like this:
1) Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DatabaseContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// other services configuration here
// IMPORTANT: This should be the last line of ConfigureServices!
IOC.CurrentProvider = services.BuildServiceProvider();
}
...
2) IOC.cs
public class IOC
{
public static IServiceProvider CurrentProvider { get; internal set; }
public static T resolve<T>()
{
return CurrentProvider.GetService<T>();
}
}
This should allow you to use dotnet core DI with existing service locator code based on Unity, with minimal fixes (basically just some using declarations to be fixed), as long as you solemnly promise to refactor your code as soon as possible to get rid of all that Service Locator code :D
I am using ASP.NET.Core to embed a web server into a large legacy desktop application. My middleware components need to reference pre-existing application objects.
With difficulty I have got this working using the native DI container, but the resulting code is extraordinarily obtuse and opaque.
What I would really like to do, is to explicitely inject the dependencies, which are specific pre-existing object instances, through constructor parameters. The auto-magic of the DI container isn't giving me any benefits, just a lot of pain!
Is it possible to use ASP.NET.Core without the DI Container?
Here's some simplified code to illustrate my current solution:
class Dependency
{
public string Text { get; }
public Dependency(string text) => Text = text;
}
class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly Dependency _dep1;
private readonly Dependency _dep2;
public MyMiddleware(RequestDelegate next, Dependency dep1, Dependency dep2)
{
_next = next;
_dep1 = dep1;
_dep2 = dep2;
}
public Task InvokeAsync(HttpContext context)
{
return context.Response.WriteAsync(_dep1.Text + _dep2.Text);
}
}
Startup and application code:
class Startup
{
private readonly Dependency _dep1;
private readonly Dependency _dep2;
public Startup(Dependency dep1, Dependency dep2)
{
_dep1 = dep1;
_dep2 = dep2;
}
public void Configure(IApplicationBuilder appBuilder)
{
appBuilder.UseMiddleware<MyMiddleware>(_dep1, _dep2);
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var dep1 = new Dependency("Hello ");
var dep2 = new Dependency("World");
int port = 5000;
StartWebServer(port, dep1, dep2);
Process.Start($"http://localhost:{port}");
}
void StartWebServer(int port, Dependency dep1, Dependency dep2)
{
IWebHostBuilder builder = new WebHostBuilder();
builder.UseUrls($"http://0.0.0.0:{port}/");
builder.UseKestrel();
builder.ConfigureServices(servicesCollection => servicesCollection.AddSingleton(new Startup(dep1, dep2)));
builder.UseStartup<Startup>();
IWebHost webHost = builder.Build();
var task = webHost.StartAsync();
}
}
Can this sample code be refactored to eliminate the DI container?
There is no way to completely remove the built-in DI Container from ASP.NET Core, since it’s completely integrated in the whole process; everything depends on its existence. That built-in container is part of the larger configuration API that ASP.NET Core provides.
This means that as application developer, in one way or another, you will have to interact with it at some point, when it comes to changing default behavior.
This doesn't mean, though, that you are forced to use the built-in DI Container, or in fact use any container, to build up object graphs of application components. Building object graphs without the use of a DI Container is a quite common practice called Pure DI, and this is, for the most part, possible as well when using ASP.NET Core.
If you wish to practice Pure DI, it typically means replacing a few common interception points. One such common interception point is the IControllerActivator abstraction. By replacing the default implementation, you can intercept the creation of MVC controller instances, which are typically the root objects of your application's object graphs. Here is an example Github repository that demonstrates how to apply Pure DI with respect to creating controllers.
In your example, however, you only seem to deal with custom middleware. In that case, using Pure DI is even simpler, because it doesn't require replacing factory abstractions, such as IControllerActivator. This can be done as follows:
var middleware = new MyMiddleware(_dep1, _dep2);
app.Use((context, next) =>
{
return middleware.InvokeAsync(context, next);
});
Notice how I moved the RequestDelegate out of the MyMiddleware constructor into the InvokeAsync method. Reason for doing this, is that makes it possible to create MyMiddleware independently of any runtime values. RequestDelegate is a runtime value and in the previous example, MyMiddleware is just created once at startup. In other words, it's simply a Singleton.
In case MyMiddleware does contain some mutable state, and therefore can’t be cached indefinitely (for instance because it depends on a DbContext), you can create it inside the delegate. This means it will be created once per request.
I am trying to instruct my ASP.NET Core MVC application to use a 3rd party DI container. Rather than writing an adapter I am trying to just plug in the the library following the advice in this post
This works pretty well - I can replace the built in IControllerActivator with my own that uses the DI container. However, I am running into a roadblock when trying to instantiate custom middleware that also relies on injected dependencies. ASP.NET cannot resolve these dependencies because it is not using my 3rd party DI container - is there an equivalent of IControllerActivator for middleware, or am I stuck using the built-in DI or writing an adapter?
** EDIT **
Here's some more of my code - I am actually trying to use Ninject using the pattern above.
internal sealed class NinjectControllerActivator : IControllerActivator
{
private readonly IKernel _kernel;
public NinjectControllerActivator(IKernel kernel)
{
_kernel = kernel;
}
[DebuggerStepThrough]
public object Create(ActionContext context, Type controllerType)
{
return _kernel.Get(controllerType);
}
}
I've discovered I have two problems:
I can't inject standard ASP.NET components into my controllers because Ninject is not aware of them
My middleware that uses application services can't be instantiated because ASP.NET isn't aware of Ninject.
For an example of the first problem, here's a controller that fails to instantiate because I'm using IUrlHelper (also note the ILogger, which also fails to instantiate):
public class SystemController : Controller
{
public SystemController(ILogger logger, IUrlHelper urlHelper)
{
/*...*/
}
}
Here's an example of the second problem with a custom middleware:
public class CustomMiddleware
{
private RequestDelegate _next;
// this is an application specific service registered via my Ninject kernel
private IPersonService _personService;
public CustomMiddleware(RequestDelegate next, IPersonService personService)
{
_next = next;
_personService = personService;
}
public async Task Invoke(HttpContext context)
{
/* ... */
}
}
I realize that in theory ASP.NET components should be in their own pipeline and my application components should be in another, but in practice I often need to use components in a cross-cutting way (as in the examples above).
The SOLID principles dictate that:
the abstracts are owned by the upper/policy layers (DIP)
Which means that our application code should not depend directly on framework code, even if they are abstractions. Instead we should define role interfaces that are tailored for the use of our application.
So instead of depending on a Microsoft.Framework.Logging.ILogger abstraction, that might or might not fit our application specific needs, the SOLID principles guide us towards abstractions (ports) that are owned by the application, and use adapter implementations that hook into framework code. Here's an example of how your own ILogger abstraction might look like.
When application code depends on your own abstraction, you need an adapter implementation that will be able to forward the call to the implementation supplied by the framework:
public sealed class MsLoggerAdapter : MyApp.ILogger
{
private readonly Func<Microsoft.Framework.Logging.ILogger> factory;
public MsLoggerAdapter(Func<Microsoft.Framework.Logging.ILogger> factory) {
this.factory = factory;
}
public void Log(LogEntry entry) {
var logger = this.factory();
LogLevel level = ToLogLevel(entry.Severity);
logger.Log(level, 0, entry.Message, entry.Exception,
(msg, ex) => ex != null ? ex.Message : msg.ToString());
}
private static LogLevel ToLogLevel(LoggingEventType severity) { ... }
}
This adapter can be registered in your application container as follows:
container.RegisterSingleton<MyApp.ILogger>(new MsLoggerAdapter(
app.ApplicationServices.GetRequiredService<Microsoft.Framework.Logging.ILogger>));
BIG WARNING: Do not make direct copies of the framework abstractions. That will almost never lead to good results. you should specify abstractions that are defined in terms of your application. This could even mean that an adapter becomes more complex and needs multiple framework components to fulfill its contract, but this results in cleaner and more maintainable application code.
But if applying SOLID is too much a hassle for you, and you just want to depend directly on external components, you can always cross-wire the required dependencies in your application container as follows:
container.Register<Microsoft.Framework.Logging.ILogger>(
app.ApplicationServices.GetRequiredService<Microsoft.Framework.Logging.ILogger>);
It is as easy as this, but do note that in order to keep your application clean and maintainable, it's much better to define application specific abstractions that adhere to the SOLID principles. Also note that, even if you do this, you only need a few of those cross-wired dependencies anyway. So it's best to still keep your application container as separated as possible from the vNext configuration system.
With the middleware, there is a completely different issue at play here. In your middleware you are injecting runtime data (the next delegate) into a component (the CustomMiddleware class). This is giving you double grief, because this complicates registration and resolving the component and prevents it to be verified and diagnosed by the container. Instead, you should move the next delegate out of the constructor and into the Invoke delegate as follows:
public class CustomMiddleware
{
private IPersonService _personService;
public CustomMiddleware(IPersonService personService) {
_personService = personService;
}
public async Task Invoke(HttpContext context, RequestDelegate next) { /* ... */ }
}
Now you can hook your middleware into the pipeline as follows:
app.Use(async (context, next) =>
{
await container.GetInstance<CustomMiddleware>().Invoke(context, next);
});
But don't forget that you can always create your middleware by hand as follows:
var frameworkServices = app.ApplicationServices;
app.Use(async (context, next) =>
{
var mw = new CustomMiddleware(
container.GetInstance<IPersonService>(),
container.GetInstance<IApplicationSomething>(),
frameworkServices.GetRequiredService<ILogger>(),
frameworkServices.GetRequiredService<AspNetSomething>());
await mw.Invoke(context, next);
});
It's really unfortunate that ASP.NET calls its own services ApplicationServices, because that's where your own application container is for; not the built-in configuration system.
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.