保证容器调用Dispose方法时的IDisposable实现

时间:2017-05-26 20:30:31

标签: dependency-injection asp.net-core .net-core idisposable asp.net-core-webapi

我使用ASP.NET Core构建了一个API服务。就像任何其他API一样,这个API必须从数据库中检索一些数据,应用一些业务逻辑,然后将数据发送回客户端。

首先,我有使用Entity Framework.Core搭建的EmployeeDataContext类。此类派生自Microsoft.EntityFrameworkCore.DbContext,如下所示。

public partial class EmployeeDataContext : DataContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ......
    }

}

此数据上下文类在数据提供程序类中使用如下。

public class EmployeeDataProvider : IEmployeeDataProvider, IDisposable
{
    private EmployeeDataContext dataContext;

    public EmployeeDataProvider(EmployeeDataContext context)
    {
        this.dataContext = context;
    }

    // Various CRUD methods


    // Dispose
    public void Dispose()
    {
        if ( this.dataContext != null )
        {
            this.dataContext.Dispose();
        }
    }
}

服务层保存对数据提供者的引用,如下所示。

public class EmployeeService : IEmployeeService
{
    private IEmployeeDataProvider dataProvider;

    public EmployeeService(IEmployeeDataProvider dataProvider)
    {
        DataProvider = dataProvider;
    }

    // Add/Delete/Update Employee related calls
}

所有依赖项都在Startup类中注入,如下所示。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IEmployeeDataProvider, EmployeeDataProvider>();
        services.AddScoped<IEmployeeService, EmployeeService>();
    }
}

根据微软doc

  

容器将为它创建的IDisposable类型调用Dispose。

这意味着EmployeeDataProvider.Dispose()方法将在请求生命周期结束时由容器调用。

我的问题是如何为EmployeeDataProvider类实现IDisposable。 link提供了针对各种场景实现IDisposable的最佳实践,这些场景可能还需要您实现Disposable(bool)。但是,对于这种情况,我不确定是否 所有需要的东西和我目前(简单)的Dispose实现是足够好的,因为(因为这里没有涉及通过终结器调用)。我的理解和IDisposable看起来对这种情况是否正确?

1 个答案:

答案 0 :(得分:4)

在您的班级为IDisposable的情况下,实施sealed是微不足道的:

public sealed class Foo : IDisposable {

    private readonly FileStream stream;

    public Foo() {
        this.stream = new FileStream( ... );
    }

    public void Dispose() {

        this.stream.Dispose();
    }
}

如果您的类将被子类化,则只需要protected virtual void Dispose(Boolean disposing)方法和IDisposable的推荐实现。

这在FxCop规则CA1063&#34;正确实施IDisposable&#34;:https://msdn.microsoft.com/en-us/library/ms244737.aspx

的文档中有所描述
  
      
  • Dispose()不公开,密封或命名为Dispose。
  •   
  • Dispose(bool)不受保护,虚拟或未密封。
  •   
  • 在未密封的类型中,Dispose()必须调用Dispose(true)。
  •   
  • 对于未密封的类型,Finalize实现不会调用Dispose(bool)或case case finalizer中的任何一个或两者。
  •   
     

[...]

     

如何修复违规行为

     

[...]   确保将$className声明为公开并密封。

另一个提示:如果您的字段仅在类型初始值设定项或构造函数中分配 - 并且永远不应分配空值 - 那么您应该使用readonly修饰符(或使用只读自动 - 属性 - 具有readonly支持字段)以及您不需要执行null的方式 - 检查Dispose方法。

请注意,Dispose()方法通常是幂等的:

https://msdn.microsoft.com/en-us/library/fs2xkftw.aspx

  

为了确保始终适当地清理资源,Dispose方法应该可以多次调用,而不会抛出异常。

从历史上看,.NET 1.x和2.x中有一些类如果它们被Disposed两次就会抛出ObjectDisposesException,但我个人观察到自升级到非幂等行为。 NET 4.x - 但是,一些写得不好的第三方库和组件可能会错误地实现它。