【问题标题】:SimpleInjector can't inject string after updateSimpleInjector 更新后无法注入字符串
【发布时间】:2018-01-16 20:39:32
【问题描述】:

在将 SimpleInjector 从版本 2.8.3 更新到 v3.0.1 后,当我尝试将连接字符串传递给构造函数时,它会返回错误。这在过去运行良好,但在更新后出现问题。错误:

发生“System.ArgumentException”类型的第一次机会异常 在 SimpleInjector.dll 中

附加信息:MwmJobUpdateNotifier 类型的构造函数 包含不能是字符串类型的参数“connectionString” 用于构造函数注入。

这里是 SimpleInjector 容器的配置位置:

    public static Container Configure(Container container)
    {
        // Force assembly reference so Interfaces load correctly.
        if (typeof(IJobRepository) != null) 
            container.RegisterAllInterfacesForClassesInAssemblyContaining<JobRepository>();

        // Force assembly reference so Interfaces load correctly.
        if (typeof(IGmcService) != null)
            container.RegisterAllInterfacesForClassesInAssemblyContaining<GmcService>();

        container.Options.AllowOverridingRegistrations = true;
        container.Register<IMwmJobUpdateNotifier>(() => new MwmJobUpdateNotifier(container.GetInstance<IJobRepository>(),
            ConfigurationManager.ConnectionStrings["Coordinate_DatabaseEntities"].ConnectionString));
        container.Options.AllowOverridingRegistrations = false;

        MWM.Service.DAL.Config.AGI.AGIIocConfig.Configure(container);

        return container;
    }

看起来不喜欢我将两个参数传递给构造函数的方式。

已编辑:异常是在我注册了所有接口的ContainerException 类中触发的:

public static Container RegisterAllInterfacesForClassesInAssemblyContaining<T>(this Container container, Lifestyle lifestyle = null) where T : class
    {
        var assembly = typeof(T).Assembly;

        var registrations = assembly.GetExportedTypes()
            .Where(type => type.IsClass && 
                type.GetInterfaces()
                    .Except(type.GetInterfaces().SelectMany(x => x.GetInterfaces()))
                    .Except(type.BaseType.GetInterfaces())
                    .Any())
            .Select(type => new 
            { 
                Services = type.GetInterfaces()
                    .Except(type.GetInterfaces().SelectMany(x => x.GetInterfaces()))
                    .Except(type.BaseType.GetInterfaces()), 
                Implementation = type
            });

        foreach (var registration in registrations)
        {
            foreach (var service in registration.Services)
            {
                if (registration.Implementation.IsGenericTypeDefinition)
                {
                    if (lifestyle == null)
                    {
                        container.Register(service.GetGenericTypeDefinition(), registration.Implementation.GetGenericTypeDefinition());
                    }
                    else
                    {
                        container.Register(service.GetGenericTypeDefinition(), registration.Implementation.GetGenericTypeDefinition(), lifestyle);
                    }
                }
                else
                {
                    if (lifestyle == null)
                        container.Register(service, registration.Implementation);
                    else
                        container.Register(service, registration.Implementation, lifestyle);
                }
            }
        }

        return container;
    }

异常在倒数第二个container.Register(...)调用中被捕获。

【问题讨论】:

  • 你在哪一行得到这个异常?
  • v2 也不支持此功能。难道是因为某种原因MwmJobUpdateNotifier 是自动连接的,而它以前不是自动连接的?
  • 我在“conatiner.Register(service, registration.Implementation);”中得到了异常。如果我将 nuget 包降级到 v2.8.3,我就不会再遇到异常了。我在 v3 的重大更改中看到,这个 SI 版本更严格github.com/simpleinjector/SimpleInjector/releases
  • 有趣的是,在容器发现字符串构造函数参数之前,您不能再替换注册。我想一种解决方案是将要排除的类型列表传递给RegisterAllInterfacesForClassesInAssemblyContaining
  • 请您包含完整的堆栈跟踪信息吗?

标签: c# dependency-injection simple-injector


【解决方案1】:

我有同样的问题,但从我在这里阅读的内容来看:How do I pass a parameter to the constructor using Simple Injector?

看来您/我们必须更改设计,以便运行时值不依赖于构造函数。

在我的特定情况下,该对象是一个数据库服务,需要连接字符串参数,这些参数存储在一个配置文件中,由于发布管道中的环境不同,它们使其成为运行时值。

我的存储库项目无法直接访问配置文件(我想它可以,但我尝试起来感觉不对)所以我引入了一个临时值依赖关系解析器。这个对象只是一个字典的包装器,包含一些管理方法来添加、删除、更新、合并和检查所需的值,因此依赖它的每个对象都可以检查它是否提供了所需的项目。

public interface IResolver 
{
    void Add<T>(string key, T keyValue);
    T Resolve<T>(string key);
    bool ResolvesAll(params string[] keys);
}

public sealed class Resolver : IResolver
{
    private Dictionary<string, object> directory;

    public void Add<T>(string key, T keyValue)
    {
        if (directory.ContainsKey(key))
          directory[key] = keyValue;
        else
          directory.Add(key, keyValue);
    }

    public T Resolve<T>(string key) 
    {
        return directory.ContainsKey(key) ? directory[key] as T : default(T);
    }
    public bool ResolvesAll(params string[] keys)
    {
        return keys.All(k => directory.ContainsKey(k));
    }

}

然后容器只是注册解析器:

container.RegisterSingleton<IResolver, Resolver>(new Resolver());

依赖类接收自动连接的对象。

public class SomeClass : ISomeClass
{
    private readonly IResolver resolver;
    public SomeClass(IResolver resolver)
    {
        this.resolver = resolver;
    }

    public void SomeMethod(string whatever)
    {
        if (!resolver.ResolvesAll("fred", "barny", "wilma"))
           throw new Exception("missing dependencies");

        var fred = resolver.Resolve<string>("fred");
        SomeOtherMethod(fred, whatever);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 2020-09-06
    • 2014-07-27
    • 2021-05-14
    • 1970-01-01
    相关资源
    最近更新 更多