Asp.net web api WebAPI:EFMVC+;MEF在每个web调用上提供相同的单例数据库上下文

Asp.net web api WebAPI:EFMVC+;MEF在每个web调用上提供相同的单例数据库上下文,asp.net-web-api,entity-framework-5,Asp.net Web Api,Entity Framework 5,我正在努力掌握WebAPI。我一直在关注codplex上的EFMVC项目:根据本博客,我选择使用MEF作为依赖项解析程序,但测试表明DBContext正在跨多个web请求重用。我曾经假设依赖解析程序会在每个web请求上为我提供一个新的容器,但似乎这并没有发生 我真的不知道如何进步。以下是我到目前为止的情况: MefConfig: public static class MefConfig { public static void RegisterMef() {

我正在努力掌握WebAPI。我一直在关注codplex上的EFMVC项目:根据本博客,我选择使用MEF作为依赖项解析程序,但测试表明DBContext正在跨多个web请求重用。我曾经假设依赖解析程序会在每个web请求上为我提供一个新的容器,但似乎这并没有发生

我真的不知道如何进步。以下是我到目前为止的情况:

MefConfig:

    public static class MefConfig
{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();

        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));

        var dependencyResolver = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver;
        System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new MefDependencyResolver(container);
    }

    private static CompositionContainer ConfigureContainer()
    {
        var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(assemblyCatalog);

        return container;
    }
}

public class MefDependencyResolver : IDependencyResolver
{
    private readonly CompositionContainer _container;

    public MefDependencyResolver(CompositionContainer container)
    {
        _container = container;
    }

    public IDependencyScope BeginScope()
    {
        return this;
    }

    public object GetService(Type serviceType)
    {
        var export = _container.GetExports(serviceType, null, null).SingleOrDefault();

        return null != export ? export.Value : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var exports = _container.GetExports(serviceType, null, null);
        var createdObjects = new List<object>();

        if (exports.Any())
        {
            foreach (var export in exports)
            {
                createdObjects.Add(export.Value);
            }
        }

        return createdObjects;
    }

    public void Dispose()
    {
        ;
    }
}

public class MefControllerFactory : DefaultControllerFactory
{
    private readonly CompositionContainer _compositionContainer;

    public MefControllerFactory(CompositionContainer compositionContainer)
    {
        _compositionContainer = compositionContainer;
    }

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        var export = _compositionContainer.GetExports(controllerType, null, null).SingleOrDefault();

        IController result;

        if (null != export)
        {
            result = export.Value as IController;
        }
        else
        {
            result = base.GetControllerInstance(requestContext, controllerType);
            _compositionContainer.ComposeParts(result);
        }

        return result;
    }
}
在一篇web文章中,根据EFMVC项目,我制作了一个CreateItemCommand,通过在commandBus上调用Submit(CreateItemCommand),commandBus的Submit方法如下

    public void Submit<TCommand>(TCommand command) where TCommand : ICommand
    {
        var handler =    System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(ICommandHandler<TCommand>)) as ICommandHandler<TCommand>;
        if (!((handler != null) && handler is ICommandHandler<TCommand>))
        {
            throw new CommandHandlerNotFoundException(typeof(TCommand));
        }
        handler.Execute(command);
    }
存储库是这样实现的:

[Export(typeof(IUnitOfWork))]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]
public class UnitOfWork : IUnitOfWork
{
    private readonly IDatabaseFactory databaseFactory;
    private ApiContext dataContext;

    [ImportingConstructor]
    public UnitOfWork(IDatabaseFactory databaseFactory)
    {
        this.databaseFactory = databaseFactory;
    }

    protected ApiContext DataContext
    {
        get { return dataContext ?? (dataContext = databaseFactory.Get()); }
    }

    public void SaveChanges()
    {
        DataContext.SaveChanges();
    }
}
    public abstract class RepositoryBase<T> where T : class
{
    private ApiContext dataContext;
    private readonly IDbSet<T> dbset;
    protected RepositoryBase(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get;
        private set;
    }

    protected ApiContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    protected IDbSet<T> DbSet
    {
        get
        {
            return this.dbset;
        }
    }

    public virtual void Add(T entity)
    {
        dbset.Add(entity);
    }
    public virtual void Update(T entity)
    {
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }
    public virtual void Delete(T entity)
    {
        dbset.Remove(entity);
    }
    public virtual void Delete(Expression<Func<T, bool>> where)
    {
        IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
        foreach (T obj in objects)
            dbset.Remove(obj);
    }
    public virtual T GetById(Guid id)
    {
        return dbset.Find(id);
    }
    public virtual IQueryable<T> Get()
    {
        return dbset;
    }
}
公共抽象类RepositoryBase,其中T:class
{
私有ApiContext数据上下文;
专用只读IDbSet数据库集;
受保护的RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory=DatabaseFactory;
dbset=DataContext.Set();
}
受保护的IDatabaseFactory数据库工厂
{
得到;
私人设置;
}
受保护的ApiContext数据上下文
{
获取{return dataContext???(dataContext=DatabaseFactory.get());}
}
受保护IDbSet数据库集
{
得到
{
返回此.dbset;
}
}
公共虚拟空添加(T实体)
{
添加(实体);
}
公共虚拟无效更新(T实体)
{
附加数据集(实体);
dataContext.Entry(entity).State=EntityState.Modified;
}
公共虚拟作废删除(T实体)
{
删除(实体);
}
公共虚拟void Delete(表达式where)
{
IEnumerable objects=dbset.Where(Where).AsEnumerable();
foreach(对象中的对象)
dbset.Remove(obj);
}
公共虚拟T GetById(Guid id)
{
返回dbset.Find(id);
}
公共虚拟IQueryable Get()
{
返回dbset;
}
}
我想我理解为什么要实现DB工厂:它确保UnitOfWork和commandHandler获得相同的上下文,以便在命令处理程序中Execute方法可以工作

但是,由于似乎每个web请求都获得相同的MEF容器,因此每个web请求都获得相同的DB工厂,该工厂为单例上下文提供服务,从而迫使我在web调用之间共享上下文

是否有人可以指导我如何更改此设置,以确保每个web请求都在db上下文中获取?如果我选择MEF作为容器,EFMVC是否是一个糟糕的项目

[编辑] 进一步考虑这个问题,我担心如果相同的MEF容器在所有web请求中都出现,那么在100000个请求之后会发生什么,MEF容器现在是否会因为引用MEF为每个请求新创建的所有非共享控制器类而变得臃肿。据我所知,当我们在容器上调用dispose时,MEF将olny dispose它创建的对象


我显然误解了一些事情。对此的任何澄清都将不胜感激。

在您引用的文章中说

如果每个请求确实需要有限的作用域,“BeginScope” 方法始终需要返回IDependencyScope类型的新对象


是的,显然需要对依赖解析程序进行更多的研究。因此,与其返回“this”;我是否应该返回“new MefDependencyResolver(ConfigureContainer());”好的,我已经将此标记为答案,但我仍然不知道如何利用MEF并根据存储库模式和工作单元为每个请求保证一个新的DBContext,所以我选择使用依赖项解析器,如上所示,在每个ApiController中创建一个新的DBContext,这种方式并不完美,但它将保证每个请求都有一个新的上下文。由于DBCOntext似乎是工作单元的一个实现,我想通过将ORM耦合到控制器实例并不是真正的失败。
[Export(typeof(IUnitOfWork))]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]
public class UnitOfWork : IUnitOfWork
{
    private readonly IDatabaseFactory databaseFactory;
    private ApiContext dataContext;

    [ImportingConstructor]
    public UnitOfWork(IDatabaseFactory databaseFactory)
    {
        this.databaseFactory = databaseFactory;
    }

    protected ApiContext DataContext
    {
        get { return dataContext ?? (dataContext = databaseFactory.Get()); }
    }

    public void SaveChanges()
    {
        DataContext.SaveChanges();
    }
}
    public abstract class RepositoryBase<T> where T : class
{
    private ApiContext dataContext;
    private readonly IDbSet<T> dbset;
    protected RepositoryBase(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get;
        private set;
    }

    protected ApiContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    protected IDbSet<T> DbSet
    {
        get
        {
            return this.dbset;
        }
    }

    public virtual void Add(T entity)
    {
        dbset.Add(entity);
    }
    public virtual void Update(T entity)
    {
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }
    public virtual void Delete(T entity)
    {
        dbset.Remove(entity);
    }
    public virtual void Delete(Expression<Func<T, bool>> where)
    {
        IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
        foreach (T obj in objects)
            dbset.Remove(obj);
    }
    public virtual T GetById(Guid id)
    {
        return dbset.Find(id);
    }
    public virtual IQueryable<T> Get()
    {
        return dbset;
    }
}