Giter Site home page Giter Site logo

dotnetcore / aspectcore-framework Goto Github PK

View Code? Open in Web Editor NEW
1.7K 103.0 318.0 2.26 MB

AspectCore is an AOP-based cross platform framework for .NET Standard.

License: MIT License

C# 100.00%
aop aspect-oriented-programming netcore aspectcore-framework aspect

aspectcore-framework's Introduction

AspectCore Framework

Build status Member project of .NET Core Community GitHub license
AspectCore is an Aspect-Oriented Programming based cross platform framework for .NET Core and .NET Framework.

Core support for aspect-interceptor, dependency injection integration, web applications, data validation, and more.

Nuget Packages

Core library

Package Name NuGet MyGet Downloads
AspectCore.Abstractions nuget myget stats
AspectCore.Core nuget myget stats
AspectCore.Extensions.Reflection nuget myget stats

Integration library

Package Name NuGet MyGet Downloads
AspectCore.Extensions.DependencyInjection nuget myget stats
AspectCore.Extensions.Autofac nuget myget stats
AspectCore.Extensions.Windsor nuget myget stats
AspectCore.Extensions.LightInject nuget myget stats
AspectCore.Extensions.Hosting nuget myget stats

Docs

Components 

Who is using

Contributors

Contribute

One of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes.

License

MIT

aspectcore-framework's People

Contributors

alexinea avatar cdcd72 avatar eduherminio avatar fs7744 avatar gilbertogwa avatar hjkl950217 avatar huoshan12345 avatar jerviscui avatar jianxuanbing avatar jsnaner avatar jtone123 avatar khaiatqbf avatar liuhaoyang avatar marsonshine avatar netcore-jroger avatar nivalxer avatar purplestviper avatar pygzfei avatar tanyongzheng avatar wangronghua avatar windsone avatar yang-xiaodong 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  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

aspectcore-framework's Issues

关于 AspectContext 中提供剥离 Task<T> 返回值到 T 的建议

针对 #49 的情况,AspectCore 能否提供 context.IsAsynccontext.AsyncReturnValue 这样的 API?

如果 AspectCore 可以提供这样的 API,那么需要考虑以下几种情况:

  • Task 的处理
  • Task<Task<Task>> 的处理(包心菜)
  • Task 的处理
  • 以及 ValueTask 的处理

Using ProxyActivator to create a dynamic proxy class instance

AspectCoreLite提供IProxyActivator 接口和它的默认实现ProxyActivator来创建目标类型的代理类。在一个基本的切面中,我们需要定义或者生成Interceptor Target Proxy PointCutJoinPoint

Interceptor系统中,框架定义了IInterceptor接口,它声明了一个返回值为Task的异步执行方法:

namespace AspectCore.Lite.Abstractions
{
    public interface IInterceptor
    {
        Task ExecuteAsync(IAspectContext aspectContext, InterceptorDelegate next);
    }
}

然而在一般情况下可以使用另一个抽象的InterceptorAttribute自定义特性类,它实现IInterceptor接口。AspectCoreLite默认实现了基于AttributePointCut。我们的自定义拦截器看起来像下面这样:

public class CustomInterceptorAttribute: InterceptorAttribute
{
    public override async Task ExecuteAsync(IAspectContext aspectContext , InterceptorDelegate next)
    {
        Console.WriteLine("Before target call");
        try
        {
            await next(aspectContext);
        }
        catch (Exception)
        {
            Console.WriteLine("Target threw an exception!");
            throw;
        }
        finally
        {
            Console.WriteLine("After target call");
        }
    }
}

执行next(aspectContext)意味着你可以继续调用下一个拦截器或原始的目标方法。

接下来我们定义Target类,声明一个标记了CustomInterceptorAttribute自定义特性的虚方法:

public class Target
{
    [CustomInterceptor]
    public virtual void Call()
    {
        Console.WriteLine("target calling...");
    }
}

最后,我们使用默认的构造器创建ProxyActivator的实例,并且调用CreateClassProxy方法创建Target类的运行时代理:

IProxyActivator proxyActivator = new ProxyActivator();
Target proxy = proxyActivator.CreateClassProxy<Target>(new Target());
proxy.Call();

输出:

Before target call
target calling...
After target call

Compile error for the latest solution

after download and compile the latest version "AspectCore.Extensions.DependencyInjection" solution,there is the error such as “CS0246 未能找到类型或命名空间名“AspectCoreOptions”(是否缺少 using 指令或程序集引用?)”.
I think the version from nuget server is not the latest, please confrim it, thank you.

Support ref return

考虑支持 ref return方法的代理 dotnet/roslyn#118

static ref int Max(ref int first, ref int second, ref int third)
{
  ref int max = first > second ? ref first : ref second;
  return max > third ? ref max : ref third;
}

全局注册没有响应

Nuget下载的版本为v0.2.4

源码如下:

using AspectCore.Configuration;
using AspectCore.DynamicProxy;
using AspectCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AspectCoreDemo1
{
    class Program
    {
        static void Main(string[] args)
        {
            RegisterAop();
            TestAop test = new TestAop();
            test.CallValue("今天是周三");
            Console.ReadLine();         
        }

        private static void RegisterAop()
        {
            IServiceCollection services = new ServiceCollection();        
            services.AddDynamicProxy(config =>
            {
                config.Interceptors.AddServiced<ExceptionLogAttribute>(Predicates.ForNameSpace("AspectCoreDemo1.*")); //拦截所有AspectCoreDemo及其子命名空间下面的接口或类                
            });
        }
    }

    /// <summary>
    /// 记录异常日志
    /// </summary>
    public class ExceptionLogAttribute : AbstractInterceptorAttribute
    {
        public override Task Invoke(AspectContext context, AspectDelegate next)
        {
            try
            {
                Console.WriteLine("Before service call");
                return next(context);
            }
            catch (Exception ea)
            {
                Console.WriteLine($"出现异常!异常信息:{ea.Message}");
                throw ea;
            }
            finally
            {
                Console.WriteLine("After service call");
            }
        }
    }

    [ExceptionLog]
    public class TestAop
    {
        public virtual void CallValue(string value)
        {
            Console.WriteLine($"我就是CallValue({nameof(value)})执行的,value:{value}");
        }
    }
}

关于拦截返回值为 dynamic 的异步方法时,拦截器内 await 的问题

以下方法:

[WrapperInterceptor]
public virtual dynamic DoSomeThing(){
    return DoSomeInterestingThingAsync();
}

其中 DoSomeInterestingThingAsync 返回 Task<Lemon> 类型的结果。

由于方法返回的是 dynamic,所以 AspectCore 会将其识别为同步方法,而不去 await 它。

因此例中的 WrapperInterceptor 内,context.ReturnValue 返回的是 Task<Lemon>。如果我要将这个 Task<T> 内的 Lemon 取出然后包装进一个包装类中,填回 ReturnValue 的话,需要判断这个 Task 是否完成执行。

这个等待的工作使用者来完成,还是由 AspectCore 内部来完成?

AspectCore与Castle.Core性能比较

我做一个AspectCore与Castle.Core的测试,分别针对同步方法与异步方法,可是执行的速度相差很大,不知道为什么,是不是使用方式有问题,求解。
我测试的结果如下:

Method Mean Error StdDev
Create_By_Castle_Core_Async 78.28 ns 1.5851 ns 1.6278 ns
Create_By_AspectCore_Async 386.44 ns 7.7314 ns 7.2319 ns
Create_By_Castle_Core 48.40 ns 0.8871 ns 0.8298 ns
Create_By_AspectCore 352.03 ns 5.2261 ns 4.8885 ns

测试代码的地址:
https://github.com/tangdf/AOPBenchmarkTest

windsor容器中代理方法,如果拦截器在Invoke(next)之前调用过异步方法则该拦截器会被无限调用

有如下拦截器:

[AttributeUsage(AttributeTargets.Method)]
public class AwaitBeforeInvokeAttribute : AbstractInterceptorAttribute
{
	public override async Task Invoke(AspectContext context, AspectDelegate next)
	{
		await Task.Delay(100);
		var output = context.ServiceProvider.GetRequiredService<ITestOutputHelper>();
		if (context.Proxy is AwaitBeforeInvokeTester tester
			&& tester.Cts.IsCancellationRequested)
		{
			context.ReturnValue = Task.FromResult(-1);
			return;
		}
		output.WriteLine("Before Invoke Next");
		await context.Invoke(next);
		output.WriteLine("After Invoke Next");
	}
}

// 被代理类
public class AwaitBeforeInvokeTester
{
	[DoNotWire]
	public CancellationTokenSource Cts { get; set; } // 增加这个为了让无限调用退出

	[AwaitBeforeInvoke]
	public virtual async Task<int> ExecuteAsync()
	{
		await Task.Delay(100);
		return 1;
	}
}

使用windsor时,会输出多次"Before Invoke Next",直到CancellationTokenSource取消。

我用相同的方式测试了autofac和msdi,输出符合预期,所以应该是windsor的相关适配存在问题
具体测试用例可以参考:https://github.com/huoshan12345/AspectCore-Framework/blob/infinite_invoke_in_windsor/extras/test/AspectCore.Extensions.Windsor.Test/AwaitBeforeInvokeNextTests.cs

Performance Diagnostic

添加性能追踪api,方便从外部调试和监控DynamicProxy创建代理类和执行方法拦截的性能

非常感谢这次的更新

非常感谢这次的更新。这个版本的代码,层次清晰,紧凑,很棒。但是样例太少了。比如字段注入,属性注入,方法注入,参数注入,返回值注入的样例太少,以至于不知道怎么使用了,只知道FromServices是对参数的注入,其他的不知道怎么使用。能抽空做个样例项目不,谢谢

It throw a exception when executing next(context):Code supposed to be unreachable.

The StackTrace is here:

   at AspectCore.Extensions.Reflection.Emit.ILGeneratorExtensions.EmitConstant(ILGenerator ilGenerator, Object value, Type valueType)
   at AspectCore.Extensions.Reflection.CustomAttributeReflector.CreateInvoker()
   at AspectCore.Extensions.Reflection.CustomAttributeReflector..ctor(CustomAttributeData customAttributeData)
   at AspectCore.Extensions.Reflection.CustomAttributeReflector.<>c.<Create>b__11_0(CustomAttributeData data)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Linq.Enumerable.SelectIListIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at AspectCore.Extensions.Reflection.MemberReflector`1..ctor(TMemberInfo reflectionInfo)
   at AspectCore.Extensions.Reflection.MethodReflector..ctor(MethodInfo reflectionInfo)
   at AspectCore.Extensions.Reflection.MethodReflector.<>c__DisplayClass0_0.<Create>g__CreateInternal0(Pair`2 item)
   at AspectCore.Extensions.Reflection.ReflectorCacheUtils`2.<>c__DisplayClass1_0.<GetOrAdd>b__0(TMemberInfo k)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at AspectCore.Extensions.Reflection.MethodReflector.Create(MethodInfo reflectionInfo, CallOptions callOption)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at AspectCore.DynamicProxy.RuntimeAspectContext.Complete()
   at Shriek.ServiceProxy.Tcp.Client.TcpServiceClient.<Invoke>d__35.MoveNext() in E:\项目\myproject\ShriekFx\src\Shriek.ServiceProxy.Tcp\Client\TcpServiceClient.cs:line 128
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at AspectCore.DynamicProxy.AspectActivator.InvokeTask[TResult](AspectActivatorContext activatorContext)
   at AspectCore.DynamicGenerated.TcpTestService.Test(String sth)
   at Shriek.Samples.WebApiProxy.Program.Main(String[] args) in E:\项目\myproject\ShriekFx\samples\Shriek.Samples.WebApiProxy\Program.cs:line 101

Callvirt与Call

public static MethodReflector GetReflector(this MethodInfo method)
{
return GetReflector(method, CallOptions.Callvirt);
}
public static MethodReflector GetReflector(this MethodInfo method, CallOptions callOption)
{
if (method == null)
{
throw new ArgumentNullException(nameof(method));
}
return MethodReflector.Create(method, callOption);
}

调用MethodInfo应该使用Callvirt还是使用Call,应该由MethodInfo类型决定,而不应该通过参数指定。

internal static MethodReflector Create(MethodInfo reflectionInfo, CallOptions callOption)
{
if (reflectionInfo == null)
{
throw new ArgumentNullException(nameof(reflectionInfo));
}
return ReflectorCacheUtils<Pair<MethodInfo, CallOptions>, MethodReflector>.GetOrAdd(new Pair<MethodInfo, CallOptions>(reflectionInfo, callOption), CreateInternal);
MethodReflector CreateInternal(Pair<MethodInfo, CallOptions> item)
{
var methodInfo = item.Item1;
if (methodInfo.ContainsGenericParameters)
{
return new OpenGenericMethodReflector(methodInfo);
}
if (methodInfo.IsStatic)
{
return new StaticMethodReflector(methodInfo);
}
if (methodInfo.DeclaringType.GetTypeInfo().IsValueType || callOption == CallOptions.Call)
{
return new CallMethodReflector(methodInfo);
}
return new MethodReflector(methodInfo);
}
}

而且在缓存时,也会减少枚举在比较时装箱与拆箱。

Attribute Interceptor ‘s life cycle

  1. Same life cycle as the service interface ?
  2. Individual life cycle : Transient (no cache) , Singleton (global cache) or Scoped ?
  3. Other better suggestions.

FormatException: Encountered an invalid type for a default value.

Details:

System.FormatException: Encountered an invalid type for a default value.

   at System.Reflection.MdConstant.GetValue(MetadataImport scope, Int32 token, RuntimeTypeHandle fieldTypeHandle, Boolean raw)

   at System.Reflection.RuntimeParameterInfo.GetDefaultValueInternal(Boolean raw)

   at System.Reflection.RuntimeParameterInfo.get_HasDefaultValue()

   at AspectCore.Utils.ProxyGeneratorUtils.ParameterBuilderUtils.DefineParameters(MethodInfo targetMethod, MethodBuilder methodBuilder)

   at AspectCore.Utils.ProxyGeneratorUtils.MethodBuilderUtils.DefineMethod(MethodInfo method, String name, MethodAttributes attributes, Type implType, TypeDesc typeDesc)

   at AspectCore.Utils.ProxyGeneratorUtils.MethodBuilderUtils.DefineInterfaceMethod(MethodInfo method, Type implType, TypeDesc typeDesc)

   at AspectCore.Utils.ProxyGeneratorUtils.MethodBuilderUtils.DefineInterfaceProxyMethods(Type interfaceType, Type targetType, Type[] additionalInterfaces, TypeDesc typeDesc)

   at AspectCore.Utils.ProxyGeneratorUtils.CreateInterfaceProxyInternal(String name, Type interfaceType, Type implType, Type[] additionalInterfaces, IAspectValidator aspectValidator)

   at AspectCore.Utils.ProxyGeneratorUtils.CreateInterfaceProxy(Type interfaceType, Type implType, Type[] additionalInterfaces, IAspectValidator aspectValidator)

   at AspectCore.DynamicProxy.ProxyTypeGenerator.CreateInterfaceProxyType(Type serviceType, Type implementationType)

   at AspectCore.Extensions.DependencyInjection.ServiceCollectionBuildExtensions.MakeProxyService(ServiceDescriptor descriptor, Type implementationType, IProxyTypeGenerator proxyTypeGenerator)

   at AspectCore.Extensions.DependencyInjection.ServiceCollectionBuildExtensions.BuildAspectCoreServiceProvider(IServiceCollection services)

My Code:

// ServiceAccessLogAttribute

public class ServiceAccessLogAttribute : AbstractInterceptorAttribute
    {
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            await next(context);
        }
    }
// Startup.ConfigureServices

services.AddTransient(provider => new ServiceAccessLogAttribute());
            services.AddDynamicProxy(config =>
            {
                config.Interceptors.AddServiced<ServiceAccessLogAttribute>(method =>
                {
                    var isService = method.DeclaringType.Name.EndsWith("Service");
                    return isService;
                });
            });
            return services.BuildAspectCoreServiceProvider();

Project Info:

OS: Windows 10
dotnet --version: 2.1.104
Target: netcoreapp2.0
AspectCore.Extensions.DependencyInjection: 0.3.1

属性注入失败

    public ValuesController(ISampleRepository repo) { }

    [FromContainer]
    public ISampleRepository repos { get; set; }
    
    其中构造函数可以获取到注入的ISampleRepository 对象,但是带有[FromContainer]的属性获取不到,

是使用的姿势不对吗,sample当中没有找到FromContainer的例子,只有在文档看到.

被AspectCore代理的类的构造函数无法匹配到最佳

考虑如下的一个类:

public class WeiboClient
{
	public Account Account { get; internal set; }
	protected internal IHttpService HttpService { get; set; }
	protected internal WeiboSettings Settings { get; }

         // 调用这个构造函数需要再执行Init进行二段构造
	public WeiboClient(WeiboSettings settings)
	{
		Settings = settings ?? throw new ArgumentNullException(nameof(settings));
	}

	public WeiboClient(string username, string password, WeiboSettings settings, IHttpService httpService = null) : this(settings)
	{
		Init(username, password, httpService);
	}
	
	public void Init(string username, string password, IHttpService httpService = null)
	{
		Account = new Account(username, password, AccountType.Weibo);
		HttpService = httpService ?? new HttpService();
	}
	
        // ReLoginAndRetry是一个继承了InterceptorAttribute的类
	[ReLoginAndRetry]
	public virtual async Task<ActionEvent> PostPicWeibo(string text, ICollection<string> picUrls = null)
	{
		// do something
	}
}	

然后将该类注册到依赖注入容器,WeiboSettings也注入。
于是该类将会被注册到AspectCore的代理类容器中(就是会调用CreateClassProxyType方法产生代理类型)
如果此时使用DI容器获取WeiboClient对象,那么将会调用第二个构造函数
——————————————
而如果该类没有被加入到AspectCore的代理类容器中(例如将PostPicWeibo方法的virtual去掉),如果此时使用DI容器获取WeiboClient对象,那么将会调用第一个构造函数

这个行为不一致的现象导致了一些问题,不知应如何解决,还望repo主指点。
我目前的临时解决方法是注释掉第二个构造函数

被代理方法返回值类型与原方法不匹配

具体来说就是AsyncAspectTests这个测试类的Async_Test测试用例,原本的代码有笔误,改正之后这个用例就不通过了

[Fact]
public void Async_Test()
{
	var proxy = ProxyGenerator.CreateClassProxy<FakeAsyncClass>();
	var result = proxy.Async(100);  // 此处原本误写作DynAsync
	Assert.IsAssignableFrom<Task<int>>(result);
}

以下是被代理方法

[AsyncTestInterceptor]
public virtual Task Async(int value)
{
	return Task.Run<int>(async () =>
	{
		await Task.Delay(value);
		return value;
	});
}

以下是测试输出:
Assert.IsAssignableFrom() Failure
Expected: typeof(System.Threading.Tasks.Task)
Actual: typeof(System.Threading.Tasks.Task)

调用了await context.Invoke(next)之后,context.ReturnValue依然为null

有如下Interceptor属性,将其添加在一个返回int的方法上。
在调用await context.Invoke(next)之后,context.ReturnValue依然是null。
环境:dotnet --version 2.1.103,aspectcore版本为0.3.1,di容器为Windsor

不知是不是我的使用方式不对。

public class InterceptorAttribute : AbstractInterceptorAttribute
{
	public override async Task Invoke(AspectContext context, AspectDelegate next)
	{
		await context.Invoke(next);
		var returnValue = context.ReturnValue;
		Assert.NotNull(returnValue);
	}
}

public interface IService
{
	[Interceptor]
	int Get();
}

完整的测试项目在:https://github.com/huoshan12345/AspectCoreTester

在Mvc Core中使用拦截器时,如何在Controller的拦截器中获取HttpContext ?

    public static class AspectContextExtensions
    {
        public static HttpContext GetHttpContext(this AspectContext context)
        {
            object value;
            if (context.Items.TryGetValue("HttpContext", out value))
            {
                return (HttpContext)value;
            }
            var controller = context.Target.ImplementationInstance as Controller;
            if (controller != null)
            {
                context.Items["HttpContext"] = controller.HttpContext;
                return controller.HttpContext;
            }
            return null;
        }
    }

使用中发现两个问题

一、假如接口IB继承IA,类C实现并注册IB,如果IB中的方法没有加入拦截器,则IA中的拦截器会无效
二、似乎不支持方法的参数或者返回值是Tuple或者ValueTuple,注册拦截器时会发生异常

NonAspectPredicates.AddMethod()方法不起作用

lib
上面是我用的引用。

我在Startup.cs中修改了ConfigureServices方法,如下:

public IServiceProvider ConfigureServices(IServiceCollection services)
 {

services.AddMvc().AddControllersAsServices();

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterDynamicProxy(config =>
{

//自定义拦截器 config.Interceptors.AddTyped<CustomInterceptorAttribute(Predicates.ForNameSpace("aoptest.Services"));
//排除Quer开头的方法
config.NonAspectPredicates.AddMethod("Quer*");
});

builder.Populate(services);


 var dataAccess = Assembly.GetExecutingAssembly();
 builder.RegisterAssemblyTypes(dataAccess)
 .Where(t => t.Name.EndsWith("Service"))
 .AsImplementedInterfaces();

var container = builder.Build();

return new AutofacServiceProvider(container);

}

拦截器CustomInterceptorAttribute的定义代码:

public class CustomInterceptorAttribute : AbstractInterceptor
{
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
await next(context);
//方法名
Console.WriteLine("执行方法: "+ context.ImplementationMethod.Name);
}
}

要拦截的业务层代码:

public class UserService : IUserService
{
public string AddUser()
{
return "AddUser()";
}

    public string QueryName()
    {
        return "QueryName()";
    }

    public string SayName()
    {
      
        return "SayName()";
    }
}

在Controller中调用,后台打印如下:

result

可以看出
config.NonAspectPredicates.AddMethod("Quer*");并没有起作用。

需要一个AspectContext.UnwrapAsyncReturnValue的镜像方法

如题。
当我需要对返回结果进行操作的时候,如果返回结果是个Task,例如Task之类的,就需要一个封装方法了。

我自己在实现一个缓存接口的时候实现了一个,凑合能用,不知道你们这边有没有更好的实现可以用。
示例代码如下:

var cacheValue = await DistributedCache.GetAsync(cacheKey);
if (cacheValue != null)
{
using (var ms = new MemoryStream(cacheValue))
{
var formatter = new BinaryFormatter();
var result = formatter.Deserialize(ms);
if (context.IsAsync())
{
dynamic member = context.ServiceMethod.ReturnType.GetMember("Result")[0];
dynamic temp = System.Convert.ChangeType(result, member.PropertyType);
context.ReturnValue = System.Convert.ChangeType(Task.FromResult(temp), context.ServiceMethod.ReturnType);

}
else
{
context.ReturnValue = System.Convert.ChangeType(result, context.ServiceMethod.ReturnType);
}
}
return;
}

Intercept async method blocks the thread

Test code:

using System;
using System.Threading.Tasks;
using AspectCore.DynamicProxy;

namespace Program
{
    public class Program
    {
        public class Intercept : AbstractInterceptorAttribute
        {
            public override Task Invoke(AspectContext context, AspectDelegate next)
            {
                context.Parameters[0] = "lemon";
                return context.Invoke(next);
            }
        }

        public interface IService
        {
            Task<string> GetValue(string val);
        }

        public class Service : IService
        {
            [Intercept]
            public async Task<string> GetValue(string val)
            {
                await Task.Delay(3000);
                return val;
            }
        }

        static void Main(string[] args)
        {
            var builder = new ProxyGeneratorBuilder();
            builder.Configure(_ => { });
            var proxyGenerator = builder.Build();
            var proxy = proxyGenerator.CreateInterfaceProxy<IService, Service>();
            // IService proxy = new Service();
            var val = proxy.GetValue("le");
            Console.WriteLine("should return immediately");
            Console.WriteLine(val.Result);
        }
    }
}

Should print "should return immediately" immediately after GetValue, then sleep 3s and print the final result.

Problem lines:




AspectContextRuntimeExtensions.AwaitIfAsync(this, returnValue);

return typeof(Task).GetTypeInfo().IsTaskWithResult();

Reference:
https://stackoverflow.com/questions/17284517/is-task-result-the-same-as-getawaiter-getresult

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.