Внедрение модуля Autofac - строка подключения

Вступление: - Я новичок в программировании, и я много использовал инжекторы конструктора и заводской паттерн. Я впервые использую сторонний инструмент Autofac для DI. Я понимаю основы, но я ищу понимание по нескольким вещам, и я надеюсь, что вы можете помочь.

Настройка проекта: приложение N-Tier MVC (данные, модели, тесты, проекты пользовательского интерфейса)(NuGet Autofac и Autofac.MVC5 установлены только в проекте пользовательского интерфейса)

Вопрос: Должен ли Autofac быть установлен через NuGet в каждом проекте в моем приложении N-Tier MVC, или это просто в UI-проекте? Я экспериментирую с модулями и мне интересно, должен ли мой DataAccessModule быть помещен в мой проект данных против проекта пользовательского интерфейса.

Вопрос из нескольких частей: я пытаюсь вставить строку подключения в свой репозиторий, и я не уверен, правильно ли я это делаю. Репозитории регистрируются в зависимости от того, какое значение для RepositoryType установлено в моем файле Web.config. Я использую ADO и хранимые процедуры в моем примере. Читая об Autofac.Module, я подумал, что это будет путь.

AutofacConfig

public static class AutofacConfig
{
    public static void RegisterComponents()
    {
        //Autofac - install Autofac and Autofac.MVC5 via NuGet

        //Autofac: create the builder with which components/services are registered.
        var builder = new ContainerBuilder();

        //register all the components that we will use in our container
        //register HomeController as I only have one
        builder.RegisterType<HomeController>().InstancePerRequest();

        //register DataAccessModule
        builder.RegisterModule(new DataAccessModule
        {
            ConnectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString,
            RepositoryType = ConfigurationManager.AppSettings["RepositoryType"].ToString()
        });

        //builds our container
        var container = builder.Build();

        //let ASP.NET MVC know that it should locate services using the AutofacDependencyResolver. This is Autofac’s implementation of the IDependencyResolver interface.
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

}

DataAccessModule

public class DataAccessModule : Module
{
    public string ConnectionString { get; set; }
    public string RepositoryType { get; set; }

    protected override void Load(ContainerBuilder builder)
    {

        switch (RepositoryType)
        {
            case "ADO":
                builder.RegisterType<DirectorRepositoryADO>().As<IDirectorRepository>().WithParameter("connectionString",ConnectionString).InstancePerRequest();
                builder.RegisterType<DvdDirectorRepositoryADO>().As<IDvdDirectorRepository>().WithParameter("connectionString", ConnectionString).InstancePerRequest();
                builder.RegisterType<DvdRepositoryADO>().As<IDvdRepository>().WithParameter("connectionString", ConnectionString).InstancePerRequest();
                builder.RegisterType<RatingRepositoryADO>().As<IRatingRepository>().WithParameter("connectionString", ConnectionString).InstancePerRequest();
                break;
        }

    }

}

вместилище

public class RatingRepositoryADO : IRatingRepository
{
    private readonly string  _connectionString;

    public RatingRepositoryADO(string connectionString)
    {
        _connectionString = connectionString;
    }

    public IEnumerable<Rating> GetAll()
    {
        List<Rating> ratings = new List<Rating>();

        using (var cn = new SqlConnection(_connectionString))
        {
            SqlCommand cmd = new SqlCommand("RatingSelectAll", cn);
            cmd.CommandType = CommandType.StoredProcedure;

            cn.Open();

            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    Rating currentRow = new Rating();
                    currentRow.RatingId = (byte)dr["RatingId"];
                    currentRow.RatingName = dr["RatingName"].ToString();

                    ratings.Add(currentRow);
                }
            }
        }

        return ratings;
    }
}
  • Могу ли я узнать, как я реализовал мой модуль и передать строку подключения?
  • Должен ли я разделить свое соединение на отдельный класс, который реализует интерфейс с методом GetConnectionString, разрешить его и задать область экземпляра как единичный экземпляр вместо того, как он у меня?
  • Должны ли репозитории использовать InstancePerRequest или InstancePerLifetimeScope? Я видел оба в некоторых примерах, поэтому я просто хочу знать, что лучше использовать и почему / когда

Вопрос: Где бы я ни увидел ключевое слово "new" в своем проекте, стоит ли мне вводить эту зависимость? Например, в моем репозитории объекты SqlConnection или SqlCommand?

Буду очень признателен за любую помощь или руководство, которое вы можете предоставить. Я пытаюсь выполнить очень простой пример, чтобы лучше понять, как я могу настроить другие компоненты

Заранее спасибо!

1 ответ

Решение

Вам необходимо установить пакет Autofac в каждой сборке, где вы хотите настроить зависимости. Я рекомендую разместить DataBaseModule в сборку с репозиториями классов. Держите интерфейсы репозитория в некоторой сборке высокого уровня, такой как BusinessLayer, добавьте ссылку на нее из сборок DataLayer и UI и создайте классы репозиториев internal, Таким образом, вы можете скрыть свои реализации за абстракциями. Делать DatabaseModulepublicОн должен быть единственным, кто знает о внедрении репозиториев. Рассмотрим шаблон CompositionRoor и взглянем на Onion Architecture, чтобы понять всю идею.

Ваша инъекция строки подключения довольно хороша. Вы также можете инкапсулировать создание SqlConnection в заводском классе с соответствующим интерфейсом. А потом вводить IConnectionFactory в ваши репозитории и получить больше гибкости. Взгляните на Dapper по пути отображения данных из БД в объекты.

В то время как хранилища не сохраняют состояния (не содержат никаких изменяемых полей или свойств), используйте SingleInstance() политика вместо других. Ваши репозитории теперь не имеют состояния, сохраняют их без сохранения состояния.

Вам не нужно заменять каждый new оператор с шаблоном DI. Используйте его только для "нестабильных" зависимостей. Например, классы 'String' и 'Int32' стабильны как скала, вам не нужно избегать new оператор для них. В контексте вашего хранилища SqlCommand а также SqlDataReader стабильны Ты никогда не изменишься SqlCommand с MongoComman, но продолжай SqlDataReader как есть. Вы измените весь репозиторий, я полагаю. Учебный класс RatingRepositoryADO Это нестабильная зависимость для вашего приложения, поэтому вы прячете ее за интерфейс и внедряете в контроллеры. Взгляните на книгу Марка Симана для теории и лучших практик.

Надеюсь, поможет.

Другие вопросы по тегам