0

У меня есть маленький проект где в коге есть зависимости которые надо убрать и добавить DI. Я впервые занимаюсь ASP.NET и тема DI мне даётся пока с трудом поэтому прошу помощи, я хочу понять как правильно писать DI

Вот весь код разделённый на несколько файлов cs Это HomeControllers в папке Controllers

using Microsoft.AspNetCore.Mvc;
using SampleAppPractice.Models;

namespace SampleAppPractice.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); }

    [HttpPost]
    public IActionResult Index(string message)
    {

        var messageFactory = new MessageFactory();
        var settings = new SmtpSettings()
        {
            Host = "smtp.example.com",
            Port = 25
        };
        var smtpClient = new SmtpClient(settings);
        var messanger = new Messanger(smtpClient, 

messageFactory);

        messanger.SendMessage(message, "admin@example.com");

        return View();
    }
}

}

Это уже 4 файла cs в папке Models

namespace SampleAppPractice.Models
{
    public class MessageFactory
    {
        internal SmtpMessage Create(string message)
        {
            return new SmtpMessage() { Body = message };
        }
    }
}

namespace SampleAppPractice.Models { public class Messanger { private readonly SmtpClient _client; private readonly MessageFactory _factory;

    public Messanger(SmtpClient client, MessageFactory factory)
    {
        _client = client;
        _factory = factory;
    }

    public void SendMessage(string message, string user)
    {
        SmtpMessage smtpMessage = _factory.Create(message);
        _client.Send(smtpMessage);
    }
}

}

using System.Diagnostics;

namespace SampleAppPractice.Models } public class SmtpClient { private readonly SmtpSettings _settings;

    public SmtpClient(SmtpSettings settings)
    {
        _settings = settings;
    }

    internal void Send(SmtpMessage smtpMessage)
    {
        Debug.WriteLine("Message sent by SmtpClient.");
    }
}

public class SmtpMessage
{
    public string Body { get; internal set; }
}

}

namespace SampleAppPractice.Models { public class SmtpSettings { public int Port { get; set; } public string Host { get; set; } } }

Ну а это просто Program.cs где происходит регистрация сервисов

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();

app.MapDefaultControllerRoute();

app.Run();

Мне дали задание убрать зависимости и добавить DI Где и как вообще выглядит зависимость я не понял на уроках. Какие именно строки означают зависимость? И как правильно сделать Dependency Injection здесь?

Изменения:

HomeController

namespace SampleAppPractice.Controllers
{
    public class HomeController : Controller
    {
        private readonly IMessageFactoryService 
_messageFactoryService;
        private readonly ISmtpClientService _smtpClientService;
        private readonly ISmtpSettingsService _smtpSettingsService;
   public HomeController(IMessageFactoryService 

messageFactoryService, ISmtpClientService smtpClientService, ISmtpSettingsService smtpSettingsService) { _messageFactoryService = messageFactoryService; _smtpClientService = smtpClientService; _smtpSettingsService = smtpSettingsService; }

//public IActionResult Index()
//{
//    return View();
//}

[HttpPost]
public IActionResult Index(string message)
{

    //var messageFactory = new MessageFactory();
    //var settings = new SmtpSettings()
    //{
    //    Host = "smtp.example.com",
    //    Port = 25
    //};
    //var smtpClient = new SmtpClient(settings);
    //var messanger = new Messanger(smtpClient, 

messageFactory); //messanger.SendMessage(message, "admin@example.com");

        _smtpSettingsService.Host = "smtp.example.com";
        _smtpSettingsService.Port = 25;
        var messanger = new Messanger(_smtpClientService, 

_messageFactoryService); messanger.SendMessage(message, "admin@example.com");

        return View();
    }
}

}

MessageFactory, Messanger, SmtpClient, SmtpSettings

namespace SampleAppPractice.Models
{
    public class MessageFactory : IMessageFactoryService
    {
        public SmtpMessage Create(string message)
        {
            return new SmtpMessage() { Body = message };
        }
    }
}

namespace SampleAppPractice.Models { public class Messanger { private readonly ISmtpClientService _client; private readonly IMessageFactoryService _factory;

    public Messanger(ISmtpClientService client, 
    IMessageFactoryService factory)
    {
        _client = client;
        _factory = factory;
    }

    public void SendMessage(string message, string user)
    {
        SmtpMessage smtpMessage = _factory.Create(message);
        _client.Send(smtpMessage);
    }
}

}

namespace SampleAppPractice.Models { public class SmtpClient : ISmtpClientService { private readonly SmtpSettings _settings;

    public SmtpClient(SmtpSettings settings)
    {
        _settings = settings;
    }

    public void Send(SmtpMessage smtpMessage)
    {
        Debug.WriteLine("Message sent by SmtpClient.");
    }
}

public class SmtpMessage
{
    public string Body { get; internal set; }
}

}

namespace SampleAppPractice.Models { public class SmtpSettings : ISmtpSettingsService { public int Port { get; set; } public string Host { get; set; } } }

И папка Services которую я добавил и добавил в него 3 интерфейса

namespace SampleAppPractice.Services
{
    public interface IMessageFactoryService
    {
        SmtpMessage Create(string message);
    }
}

namespace SampleAppPractice.Services { public interface ISmtpClientService { void Send(SmtpMessage smtpMessage); } }

namespace SampleAppPractice.Services { public interface ISmtpSettingsService { public int Port { get; set; } public string Host { get; set; } } }

Ну и зарегистрировал всё в builder.Services в классе Program

using SampleAppPractice.Models;

using SampleAppPractice.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
builder.Services.AddSingleton<IMessageFactoryService, MessageFactory>();
builder.Services.AddSingleton<ISmtpClientService, SmtpClient>();
builder.Services.AddSingleton<ISmtpSettingsService, SmtpSettings>();

app.MapDefaultControllerRoute();

app.Run();

Укажите пожалуйста где я ошибся, что я добавил не правильно или где что я забыл. Повторяюсь, я впервые делаю проект с ASP.NET и хочу научиться всё писать правильно. Что мне делать дальше? Что писать? Что изменить и исправить?

  • Прочитайте часть этого ответа, со строк Что такое сервис:, думаю сразу поймете что от вас хотят. Если коротко, то вы делаете var messageFactory = new MessageFactory();, то есть ваш контроллер зависит от класса MessageFactory, без его логики он работать не будет. Чтоб это избежать, вы должны создать интерфейс, в котором лишь объявите метод, условный Create(), фабрику унаследовать от него, и уже в контроллере через конструктор просить этот интерфейс, это называется "IoC". – EvgeniyZ Jun 19 '23 at 11:30
  • Хороший способ понять и освоить DI - начать писать модульные тесты. Если тест не получается написать, значит наверняка этому мешает зависимость. Выносим её - становится возможно написать тест - DI внедрён! – Alexander Petrov Jun 19 '23 at 11:51
  • Я прочитал но всё равно не понял что мне писать. Я создал папку Services, добавил туда 3 интерфейса IMessageFactory, ISmtpClient, ISmtpSettings а дальше что? Я даже их зарегистрировал в Program.cs Что мне дальше писать? Я вроде код в классах изменил, почему он не хочет запускаться? – Avatar Killer Jun 19 '23 at 15:59
  • Я вроде код в классах изменил - такое надо добавлять в вопрос (кнопка "править" под ним), мы не видим что вы там сделали и как. Если все правильно зарегистрировали, то теперь просто просите нужный объект через конструктор так, как у вас сделано например в Messanger, только уже интерфейсы нужные просите, и у контроллера. – EvgeniyZ Jun 19 '23 at 17:51
  • Добавил изменения. Все до единого. – Avatar Killer Jun 20 '23 at 10:21
  • builder.Build(); после всех регистраций. А так, более конкретно говорите, что за ошибки у вас возникают. – EvgeniyZ Jun 20 '23 at 10:49
  • Программа не запускается. Пишет Cannot modify ServiceCollection after application is built и указывает на регистрацию сервисов – Avatar Killer Jun 20 '23 at 11:09
  • Ну тогда да, что я вам сказал выше сделайте, и будет счастье. Вы добавляете зависимости после того, как уже собрали контейнер, когда как зависимости регистрируются только раз, при старте проекта, до билда контейнера. – EvgeniyZ Jun 20 '23 at 11:31
  • Сделал! Но теперь он пишет так "Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: SampleAppPractice.Services.ISmtpClientService Lifetime: Singleton ImplementationType: SampleAppPractice.Models.SmtpClient': Unable to resolve service for type 'SampleAppPractice.Models.SmtpSettings' while attempting to activate 'SampleAppPractice.Models.SmtpClient'.)" – Avatar Killer Jun 20 '23 at 11:41
  • 2
    public SmtpClient(SmtpSettings settings) -> public SmtpClient(ISmtpSettingsService settings). Вы регистрируете связь между интерфейсом и классом, а не сам класс, но просите внутри именно сами классы, когда должны интерфейсы. Если вам такое не подходит, то регистрируйте конкретные типы, без указания интерфейса. – EvgeniyZ Jun 20 '23 at 12:39
  • О спасибо большое, наконец заработало. Вот только страница открывается и пишет "сейчас эта страница не работает" – Avatar Killer Jun 20 '23 at 12:56
  • А всё, заработал. Я просто закоментировал public IActionResult Index(). Открыл его и заработало. Ещё раз спасибо, немножко разобрался в ASP.NET – Avatar Killer Jun 20 '23 at 13:14

0 Answers0