将ISession注入自定义值解析器

时间:2015-05-06 15:44:37

标签: nhibernate asp.net-web-api dependency-injection automapper structuremap

我正在尝试将ISession的实例注入自定义 AutoMapper ValueResolver

这是解析器

public class ContactTypeResolver 
    : ValueResolver<Common.Models.ContactType, Models.ContactType>
{
    ISession _session;

    public ContactTypeResolver(ISession session)
    {
        _session = session;
    }

    protected override Models.ContactType ResolveCore(Common.Models.ContactType source)
    {
        return _session.Load<Models.ContactType>(source.Id);
    }
}

我有设置AutoMapper的个人资料

this.CreateMap<Models.PhoneNumber, Common.Models.PhoneNumber>()
    .ReverseMap()
    .ForMember(d => d.Type, o => o.ResolveUsing<ContactTypeResolver>());

我在一个StructureMap注册表中注册了解析器,如此

For<ValueResolver<Common.Models.ContactType, Models.ContactType>>()
   .Add<ContactTypeResolver>();

我正在使用session-per-request,我将会话设置在StructureMapDependencyScope.cs内的嵌套容器内,这是在我将StructureMap添加到Web Api项目时创建的。这是代码

public void CreateNestedContainer()
{
    if (CurrentNestedContainer != null)
    {
        return;
    }
    CurrentNestedContainer = Container.GetNestedContainer();
    CurrentNestedContainer.Configure(c => c.For<ISession>().Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession()));

}

这就是我的容器设置方式

var container = StructuremapMvc.StructureMapDependencyScope.Container;
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapWebApiDependencyResolver(container);

container.Configure(x =>
{
    x.IncludeRegistry<DefaultRegistry>();
});

Mapper.Initialize(cfg =>
{
    cfg.ConstructServicesUsing(container.GetInstance);

    foreach (var profile in container.GetAllInstances<Profile>())
        cfg.AddProfile(profile);
});

我甚至尝试使用像这样的服务定位器

this.CreateMap<Models.PhoneNumber, Common.Models.PhoneNumber>()
    .ReverseMap()
    .ForMember(d => d.Type, o => o
         .ResolveUsing<ContactTypeResolver>()
         .ConstructedBy(StructureMap.ObjectFactory.GetInstance<ContactTypeResolver>));

然而,当代码运行时,我得到一个运行时异常陈述

  

没有注册默认实例,无法自动确定类型'NHibernate.ISession'。

我也试过注入我的容器中注册的另一种类型,这也没用。我错过了什么?会话实例会注入其他对象。此外,在同一个配置文件中不需要依赖注入的其他映射也可以正常工作。

2 个答案:

答案 0 :(得分:2)

我相信@RadimKöhler是对的。

您的父容器(配置了AutoMapper类型)无法访问嵌套容器中定义的plugin types。它只是不知道ISession plugin type因此得到的例外。

我可以在这里想到几个解决方案。 免责声明我没有对它们进行过测试。

  1. ISession类型的注册移动到您的父容器。您也应该能够将其范围限定为HTTP请求。
  2. 例如,使用以下注册码。我对ASP.NET WebAPI一无所知,所以可能存在一些差异,但你明白了。

    public class NHibernateRegistry : Registry
    {
          public NHibernateRegistry()
          {
            For<Configuration>().Singleton().Use(c => new ConfigurationFactory().AssembleConfiguration());
            For<ISessionFactory>().Singleton().Use(c => c.GetInstance<Configuration>().BuildSessionFactory());
            For<ISession>().HybridHttpOrThreadLocalScoped().Use(c =>
            {
              var sessionFactory = c.GetInstance<ISessionFactory>();
              return sessionFactory.OpenSession();
            });
          }
        }
    
    1. Tell AutoMapper you want to use the nested container

答案 1 :(得分:1)

一般来说,我会说,问题是:

  

没有注册默认实例... ISession

我们应该通过在容器内注册ISession来解决:

x.For<ISession>()
 .Use...

有什么用?如何检索上下文ISession可能是我们自己的方式。可能有这样的代码:

x.For<ISession>()
 .Use(() => MySessionProvider.GetCurrentSession());

这足以让 StructureMap 将这种实例正确地注入我们的Web API服务中。

MySessionProvider.GetCurrentSession()后面可以调用静态内部API,它返回与HttpContext 相关的 ISession (在请求开始和结束时启动和处理)

或者我们可以遵循:

同时检查这部分文档/指南:

Retrieving a Service from IContext

和小节:

从IContext检索服务,表明我们可以这样做

  

您还可以在对象构造期间从IContext检索其他服务。因为底层BuildSession管理自动布线,所以通常可以假设您正在使用与同一对象图中的其他对象将接收的PluginType完全相同的对象实例。当您谈论在任何类型的桌面应用程序或任何类型的NHibernate对象中使用View时,这是一个有用的功能,其中所请求对象的状态或身份很重要。

     

我的团队在NHibernate引导中使用此功能。我们有一个名为ISessionSource的接口,它负责创建NHibernate ISession对象(它包装了一个Session)。

public interface ISessionSource
{
    ISession CreateSession();
}
  

我们不能直接走路并直接创建一个ISession对象。相反,您必须使用ISessionSource为您创建ISession。我们仍然希望StructureMap将ISession对象注入到其他类中,因此我们使用Lambda中的IContext.GetService<ISession>()方法来构建ISession对象:

ForRequestedType<ISession>().TheDefault.Is.ConstructedBy(
    context => context.GetInstance<ISessionSource>().CreateSession());
相关问题