2013-02-13 56 views
5

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

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

回答

3

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

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

一个实现方式是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,反之亦然接受模型。因此,考虑到以下两个版本的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

我认为单独发展Web API和下划线DB模型(或EF模型)是一种很好的做法。这意味着Web API的DTO模型被映射到Web API中的EF模型。这种间接方式会让您有机会进行更改,这可能只会影响Web API或EF模型。另外,Web API中的新版本可能不会直接影响现有的EF模型。例如,使用完全不同的一组表的Web API的新版本。

Regards, Pablo。