使用ASP.NET Web API和实体框架进行API版本控制

时间:2013-02-13 16:07:08

标签: entity-framework rest asp.net-web-api versioning

我正在使用ASP.NET Web API,Code-First Entity Framework 5和SQL Server 2012开发REST API,我需要能够对API进行版本控制。我已经阅读了一些博客文章和文章,关于在URI或自定义HTTP标头中指示API版本,并使用自定义IHttpControllerSelector根据指定的版本选择不同的ApiControllers。这一切都有道理。

我正在努力弄清楚如何管理Web API层以外的版本控制的影响,特别是在Entity Framework中。如何在不破坏旧版本API的情况下改进我的DbContext?我也可以对DbContext进行版本控制吗?如果是这样,怎么样?

2 个答案:

答案 0 :(得分:4)

我最终做的是将Repository Pattern与Pablo的答案结合起来。它的要点是我的EF模型是版本化的,我使用EF Code-First Migrations将数据库迁移到模型的新版本,我DbContext总是使用最新版本的模型,我开发了一个每个实现下面IRepository<TItem>接口的具体存储库的数量。

public interface IRepository<TItem> : IQueryable<TItem>, ICollection<TItem>, IDisposable
    where TItem : class
{
    void Update(TItem item);
    void SaveChanges();
}

IRepository<TItem>的一个实现是DbRepository<TItem>,它包含用于与数据库通信的实体框架代码。

public class DbRepository<TItem> : IRepository<TItem> 
    where TItem : class
{
    private MyDbContext _db;

    public DbRepository()
    {
        _db = new MyDbContext();
    }

    // Implementation of IRepository<TItem> methods
}

IRepository<TItem>的另一个实现是TypeConversionRepository<TExternal,TInternal>,它是一个抽象类,便于从一种模型类型转换为另一种模型类型。

public abstract class TypeConversionRepository<TExternal, TInternal> : IRepository<TExternal>
    where TExternal : class
    where TInternal : class
{
    protected IRepository<TInternal> InternalRepository { get; set; }

    protected abstract TInternal ConvertInbound(TExternal externalItem);

    protected abstract TExternal ConvertOutbound(TInternal internalItem);

    // Implementation of IRepository<TItem> methods
}

返回模型或接受模型作为参数的方法使用ConvertInbound()ConvertOutbound()TExternal类型的模型转换为TInternal,反之亦然。因此,给定以下2个MyModel版本,我们可以编写2个版本的MyModelRepository;版本2可以直接与数据库通信,而版本1需要从版本2转换回版本1.

namespace Models.v1
{
    public class MyModel
    {
        public int Id { get; set; }
        public string MyProperty { get; set; }
    }

    public class MyModelRepository : TypeConversionRepository<Models.v1.MyModel,Models.v2.MyModel>
    {
        MyModelRepository()
        {
            this.InternalRepository = new Models.v2.MyModelRepository();
        }

        protected override TInternal ConvertInbound(TExternal externalItem)
        {
            return new Models.v2.MyModel
            {
                Id = externalItem.Id,
                MyNewProperty = externalItem.MyProperty
            };
        }

        protected override TExternal ConvertOutbound(TInternal internalItem)
        {
            return new Models.v1.MyModel
            {
                Id = internalItem.Id,
                MyProperty = internalItem.MyNewProperty
            };
        }
    }
}

namespace Models.v2
{
    public class MyModel
    {
        public int Id { get; set; }
        public string MyNewProperty { get; set; }
    }

    public class MyModelRepository : DbRepository<MyModel>
    {

    }
}

现在v1 ApiController可以使用v1 MyModelRepository,v2 ApiController可以使用v2 MyModelRepository,但最后所有请求都使用已迁移到v2的数据库。

答案 1 :(得分:1)

我认为单独发展Web API和下划线数据库模型(或EF模型)是一种很好的做法。这意味着Web API的DTO模型,它映射到Web API中的EF模型。该间接层将使您有机会进行可能仅影响Web API或EF模型的更改。此外,Web API中的新版本可能不会直接影响现有的EF模型。例如,Web API的新版本使用完全不同的表集。

此致 巴勃罗。