Разрешить 2 свойства одного и того же типа в приложении «Внедрение свойств» Autofac / ASP.NET Webforms Application - PullRequest
0 голосов
/ 06 июня 2019

У меня есть класс BasePage с двумя свойствами одного и того же типа зависимости, и я не смог найти способ предоставить требуемые параметры с помощью Autofac

Я попытался зарегистрировать типы, и оба свойства BasePage теперь указываютк тому же последнему зарегистрированному компоненту, который является FaxSender, я добавил точку останова в функцию TryGetDeclaringProperty, и она отлично работает и проверяет имена свойств класса BasePage.

[ОБНОВЛЕНО Пример]

public class BasePage : System.Web.UI.Page
{
    public ISender EmailSender { get; set; }
    public ISender FaxSender { get; set; }
}

public class EmailSender : ISender
{
    private readonly SmtpClient _smtpClient;

    public EmailSender(SmtpClient smtpClient)
    {
        _smtpClient = smtpClient;
    }
    public void Send(INotification notification)
    {
        //...
    }
}

public class FaxSender : ISender
{
    private readonly SmtpClient _smtpClient;

    public FaxSender(SmtpClient smtpClient)
    {
        _smtpClient = smtpClient;
    }
    public void Send(INotification notification)
    {
        //...
    }
}

в Global.asax.cs

  var emailSmtp = new SmtpClient
        {
            ...
        };

        var emailSender = new EmailSender(emailSmtp);

        var faxSmtp = new SmtpClient
        {
            ...
        };

        var faxSender = new FaxSender(faxSmtp);

        var builder = new ContainerBuilder();

//--------------------------------
        builder.RegisterType<BasePage>()
            .WithProperties(new Parameter[]{
                new NamedPropertyParameter("EmailSender", emailSender),
                new NamedPropertyParameter("FaxSender", faxSender),
            });
 //--------------------------------  

    //OR

//--------------------------------

builder.RegisterType<EmailSender>()
            .Named<ISender>("email")
            .WithParameter("smtpClient", emailSmtp);
        builder.RegisterType<FaxSender>()
            .Named<ISender>("fax")
            .WithParameter("smtpClient", faxSmtp);

        builder.RegisterType<BasePage>()
            .AsSelf()
            .WithProperties(new Parameter[] {
                new ResolvedParameter(
                    (pi, c) => {
                        PropertyInfo ppi = null;
                        if (pi.TryGetDeclaringProperty(out ppi)) {
                            return ppi.Name == "EmailSender";
                        } else {
                            return false;
                        }
                    },
                    (pi, c) => c.ResolveNamed<ISender>("email")),
                new ResolvedParameter(
                    (pi, c) => {
                        PropertyInfo ppi = null;
                        if (pi.TryGetDeclaringProperty(out ppi)) {
                            return ppi.Name == "FaxSender";
                        } else {
                            return false;
                        }
                    },
                    (pi, c) => c.ResolveNamed<ISender>("fax"))
            });

//--------------------------------
//and then

        var container = builder.Build();

        _containerProvider = new ContainerProvider(container);

        using (var scope = container.BeginLifetimeScope())
        {
            scope.Resolve<BasePage>();
        }

в Default.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
    //Object reference not set to an instance of an object.  [Exception in both cases]
    EmailSender.Send(new EmailNotification(...);

    FaxSender.Send(new FaxNotification(...));
}

1 Ответ

0 голосов
/ 06 июня 2019

Из-за архитектуры веб-формы ASP.net Page экземпляры не создаются Autofac , вы не можете настроить регистрацию для экземпляра страницы.В этом случае метод WithProperty не будет использоваться.

В вашем случае одним из решений было бы вручную разрешить зависимость.

В вашем BasePage компоненте

public ISender EmailSender
{
    get
    {
        var cpa = (IContainerProviderAccessor)this.Context.ApplicationInstance;
        return cpa.ContainerProvider.RequestLifetime.ResolveNamed<ISender>("email");
    }
}

Другим решением будет использование IIndex<TKey, TValue>.Вместо двух свойств вы можете иметь только одно, содержащее все ваши ISender.

public IIndex<String, ISender> Senders {get; set; } 

И когда вам нужен определенный отправитель, вы можете получить к нему доступ через

ISender emailSender = this.Senders["email"]; 

Кстати, если вы хотите ожидаемое поведение, но для экземпляра, созданного Autofac Вы должны использовать NamedPropertyParameter вместо NamedParameter.

// not working for webform !!! 
builder.RegisterType<BasePage>()
       .WithProperties(new Parameter[]{
           new NamedPropertyParameter("X", emailSender),
           new NamedPropertyParameter("Y", faxSender),
       });

Если вы хотите получить значения с помощью внедрения зависимостей, простого способа сделать это не существует.

Autofac внутренне использует этот метод расширения:

public static class ParameterInfoExtensions
{
  public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
  {
    MethodInfo mi = pi.Member as MethodInfo;
    if (mi != (MethodInfo)null && mi.IsSpecialName 
        && mi.Name.StartsWith("set_", StringComparison.Ordinal) 
        && mi.DeclaringType != (Type)null)
    {
      prop = mi.DeclaringType.GetTypeInfo().GetDeclaredProperty(mi.Name.Substring(4));
      return true;
    }
    prop = null;
    return false;
  }
}

, и вы можете использовать его с ResolvedParameter следующим образом:

builder.RegisterType<EmailSender>() 
       .Named<ISender>("email")
       .WithParameter("smtpClient", emailSmtp);
builder.RegisterType<FaxSender>()
       .Named<ISender>("fax")
       .WithParameter("smtpClient", faxSmtp);

builder.RegisterType<BasePage>()
       .AsSelf()
       .WithProperties(new Parameter[] {
           new ResolvedParameter(
             (pi, c) => {
               PropertyInfo ppi = null;
               if (pi.TryGetDeclaringProperty(out ppi)) {
                 return ppi.Name == "SmtpClient";
               } else {
                 return false;
               }
             },
             (pi, c) => c.ResolveNamed<ISender>("email")),
           new ResolvedParameter(
             (pi, c) => {
               PropertyInfo ppi = null;
               if (pi.TryGetDeclaringProperty(out ppi)) {
                 return ppi.Name == "FaxClient";
               } else {
                 return false;
               }
           },
           (pi, c) => c.ResolveNamed<ISender>("fax"))
       });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...