1
votes

I have built a API service using ASP.NET Core. Just like any other API, this one has to retrieve some data from database, apply some business logic and then send data back to the client.

To start with, I have EmployeeDataContext class that is scaffolded using Entity Framework.Core. This class is derived from Microsoft.EntityFrameworkCore.DbContext as shown below.

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

}

This data context class is used in a data provider class as follows.

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();
        }
    }
}

The service layer holds a reference to data provider as follows.

public class EmployeeService : IEmployeeService
{
    private IEmployeeDataProvider dataProvider;

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

    // Add/Delete/Update Employee related calls
}

All the dependencies are injected in Startup class as follows.

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

According to Microsoft doc

The container will call Dispose for IDisposable types it creates.

This mean that EmployeeDataProvider.Dispose() method will be called by container at the end of request lifecycle.

The question I have is about how to implement IDisposable for EmployeeDataProvider class. The link provides best practices for implementing IDisposable for various scenarios which may require you to implement Disposable(bool) also. However, for this scenario, I am not sure if all that is needed and my current (simple) implementation of Dispose is good enough because (since there is no call via finalizer is involved here). Is my understanding and IDisposable look correct for this situation?

1
If your class is sealed you don't need the virtual Dispose(Boolean disposing) method. If it is sealed you only need a single non-virtual (or overridden if your class is a subclass) Dispose method without any parameters. - Dai

1 Answers

4
votes

Implementing IDisposable is trivial in the case where your class is sealed:

public sealed class Foo : IDisposable {

    private readonly FileStream stream;

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

    public void Dispose() {

        this.stream.Dispose();
    }
}

You only need the protected virtual void Dispose(Boolean disposing) method, and the recommended implementation of IDisposable if your class will be subclassed.

This is described in the documentation for FxCop rule CA1063 "Implement IDisposable correctly": https://msdn.microsoft.com/en-us/library/ms244737.aspx

  • Dispose() is not public, sealed, or named Dispose.
  • Dispose(bool) is not protected, virtual, or unsealed.
  • In unsealed types, Dispose() must call Dispose(true).
  • For unsealed types, the Finalize implementation does not call either or both Dispose(bool) or the case class finalizer.

[...]

How to Fix Violations

[...] Ensure that $className is declared as public and sealed.

Another tip: if your fields are only ever assigned in the type initializer or in the constructor - and should never be assigned a null value - then you should use the readonly modifier (or use read-only auto-properties - which have a readonly backing field) and that way you don't need to do a null-check in your Dispose method.

Note that Dispose() methods are generally idempotent:

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

To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.

Historically there were a few classes in .NET 1.x and 2.x that did throw ObjectDisposesException if they were Disposed twice, but I haven't personally observed non-idempotent behaviour since upgrading to .NET 4.x - though it's possible that some poorly-written third-party libraries and components might implement it incorrectly, however.