如何调试nHibernate / RhinoMocks TypeInitializer异常

时间:2009-04-22 02:35:30

标签: nhibernate

拔掉我的头发试图调试这个。今天早上早些时候,这段代码工作正常,我看不出我改变了什么来打破它。现在,每当我尝试打开一个nHibernate会话时,我都会收到以下错误:

测试方法BCMS.Tests.Repositories.BlogBlogRepositoryTests.can_get_recent_blog_posts抛出异常:System.TypeInitializationException:'NHibernate.Cfg.Environment'的类型初始值设定项引发异常。 ---> System.Runtime.Serialization.SerializationException:未解析成员'Castle.DynamicProxy.Serialization.ProxyObjectReference,Rhino.Mocks,Version = 3.5.0.1337,Culture = neutral,PublicKeyToken = 0b3305902db7183f'..

有关如何调试此处发生的事情的想法吗?

5 个答案:

答案 0 :(得分:2)

我和你一样遇到了同样的问题 - 就我而言,这是用NLog的静态方法:

LogManager.GetCurrentClassLogger()

我用Rhinomocks存根替换了当前线程的主体:

var identity = MockRepository.GenerateStub<IIdentity>();
identity.Stub(x => x.IsAuthenticated).Return(true);
var principal = MockRepository.GenerateStub<IPrincipal>();
principal.Stub(x => x.Identity).Return(identity);
Thread.CurrentPrincipal = principal;

对我的代码运行单元测试引发了与原始问题相同的异常。

堆栈跟踪:

at System.AppDomain.get_Evidence()
at System.AppDomain.get_EvidenceNoDemand()
at System.AppDomain.get_Evidence()
at System.Configuration.ClientConfigPaths.GetEvidenceInfo(AppDomain appDomain, String exePath, String& typeName)
at System.Configuration.ClientConfigPaths.GetTypeAndHashSuffix(AppDomain appDomain, String exePath)
at System.Configuration.ClientConfigPaths..ctor(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigPaths.GetPaths(String exePath, Boolean includeUserConfig)
at System.Configuration.ClientConfigurationHost.RequireCompleteInit(IInternalConfigRecord record)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at NLog.Config.XmlLoggingConfiguration.get_AppConfig()
at NLog.LogFactory.get_Configuration()
at NLog.LogFactory.GetLogger(LoggerCacheKey cacheKey)
at NLog.LogFactory.GetLogger(String name)
at NLog.LogManager.GetCurrentClassLogger()
at MyClassHere...

因此,您可以从堆栈跟踪中看到尝试读取配置文件,这将无效 - 为什么?因为现在模拟的当前主体不再是我们原来的WindowsPrincipal - 它现在是一个模拟的主体,不会有任何类型的Windows文件访问。

在这里思考袖口有两种方法可以解决这个问题。

  1. 将记录器注入我的类,以便它可以被存根(我可能应该这样做,无论如何我想...)。这将允许我为Thread主体使用存根。
  2. 修改线程上的现有WindowsPrincipal(或基于它创建另一个)以添加调用我的方法所需的角色。
  3. - 更新 -

    为了解决我的问题,最后我决定按照上面的第一个建议运行。为了避免编写我自己的NLog Logger抽象,我只是利用了Common.Logging提供的东西。类构造函数现在接受ILog作为它们的参数之一,并且注入记录器的Unity配置看起来像这样:

    container.RegisterType<ILog>(new TransientLifetimeManager(), new InjectionFactory(x => LogManager.GetCurrentClassLogger()));
    

    与此同时,我的单元测试现在允许我传入一个模拟的记录器。

    var logger = MockRepository.GenerateStub<ILog>();
    

答案 1 :(得分:1)

更多信息......它似乎与将Thread.CurrentPrincipal切换为模拟的IPrincipal实现有关。我在实体内部的域模型中进行所有安全检查。实体的方法在修改实体的属性之前检查Thread.CurrentPrincipal.IsInRole()。

因此,为了测试实体的方法,我必须在进行实体方法调用之前设置不同的用户(贡献者用户,主持人用户等)。

我还没弄清楚为什么昨天工作正常。

以下是我的Mocked IPrincipal的一个例子:

        private static IPrincipal _blogContributorUser = null;
    public static IPrincipal BlogContributorUser
    {
        get
        {
            if (null == _blogContributorUser)
            {
                var identity = MockRepository.GenerateStub<IIdentity>(); 
                identity.Stub(p => p.Name).Return("BlogContributor").Repeat.Any(); 
                var principal = MockRepository.GenerateStub<IPrincipal>(); 
                principal.Stub(p => p.Identity).Return(identity).Repeat.Any();
                principal.Stub(p => p.IsInRole(UserRoles.BlogContributor)).Return(true).Repeat.Any();
                principal.Stub(p => p.IsInRole(UserRoles.CommentContributor)).Return(true).Repeat.Any();
                principal.Stub(p => p.IsInRole(UserRoles.TagContributor)).Return(true).Repeat.Any();
                _blogContributorUser = principal;
            }
            return _blogContributorUser;
        }
    }

答案 2 :(得分:1)

这样的错误通常表明版本问题。

我怀疑可能发生的是RhinoMocks和NHibernate都在使用Castle.DynamicProxy类型,但他们要求使用该类型的不同版本。

您最近是否将RhinoMocks或NHibernate升级为新版本?

如果这不是问题,那么更多信息会有所帮助 - 所有测试都失败了,还是仅仅是这个?

编辑您可能还想尝试将这些行添加到Properties \ AssemblyInfo.cs文件中:

[assembly: InternalsVisibleTo("Rhino.Mocks")] 
[assembly: InternalsVisibleTo("Castle.DynamicProxy")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

答案 3 :(得分:0)

我有同样的问题。看起来它在阅读配置文件时遇到了麻烦,因为CurrentPrincipal已经更改。在更换CurrentPrincipal(例如,打开NHibernate会话,初始化Unity和那种东西)之前,我已经将所有必须从配置文件初始化的内容移动了,之后一切正常。当然,这不是一个解决方案,只是一个绝望的人所解决的解决方法。

答案 4 :(得分:0)

如果错误与使用RhinoMocks或Moq模拟IPrincipal和/或IIdentity有关,解决方案实际上非常简单:不要使用这些框架,而是创建简单的假类型。

这是一个简单的例子&#34;允许一切&#34;实现:

public class FakeIdentity : IIdentity
{
    public string Name { get { return "IntegrationTest"; } }

    public string AuthenticationType { get { return "Kerberos"; } }

    public bool IsAuthenticated { get { return true; } }
}

public class FakePrincipal : IPrincipal
{
    public FakePrincipal() { this.Identity = new FakeIdentity(); }

    public IIdentity Identity { get; private set; }

    public bool IsInRole(string role) { return true; }
}

如果您需要更多复杂性,请查看System.Security.Principal.GenericPrincipal类。