Ваше определение прикладных услуг правильное. Я вижу службы приложений больше как обработчики команд. Получите команду, загрузите агрегат, вызовите метод агрегата и сохраните шанс. Одна команда обрабатывается в одной транзакции.
Доменные службы используются для выполнения чего-то, что необходимо агрегатам, но не может сделать. Типичными примерами могут быть получение дополнительной информации из внешнего мира или выполнение некоторых вычислений. Служба приложения не обязательно знает, понадобится ли агрегату та или иная информация, но она может разрешить необходимые зависимости и передать доменную службу агрегату при вызове.
В моей практике доменные службы чаще всего реализуются как функции. Помните, что доменные службы не используются исключительно агрегатами. Объекты со сложным значением могут отлично использовать доменные службы для той же цели.
В моей книге я использую доменную службу, чтобы разрешить объект значения , чтобы гарантировать, что он не будет создан с текстом, содержащим ненормативную лексику.
public static DisplayName FromString(
string displayName,
CheckTextForProfanity hasProfanity)
{
if (displayName.IsEmpty())
throw new ArgumentNullException(nameof(FullName));
if (hasProfanity(displayName).GetAwaiter().GetResult())
throw new DomainExceptions.ProfanityFound(displayName);
return new DisplayName(displayName);
}
Следовательно, в домене определен договор на обслуживание домена (в данном случае именованный делегат),
namespace Marketplace.Domain.Shared
{
public delegate Task<bool> CheckTextForProfanity(string text);
}
, но его реализация является проблемой инфраструктуры и осуществляется на стороне приложения.
namespace Marketplace.Infrastructure
{
/// <summary>
/// PurgoMalum is a simple, free, RESTful web service for filtering and removing content of profanity, obscenity and other unwanted text.
/// Check http://www.purgomalum.com
/// </summary>
public class PurgomalumClient
{
private readonly HttpClient _httpClient;
public PurgomalumClient() : this(new HttpClient()) { }
public PurgomalumClient(HttpClient httpClient) => _httpClient = httpClient;
public async Task<bool> CheckForProfanity(string text)
{
var result = await _httpClient.GetAsync(
QueryHelpers.AddQueryString("https://www.purgomalum.com/service/containsprofanity", "text", text));
var value = await result.Content.ReadAsStringAsync();
return bool.Parse(value);
}
}
}