Метод c# цепочки для электронной почты


Я смотрел на вещи, как метод цепочки, Каскад-лямда-картина etc.

Я создал класс, который, кажется, работает нормально. Однако, я просто хотел подтвердить, если это лучший способ и правильный путь для реализации этой цели.

Для схемы каскада лямда-я не смог использовать действие в качестве параметра метода Send (). Я не мог понять, как его использовать.

Любые предложения приветствуются.

Вот код:

public class MailManager
{
    MailMessage _mail { get; set; }
    SmtpClient _smtp { get; set; }

    public MailManager()
    {
        _mail = new MailMessage();
        _smtp = new SmtpClient();
    }

    public MailManager To(string address)
    {
        _mail.From = new MailAddress(address);
        return this;
    }

    public MailManager From(string address)
    {
        _mail.To.Add(new MailAddress(address));
        return this;
    }

    public MailManager Subject(string subject)
    {
        _mail.Subject = subject;
        return this;
    }

    public MailManager Body(string body)
    {
        _mail.Body = body;
        return this;
    }

    public MailManager IsBodyHtml(bool isBodyHtml = true)
    {
        _mail.IsBodyHtml = isBodyHtml;
        return this;
    }

    public MailManager AlternateViews(AlternateView alternateView)
    {
        _mail.AlternateViews.Add(alternateView);
        return this;
    }

    public MailManager Host(string host)
    {
        _smtp.Host = host; return this;
    }

    public MailManager Port(int port)
    {
        _smtp.Port = port; return this;
    }

    public MailManager Credentials(NetworkCredential credentials)
    {
        _smtp.Credentials = credentials; return this;
    }

    public MailManager EnableSsl(bool enableSsl = true)
    {
        _smtp.EnableSsl = enableSsl; return this;
    }        

    public void Send()
    {
        using (_smtp)
        {
            _smtp.Send(_mail);
        }
    }
}

Это, как я использую это:

mailManager.From(_emailSettings.Email)
           .To(item.Email)
           .Subject(string.Format(_emailSettings.Subject, item.Name)).AlternateViews(htmlView)
           .Body(body).IsBodyHtml()
           .Host(_emailSettings.Domain)
           .Port(_emailSettings.Port)
           .Credentials(new NetworkCredential(_emailSettings.Email, _emailSettings.Password))
           .EnableSsl()
           .Send(); 


2148
14
задан 28 марта 2018 в 09:03 Источник Поделиться
Комментарии
6 ответов

Насколько цепочкой идет, это аккуратно выполнены.


Ты поменял местами В и с, метод имена инвертируются. Я предполагаю, что это просто опечатка.

public MailManager To(string address)
{
_mail.From = new MailAddress(address);
return this;
}

public MailManager From(string address)
{
_mail.To.Add(new MailAddress(address));
return this;
}


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

Это вопрос предпочтений, но в C# я был бы более склонны использовать публичные свойства в отличие от методов.
В прошлом, все мы были поля и методы. Когда крошечное количество логики была необходима, чтобы установить значение поля, нам пришлось полагаться на методы. Свойства были добавлены в качестве компромисса: они используются для установки значений полей, но вы можете добавить некоторые незначительные логики (в пределах разумного).

Простые строковые значения могут быть обработаны основные свойства:

public string Subject
{
get { return _mail.Subject; }
set { _mail.Subject = value; }
}

Примечание: в этом примере напрямую устанавливает значение _mail.Subject. Лично я предпочитаю не использовать _mail пока Send() был спровоцирован (и хранить значения в свойствах до тех пор), но это может быть слишком субъективны для обзора.

Вашего текущего To() способ несколько скрадывает тот факт, что вы можете добавить более одного получателя. Это не означает, что вы добавляете в список. Используя свойство, это немного легче понять:

public List<string> To { get; set; }

Вы можете бросить их в соответствующие MailAddress объект и добавить его в _mail внутри Send() метод:

_mail.To.AddRange(this.To.Select(s => new MailAddress(s));

Пример, как вы бы использовать свойство подхода:

var mailManager = new MailManager() {
From = _emailSettings.Email,
To = new List<string>() { item.Email },
Subject = string.Format(_emailSettings.Subject, item.Name),
Body = body,
IsBodyHtml = true,
Host = _emailSettings.Domain,
Port = _emailSettings.Port,
Credentials =new NetworkCredential(_emailSettings.Email, _emailSettings.Password),
EnableSsl = true
};

mailManager.Send();

Примечание: Вы можете также встроенной все, я.Е; (new MailManager() { ... }).Send();.

Примечание: Я установить значения свойств в инициализаторе собственность. Вы не обязаны это делать, вы также можете просто хранить MailManager в переменную и установить его свойства, когда вы хотите на более позднем этапе (но, очевидно, перед вызовом Send()).


Вы должны избегать цепочкой?
Нет. Ты хотел использовать его, и вы использовать его в хорошем смысле. Я просто пытаюсь предложить вам вариант, который требует меньше кода для достижения того же результата.

При реализации метода цепочки в класс, где есть много бизнес-логики имеет место, когда метод получает звонки, то способ сцепления становится наиболее предпочтительным.
Для текущего MailManager класс, я считаю, что это не хватает бизнес-логику, чтобы оправдать способ сцепления просто нет. Но это не особенно неправильно это делать, просто немного сложнее (на мой взгляд).


Некоторые незначительные что доставит некоторое неудобство:


  • Если вы собираетесь использовать метод цепочки, чтобы упростить синтаксис, представляется логичным изменить Credentials способ взять две строки (email,пароль) вместо NetworkCredentialили как минимум создать две перегруженные методы, чтобы позволить любой вариант. Credentials(_emailSettings.Email, _emailSettings.Password) это приятнее читать, чем Credentials(new NetworkCredential(_emailSettings.Email, _emailSettings.Password))

  • IsBodyHtml() на основе его имени, это должен быть метод, который возвращает логическое значение, а не логическое. Лучшее название будет SetBodyHtml()

  • AlternateViews(AlternateView alternateView) на самом деле должно называться AddAlternateView(AlternateView alternateView)

  • Аналогично, To на самом деле должны называться AddRecipientпоскольку вызов метода добавляет второе значение вместо перезаписи первое значение.


    • Я выбрал AddRecipient вместо AddTo чтобы избежать семантической путаницы между "добавить вполучателя" и "добавить к этому".


  • Я бы лично менять EnableSsl(bool enableSsl = true)хотя я вижу, почему вы использовали свои версии.


    • UseSsl(bool useSsl = true)

    • EnableSsl() и DisableSsl()


13
ответ дан 28 марта 2018 в 09:03 Источник Поделиться

Это выглядит подозрительно

public MailManager To(string address)
{
_mail.From = new MailAddress(address);
return this;
}

public MailManager From(string address)
{
_mail.To.Add(new MailAddress(address));
return this;
}

To добавление к From и Fromдобавление к To.


Вы не последовательны в ваш стиль кодирования. Что-то вроде _smtp.Credentials = credentials; return this; это большой нет-идти, потому что это уменьшает читаемость кода. Кроме того, вы использовать стиль такой

public MailManager AlternateViews(AlternateView alternateView)
{
_mail.AlternateViews.Add(alternateView);
return this;
}

как хорошо.


Хотя вы используете using С _smtp что обычно надо делать, то это создает необходимость, если другой почты должен быть отправлен, чтобы создать новый MailManager объект, потому что _smtp будут удаляться после отправки по почте.

6
ответ дан 28 марта 2018 в 09:03 Источник Поделиться

@Флатер и @Heslacher уже упоминалось большинство вопросов, поэтому я добавлю еще один комментарий...

Что вы реализовали очень похож на строителя образец и свободно интерфейс.

Однако в вашем случае это не очень полезно, потому что это на самом деле не добавить любой новый функционал, абстракций, а также не делает ничего проще. Он просто делегирует все вызовы фактическое базовых объектов.

Я тоже поддерживаю optinion, что это не правильно и что инициализатор объекта в этом случае достаточно.

Если бы вы ввели какие-либо абстракции для email-клиент или email-сообщения, то строитель может быть лучшим выбором, но не в этот раз.

6
ответ дан 28 марта 2018 в 10:03 Источник Поделиться

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

Если вы хотите написать модульные тесты, которые будут проверять ваши MailManager работает, как ожидалось, вы должны быть в состоянии издеваться над зависимостями класс тестируется зависит. Другими словами, например, вы не хотите, чтобы послать по электронной почте, так что вам нужно, чтобы поглумиться или использовать поддельные SMTP-клиент.

Для того, чтобы достичь этого, вы могли бы сделать что-то вроде:

public class MailManager
{
private readonly IMailMessage _mailMessage;
private readonly ISmtpClient _smtpClient;

public MailManager(IMailMessage mailMessage, ISmtpClient smtpClient)
{
_mailMessage = mailMessage;
_smtpClient = smtpClient;
}
...
}

А потом впрыскивают реализации требуется MailManager чтобы использовать.

5
ответ дан 28 марта 2018 в 12:03 Источник Поделиться

Было бы неплохо, если значений может быть передан в конструктор.

Зачем тебе { get; set; } на _mailMessage и _smtpClient.

Вы не тест для требуемых значений перед вызовом _smtp.Send(_mail);

0
ответ дан 28 марта 2018 в 05:03 Источник Поделиться

Похоже, у вас сложные вещи немного.


  1. Избегайте моделей, если функциональность может быть достигнута с помощью простых свойств, я думаю, использовать свободно шаблон интерфейса.

  2. MailManagaer должен реализовывать интерфейс IValidate, чтобы проверить правильность почты перед отправкой сообщения.

     public interface IValidate
    {
    bool IsValid();
    }

  3. MailManager должен интерфейс IMailManager для отправки сообщения

    public interface IMailManager
    {
    void Send()
    }

  4. Мы можем расширить функциональные возможности путем создания новых методов расширения на IMailManager

     public static class MailManagerExtensions
    {
    public static IMailManager Draft(this IMailManager mailManager, ....)
    {
    }
    }

  5. Создание перегруженных конструкторов для MailManager, и выставить свойства

     public MailManager(string fromAddress, List<string> toAddresses, string subject)
    public MailManager(string fromAddress, List<string> toAddresses, string subject, ....)

  6. Использование класса выглядит следующим образом

    IMailManager mailManager = new MailManager(.....);
    mailManager.send();

0
ответ дан 9 апреля 2018 в 10:04 Источник Поделиться