c# - 是否可以使用面向方面的方法通过 Autofac 和 DynamicProxy 登录 Azure 函数

标签 c# azure dependency-injection autofac azure-functions

是否可以使用面向方面的方法通过 Autofac 和 DynamicProxy 来登录 Azure 函数,如下所示:

https://nearsoft.com/blog/aspect-oriented-programming-aop-in-net-core-and-c-using-autofac-and-dynamicproxy/

我研究了以下链接

  1. http://codingsoul.de/2018/01/19/azure-function-dependency-injection-with-autofac/
  2. https://blog.wille-zone.de/post/azure-functions-proper-dependency-injection/
  3. http://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html

然后尝试使用下面的代码扩展 Holger Leichsenring 的帖子 (#1)。然而,Intercept() 函数从未被触发。有任何想法吗?

其他 Nuget 引用(您还需要将 Autofac 降级到 4.0.1)

using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;

测试

添加拦截器和带参数的函数...

[Intercept(typeof(ICallLogger))]
public class TestIt : ITestIt
{
    public string Name { get; set; }

    public string CallMe()
    {
        return "Dependency Injection Test method had been called...";
    }

    public string CallMeWithParameter(string parameter)
    {
        return "Dependency Injection Test method had been called with [" + parameter + "]";
    }
}

服务模块

public class ServicesModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<CallLogger>().As<ICallLogger>();
        builder.RegisterType<TestIt>().As<ITestIt>().EnableClassInterceptors();

        // How can you pass context to the AutoFac.ServicesModule()? Commenting out for now and using parameterless constructor instead.
        // builder.Register(c => new CallLogger(context.Trace)).Named<IInterceptor>("log-calls");

        // Switch to use Type based interceptor attribute instead of Name based interceptor attribute
        // builder.Register(c => new CallLogger()).Named<IInterceptor>("log-calls");

    }
}

通话记录器

public interface ICallLogger
{
    void Intercept(IInvocation invocation);
}

/// <summary>
/// Logging class that would hopefully wrap TraceWriter - trying the Debug Output Window for now...
/// </summary>
public class CallLogger : IInterceptor, ICallLogger
{
    TraceWriter _log;

    public CallLogger(TraceWriter log)
    {
        _log = log;
    }

    public CallLogger()
    {
        _log = null;
    }

    public void Intercept(IInvocation invocation)
    {
        string message = string.Empty;

        message = "Calling method {0} with parameters {1}... " +
                  invocation.Method.Name +
                  string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray());

        if (_log != null)
        {
            _log.Info(message);
        }

        Debug.WriteLine(message);

        invocation.Proceed();

        message = "Done: result was {0}." + invocation.ReturnValue;
        Debug.WriteLine(message);

        if (_log != null)
        {
            _log.Info(message);
        }
    }
}

最佳答案

这可以使用 Autofac Type Interceptors 实现,但正如您所发现的,配置拦截器可能很棘手。我所知道的实现此目的的最简单方法是使用 Functionless 。完全公开,这是我编写的一个开源项目。我对 self 推销不感兴趣,只是想帮助别人。我只在这里提到它,因为据我所知,这是实现您的目标的最简单方法,如果发布,我很乐意接受其他更好的解决方案。

这里有一个完整的要点 FunctionAppLogingInterception ,您应该能够下载、构建和运行它,它演示了一个简单的日志记录拦截器。这是一个简短的解释...

  1. host.json 中配置适当的日志级别(请参阅 host.json reference for Azure Functions 2.x and later)
    "logLevel": {
      "FunctionAppLogingInterception": "Debug"
    }
  • 添加您的记录器 IInterceptor 实现,Functionless 将自动拾取并注册该实现。
  •     public class LoggingInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                ...
            }
        }
    
  • 添加一个具有一个或多个您想要拦截的 public 可重写(即标记为 virtualoverride)方法的类,如 Autofac | Type Interceptors: Tips 中所述.
  •     public class ReportJob
        {
            [NewOrchestration]
            public virtual async Task ExecuteAsync()
            {
                ...
            }
        }
    
  • 使用 Functionless 的内置协调器调用您的类,或添加您自己的函数触发器来调用您的类和拦截器。
  • POST /api/orchestrator?$method=ReportJob.<ExecuteAsync>()
    

    或者...

    [FunctionName("reportjob-execute")]
    public async Task Execute(
        [HttpTrigger] HttpRequest request,
        [DurableClient] IDurableOrchestrationClient client)
    {
        await client.DurablyInvokeAsync(
            async () => await this.reportJob.ExecuteAsync()
        );
    }
    
    POST /api/reportjob-execute
    
  • 观察截获的日志输出。如果使用上述要点( FunctionAppLogingInterception ),它应该产生类似于以下内容的输出(注意以“invoked”结尾的行)...
  • [2020-12-22T18:20:10.816Z] Host lock lease acquired by instance ID '000000000000000000000000D771FED2'.
    [2020-12-22T18:20:16.207Z] Executing 'orchestrator' (Reason='This function was programmatically called via the host APIs.', Id=bdc7d19e-1250-4692-bde2-98cf663cacb8)
    [2020-12-22T18:20:16.403Z] Executed 'orchestrator' (Succeeded, Id=bdc7d19e-1250-4692-bde2-98cf663cacb8, Duration=243ms)
    [2020-12-22T18:20:16.481Z] Executing 'orchestration' (Reason='(null)', Id=2d17ea99-959c-43ef-b7ba-ed194de38165)
    [2020-12-22T18:20:17.133Z] System.Threading.Tasks.Task ExecuteAsync() invoked
    [2020-12-22T18:20:17.272Z] Executed 'orchestration' (Succeeded, Id=2d17ea99-959c-43ef-b7ba-ed194de38165, Duration=793ms)
    [2020-12-22T18:20:17.339Z] Executing 'orchestration' (Reason='(null)', Id=ff5c08e7-f678-48a3-9a82-bc2e231195e3)
    [2020-12-22T18:20:17.582Z] System.Threading.Tasks.Task GenerateReportsAsync() invoked
    [2020-12-22T18:20:17.597Z] Executed 'orchestration' (Succeeded, Id=ff5c08e7-f678-48a3-9a82-bc2e231195e3, Duration=258ms)
    [2020-12-22T18:20:17.642Z] Executing 'activity' (Reason='(null)', Id=cc4f89ef-f64c-4851-8e7c-3b7acbfcc915)
    [2020-12-22T18:20:17.646Z] Executing 'activity' (Reason='(null)', Id=3a7747a6-5568-4561-a028-9c319263ccf7)
    [2020-12-22T18:20:17.659Z] Executing 'activity' (Reason='(null)', Id=caea5602-9c0b-463a-b0b0-112e512eaf25)
    [2020-12-22T18:20:17.808Z] System.Threading.Tasks.Task GenerateReportAsync() invoked
    [2020-12-22T18:20:17.808Z] System.Threading.Tasks.Task GenerateReportAsync() invoked
    [2020-12-22T18:20:17.808Z] System.Threading.Tasks.Task GenerateReportAsync() invoked
    [2020-12-22T18:20:18.536Z] Executed 'activity' (Succeeded, Id=caea5602-9c0b-463a-b0b0-112e512eaf25, Duration=878ms)
    [2020-12-22T18:20:18.540Z] Executed 'activity' (Succeeded, Id=cc4f89ef-f64c-4851-8e7c-3b7acbfcc915, Duration=901ms)
    [2020-12-22T18:20:18.541Z] Executed 'activity' (Succeeded, Id=3a7747a6-5568-4561-a028-9c319263ccf7, Duration=897ms)
    [2020-12-22T18:20:18.610Z] Executing 'orchestration' (Reason='(null)', Id=9500673c-7c4d-4d91-bfea-b6e095f51197)
    [2020-12-22T18:20:18.716Z] System.Threading.Tasks.Task GenerateReportsAsync() invoked
    [2020-12-22T18:20:18.728Z] Executed 'orchestration' (Succeeded, Id=9500673c-7c4d-4d91-bfea-b6e095f51197, Duration=120ms)
    [2020-12-22T18:20:18.782Z] Executing 'orchestration' (Reason='(null)', Id=8c9dc2d6-71f9-47b0-8c1a-4409da6b23d7)
    [2020-12-22T18:20:18.896Z] System.Threading.Tasks.Task ExecuteAsync() invoked
    [2020-12-22T18:20:18.901Z] Executed 'orchestration' (Succeeded, Id=8c9dc2d6-71f9-47b0-8c1a-4409da6b23d7, Duration=120ms)
    

    有关 Functionless 如何实现这一点的更多信息,请参阅其 Autofac Module implementation ,其中包含以下代码片段,如果您想使用 Autofac 但不使用 Functionless 获得类似的结果,该代码片段可以适用于许多其他场景...

    assemblies.ForEach(
        assembly => builder
            .RegisterAssemblyTypes(assembly)
            .Where(p => p.IsPublic && p.IsClass)
            .AsSelf().AsImplementedInterfaces()
            .PreserveExistingDefaults()
            .EnableClassInterceptors()
            .InterceptedBy(interceptorTypes)
    );
    

    关于c# - 是否可以使用面向方面的方法通过 Autofac 和 DynamicProxy 登录 Azure 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50556012/

    相关文章:

    c# - 线程类 'Splash-Type' 屏幕的 TPL 等效项

    c# - IQueryable 表达式翻译

    c# - 关于委托(delegate)的澄清

    c# - 如何使用 C# 在 app.config 中为 mysql 数据库提供默认连接字符串

    Azure AD B2C 身份提供商

    azure - 如何防止在 WebJob 处理时重复消息不插入到服务总线队列中?

    Azure计时器触发器在.net 5独立函数应用程序中不起作用

    java - Autowiring 构造函数和字段

    c++ - 依赖注入(inject) : all service methods receive the same newable object

    java - 使用反射调用多个类时的 Guice 注入(inject)