7

Our web application is built on the .NET Framework 4.6+. We're using WebForms, MVC 5.2, and Web API 2.

I'm in the process of trying to integrate Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Http into this solution so we can take advantage of the new HttpClientFactory that's in ASP.NET Core. We also want to start using DI in our MVC and API controllers.

It appears there are two ways this can be achieved:

  • Write a custom ControllerActivator
  • Write a custom DependencyResolver

Based on the reading I've done, it appears the ControllerActivator method is the old way of doing this, and the DependencyResolver is the current, preferred way of handling this. I've written code for both, and both methods appear to work.

Considering the DependencyResolver appears to be the preferred solution for DI now, I'd like to use it but I'm not sure if I'm handling scope object disposal correctly.

Here's how I'm configuring the DependencyResolvers in Global.asax:

Web.Mvc.DependencyResolver.SetResolver(New Mvc.DependencyInjection.DependencyResolver(serviceProvider))
GlobalConfiguration.Configuration.DependencyResolver = New Api.DependencyInjection.DependencyResolver(serviceProvider)

My System.Web.Http.Dependencies.IDependencyResolver implementation for Web API is:

public class DependencyResolver : IDependencyResolver
{
    private IServiceProvider ServiceProvider { get; }

    public DependencyResolver(IServiceProvider serviceProvider) => ServiceProvider = serviceProvider;

    public IDependencyScope BeginScope() => new DependencyResolver(ServiceProvider.CreateScope().ServiceProvider);

    public void Dispose() => (ServiceProvider as IDisposable)?.Dispose();

    public object GetService(Type serviceType) => ServiceProvider.GetService(serviceType);

    public IEnumerable<object> GetServices(Type serviceType) => ServiceProvider.GetServices(serviceType);
}

My System.Web.Mvc.IDependencyResolver implementation for MVC is:

public class DependencyResolver : IDependencyResolver
{
    private IServiceProvider ServiceProvider { get; }

    public DependencyResolver(IServiceProvider serviceProvider) => ServiceProvider = serviceProvider;

    public object GetService(Type serviceType) => ServiceProvider.GetService(serviceType);

    public IEnumerable<object> GetServices(Type serviceType) => ServiceProvider.GetServices(serviceType);
}

The System.Web.Http.Dependencies.IDependencyResolver interface has Dispose(), and it appears API requests do call my implementation's Dispose method. So that appears to be working (I think).

My concern is the System.Web.Mvc.IDependencyResolver interface doesn't have Dispose(), I'm not clear if these service objects are being properly disposed after a MVC request.

If anyone can provide some insight into this I'd really appreciate it. Don't want to roll this out and find out we're leaking memory.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Jason
  • 111
  • 3
  • See [https://blog.rsuter.com/how-to-implement-and-register-a-custom-dependency-resolver-in-asp-net-mvc/](https://blog.rsuter.com/how-to-implement-and-register-a-custom-dependency-resolver-in-asp-net-mvc/). There's isn't a Dispose method to be had anywhere. – Robert Harvey Jun 20 '19 at 22:09
  • Right. I'm trying to understand why the Web API IDependencyResolver has one, but the MVC IDependencyResolver does not. And will the lack of a Dispose method cause a problem with our MVC controllers? How are the scoped objects cleaned up? Just via normal garbage collection? And if so, is that okay? – Jason Jun 20 '19 at 22:19
  • I'm guessing that the Web API resolver is designed in such a way that it doesn't need one. Remember, `Dispose()` was originally intended to be used to clean up unmanaged resources, before it began being abused for things like [closing html tags](https://stackoverflow.com/questions/29628384/is-abusing-idisposable-to-benefit-from-using-statements-considered-harmful). Dispose is not needed for ordinary garbage collection. The rule is that, if the contract includes Dispose, you should follow the disposable pattern. If the contract doesn't have it, then you don't need it. – Robert Harvey Jun 20 '19 at 22:23
  • In other words, if `IDisposable` is not implemented, then there's nothing to dispose. – Robert Harvey Jun 20 '19 at 22:26
  • In any case, the source for `DependencyResolver` is [here](https://github.com/aspnet/AspNetWebStack/blob/749384689e027a2fcd29eb79a9137b94cea611a8/src/System.Web.Mvc/DependencyResolver.cs), if you're so inclined. – Robert Harvey Jun 20 '19 at 22:30
  • Hi Jason. For HttpClientFactory, you can take a look at [my fork](https://github.com/uhaciogullari/HttpClientFactoryLite). It has no dependencies and targets netstandard2.0. – Ufuk Hacıoğulları Jun 21 '19 at 08:16
  • 1
    Thanks @UfukHacıoğulları - I'll check that out. – Jason Jun 21 '19 at 12:06
  • I have a Problem To Config My DependencyResolver For Api And I Am 4 Hours Search For a Solution. I Wanna Tell you Your Config Save Me Tnx Dude – Mrbanad Jul 10 '23 at 07:46

1 Answers1

0

After a lot of research and discussion, we're leaning towards a hybrid solution for this problem.

For API controllers, since System.Web.Http.Dependencies.IDependencyResolver provides a way to dispose of the service container/provider (and the objects it creates), we're going to use the Dependency Resolver approach laid out above.

For MVC controllers, we're going with the Controller Activation approach laid out by Steven van Deursen here: ASP.NET Dependency Injection Scoped life time

I created a dummy service that implements IDisposable, and confirmed Dispose gets called using both DI approaches.

Jason
  • 111
  • 3