首页 > 解决方案 > 在 WebAPI 中处理对象

问题描述

我将维护一个现有的 API 实现。当我查看代码时,我发现对象处理存在一些问题。

以下是我的基本控制器,它充当所有人的父控制器。

[LoggingFilter]
[System.Web.Http.Authorize]
public abstract class BaseV1Controller : ApiController
{
    private ModelFactoryV1 _modelFactoryV1;
    private MyDBContext __db;
    private MyLoggingService _loggingService;
    private int _customerId;

    protected string __IPAddress;
    protected ILogger __logger;
    protected const int PAGE_SIZE_NORMAL = 20;
    protected const int PAGE_SIZE_MEDIA = 2;
    // GET: Base
    protected string __loggingResourceName = "Undefined - base controller";
    private void InitLogger()
    {
       Log.Logger.ForContext<BaseV1Controller>();
    }

    protected MyDBContext _db
    {
        get { return __db; }
        set { __db = value; }
    }

    public BaseV1Controller()
    {
        IEnumerable<string> values;
        __db = new MyDBContext();
        _loggingService = new MyLoggingService ();
        InitLogger();
    }

    public BaseV1Controller(MyDBContext db)
    {
        __db = db;
        _loggingService = new MyLoggingService ();
        InitLogger();
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        _loggingService = null;
    }

  }

我们没有覆盖控制器中的 dispose 方法。在控制器中,我们调用 Repository 类来执行 CRUD 操作。

下面的示例实现;

控制器:

   [LoggingFilter]
    [ValidateModel]
    [Authorize]
    public class CustomersV1Controller : BaseV1Controller
    {
        IAsyncRepository<Customer> _repo = new CustomerAsyncRepository();
        public CustomersV1Controller() : base()
        {
            _repo = new CustomerAsyncRepository();
        }

        public CustomersV1Controller(IAsyncRepository<Customer> repo, MyDBContext db) : base(db)
        {
            __loggingResourceName = "Customer";
            _repo = repo;
        }

       //All Actions implemented here

    }

存储库接口和类:

    public interface IAsyncRepository<T>
    {

        Task<T> Add(T type);
        Task<T> Get(int Id);
        Task Update(T type);
    }

public class CustomerAsyncRepository : IAsyncRepository<Customer>
    {
        //saves the customer view models
        private MyDBContext _db { get; }

        public CustomerAsyncRepository(MyDBContext db)
        {
            this._db = db;
        }

        public CustomerAsyncRepository()
        {
            _db = new MyDBContext ();
        }

        public async Task<Customer> Add(Customer model)
        {
            //Add method implmementation
            return model;
        }

        public async Task<Customer> Get(int id)
        {
           //Implementation to return customer model
        }

        public async Task Update(Customer model)
        {
           //Implementation to update customer model
        }

    }

基于此,我有以下澄清

  1. 我认为我们应该在 BaseV1Controller 的 dispose 方法中包含 _db.Dispose()。目前我无法实现 DI 模式。请建议?
  2. 在存储库中 IDisposable 未实现。这个对吗?
  3. 还有其他改进吗?

标签: c#asp.net-web-api2dbcontext

解决方案


是的,您应该在基本控制器的 Dipose 方法中处理您的 DbContext。否则,没有人知道它需要处理。它最终可能会在请求完成后的某个时间完成,但在此之前,底层数据库连接将保持打开且不可用,这意味着您将更快地耗尽连接池。

为了确保发生这种情况,您可能不希望您的 _db 属性(可能应该重命名为 Db,或者更好的 DataContext,因为 .Net 中的属性名称通常不以 _ 开头)具有受保护的设置器;子类可以更改属性的值,并且原始上下文将丢失而不会被处置。

关于存储库,规范是,如果该类有一个 IDisposable 字段,则您也应该在该类中实现 IDisposable。在这种情况下,我可能会做的是将您更改IAsyncRepository<T>为也需要实现 IDisposable 。然后,您的存储库实现应该处置 DbConext,而您的控制器将处置存储库实例。在这种情况下,最好不要让控制器保留对 DbContext 的任何引用,而是只公开 repo 实例。

您可以在此处阅读有关如何正确实施 IDisposable 的更多信息https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose?view=netframework-4.7.2


推荐阅读