0

我有两个接口说明服务必须是单例的还是瞬态的:

public interface ITransient {}
public interface ISingleton {}

我在其他接口和类中实现了这个接口:

public interface ISession : ISingleton
{
    int? UserId {get;set;}
}

public class Session : ISession
{
    public int? UserId {get;set;}
}

然后我在其他服务中注入 Session:

public interface IBookService : ITransient
{
    ...
}

public class BookService : IBookService
{
    public BookService(ISession session) { ... }
    ...
}

如何配置 StructureMap 以使实现 ISingleton 类型的所有实例请求都必须使用 Singleton 生命周期创建?

我试过了:

Container.Configure(conf => {
    conf.For<ITransient>().Transient();
    conf.For<ISingleton>().Singleton();
}

但是什么都没有......不工作,创建一个会话对象作为瞬态。

我也试过了:

        Container.Configure(conf =>
        {
            conf.Scan(s =>
            {
                s.Assembly(assembly);
                s.LookForRegistries();

                s.AddAllTypesOf<ISingletonDependency>();
                s.AddAllTypesOf<ITransientDependency>();
            });

            conf.For<ITransientDependency>().Transient();
            conf.For<ISingletonDependency>().Singleton();
        });

没事了 ...

我已经看到如何使用温莎城堡做到这一点:

        context.IocContainer.Register(
            Classes.FromAssembly(context.Assembly)
                .IncludeNonPublicTypes()
                .BasedOn<ITransient>()
                .WithService.Self()
                .WithService.DefaultInterfaces()
                .LifestyleTransient()
        );

        //Singleton
        context.IocContainer.Register(
            Classes.FromAssembly(context.Assembly)
                .IncludeNonPublicTypes()
                .BasedOn<ISingleton>()
                .WithService.Self()
                .WithService.DefaultInterfaces()
                .LifestyleSingleton()

但我不知道如何使用 StructureMap ...

其他可能性是使用约定(IRegistrationConvention),但我不知道该怎么做,例如:

    public class LifecycleConvention : IRegistrationConvention
    {
        public void Process(Type type, Registry registry)
        {
            if (type.GetInterface(typeOf(ISingleton) != null)
                **???? what to do ??!!**
        }
    }

有人可以帮助我吗?

更新

我已经建立了一个约定:

public class BasicConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (!type.IsAbstract && typeof(ISingleton).IsAssignableFrom(type))
        {
            registry.For(type, new SingletonLifecycle());
        }
        if (!type.IsAbstract && typeof(ITransient).IsAssignableFrom(type))
        {
            registry.For(type, new TransientLifecycle());
        }
    }
}

这似乎可行,但它将每个类注册为插件类型,在这种情况下:

会话 => 会话 [单例] BookService => BookService [瞬态]

但是,如果我将 Session 作为 ISession 注入...由于 ISession 未注册而找不到实例...但是我可以使用默认对流...然后工作但将实例检索为瞬态...

调用 WhatDoIHave() 我可以看到它:

===============================================================================================================================================================================================================================================================================
PluginType                  Namespace                          Lifecycle     Description                                                                                                                                               Name                                    
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
....
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession                     Paf.Application.Session            Transient     Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')                        Paf.Application.Session,... (Default)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
.....
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Session                     Paf.Application                    Singleton     Paf.Application.Session                                                                                                                                (Default)                               
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
...
===============================================================================================================================================================================================================================================================================

我能解决这个吗?

4

1 回答 1

0

好的,我已经到 StructureMap 来源查看如何处理默认争用。

我找到了 DefaultConventionScanner 类:

public class DefaultConventionScanner : ConfigurableRegistrationConvention
{
    public override void Process(Type type, Registry registry)
    {
        if (!type.IsConcrete()) return;

        var pluginType = FindPluginType(type);
        if (pluginType != null && type.HasConstructors())
        {
            registry.AddType(pluginType, type);
            ConfigureFamily(registry.For(pluginType));
        }
    }

    public virtual Type FindPluginType(Type concreteType)
    {
        var interfaceName = "I" + concreteType.Name;
        return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
    }
}

我可以推断我可以更改插件类型注册(registry.AddType(pluginType, type) 代码行)并编写它:

            if(typeof(ISingleton).IsAssignableFrom(type))
                registry.For(pluginType).Use(type).Singleton();
            else if (typeof(ITransient).IsAssignableFrom(type))
                registry.For(pluginType).Use(type).Transient();
            else
            {
                registry.AddType(pluginType, type);
            }
            ConfigureFamily(registry.For(pluginType));

因此,如果 pluginType(接口类型)是 ISingleton 或 ITransient,我将新插件类型注册为 Singleton 或 Transient,否则将 pluginType 注册为 allwais。

我已经尝试并知道工作!是的!

只有一个考虑,我不知道是否存在一些差异:

            registry.AddType(pluginType, type);

和:registry.For(pluginType).Use(type);

我比较了WhaDoIHave()之前和之后的结果,我只能看到一个差异。

旧结果:

===============================================================================================================================================================================================================================================================================
PluginType                  Namespace                          Lifecycle     Description                                                                                                                                               Name                                    
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession                    Paf.Application.Session            Transient     Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')                              Paf.Application.Session,... (Default)
===============================================================================================================================================================================================================================================================================

新结果:

===============================================================================================================================================================================================================================================================================
PluginType                  Namespace                          Lifecycle     Description                                                                                                                                               Name                                    
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession                    Paf.Application.Session            Singleton     Paf.Application.Session                                                                                                                                (Default)                               
===============================================================================================================================================================================================================================================================================

新结果是Ok,是Singleton,区别只在于描述,我觉得没什么重要的。

更新

根据在我的问题评论中与史蒂夫的对话,我决定不使用 ITransient 和 ISingleton 接口。我决定在实现类中使用属​​性。

我创建了 2 个属性:

[AttributeUsage(AttributeTargets.Class)]
public class SingletonLifecycleAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class)]
public class TransientLifecycleAttribute : Attribute
{
}

我已经将其分配给我的课程:

public interface ISession   {       int? UserId {get;set;}  }

[SingletonLifecycle]
public class Session : ISession {       public int? UserId {get;set;}   }   

public interface IBookService { ... }

[TransientLifecycle]
public class BookService : IBookService { public BookService(ISession session) { ... }  }

然后我修改了我的约定:

public class BasicConvention : ConfigurableRegistrationConvention
{
    public override void Process(Type type, Registry registry)
    {
        if (!type.IsConcrete()) return;

        var pluginType = FindPluginType(type);
        if (pluginType != null && type.HasConstructors())
        {
            var ci = registry.For(pluginType).Use(type);
            if (type.GetCustomAttributes(true).FirstOrDefault(a => a is TransientLifecycleAttribute) != null)
                ci.Transient();
            if (type.GetCustomAttributes(true).FirstOrDefault(a => a is SingletonLifecycleAttribute) != null)
                ci.Singleton();             
            ConfigureFamily(registry.For(pluginType));
        }
    }

    public virtual Type FindPluginType(Type concreteType)
    {
        var interfaceName = "I" + concreteType.Name;
        return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
    }
}

我认为现在一切都很好,更好;)谢谢史蒂夫!

于 2014-08-16T00:05:00.143 回答