Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f074048
Issue/736 add more warnings as errors (#11)
MartinHock Jun 9, 2026
dc9e756
Merge branch 'main' of https://github.com/MartinHock/CleanArchitecture
MartinHock Jun 18, 2026
d59828c
Ignore .localpilot/ directory in .gitignore
MartinHock Jun 25, 2026
ee1da7d
Add SQLitePCLRaw.bundle_e_sqlite3 to package management
MartinHock Jun 25, 2026
4bcbe37
Merge branch 'ardalis:main' into main
MartinHock Jul 13, 2026
b6ce984
Update dependabot.yml
MartinHock Jul 16, 2026
a9d99d4
deps: Bump the microsoft-packages group with 6 updates (#23)
dependabot[bot] Jul 16, 2026
b958086
deps: Bump coverlet.collector from 10.0.0 to 10.0.1 (#29)
dependabot[bot] Jul 16, 2026
3432773
deps: Bump FastEndpoints and 8 others (#32)
dependabot[bot] Jul 16, 2026
4ab4eec
deps: Bump NSubstitute from 5.3.0 to 6.0.0 (#31)
dependabot[bot] Jul 16, 2026
940a91f
deps: Bump the all-other-non-major group with 10 updates (#30)
dependabot[bot] Jul 16, 2026
53f0bcf
fixed sqlite securityy problem
MartinHock Jul 16, 2026
622ba21
Aspire.Hosting.AppHost" Version="13.4.5" />
MartinHock Jul 16, 2026
864411e
deps: Bump NSubstitute from 5.3.0 to 6.0.0 (#35)
dependabot[bot] Jul 16, 2026
34a735a
deps: Bump the microsoft-packages group with 8 updates (#33)
dependabot[bot] Jul 16, 2026
0866c7a
deps: Bump the all-other-non-major group with 4 updates (#34)
dependabot[bot] Jul 16, 2026
b647753
Fix duplicate central package versions
MartinHock Jul 16, 2026
1699802
deps: Bump the all-other-non-major group with 5 updates (#37)
dependabot[bot] Jul 18, 2026
9f6f2c6
deps: Bump the microsoft-packages group with 1 update (#36)
dependabot[bot] Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,19 @@ csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent

dotnet_diagnostic.CA1707.severity = none

dotnet_diagnostic.CA1014.severity = none
// CA1848: Use 'LoggerMessage.Define' instead of 'LoggerMessage.Define<T>'
// DO not force Logger Massages Delegates all everywhere
dotnet_diagnostic.CA1848.severity= none
# Avoid forcing LoggerMessage-style logging everywhere in this template/sample repository.
dotnet_diagnostic.CA1873.severity = none

###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
57 changes: 52 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,54 @@
version: 2

updates:
- package-ecosystem: nuget
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: "nuget"
directory: "/"

schedule:
interval: "daily"
time: "16:45"
timezone: "Europe/Berlin"


open-pull-requests-limit: 10

groups:
microsoft-packages:
patterns:
- "Microsoft.*"
update-types:
- "minor"
- "patch"

test-packages:
patterns:
- "Microsoft.NET.Test.Sdk"
- "xunit*"
- "NUnit*"
- "coverlet*"
- "FluentAssertions"
update-types:
- "minor"
- "patch"

all-other-non-major:
patterns:
- "*"
exclude-patterns:
- "Microsoft.*"
- "Microsoft.NET.Test.Sdk"
- "xunit*"
- "NUnit*"
- "coverlet*"
- "FluentAssertions"
update-types:
- "minor"
- "patch"

commit-message:
prefix: "deps"
include: "scope"

labels:
- "dependencies"
- "nuget"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ bld/
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Local SonarQube Scanner working directory
.sonarqube/

# Visual Studio local workspace state
.vs/
# Hugo generated site output
docs/public/

Expand Down Expand Up @@ -271,3 +275,4 @@ Packages.props
#Local Log Files
log*.txt
/sample/src/NimblePros.SampleToDo.Web/appsettings.Development.json
.localpilot/
3 changes: 3 additions & 0 deletions Clean.Architecture.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
</Configurations>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path=".gitignore" />
<File Path=".template.config/template.json" />
<File Path="CleanArchitecture.nuspec" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
</Folder>
<Folder Name="/src/">
<File Path=".editorconfig" />
<Project Path="src/Clean.Architecture.Core/Clean.Architecture.Core.csproj" />
<Project Path="src/Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj" />
<Project Path="src/Clean.Architecture.UseCases/Clean.Architecture.UseCases.csproj" />
Expand All @@ -22,6 +24,7 @@
<Project Path="src/Clean.Architecture.ServiceDefaults/Clean.Architecture.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/tests/">
<File Path="tests/.editorconfig" />
<Project Path="tests/Clean.Architecture.FunctionalTests/Clean.Architecture.FunctionalTests.csproj">
<BuildDependency Project="src/Clean.Architecture.Web/Clean.Architecture.Web.csproj" />
</Project>
Expand Down
3 changes: 3 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>Recommended</AnalysisMode>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
59 changes: 30 additions & 29 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,48 @@
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="9.3.1" />
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
<PackageVersion Include="coverlet.collector" Version="10.0.0" />
<PackageVersion Include="FastEndpoints" Version="8.1.0" />
<PackageVersion Include="FastEndpoints" Version="8.2.0" />
<PackageVersion Include="FastEndpoints.ApiExplorer" Version="2.2.0" />
<PackageVersion Include="FastEndpoints.Swagger" Version="8.1.0" />
<PackageVersion Include="FastEndpoints.Swagger" Version="8.2.0" />
<PackageVersion Include="MailKit" Version="4.17.0" />
<PackageVersion Include="MessagePack" Version="3.1.7" />
<PackageVersion Include="MessagePack" Version="3.1.8" />
<PackageVersion Include="Mediator.Abstractions" Version="3.0.2" />
<PackageVersion Include="Mediator.SourceGenerator" Version="3.0.2" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.10" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
<PackageVersion Include="NimblePros.Metronome" Version="0.4.1" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="ReportGenerator" Version="5.5.9" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.16.4" />
<PackageVersion Include="NSubstitute" Version="6.0.0" />
<PackageVersion Include="ReportGenerator" Version="5.5.10" />
<PackageVersion Include="Scalar.AspNetCore" Version="2.16.15" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="SQLite" Version="3.13.0" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="Testcontainers" Version="4.11.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.11.0" />
<PackageVersion Include="Testcontainers" Version="4.13.0" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.13.0" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="13.3.5" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.5.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.16.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="13.4.6" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.17.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.8.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.8.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.17.0" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="9.5.1" />
<PackageVersion Include="Vogen" Version="8.0.5" />
<PackageVersion Include="Vogen" Version="8.0.6" />
</ItemGroup>
</Project>
</Project>
5 changes: 3 additions & 2 deletions sample/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.2.0" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="SQLite" Version="3.13.0" />
<PackageVersion Include="SQLitePCLRaw.lib.e_sqlite3" Version="3.53.3" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="Testcontainers" Version="4.11.0" />
<PackageVersion Include="Vogen" Version="8.0.5" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.2.3" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.4.5" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.5.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
Expand All @@ -60,4 +61,4 @@
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="9.0.0" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="NimblePros.Metronome" />
<PackageReference Include="SQLite" />
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" />
<PackageReference Include="Vogen" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class ContributorDeletedHandler(ILogger<ContributorDeletedHandler> logger
{
public async ValueTask Handle(ContributorDeletedEvent domainEvent, CancellationToken cancellationToken)
{
logger.LogInformation("Handling Contributed Deleted event for {contributorId}", domainEvent.ContributorId);
logger.LogInformation("Handling Contributed Deleted event for {ContributorId}", domainEvent.ContributorId);

await emailSender.SendEmailAsync("to@test.com",
"from@test.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class ContributorNameUpdatedEmailNotificationHandler(
{
public async ValueTask Handle(ContributorNameUpdatedEvent domainEvent, CancellationToken cancellationToken)
{
logger.LogInformation("Handling Contributor Name Updated event for {contributorId}", domainEvent.Contributor.Id);
logger.LogInformation("Handling Contributor Name Updated event for {ContributorId}", domainEvent.Contributor.Id);

await emailSender.SendEmailAsync("to@test.com",
"from@test.com",
Expand Down
2 changes: 1 addition & 1 deletion src/Clean.Architecture.Core/Interfaces/IEmailSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public interface IEmailSender
{
Task SendEmailAsync(string to, string from, string subject, string body);
Task SendEmailAsync(string recipientEmail, string senderEmail, string subject, string body);
}
34 changes: 26 additions & 8 deletions src/Clean.Architecture.Core/Services/DeleteContributorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,41 @@
namespace Clean.Architecture.Core.Services;

/// <summary>
/// This is here mainly so there's an example of a domain service
/// This service is here mainly so there's an example of a domain service
/// and also to demonstrate how to fire domain events from a service.
/// </summary>
/// <param name="_repository"></param>
/// <param name="_mediator"></param>
/// <param name="_logger"></param>
public class DeleteContributorService(IRepository<Contributor> _repository,
IMediator _mediator,
ILogger<DeleteContributorService> _logger) : IDeleteContributorService
/// <remarks>
/// The logging call intentionally uses a precompiled <see cref="LoggerMessage" /> delegate.
/// This avoids analyzer warning CA1848 and demonstrates the recommended high-performance
/// logging pattern without using <c>LoggerExtensions.LogInformation</c> directly.
/// </remarks>
/// <param name="repository">The repository used to load and delete contributors.</param>
/// <param name="mediator">The mediator used to publish domain events.</param>
/// <param name="logger">The logger used by the service.</param>
public class DeleteContributorService(
IRepository<Contributor> repository,
IMediator mediator,
ILogger<DeleteContributorService> logger) : IDeleteContributorService
{
private static readonly Action<ILogger, ContributorId, Exception?> LogDeletingContributor =
LoggerMessage.Define<ContributorId>(
LogLevel.Information,
new EventId(1, nameof(DeleteContributor)),
"Deleting Contributor {ContributorId}");

private readonly IRepository<Contributor> _repository = repository;
private readonly IMediator _mediator = mediator;
private readonly ILogger<DeleteContributorService> _logger = logger;

public async ValueTask<Result> DeleteContributor(ContributorId contributorId)
{
_logger.LogInformation("Deleting Contributor {contributorId}", contributorId);
LogDeletingContributor(_logger, contributorId, null);

Contributor? aggregateToDelete = await _repository.GetByIdAsync(contributorId);
if (aggregateToDelete == null) return Result.NotFound();

await _repository.DeleteAsync(aggregateToDelete);

var domainEvent = new ContributorDeletedEvent(contributorId);
await _mediator.Publish(domainEvent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public static class DataSchemaConstants
{
public const int DEFAULT_NAME_LENGTH = 100;
public const int DefaultNameLength = 100;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ namespace Clean.Architecture.Infrastructure.Data.Config;

[EfCoreConverter<ContributorId>]
[EfCoreConverter<ContributorName>]
internal partial class VogenEfCoreConverters;
internal sealed partial class VogenEfCoreConverters;
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEvent
// Retrieve all tracked entities that have domain events
var entitiesWithEvents = appDbContext.ChangeTracker.Entries<HasDomainEventsBase>()
.Select(e => e.Entity)
.Where(e => e.DomainEvents.Any())
.Where(e => e.DomainEvents.Count != 0)
.ToArray();

// Dispatch and clear domain events
Expand Down
4 changes: 2 additions & 2 deletions src/Clean.Architecture.Infrastructure/Data/SeedData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Clean.Architecture.Infrastructure.Data;

public static class SeedData
{
public const int NUMBER_OF_CONTRIBUTORS = 27; // including the 2 below
public const int NumberOfContributors = 27; // including the 2 below
public static readonly ContributorName Contributor1Name = ContributorName.From("Ardalis");
public static readonly ContributorName Contributor2Name = ContributorName.From("Ilyana");

Expand All @@ -22,7 +22,7 @@ public static async Task PopulateTestDataAsync(AppDbContext dbContext)
await dbContext.Database.ExecuteSqlInterpolatedAsync($"INSERT INTO [Contributors] ([Name], [Status]) VALUES ({Contributor2Name.Value}, {ContributorStatus.NotSet.Value})");

// Add a bunch more contributors to support demonstrating paging.
for (int i = 1; i <= NUMBER_OF_CONTRIBUTORS - 2; i++)
for (int i = 1; i <= NumberOfContributors - 2; i++)
{
await dbContext.Database.ExecuteSqlInterpolatedAsync($"INSERT INTO [Contributors] ([Name], [Status]) VALUES ({$"Contributor {i}"}, {ContributorStatus.NotSet.Value})");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ namespace Clean.Architecture.Infrastructure.Email;
public class FakeEmailSender(ILogger<FakeEmailSender> logger) : IEmailSender
{
private readonly ILogger<FakeEmailSender> _logger = logger;
public Task SendEmailAsync(string to, string from, string subject, string body)
public Task SendEmailAsync(string recipientEmail, string senderEmail, string subject, string body)
{
_logger.LogInformation("Not actually sending an email to {to} from {from} with subject {subject}", to, from, subject);
_logger.LogInformation("Not actually sending an email to {To} from {From} with subject {Subject}", recipientEmail, senderEmail, subject);
return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ public class MimeKitEmailSender(ILogger<MimeKitEmailSender> logger,
private readonly ILogger<MimeKitEmailSender> _logger = logger;
private readonly MailserverConfiguration _mailserverConfiguration = mailserverOptions.Value!;

public async Task SendEmailAsync(string to, string from, string subject, string body)
public async Task SendEmailAsync(string recipientEmail, string senderEmail, string subject, string body)
{
_logger.LogWarning("Sending email to {to} from {from} with subject {subject} using {type}.", to, from, subject, this.ToString());
_logger.LogWarning("Sending email to {To} from {From} with subject {Subject} using {Type}.", recipientEmail, senderEmail, subject, this.ToString());

using var client = new MailKit.Net.Smtp.SmtpClient();
await client.ConnectAsync(_mailserverConfiguration.Hostname,
using var client = new MailKit.Net.Smtp.SmtpClient();
await client.ConnectAsync(_mailserverConfiguration.Hostname,
_mailserverConfiguration.Port, false);
var message = new MimeMessage();
message.From.Add(new MailboxAddress(from, from));
message.To.Add(new MailboxAddress(to, to));
message.From.Add(new MailboxAddress(senderEmail, senderEmail));
message.To.Add(new MailboxAddress(recipientEmail, recipientEmail));
message.Subject = subject;
message.Body = new TextPart("plain") { Text = body };

await client.SendAsync(message);

await client.DisconnectAsync(true,
await client.DisconnectAsync(true,
new CancellationToken(canceled: true));
}
}
Loading
Loading