c# - Ninject WCF 自托管注入(inject)

标签 c# wcf ninject

我已经构建了一个自托管的 WCF 服务,该服务使用一个工作单元以及其中的所有存储库。存储库使用代码优先 EF 连接到数据库。我正在使用 Ninject.Extensions.Wcf.SelfHost 包来启动服务并使注入(inject)工作。

一切正常,直到我想向数据库提交一些东西。我可以从数据库中读取记录,但是写入不起作用。在挖掘和调试之后,我发现我的数据库上下文没有在工作单元和存储库之间共享。因此,当我在我的工作单元中提交时,上下文没有要提交的更改。

有什么建议吗?

这里是代码:

服务的启动代码

    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

最佳答案

所以经过更多的调试和测试后,我设法自己解决了这个问题。这是我所做的和我发现的:

我开始查看 ninject 范围并尝试了所有可用选项,但没有一个有效。下一步是跳过 binderClasses 并手动链接我所有的接口(interface)和实现。起初这也是行不通的,所以我又开始玩示波器设置。

我在 RequestScope 中使用手动绑定(bind)完成了整个工作。当然手动绑定(bind)不是我想要的。

经过更多测试后,我有了这个

    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 中绑定(bind)上下文会为它需要的每个实例创建一个单独的上下文。所以如果有人可以澄清。

我将此标记为已解决,因为上面的代码对我有用。

关于c# - Ninject WCF 自托管注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36789144/

相关文章:

c# - WCF 公共(public) Web 服务的安全性

c# - 在桌面应用程序中管理 session 的 Ninject 范围

asp.net-mvc-3 - 使用 Ninject 将参数传递给 Controller ​​构造函数

c# - 在 Xamarin Forms 中获取缓存图像源的原始高度和宽度

c# - 如何绑定(bind)到 WPF 应用程序中的 subview 模型属性?

c# - MongoDB 在 InsertOne 上抛出 "MongoDB.Bson.BsonSerializationException"

c# - 连接到 WCF RESTful 服务时创建 Ssl 服务器凭据时发生 fatal error

wcf - 你见过哪些学习 WCF 的最佳资源? (书籍、网站等)

c# - 用于 .NET 的强大 SMPP 库

asp.net-mvc - Multi-Tenancy 应用程序示例(MVC + Ninject)