我已经构建了一个自托管的WCF服务,该服务使用了我的所有存储库中的一个单元。存储库首先使用代码EF连接到数据库。我正在使用Ninject.Extensions.Wcf.SelfHost包来启动服务并使注入工作。
一切正常,直到我想向数据库提交内容。我可以从数据库中读取记录,但写入不起作用。在挖掘和调试之后,我发现我的数据库上下文不在工作单元和存储库之间共享。因此,当我在我的工作单元中提交时,上下文没有提交更改。
任何建议?
这里是代码:
服务的启动代码
private static void StartNinjectSelfHosted(string address)
{
var service =
NinjectWcfConfiguration.Create<SecurityService, NinjectServiceSelfHostFactory>(
serviceHost =>
serviceHost.AddServiceEndpoint(typeof(ISecurityService), new BasicHttpBinding(), address));
selfHosted = new NinjectSelfHostBootstrapper(CreateKernel, service);
selfHosted.Start();
serviceAddress = address;
}
private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
ConfigurationAction scope = bind => bind.InRequestScope();
kernel.Load((new NinjectModule[]
{
new ContextBinder(scope),
new ServiceBinder(scope) ,
new UnitOfWorkBinder(scope),
new RepositoryBinder(scope),
}));
return kernel;
}
粘合剂
public class ContextBinder : NinjectModule
{
private readonly ConfigurationAction _bindInScope;
public ContextBinder(ConfigurationAction bindInScope)
{
_bindInScope = bindInScope;
}
public override void Load()
{
Kernel.Bind(typeof(SecurityContext)).ToSelf().InSingletonScope();
}
}
public class ServiceBinder : NinjectModule
{
private readonly ConfigurationAction _configurationAction;
public ServiceBinder(ConfigurationAction configurationAction)
{
_configurationAction = configurationAction;
}
public override void Load()
{
Kernel.Bind(
x => x.FromAssembliesMatching("WcfInterfaces*")
.SelectAllInterfaces()
.Join.FromAssembliesMatching("*Facade*")
.SelectAllClasses()
.BindDefaultInterface()
.Configure(_configurationAction));
}
}
public class UnitOfWorkBinder : NinjectModule
{
private readonly ConfigurationAction _configurationAction;
public UnitOfWorkBinder(ConfigurationAction configurationAction)
{
_configurationAction = configurationAction;
}
public override void Load()
{
Kernel.Bind(x => x
/** Select all unit of work interfaces */
.FromAssembliesMatching("SecurityDomain*")
.SelectAllUnitOfWorkInterfaces()
/** Select all unit of work implementations */
.Join.FromAssembliesMatching("SecurityImplementation*")
.SelectAllUnitOfWorkImplementations()
/** Bind interfaces to implementations */
.BindDefaultInterface()
/** Configure the scope */
.Configure(_configurationAction));
}
}
public class RepositoryBinder : NinjectModule
{
private readonly ConfigurationAction _configurationAction;
public RepositoryBinder(ConfigurationAction configurationAction)
{
_configurationAction = configurationAction;
}
public override void Load()
{
Kernel.Bind(x => x
/** Select all default repository interfaces */
.FromAssembliesMatching("SecurityDomain*")
.SelectAllRepositoryInterfaces()
/** Select all repository implementations */
.Join.FromAssembliesMatching("SecurityImplementation*")
.SelectAllRepositoryImplementations()
/** Bind interfaces to implementations */
.BindDefaultInterface()
/** Configure the scope */
.Configure(_configurationAction));
}
}
工作单元
public class UnitOfWork : IUnitOfWork
{
private readonly SecurityContext _context;
public UnitOfWork(SecurityContext context, ISecurityUnitOfWork security)
{
Console.WriteLine("*** Unit Of Work ContextHash: {0}***", context.Hash);
_context = context;
Security = security;
}
public void Commit(int userId)
{
Console.WriteLine("Context hash {0}", _context.Hash);
using (var transaction = _context.Database.BeginTransaction())
{
try
{
DateTime now = DateTime.Now;
foreach (var entry in _context.ChangeTracker.Entries<Entity>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreationDate = now;
entry.Entity.CreationUserId = userId;
break;
case EntityState.Modified:
entry.Entity.ModificationDate = now;
entry.Entity.ModificationUserId = userId;
break;
case EntityState.Deleted:
entry.State = EntityState.Modified;
entry.Entity.Deleted = true;
break;
}
}
_context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
}
}
public ISecurityUnitOfWork Security { get; private set; }
}
安全工作单位
public class SecurityUnitOfWork : ISecurityUnitOfWork
{
public SecurityUnitOfWork(IAccountRepository accounts, IRoleRepository roles, IRightRepository rights, IUserRepository users, IApplicationRepository applications)
{
Applications = applications;
Users = users;
Rights = rights;
Roles = roles;
Accounts = accounts;
}
public IAccountRepository Accounts { get; private set; }
public IRoleRepository Roles { get; private set; }
public IRightRepository Rights { get; private set; }
public IUserRepository Users { get; private set; }
public IApplicationRepository Applications { get; private set; }
}
存储库
public class AccountRepository : GenericRepository<SecurityContext, Account>, IAccountRepository
{
public AccountRepository(SecurityContext context)
: base(context)
{
}
}
public class GenericRepository<TContext, TEntity> : IGenericRepository<TEntity>
where TContext : DbContext
where TEntity : class, IDeletable, IIdentifiable
{
private readonly TContext _context;
private readonly DbSet<TEntity> _entitySet;
private IQueryable<TEntity> _entities;
public GenericRepository(TContext context)
{
_context = context;
_entitySet = context.Set<TEntity>();
_entities = _entitySet;
}
/// <summary>
/// Gets the DbContext
/// </summary>
protected virtual TContext Context
{
get { return _context; }
}
/// <summary>
/// Gets the entities
/// </summary>
protected virtual IQueryable<TEntity> Entities
{
get { return _entities; }
set { _entities = value; }
}
/// <summary>
/// Gets the editable dbset
/// </summary>
public virtual IDbSet<TEntity> EntitySet
{
get { return _entitySet; }
}
/// <summary>
/// Gets the entities
/// </summary>
protected virtual IQueryable<TEntity> Process(IEntityFilter<TEntity> filter = null, IEntitySorter<TEntity> sorter = null, IEntityIncluder<TEntity> includer = null)
{
var entities = _entities.Where(x => !x.Deleted);
if (includer != null)
entities = includer.AddInclusions(entities);
if (filter != null)
entities = filter.Filter(entities);
if (sorter != null)
entities = sorter.Sort(entities);
return entities;
}
public virtual IQueryable<TEntity> List(IEntitySorter<TEntity> sorter = null, IEntityFilter<TEntity> filter = null, int? page = null, int? pageSize = null, IEntityIncluder<TEntity> includer = null)
{
if ((page.HasValue || pageSize.HasValue) && sorter == null)
{
throw new ArgumentException("You have to define a sorting order if you specify a page or pageSize! (IEntitySorter was null)");
}
if (page.HasValue && !pageSize.HasValue)
{
throw new ArgumentException("You have to define a pageSize if you specify a page!");
}
var entities = Process(filter, sorter, includer);
if (page != null)
entities = entities.Skip(pageSize.Value * page.Value);
if (pageSize != null)
entities = entities.Take(pageSize.Value);
return entities;
}
public virtual int Count(IEntityFilter<TEntity> filter = null)
{
return Process(filter).Count();
}
public bool Any(IEntityFilter<TEntity> filter = null)
{
return Process(filter).Any();
}
public TEntity SingleOrDefault(IEntityFilter<TEntity> filter = null, IEntityIncluder<TEntity> includer = null)
{
return Process(filter, includer: includer).SingleOrDefault();
}
public TEntity Single(IEntityFilter<TEntity> filter = null, IEntityIncluder<TEntity> includer = null)
{
return Process(filter, includer: includer).Single();
}
public TEntity FirstOrDefault(IEntityFilter<TEntity> filter = null, IEntitySorter<TEntity> sorter = null, IEntityIncluder<TEntity> includer = null)
{
return Process(filter, sorter, includer).FirstOrDefault();
}
public TEntity First(IEntityFilter<TEntity> filter = null, IEntitySorter<TEntity> sorter = null, IEntityIncluder<TEntity> includer = null)
{
return Process(filter, sorter, includer).First();
}
public virtual TEntity Find(int id)
{
var entity = EntitySet.FirstOrDefault(x => x.Id == id);
if (entity != null && entity.Deleted)
{
return null;
}
return entity;
}
public virtual void AddOrUpdate(TEntity entity)
{
if (entity.Id == 0)
{
Add(entity);
}
else
{
Update(entity);
}
}
public virtual void Delete(TEntity entity)
{
entity.Deleted = true;
Update(entity);
}
public virtual void Delete(IEnumerable<TEntity> entities)
{
foreach (TEntity entity in entities)
{
Delete(entity);
}
}
public virtual void Delete(int id)
{
TEntity entity = Find(id);
if (entity != null)
Delete(entity);
}
public virtual void HardDelete(TEntity entity)
{
DbEntityEntry entry = Context.Entry(entity);
if (entry.State != EntityState.Deleted)
{
entry.State = EntityState.Deleted;
}
else
{
EntitySet.Attach(entity);
}
}
public virtual void HardDelete(int id)
{
TEntity entity = Find(id);
if (entity != null)
HardDelete(entity);
}
public TResult Query<TResult>(Func<IQueryable<TEntity>, TResult> query)
{
return query(Entities);
}
/// <summary>
/// Gets the queryable entities
/// </summary>
public IQueryable<TEntity> QueryableEntities
{
get
{
return _entitySet;
}
}
protected virtual void Add(TEntity entity)
{
DbEntityEntry entry = Context.Entry(entity);
if (entry.State != EntityState.Detached)
{
entry.State = EntityState.Added;
}
else
{
EntitySet.Add(entity);
}
}
protected virtual void Update(TEntity entity)
{
DbEntityEntry entry = Context.Entry(entity);
if (entry.State == EntityState.Detached)
{
EntitySet.Attach(entity);
}
entry.State = EntityState.Modified;
}
}
当我启动服务时,这是输出
Starting service
**** CONTEXT CONSTRUCTED, HASH:63174400 ****
**** CONTEXT CONSTRUCTED, HASH:24275713 ****
**** CONTEXT CONSTRUCTED, HASH:34631232 ****
**** CONTEXT CONSTRUCTED, HASH:66590816 ****
**** CONTEXT CONSTRUCTED, HASH:24695352 ****
**** CONTEXT CONSTRUCTED, HASH:11985038 ****
*** Unit Of Work ContextHash: 63174400***
--------------------------------
Security service is running @ http://localhost/security
答案 0 :(得分:0)
所以经过一些调试和测试后,我自己设法解决了这个问题。这是我做的和我发现的:
我开始查看ninject范围并尝试了所有可用的选项,但都没有。下一步是跳过binderClasses并手动链接我的所有接口和实现。起初这也没有,所以我再次开始使用示波器设置。
我完全使用了RequestScope中的手动绑定。当然手动绑定不是我想要的。
经过一些更多的测试后,我有了这个 private static StandardKernel CreateKernel()
{
var kernel = new StandardKernel();
ConfigurationAction scope = bind => bind.InRequestScope();
/* this works*/
scope(
kernel.Bind(typeof(SecurityContext))
.ToSelf());
/*
* This works
*
* kernel.Bind(typeof(SecurityContext))
.ToSelf()
.InRequestScope();*/
/*
* This does not work
kernel.Load(new ContextBinder(scope));
*/
kernel.Load(new UnitOfWorkBinder(scope));
kernel.Load(new RepositoryBinder(scope));
kernel.Load(new ServiceBinder(scope));
return kernel;
}
我不知道为什么在contextbinder中绑定上下文为它需要的每个实例创建一个单独的上下文。所以,如果有人可以澄清。
我将此标记为已解决,因为上面的代码对我有效。