StructureMap предоставляет строковый параметр конструктору при запросе экземпляра

#c# #dependency-injection #inversion-of-control #instantiation #structuremap

#c# #внедрение зависимости #инверсия управления #создание экземпляра #structuremap

Вопрос:

Привет, в Autofac я могу это сделать:

 public class Service1_Client
{
    private const string ServiceName = "Service1";
    Func<string, RabitMqClient> _clientFunc;

    public Service1_Client(Func<string, RabitMqClient> clientFunc) 
    { 
         _clientFunc = clientFunc;
    }

    public IList<object> GetData()
    {
        return _clientFunc(this.ServiceName).Get<IList<object>>();               
    }
}

public class Service2_Client
{
    private const string ServiceName = "Service2";
    Func<string, RabitMqClient> _clientFunc;

    public Service2_Client(Func<string, RabitMqClient> clientFunc) 
    { 
         _clientFunc = clientFunc;
    }

    public IList<object> GetData()
    {
        return _clientFunc(this.ServiceName).Get<IList<object>>();               
    }
}

public class RabitMqClient
{
    private IConnectionFactory _connectionFactory;
    private string _baseServiceName;
    public RabitMqClient(IConnectionFactory connectionFactory, string baseServiceName)
    {
        _connectionFactory = connectionFactory;
        _baseServiceName = baseServiceName;
    }

    public TResult Get<TResult>()
    {
        string topicName = this.GetTopicName();
        ///Connect to the channel that uses the topic and ask for data...
    }

    private string GetTopicNAme()
    {
        /// this should be an algoritam for getting the topic from the speccified baseServiceName (I have omitted the details)
        return this._baseServiceName;
    }     
}
  

Теперь объяснение:
В принципе, у меня есть класс (RabitMqClient), который зависит от двух параметров:

  1. ConnectionFactory (IConnectionFactory )
  2. baseServiceName (строка)

Эти параметры используются для подключения к серверу RabbitMQ. Теперь я использую разделы в RabbitMQ для диверсификации сервисов, и для получения правильного раздела используется строковый параметр baseServiceName. Ожидается, что вызывающий объект (Service1_Client, Service2_Client) предоставит строковый параметр baseServiceName.

В Autofac я могу зарегистрировать этот класс следующим образом:

 builder.Register((context, parameters) =>
{
    var param = parameters.First() as Autofac.TypedParameter;
    return new HcRabbitMqClient(
        context.Resolve<IConnectionFactory>(),param.Value.ToString());
}).AsSelf().InstancePerDependency();
  

Это сообщает Autofac, что при запросе этого класса позвольте Autofac разрешить первый параметр, но вызывающий объект предоставит второй (строковый) параметр на сайте вызова. Затем этот строковый параметр будет помещен в значение параметров.
Использование этого можно увидеть в приведенном выше коде (Service1_Client, Service2_Client) Методы getData();

Как это сделать в StructureMap?

Комментарии:

1. Не могли бы вы немного подробнее рассказать о том, как это используется в вашем приложении с Autofac, пожалуйста?

Ответ №1:

Как насчет расширения этого заводского шаблона?

 public interface IRabitMqClientFactory
{
    IRabitMqClientFactory Create(string baseServiceName);
}

public class RabitMqClientFactory : IRabitMqClientFactory
{
    public RabitMqClientFactory(IConnectionFactory connectionFactory){
        _connectionFactory = connectionFactory;
    }

    public IRabitMqClientFactory Create(string baseServiceName)
    {
        _baseServiceName = baseServiceName;
    }
}
  

а затем просто

 public class Service1_Client
{
    private const string ServiceName = "Service1";
    private RabbitMqClient _rabbitMqClient;

    public Service1_Client(IRabitMqClientFactory rabitMqClientFactory) 
    { 
         _rabbitMqClient = rabitMqClientFactory.Create(ServiceName);
    }

    public IList<object> GetData()
    {
        return _rabbitMqClient.Get<IList<object>>();               
    }
}
  

это также немного более читабельно, чем наличие сложной логики внутри вашего IoC.

Комментарии:

1. Хорошо, это решение даже лучше, чем в моем примере. Спасибо

Ответ №2:

Попробуйте это
For<Func<string, RabitMqClient>>().Use(cstr => new RabitMqClient(cstr));

Комментарии:

1. Хорошо, это работает для 1 параметра, но что, если у меня их больше? ie. Func<строка,int,string,RabitMqClient>

2. Затем добавьте параметры, подобные этому For<Func<string, int, RabitMqClient>>().Use((cstr, int) => { return new RabitMqClient(cstr, int) });