より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

Autofacを利用して、メソッド呼び出し時にログ出力

メソッド呼び出し時にログを出力してみたいなと探したところ、Autofacというライブラリを使えば、.NET Coreでも行けそうだということで試してみました。

このライブラリそのものはIoCのためのライブラリです。

やってみた感触としては、

  • 出力したいメソッドにvirutalの指定が必要で、これが微妙。
  • internalなクラスに適用するためにフレンドアセンブリの指定が必要。

でした。

f:id:rimever:20191123180252p:plain

autofaccn.readthedocs.io

using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;

// internalなクラスにも適用出来るためフレンドアセンブリの指定が必要。
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<First>()
                .EnableClassInterceptors();
            builder.Register(c => new CallLogger(Console.Out));
            var container = builder.Build();
            using (var scope = container.BeginLifetimeScope())
            {
                var first = scope.Resolve<First>();
                first.GetValue();
                Console.WriteLine("Hello World!");
                
            }
        }
    }
    [Intercept(typeof(CallLogger))]
    internal class First
    {
        public virtual int GetValue()
        {
            return 5;
        }
    }

    public class CallLogger : IInterceptor
    {
        readonly TextWriter _output;

        public CallLogger(TextWriter output)
        {
            _output = output;
        }

        public void Intercept(IInvocation invocation)
        {
            _output.Write("Calling method {0} with parameters {1}... ",
                invocation.Method.Name,
                string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

            invocation.Proceed();

            _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
        }
    }
}
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.2</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Autofac.Extras.DynamicProxy" Version="4.5.0" />
      <PackageReference Include="Castle.Core" Version="4.4.0" />
    </ItemGroup>

</Project>

仕組みとしては、DIを解決して生成されたオブジェクトは、指定されたクラスの純粋のインスタンスではありません。

MethodIntercepterで指定されたメソッドを注入したオブジェクトになります。

f:id:rimever:20191123175742p:plain
FirstProxy

参考記事

stackoverflow.com