是否可以在AUTOFAC的解决方案中获取请求服务类型?

发布于 2025-01-30 11:51:28 字数 1219 浏览 7 评论 0 原文

我正在使用 serilog autoFac 我想使用 ilogger 使用 .forcontext()在解决方案时,并用要注入的对象的类型 ilogger 。使用调试器,我可以走 icomponentContext ,看看我想要什么,但是要获得的类型都是内部的我的代码。我的注册代码(如上所述不起作用)看起来像:

builder.RegisterType<SerilogLoggerFactory>().As<ISerilogLoggerFactory>().SingleInstance();
builder.Register(context =>
{
    var defaultResolveRequestContext = (Autofac.Core.Resolving.Pipeline.DefaultResolveRequestContext)context;
    var resolveOperation = (Autofac.Core.Resolving.ResolveOperation)defaultResolveRequestContext.Operation;
    var initiatingRequestService = (Autofac.Core.TypedService)resolveOperation.InitiatingRequest.Service;
    return context.Resolve<ISerilogLoggerFactory>().Create().ForContext(initiatingRequestService.ServiceType);
});

defaultresolverequestcontext resolve> resolveOperation initiatingRequest aintiatingRequest 都是不可接受的。保护水平。

任何想法或想法都将不胜感激。

I'm using Serilog and Autofac and I would like to register an ILogger using .ForContext() at resolution time with the type of the object to be injected with the ILogger. Using the debugger, I can walk the IComponentContext and see what I want but the types to get to it are all internal so I can't (as far as I'm aware) actually get to it in my code. My registration code (which doesn't work as stated above) looks like this:

builder.RegisterType<SerilogLoggerFactory>().As<ISerilogLoggerFactory>().SingleInstance();
builder.Register(context =>
{
    var defaultResolveRequestContext = (Autofac.Core.Resolving.Pipeline.DefaultResolveRequestContext)context;
    var resolveOperation = (Autofac.Core.Resolving.ResolveOperation)defaultResolveRequestContext.Operation;
    var initiatingRequestService = (Autofac.Core.TypedService)resolveOperation.InitiatingRequest.Service;
    return context.Resolve<ISerilogLoggerFactory>().Create().ForContext(initiatingRequestService.ServiceType);
});

DefaultResolveRequestContext, ResolveOperation, and InitiatingRequest are all inaccessible due to their protection level.

Any thoughts or ideas would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

虐人心 2025-02-06 11:51:28

给定的目标是为给定的请求类型注入正确的 ilogger ,您可能需要查看寄存器 ilogger ,它将适当的参数添加到 resolve 链条中,以便将其正确设置。

Given the goal is to inject the right ILogger for a given requesting type, you may want to look at the log4net example in the documentation and adapt it. Basically, rather than trying to register the ILogger, it adds the appropriate parameter to the resolve chain so it'll be set up correctly.

思慕 2025-02-06 11:51:28

感谢@travis Illig的响应,我们创建了以下实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using Autofac.Core;
using Autofac.Core.Resolving.Pipeline;

using Serilog;

namespace YOUR_COMPANY_NAME.Core.Logging.Serilog;

/// <summary>
/// Injects resolved types with <see cref="ILogger.ForContext(Type)"/> for <see cref="ILogger"/>.
/// Supports both constructor and property injection.
/// Inspired by <see href="link">https://autofac.readthedocs.io/en/latest/examples/log4net.html</see>.
/// </summary>
public class AutofacSerilogMiddleware : IResolveMiddleware
{
    private readonly ILogger _rootLogger;
    private readonly Dictionary<Type, List<PropertyInfo>> _loggerPropertiesCache = new();

    public PipelinePhase Phase => PipelinePhase.ParameterSelection;

    public AutofacSerilogMiddleware(ILogger rootLogger)
    {
        _rootLogger = rootLogger;
    }

    public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
    {
        context.ChangeParameters(context.Parameters.Union(new[] { new ResolvedParameter((p, i) => p.ParameterType == typeof(ILogger), (p, i) => p.Member.DeclaringType != null ? _rootLogger.ForContext(p.Member.DeclaringType) : _rootLogger), }));

        // Continue the resolve.
        next(context);

        // Has an instance been activated?
        if (!context.NewInstanceActivated || context.Instance == null)
        {
            return;
        }

        var instanceType = context.Instance.GetType();

        if (!_loggerPropertiesCache.TryGetValue(instanceType, out var propertyInfos))
        {
            // Get all the injectable properties to set.
            propertyInfos = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.PropertyType == typeof(ILogger) && p.CanWrite && p.GetIndexParameters().Length == 0).ToList();

            _loggerPropertiesCache[instanceType] = propertyInfos;
        }

        if (!propertyInfos.Any())
        {
            return;
        }

        var contextLogger = _rootLogger.ForContext(instanceType);

        foreach (var propertyInfo in propertyInfos)
        {
            //Performance could be improved by generating and caching setter delegates instead of using PropertyInfo.SetValue
            propertyInfo.SetValue(context.Instance, contextLogger, null);
        }
    }
}

Thanks to @Travis Illig's response, we created the following implementation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using Autofac.Core;
using Autofac.Core.Resolving.Pipeline;

using Serilog;

namespace YOUR_COMPANY_NAME.Core.Logging.Serilog;

/// <summary>
/// Injects resolved types with <see cref="ILogger.ForContext(Type)"/> for <see cref="ILogger"/>.
/// Supports both constructor and property injection.
/// Inspired by <see href="link">https://autofac.readthedocs.io/en/latest/examples/log4net.html</see>.
/// </summary>
public class AutofacSerilogMiddleware : IResolveMiddleware
{
    private readonly ILogger _rootLogger;
    private readonly Dictionary<Type, List<PropertyInfo>> _loggerPropertiesCache = new();

    public PipelinePhase Phase => PipelinePhase.ParameterSelection;

    public AutofacSerilogMiddleware(ILogger rootLogger)
    {
        _rootLogger = rootLogger;
    }

    public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next)
    {
        context.ChangeParameters(context.Parameters.Union(new[] { new ResolvedParameter((p, i) => p.ParameterType == typeof(ILogger), (p, i) => p.Member.DeclaringType != null ? _rootLogger.ForContext(p.Member.DeclaringType) : _rootLogger), }));

        // Continue the resolve.
        next(context);

        // Has an instance been activated?
        if (!context.NewInstanceActivated || context.Instance == null)
        {
            return;
        }

        var instanceType = context.Instance.GetType();

        if (!_loggerPropertiesCache.TryGetValue(instanceType, out var propertyInfos))
        {
            // Get all the injectable properties to set.
            propertyInfos = instanceType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.PropertyType == typeof(ILogger) && p.CanWrite && p.GetIndexParameters().Length == 0).ToList();

            _loggerPropertiesCache[instanceType] = propertyInfos;
        }

        if (!propertyInfos.Any())
        {
            return;
        }

        var contextLogger = _rootLogger.ForContext(instanceType);

        foreach (var propertyInfo in propertyInfos)
        {
            //Performance could be improved by generating and caching setter delegates instead of using PropertyInfo.SetValue
            propertyInfo.SetValue(context.Instance, contextLogger, null);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文