Code Monkey home page Code Monkey logo

autofac.annotation's Introduction

Autofac extras library for component registration via attributes

支持netcore2.0 + framework4.6+

NUGET

Install-Package Autofac.Annotation

Document

https://github.com/yuzd/Autofac.Annotation/wiki

Benchmark

BenchmarkDotNet=v0.11.3, OS=Windows 10.0.18362
Intel Core i7-7700K CPU 4.20GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.2.300
  [Host]     : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT  [AttachedDebugger]
  DefaultJob : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT

Method Mean Error StdDev
AutofacAnnotation 29.77 us 0.2726 us 0.2550 us
Autofac 28.61 us 0.2120 us 0.1879 us

autofac.annotation's People

Contributors

jasongrass avatar massimilianocuccia avatar yuzd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

autofac.annotation's Issues

如何给方法加注释,AOP中获取注释

AOP中[After(Returing = "value")]获取执行结果,想要记录此方法的可理解的中文日志。
感觉在方法上加特性注解,写上中文注释,AOP中获取特性注解中的中文注释,就可以方便进行日志记录了。

IOC注入,可以在构造函数中使用吗

public class A
{
[Autowired]
public B b{ get; set; }
private C c;

    public A()
    {
        this.c = b.c;
    }
}

A构造函数中不能使用b,b还没注入,是null。
如何实现构造函数中访问注入的对象

如何我要使用Autowired特性装载对象,是不是Autowired特性标记属性的类要交由容器创建

大佬,如题:

[Component]
public class test1
{}

public class test2
{
     [Autowired]
     public test1 test{get;set;}
}

这种情况,test2是不是拿不到属性test(为null),必须:

[Component]
public class test1
{}

[Component]
public class test2
{
     [Autowired]
     public test1 test{get;set;}
}

test2也要打上Component特性,不能手动创建。
大佬,你的文档我看的不是很详细,使用中遇到这个问题,不知道框架支不支持

我想用AspectPointAttribute写一个方法自动存取缓存的AOP,当获得缓存值时,如何不运行方法直接返回结果。

我通过 invocation.ReturnValue来获得和返回原始方法的值,但好像不行
代码如下:

[AttributeUsage(AttributeTargets.Method,Inherited = true)]
 public class AutoCacheAbleAttribute : AspectPointAttribute
{
        public override async Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
        {
            ......
            ......
             var cacheValue = await ProcessGetAsync(invocation, methodInfo, returnType);
             //如果缓存存在,则直接返回
             if (cacheValue != null)
            {
                invocation.ReturnValue = cacheValue;
                return;
            }

            //执行原方法
            await _next(aspectContext);
            
            //缓存方法结果 
            await ProcessPutAsync(invocation, methodInfo, returnType, invocation.ReturnValue );
        }
}

我看了源代码。
在AopIntercept.cs里,方法的返回值是通过 aspectContext.Result 来传递,但是aspectContext.Result是internal的外部程序集是访问不到。
请问该如何处理。

[建议] 完善ConditionOnClass的Wiki部分说明

目前ConditionOnClass使用的是Type.GetType()来获取:

internal static bool FindClass(this string classPath)
{
try
{
return Type.GetType(classPath) != null;
}
catch (Exception)
{
return false;
}
}

8. 有条件的DI也有提到,入参应为“类的完整名称”,而这个所谓的名称其实是AssemblyQualifiedName。官方的定义是:

The assembly-qualified name of a type consists of the type name, including its namespace, followed by a comma, followed by the display name of the assembly. The display name of an assembly is obtained using the Assembly.FullName property.

即,AssemblyQualifiedName由①命名空间+类名、②逗号、③程序集名组成。

它长这样(来自官方示例代码):

using System;

class MyAssemblyClass
{
    public static void Main()
    {
        Type objType = typeof(Array);

        // Print the assembly full name.
        Console.WriteLine($"Assembly full name:\n   {objType.Assembly.FullName}.");

        // Print the assembly qualified name.
        Console.WriteLine($"Assembly qualified name:\n   {objType.AssemblyQualifiedName}.");
    }
}
// The example displays the following output if run under the .NET Framework 4.5:
//    Assembly full name:
//       mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
//    Assembly qualified name:
//       System.Array, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.

而对于Type.GetType(string typeName),官方有说明:

If typeName includes the namespace but not the assembly name, this method searches only the calling object's assembly and mscorlib.dll/System.Private.CoreLib.dll, in that order. If typeName is fully qualified with the partial or complete assembly name, this method searches in the specified assembly. If the assembly has a strong name, a complete assembly name is required.

https://learn.microsoft.com/en-us/dotnet/api/system.type.gettype?view=net-8.0#system-type-gettype(system-string)

经过测试,入参时对于跨程序集的类,还需要加上逗号分隔的第二段部分,也就是程序集名才能正常获取。例如在当前程序集MyProject获取跨程序集的MyProject.Common下的MyProject.Common.Configs.MyConfig,就需要写成

Type.GetType("MyProject.Common.Configs.MyConfig, MyProject.Common");

但因为对于Autofac.Annotation来说使用者是第三方程序集,因此使用者在使用ConditionOnClass时始终需要写上程序集名

此外对于逗号前后的空格官方也有要求,即逗号前不能有空格但逗号后可以有空格:

Spaces are relevant in all type name components except the assembly name. In the assembly name, spaces before the ',' separator are relevant, but spaces after the ',' separator are ignored.

此外还有关于泛型参数和可空类型要怎么写的说明,详见https://learn.microsoft.com/en-us/dotnet/api/system.type.gettype?view=net-8.0#system-type-gettype(system-string)

建议完善下Wiki,以免有人摸不着头脑。

Debug模式下,动态程序集会导致异常

项目是一个RazorPage项目,在Debug模式下会出现异常
autofac The invoked member is not supported in a dynamic assembly
Release模式就不会。

调试后发现,是AutofacAnnotationModule里的几个方法中,下面的这行代码导致异常:
var types = assembly.GetExportedTypes();
当程序集集合中有动态程序集时会产生异常,这个动态程序集应该是使用dynamic时自动增加的,名字为
Anonymously Hosted DynamicMethods Assembly

在上面的代码前面加上动态程序集的判断后,异常就没有了,代码如下:
if (assembly.IsDynamic) continue;

Component注解的InitMethod无法是父类方法

问题描述:

我定义了一个基类,用于约束所有子类的行为,其中我定义了一个初始化方法Init。我的子类继承这个基类,通过Component注册到Autofac容器。想要正常使用这个类,一定要调用初始化方法,其中有一部分是在父类统一管理,一部分交给子类扩展。但我发现
[Component(InitMethod = "Init", AutoActivate = true)] 这里的方法一定要求是当前类的。希望能解答一下这是为什么?

代码实例

 public abstract class BaseManager<T, PK> 
{
      public void Init()
     {
          // 父类的初始化
         DoInit();
     }
     // 子类扩展的初始化方法
     public abstract void DoInit();
}

[Component(InitMethod = "Init", AutoActivate = true)]
public class B : BaseManager<string, int>
{
    public override void DoInit()
    {
    }
}

我想用AspectArround写一个方法自动存取缓存的AOP,当获得缓存值时,如何跳过当前方法执行下一个拦截器。

https://github.com/yuzd/Autofac.Annotation/issues/12

  1. 一个方法上有两个环绕拦截器,如:
[LogAOP,CacheAOP(AbsoluteExpiration = 360)]
        public virtual bool IsExist(string deviceId)
        {
            List<Device> deviceList = _dal.Find(x => x == deviceId);
            return deviceList?.Count > 0;
        }

public class LogAOP : AspectArround
    {
        private ILogger<LogAOP> _logger;

        public override Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
        {
            _logger = aspectContext.ComponentContext.Resolve<ILogger<LogAOP>>();

            Stopwatch watch = new Stopwatch();
            watch.Start();

            _next(aspectContext);

            watch.Stop();
            var mSeconds = watch.ElapsedMilliseconds;

            _logger.LogInformation($"方法:{aspectContext.Method.DeclaringType.FullName}#{aspectContext.Method},参数:{string.Join(',', aspectContext.Arguments)}耗时:{mSeconds}ms");
            return Task.CompletedTask;
        }
    }

public class CacheAOP : AspectArround
    {
        private ICaching _cache;

        /// <summary>
        /// 缓存绝对过期时间(分钟)
        /// </summary>
        public int AbsoluteExpiration { get; set; } = 30;

        public override Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
        {
            _cache = aspectContext.ComponentContext.Resolve<ICaching>();

            var method = aspectContext.Method;
            CacheAOP cachingAttr = (CacheAOP)(method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(CacheAOP)));
            //获取自定义缓存键
            var cacheKey = CustomCacheKey(aspectContext);
            //根据key获取相应的缓存值
            var cacheValue = _cache.Get(cacheKey);
            if (cacheValue != null)
            {
                //将当前获取到的缓存值,赋值给当前执行方法
                aspectContext.ReturnValue = cacheValue;
                return Task.CompletedTask;
            }
            //去执行当前的方法
            _next(aspectContext);
            //存入缓存
            if (!string.IsNullOrWhiteSpace(cacheKey))
            {
                _cache.Set(cacheKey, aspectContext.ReturnValue, cachingAttr.AbsoluteExpiration);
            }
            return Task.CompletedTask;

        }
    }
  1. CacheAOP的特性得放到最后才可以,有没有方法放到任意位置,麻烦请指教下

自定义函数执行慢的问题

我这边在使用的过程中,发现如果在表达式中使用自定义函数的时候,spring.el是通过创建委托的方式来实现,这个时间比较久,我这边测似乎在0.2S以上,有什么优化的方式

4.0.2升级到4.0.4的报错问题

我项目部分结构如下:
TookitServerCore: webapi接口层
TookitServerCore.Core :业务代码层
问题代码:
在webapi接口层下有个Startup类

public void ConfigureContainer(ContainerBuilder builder)
{
// ClaimsSession这个类是在webapi接口层里面的,我想扫描webapi接口层下面所有含注解的类
builder.RegisterModule(new AutofacAnnotationModule(typeof(ClaimsSession).Assembly));
// AuthenticationService这个类是在业务代码层里面的,我想扫描业务代码层下面所有含注解的类
builder.RegisterModule(new AutofacAnnotationModule(typeof(AuthenticationService).Assembly));
// 其余代码已省略
}
这段代码在4.0.2版本下面是能正常运行的,然后在4.0.4下面就报错了,信息如下:
System.ArgumentException:“An item with the same key has already been added. Key: _ALL_COMPOMENT”

简单翻译一下 大概是说 key重复 不能再添加了
堆栈如下
at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException[T](T key)
at System.Collections.Generic.Dictionary2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value)
at Autofac.Annotation.AutofacAnnotationModule.GetAllComponent(ContainerBuilder builder, PointCutConfigurationList pointCutConfigurationList)
at Autofac.Annotation.AutofacAnnotationModule.Load(ContainerBuilder builder)
at Autofac.Module.Configure(IComponentRegistryBuilder componentRegistry)
at Autofac.ContainerBuilder.Build(IComponentRegistryBuilder componentRegistry, Boolean excludeDefaultModules)
at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
at Autofac.Extensions.DependencyInjection.AutofacServiceProviderFactory.CreateServiceProvider(ContainerBuilder containerBuilder)
at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at TookitServerCore.Program.Main(String[] args) in
D:\code\TookitServerCore\TookitServerCore\Program.cs:line 18

Value的IgnoreUnresolvablePlaceholders=true未起作用

假设有如下的配置:

{
    "abc": "abc"
}

然后映射类如下:

[Component]
public class MyConfig 
{
    [Value("${abc}")]
    public string Abc { get; set; }

    [Value("${test}", IgnoreUnresolvablePlaceholders = true)]
    public int Test { get; set; }
}

此时就会报错:

Autofac.Core.DependencyResolutionException: An exception was thrown while activating MyProject.MyConfig.
 ---> Autofac.Core.DependencyResolutionException: Value set error,can not resolve class type:MyProject.MyConfig =====> Int32 ,with value:[${test}]
 ---> Spring.Core.TypeMismatchException: Cannot convert property value of type [System.String] to required type [System.Int32] for property ''.
 ---> System.ArgumentException: ${test} is not a valid value for Int32. (Parameter 'value')
 ---> System.FormatException: The input string '${test}' was not in a correct format.

其原因是Value.Resolve()中的ResolveSpel()在找不到值时返回了配置的键名赋给parameterValue

//先把 ${} 的 placehoder 全部替换掉
var parameterValue = ResolveSpel(context, classType, this.value, autoConfigurationDetail,
IgnoreUnresolvablePlaceholders, this.EnvironmentVariableMode);
if (parameterValue == null) return null;
return TypeConversionUtils.ConvertValueIfNecessary(memberType, parameterValue, null);

而TypeMismatchException则是在ConvertValueIfNecessary()中抛出。

ResolveSpel()在找不到值时且IgnoreUnresolvablePlaceholders=true返回的是配置项的键名很奇怪。按理说ResolveSpel()应该返回个null然后进入161行的if (parameterValue == null) return null;处,Resolve()最终返回null跳过此配置项。


以我的理解,在ResolveEmbeddedValue()里的第260行处应该返回null而不是strVal

int pos = startIndex + DefaultPlaceholderPrefix.Length;
string placeholder = strVal.Substring(pos, endIndex - pos);
string resolvedValue = ResolvePlaceholder(mode, context, classType, placeholder, autoConfigurationDetail);
if (resolvedValue != null)
{
strVal = strVal.Substring(0, startIndex) + resolvedValue + strVal.Substring(endIndex + 1);
startIndex = strVal.IndexOf(DefaultPlaceholderPrefix, startIndex + resolvedValue.Length, StringComparison.Ordinal);
}
else if (ignoreFail)
{
return strVal;
}

然后在ResolveSpel()里的第195行前写上if判空提前返回:

//先把 ${} 的 placehoder 全部替换掉
var parameterValue = ResolveEmbeddedValue(mode, context, classType, strVal, autoConfigurationDetail,
ignoreFail);
int startIndex = parameterValue.ToString().IndexOf("#{", StringComparison.Ordinal);
if (startIndex != -1)

if (parameterValue == null)
    return null;

Pointcut排除namespace 正则表达式如何写

PointCut,
两个命名空间
命名空间A.B.Command.D.Controller下有很多Controller类
命名空间A.B.Config.Controller下有很多Controller类
对A.B.Command.D.Controller进行AOP,排除A.B.Config.Controller。
PointCut怎么写
[Pointcut(NameSpace = "%[^m]%", Class = "*Controller")]
[Pointcut(NameSpace = "A.B.Co[^m]%", Class = "*Controller")]
均不起作用

Autowired(name: )可以是对象属性?

class A
{
public string str = "test";

    [Autowired(name: str)]
    public B b {get; set;}

}
B有多个子类,每个子类指定名字,将B注入时,使用属性str指向其中的子类。
目前会报错,请问可以这样实现吗?
class A
{
public const string str = "test";

    [Autowired(name: str)]
    public B b {get; set;}

}
const就没问题,但是我想从配置文件读取相应的子类名字,启动对应的子类。str的值实际上从配置文件获取,就不能时const。

拦截器是否可以根据业务的上下文进行路由

拦截器是否可以根据业务的上下文进行路由?
业务场景,asp.net mvc 有一些虚方法,在执行操作时,有业务代码就会在控制器中实现这些虚方法,但是这个依赖与 mvc管道,想用Autofac.Annotation代替,所以请问有什么方法摆脱这种方式,想像博主这样,使用AOP标签这种方式,如果有业务需要,就打上标签就行了。
请博主多多指教,谢谢。

使用AspectArround做缓存时,内存一直增加

使用AspectArround做缓存时,调取方法频繁时内存泄露

namespace Autofac.Configuration.Test.test7
{
    public class UnitTest7
    {
        [Fact]
        public async Task Test_Type_01()
        {
            var builder = new ContainerBuilder();

            // autofac打标签模式
            builder.RegisterModule(new AutofacAnnotationModule(typeof(UnitTest7).Assembly));

            var container = builder.Build();

            var a1 = container.Resolve<TestCacheAop>();
            var result = await a1.TestInterceptor1();
            Assert.NotEmpty(result);

            while (true)
            {
                var result2 = await a1.TestInterceptor1();

                Assert.Equal(result + "_Cache", result2);
            }
            
          
        }
    }
}

两个模块循环引用报错

有设置循环引用,但调试时依然报错 .
` foreach (IConfigurationSection item in config.GetChildren())
{
string assemblyName = item.GetSection("name").Value;
var assembly = Assembly.LoadFile(AppContext.BaseDirectory + @"" + assemblyName + ".dll");
assemblyList.Add(assembly);
}

        var autofacAnnoMe = new AutofacAnnotationModule(assemblyList.ToArray());
        autofacAnnoMe.SetAllowCircularDependencies(true); //允许循环引用
        builder.RegisterModule(autofacAnnoMe);

定义类时,加上属性 InjectPropertyType = InjectPropertyType.ALL 可解决此问题. 但是所有接口又都全部自动装配了. [Component(AutofacScope= AutofacScope.SingleInstance,InjectPropertyType = InjectPropertyType.ALL )]`

pointcut 使用异常问题

[Pointcut(Class = "*Controller", Method = "Get*")]

The requested service '***.HomeController' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency
再homecontroller 中添加了getuser 无法正常使用

Question about internal classes with [Component] annotation

From my limited testing, internal classes (with a public constructor) do not get registered. Is there a setting or property that I may be missing?

[Component]
internal class IntReader
{
    public int ReadInt()
    {
        return new Random().Next();
    }
}

[问题]在asp.net mvc 中,Aspect不起作用。

已经在 class 打上了标签:
image

在程序的入口 ,已注入相关的程序集。
builder.RegisterModule(new AutofacAnnotationModule(typeof(MvcApplication).Assembly));

但是自定义的Interceptor不进去

最有可能的原因是什么?

[Pointcut(AttributeType = typeof(LogAttribute))]不起作用

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class LogAttribute : Attribute
{
public string message { get; set; }
public string actionName { get; set; }

    public LogAttribute(string message, string actionName)
    {
        this.message = message;
        this.actionName = actionName;
    }
}

//[Pointcut(Class = "[^Api]*Controller")]
[Pointcut(AttributeType = typeof(LogAttribute))]
public class LogInterceptor : IInterceptor
{
[Around]
public async Task Around(AspectContext context, AspectDelegate next)
{
//没有执行
}
}

[LogAttribute("", "")]
public virtual void CheckCommand(byte[] cmd)
{
//执行此方法,没有进入AOP的Around
}

AOP类没问题,因为[Pointcut(Class = "[^Api]*Controller")]可以对Controller类进行Around操作,换成[Pointcut(AttributeType = typeof(LogAttribute))],就不会对LogAttribute注解类进行Around操作。
哪里写的不对吗?

并行注入多个builder.RegisterModule, Autowired标注使用的地方会出现null的情况

并行注入多个builder.RegisterModule, Autowired使用的地方会出现null的情况
是因为autofac加载Load了多次,导致属性注入DoAutoWired方法执行不成功,componentModelCacheSingleton.ComponentModelCache没有包含实例.

` public void ConfigureContainer(ContainerBuilder builder)
{
// Autofac.Annotation 注入
builder.RegisterModule(new AutofacAnnotationModule(typeof(TestInterface123).Assembly));

        builder.RegisterModule(new AutofacAnnotationModule(typeof(AabcTestInterface123).Assembly));


        // Autowired 标注的属性注入
        var ControllerBaseType = typeof(ControllerBase);
        builder.RegisterAssemblyTypes(typeof(Program).Assembly)
          .Where(t => ControllerBaseType.IsAssignableFrom(t) && t != ControllerBaseType)
          .PropertiesAutowired(new AutowiredPropertySelector());

    }`

image

automatically build the container

Hi,
is there a way to automatically build the container?

to build the container I must list each class in this way
image
and then call Build.

I would like to create the container by loading all annotated classes in the project, something like this example:
var container = new AutodiscoveryContainerBuilder().Build();
`

thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.