2
votes

I'm trying to use an Autofac module to inject NLog logger to asp.net Web Forms application (code behind) but i'm getting an error when trying to use a ResolvedParameter:

Global asax & Logging module:

public class Global : HttpApplication, IContainerProviderAccessor
{

    static IContainerProvider _containerProvider;
    public IContainerProvider ContainerProvider
    {
        get { return _containerProvider; }
    }

    void Application_Start(object sender, EventArgs e)
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<LoggingModule>();
        _containerProvider = new ContainerProvider(builder.Build());

    }
}

 public class LoggingModule : Module
 {
     protected override void Load(ContainerBuilder builder)
     {
         builder.Register(RegsiterFunc).AsImplementedInterfaces();
     }

     private NLogger RegsiterFunc(IComponentContext arg, IEnumerable<Parameter> parameters)
     {
         return new NLogger(parameters.TypedAs<Type>());
     }

    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        registration.Preparing +=
            (sender, args) =>
            {
                var forType = args.Component.Activator.LimitType;

                var logParameter = new ResolvedParameter(
                    (p, c) => p.ParameterType == typeof(ILogger),
                    (p, c) => c.Resolve<ILogger>(TypedParameter.From(forType)));

                 args.Parameters = args.Parameters.Union(new[] { logParameter });
            };
    }


}

NLogger class:

public class NLogger : ILogger
    {
        private readonly Logger m_Logger;

        public NLogger(Type type)
        {
            m_Logger = LogManager.GetLogger(type.FullName);
        }

        public NLogger(string typeName)
        {
            m_Logger = LogManager.GetLogger(typeName);
        }

    .......
}

Aspx page code behind:

public partial class _Default : Page
{
    public ILogger m_Logger { get; set; }
    protected void Page_Load(object sender, EventArgs e)
    {
        m_Logger.Error("test");
    }
}

To initiate the log based on the requesting type I'm using a ResolvedParameter.

The line parameters.TypedAs() in RegsiterFunc throws an exception: "Sequence contains no elements".

Same code works in asp.net MVC application but fails in the web forms project.

System.InvalidOperationException occurred HResult=0x80131509 Message=Sequence contains no elements Source=Autofac StackTrace: at Autofac.ParameterExtensions.ConstantValue[TParameter,TValue](IEnumerable`1 parameters, Func`2 predicate) at Autofac.ParameterExtensions.TypedAs[T](IEnumerable`1 parameters) at WebApplication1.LoggingModule.RegsiterFunc(IComponentContext arg, IEnumerable`1 parameters) in Global.asax.cs:line 55 at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass0_0`1.b__0(IComponentContext c, IEnumerable`1 p) at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)

1

1 Answers

2
votes

As far as I understand, in RegsiterFunc you are attempting to retrieve type of component the logger is being injected into.

But the parameter that carries component type is not a TypedParameter, but rather it's a NamedParameter. That's why you get the exception.

Though less elegant, but working version of RegsiterFunc:

private NLogger RegsiterFunc(IComponentContext arg, IEnumerable<Parameter> parameters)
{
    var type = (Type)((NamedParameter)parameters.First()).Value;
    return new NLogger(type);
}

Then for Default.aspx page, the type passed to NLogger will be ASP.default_aspx.

The second parameter you create:

new ResolvedParameter(
    (p, c) => p.ParameterType == typeof(ILogger),
    (p, c) => c.Resolve<ILogger>(TypedParameter.From(forType)));

is not in use, so that overriding AttachToComponentRegistration is unnecessary.