在 WebAPI 中处理对象
Disposing Objects in WebAPI
我将维护一个现有的 API 实现。当我查看代码时,我发现对象处理存在一些问题。
以下是我的 Base Controller,它充当所有人的父控制器。
[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
}
存储库接口和Class:
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
}
}
基于此我有以下澄清
- 我认为我们应该在 BaseV1Controller 的 dispose 方法中包含 _db.Dispose()。目前我无法实现 DI 模式。请建议?
- 存储库中的 IDisposable 未实现。这个对吗?
- 还有其他改进吗?
是的,您应该在基本控制器的 Dipose 方法中处理您的 DbContext。否则,没有人知道它需要处理。它最终可能会在请求完成后的某个时间完成,但在此之前,底层数据库连接将保持打开状态且不可用,这意味着您将更快地耗尽连接池。
为确保发生这种情况,您可能不想让 _db 属性(它可能应该重命名为 Db,或者更好的 DataContext 作为 .Net 中的 属性 名称t 通常以 _) 开头,具有受保护的 setter;子 class 可以更改 属性 的值,并且那里的原始上下文将丢失而不会被释放。
关于存储库,如果 class 有一个 IDisposable 字段,您也应该在 class 中实现 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
我将维护一个现有的 API 实现。当我查看代码时,我发现对象处理存在一些问题。
以下是我的 Base Controller,它充当所有人的父控制器。
[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
}
存储库接口和Class:
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
}
}
基于此我有以下澄清
- 我认为我们应该在 BaseV1Controller 的 dispose 方法中包含 _db.Dispose()。目前我无法实现 DI 模式。请建议?
- 存储库中的 IDisposable 未实现。这个对吗?
- 还有其他改进吗?
是的,您应该在基本控制器的 Dipose 方法中处理您的 DbContext。否则,没有人知道它需要处理。它最终可能会在请求完成后的某个时间完成,但在此之前,底层数据库连接将保持打开状态且不可用,这意味着您将更快地耗尽连接池。
为确保发生这种情况,您可能不想让 _db 属性(它可能应该重命名为 Db,或者更好的 DataContext 作为 .Net 中的 属性 名称t 通常以 _) 开头,具有受保护的 setter;子 class 可以更改 属性 的值,并且那里的原始上下文将丢失而不会被释放。
关于存储库,如果 class 有一个 IDisposable 字段,您也应该在 class 中实现 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