简体   繁体   English

Ninject WCF自托管注入

[英]Ninject WCF self hosted injection

I have build a self hosted WCF service which consumes a unit of work with all my repositories in it. 我建立了一个自托管的WCF服务,该服务消耗了包含我所有存储库的工作单元。 The repositories use code first EF to connect to the database. 存储库使用代码优先EF连接到数据库。 I am using the Ninject.Extensions.Wcf.SelfHost package to start the service and get the injection working. 我正在使用Ninject.Extensions.Wcf.SelfHost包来启动服务并使注入工作。

Everything works just fine until i want to commit something to the database. 一切正常,直到我想将某些东西提交到数据库。 I can read records from the database, but writing does not work. 我可以从数据库中读取记录,但是无法正常工作。 After digging and debugging i found that my db context is not shared between the unit of work and the repositories. 在进行挖掘和调试后,我发现工作单元和存储库之间没有共享我的数据库上下文。 So when i commit in my unit of work the context has no changes to commit. 因此,当我在工作单元中提交内容时,上下文没有要提交的更改。

any advice? 有什么建议吗?

And here the code: 这里的代码:

Startup code for the service 服务的启动代码

    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;
    }

Binders 粘合剂

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));
    }
}

Unit of work 工作单位

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; }
}

Security Unit of work 安全工作单位

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; }
}

Repositories

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;


    }
}

when i start the service this is the output 当我启动服务时,这是输出


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

So after some more debugging and testing i managed to solve this myself. 因此,经过更多的调试和测试后,我设法自己解决了这一问题。 here's a what i did and what i found: 这是我所做的和发现的事情:

I started looking at the ninject scope and tried all the available options, none of them worked. 我开始研究ninject范围,并尝试了所有可用选项,但没有一个起作用。 next step was skip the binderClasses and manually link all my Interfaces and implementations. 下一步是跳过粘结剂类,并手动链接我的所有接口和实现。 At first this was also no go, so i started playing with the scope setting again. 起初这也不可行,所以我再次开始使用示波器设置。

I got the whole thing working with the manual binding an in RequestScope. 我将整个工作与手动绑定在RequestScope中一起使用。 Of course manual binding was not what i wanted. 当然,手动绑定不是我想要的。

after some more testing i have this 经过一些测试我有这个

    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;
    }

I have no Idea why binding the context in the contextbinder create a separate context for every instance it needs. 我不知道为什么在contextbinder中绑定上下文会为它需要的每个实例创建一个单独的上下文。 So if anyone could clarify. 因此,如果有人可以澄清。

I marked this as resolved because the code above is working for me. 我将其标记为已解决,因为上面的代码对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM