Skip to content

Commit 3b7ef2b

Browse files
Add the UseRazorEmailTemplates() extension method.
1 parent 04c77b6 commit 3b7ef2b

File tree

7 files changed

+146
-41
lines changed

7 files changed

+146
-41
lines changed

src/Emailing.Azure/AzureEmailingBuilderExtensions.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ public static class AzureEmailingBuilderExtensions
2525
/// <param name="builder"><see cref="EmailingBuilder"/> which to configure.</param>
2626
/// <param name="uri">Uri to the the <c>Azure Communication Service</c> instance.</param>
2727
/// <param name="clientBuilder">Allows to configure the <see cref="EmailClient"/> used by the provider.</param>
28+
/// <returns>The <paramref name="builder"/> instance to continue the configuration of the emailing feature.</returns>
2829
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="builder"/> argument is <see langword="null"/>.</exception>
2930
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="uri"/> argument is <see langword="null"/>.</exception>
30-
public static void UseAzureCommunicationService(this EmailingBuilder builder, Uri uri, Action<IAzureClientBuilder<EmailClient, EmailClientOptions>>? clientBuilder = null)
31+
public static EmailingBuilder UseAzureCommunicationService(this EmailingBuilder builder, Uri uri, Action<IAzureClientBuilder<EmailClient, EmailClientOptions>>? clientBuilder = null)
3132
{
3233
ArgumentNullException.ThrowIfNull(builder);
3334
ArgumentNullException.ThrowIfNull(uri);
@@ -43,6 +44,8 @@ public static void UseAzureCommunicationService(this EmailingBuilder builder, Ur
4344
clientBuilder(emailClientBuilder);
4445
}
4546
});
47+
48+
return builder;
4649
}
4750

4851
/// <summary>
@@ -51,9 +54,10 @@ public static void UseAzureCommunicationService(this EmailingBuilder builder, Ur
5154
/// <param name="builder"><see cref="EmailingBuilder"/> which to configure.</param>
5255
/// <param name="connectionString">Connection string to the <c>Azure Communication Service</c> instance.</param>
5356
/// <param name="clientBuilder">Allows to configure the <see cref="EmailClient"/> used by the provider.</param>
57+
/// <returns>The <paramref name="builder"/> instance to continue the configuration of the emailing feature.</returns>
5458
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="builder"/> argument is <see langword="null"/>.</exception>
5559
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="connectionString"/> argument is <see langword="null"/>.</exception>
56-
public static void UseAzureCommunicationService(this EmailingBuilder builder, string connectionString, Action<IAzureClientBuilder<EmailClient, EmailClientOptions>>? clientBuilder = null)
60+
public static EmailingBuilder UseAzureCommunicationService(this EmailingBuilder builder, string connectionString, Action<IAzureClientBuilder<EmailClient, EmailClientOptions>>? clientBuilder = null)
5761
{
5862
ArgumentNullException.ThrowIfNull(builder);
5963
ArgumentNullException.ThrowIfNull(connectionString);
@@ -69,6 +73,8 @@ public static void UseAzureCommunicationService(this EmailingBuilder builder, st
6973
clientBuilder(emailClientBuilder);
7074
}
7175
});
76+
77+
return builder;
7278
}
7379
}
7480
}

src/Emailing.Graph/GraphEmailingBuilderExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ public static class GraphEmailingBuilderExtensions
2424
/// <param name="builder"><see cref="EmailingBuilder"/> which to configure.</param>
2525
/// <param name="tokenCredential">The <see cref="TokenCredential"/> for authenticating to Microsoft Graph API.</param>
2626
/// <param name="baseUrl">The base service URL of the API Graph. If not specified the <c>https://graph.microsoft.com/v1.0</c> will be use.</param>
27+
/// <returns>The <paramref name="builder"/> instance to continue the configuration of the emailing feature.</returns>
2728
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="builder"/> argument is <see langword="null"/>.</exception>
2829
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="tokenCredential"/> argument is <see langword="null"/>.</exception>
29-
public static void UseGraph(this EmailingBuilder builder, TokenCredential tokenCredential, string? baseUrl = null)
30+
public static EmailingBuilder UseGraph(this EmailingBuilder builder, TokenCredential tokenCredential, string? baseUrl = null)
3031
{
3132
ArgumentNullException.ThrowIfNull(builder);
3233
ArgumentNullException.ThrowIfNull(tokenCredential);
@@ -37,6 +38,8 @@ public static void UseGraph(this EmailingBuilder builder, TokenCredential tokenC
3738

3839
return new GraphEmailProvider(serviceClient);
3940
});
41+
42+
return builder;
4043
}
4144
}
4245
}

src/Emailing.Templates.Razor/README.md

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ provides helpers to create `EmailTemplate<TModel>` instances using Razor compone
1010

1111
It is built on top of:
1212

13-
- [PosInformatique.Foundations.Emailing](https://www.nuget.org/packages/PosInformatique.Foundations.Emailing.Templates.Razor/)
14-
- [PosInformatique.Foundations.Text.Templates.Razor](https://www.nuget.org/packages/PosInformatique.Foundations.Emailing.Templates.Razor/)
13+
- [PosInformatique.Foundations.Emailing](https://www.nuget.org/packages/PosInformatique.Foundations.Emailing/)
14+
- [PosInformatique.Foundations.Text.Templates.Razor](https://www.nuget.org/packages/PosInformatique.Foundations.Text.Templating.Razor/)
1515

1616
This allows you to design your email content with Blazor-style Razor components, benefiting from layout reuse, strongly-typed models, and familiar Razor syntax.
1717

@@ -33,10 +33,30 @@ You also need a Blazor-compatible environment for compiling/executing Razor comp
3333
- `RazorEmailTemplateBody<TModel>` for email HTML body.
3434
- Strongly-typed model support via the `Model` parameter.
3535
- Supports Razor layout features for the email body (reuse consistent layout across multiple templates).
36+
- `UseRazorEmailTemplates()` extension method to enable Razor-based email templates in the emailing configuration.
3637

37-
## Creating Razor components for subject and body
38+
## Configuring emailing with Razor email templates
3839

39-
### 1. Define the email model
40+
### 1. Configure emailing services
41+
42+
Use `AddEmailing(...)` and then `UseRazorEmailTemplates()`.
43+
44+
```csharp
45+
using Microsoft.Extensions.DependencyInjection;
46+
47+
var services = new ServiceCollection();
48+
49+
var emailingBuilder = services.AddEmailing(options =>
50+
{
51+
// Configure emailing options here and register the templates
52+
})
53+
UseRazorEmailTemplates();.
54+
```
55+
56+
- `AddEmailing(...)` registers the core emailing services and the templates.
57+
- `UseRazorEmailTemplates()` enables Razor-based text templating for emailing.
58+
59+
### 2. Define the email model
4060

4161
Example model used by the templates:
4262

@@ -50,7 +70,7 @@ public sealed class InvitationEmailTemplateModel
5070
}
5171
```
5272

53-
### 2. Subject component
73+
### 3. Subject component
5474

5575
Create a Razor component for the subject that inherits from `RazorEmailTemplateSubject<TModel>` and uses the `Model` parameter.
5676

@@ -69,7 +89,7 @@ This component:
6989
- Renders a single line of text.
7090
- Uses the strongly-typed `Model` to build the subject.
7191

72-
### 3. Body component with layout
92+
### 4. Body component with layout
7393

7494
You can define a layout component that centralizes common HTML structure (header, footer, styles, etc.),
7595
then reuse it across different email bodies.
@@ -85,33 +105,33 @@ then reuse it across different email bodies.
85105
<meta charset="utf-8" />
86106
<title>@Title</title>
87107
<style>
88-
body {
89-
font-family: Arial, sans-serif;
90-
font-size: 14px;
91-
}
92-
93-
.email-container {
94-
max-width: 600px;
95-
margin: 0 auto;
96-
}
97-
98-
.email-header {
99-
background-color: #1f2937;
100-
color: #ffffff;
101-
padding: 16px;
102-
font-size: 18px;
103-
font-weight: bold;
104-
}
105-
106-
.email-content {
107-
padding: 16px;
108-
}
109-
110-
.email-footer {
111-
padding: 16px;
112-
font-size: 12px;
113-
color: #6b7280;
114-
}
108+
body {
109+
font-family: Arial, sans-serif;
110+
font-size: 14px;
111+
}
112+
113+
.email-container {
114+
max-width: 600px;
115+
margin: 0 auto;
116+
}
117+
118+
.email-header {
119+
background-color: #1f2937;
120+
color: #ffffff;
121+
padding: 16px;
122+
font-size: 18px;
123+
font-weight: bold;
124+
}
125+
126+
.email-content {
127+
padding: 16px;
128+
}
129+
130+
.email-footer {
131+
padding: 16px;
132+
font-size: 12px;
133+
color: #6b7280;
134+
}
115135
</style>
116136
</head>
117137
<body>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="RazorEmailTemplateServiceCollectionExtensions.cs" company="P.O.S Informatique">
3+
// Copyright (c) P.O.S Informatique. All rights reserved.
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
namespace Microsoft.Extensions.DependencyInjection
8+
{
9+
/// <summary>
10+
/// Extension methods to configure the Email templates based on Razor components.
11+
/// </summary>
12+
public static class RazorEmailTemplateServiceCollectionExtensions
13+
{
14+
/// <summary>
15+
/// Adds Razor text templating support to the emailing services.
16+
/// </summary>
17+
/// <param name="builder"><see cref="EmailingBuilder"/> to configure.</param>
18+
/// <returns>The <paramref name="builder"/> instance to continue the configuration of the emailing service.</returns>
19+
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="builder"/> argument is <see langword="null"/>.</exception>
20+
public static EmailingBuilder UseRazorEmailTemplates(this EmailingBuilder builder)
21+
{
22+
ArgumentNullException.ThrowIfNull(builder);
23+
24+
builder.Services.AddRazorTextTemplating();
25+
26+
return builder;
27+
}
28+
}
29+
}

tests/Emailing.Azure.Tests/AzureEmailingBuilderExtensionsTest.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public void UseAzureCommunicationService_WithConnectionString()
1818
var serviceCollection = new ServiceCollection();
1919
var builder = new EmailingBuilder(serviceCollection);
2020

21-
builder.UseAzureCommunicationService("endpoint=https://my-acs-resource.communication.azure.com/;accesskey=2x3Yz==");
21+
builder.UseAzureCommunicationService("endpoint=https://my-acs-resource.communication.azure.com/;accesskey=2x3Yz==")
22+
.Should().BeSameAs(builder);
2223

2324
var sp = builder.Services.BuildServiceProvider();
2425

@@ -44,7 +45,8 @@ public void UseAzureCommunicationService_WithConnectionString_WithClientBuilder(
4445
builder.UseAzureCommunicationService("endpoint=https://my-acs-resource.communication.azure.com/;accesskey=2x3Yz==", clientBuilder =>
4546
{
4647
clientBuilderCalled = true;
47-
});
48+
})
49+
.Should().BeSameAs(builder);
4850

4951
var sp = builder.Services.BuildServiceProvider();
5052

@@ -93,7 +95,8 @@ public void UseAzureCommunicationService_WithUri()
9395
var serviceCollection = new ServiceCollection();
9496
var builder = new EmailingBuilder(serviceCollection);
9597

96-
builder.UseAzureCommunicationService(new Uri("https://my-acs-resource.communication.azure.com/"));
98+
builder.UseAzureCommunicationService(new Uri("https://my-acs-resource.communication.azure.com/"))
99+
.Should().BeSameAs(builder);
97100

98101
var sp = builder.Services.BuildServiceProvider();
99102

@@ -119,7 +122,8 @@ public void UseAzureCommunicationService_WithUri_WithClientBuilder()
119122
builder.UseAzureCommunicationService(new Uri("https://my-acs-resource.communication.azure.com/"), clientBuilder =>
120123
{
121124
clientBuilderCalled = true;
122-
});
125+
})
126+
.Should().BeSameAs(builder);
123127

124128
var sp = builder.Services.BuildServiceProvider();
125129

tests/Emailing.Graph.Tests/GraphBuilderExtensionsTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ public void UseGraph(string baseUrl, string expectedBaseUrl)
2424

2525
var credential = Mock.Of<TokenCredential>(MockBehavior.Strict);
2626

27-
builder.UseGraph(credential, baseUrl);
27+
builder.UseGraph(credential, baseUrl)
28+
.Should().BeSameAs(builder);
2829

2930
var sp = builder.Services.BuildServiceProvider();
3031

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="RazorEmailTemplateServiceCollectionExtensionsTest.cs" company="P.O.S Informatique">
3+
// Copyright (c) P.O.S Informatique. All rights reserved.
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
namespace Microsoft.Extensions.DependencyInjection.Tests
8+
{
9+
using Microsoft.Extensions.Logging;
10+
11+
public class RazorEmailTemplateServiceCollectionExtensionsTest
12+
{
13+
private static readonly Type IRazorTextTemplateRendererInterface = Type.GetType("PosInformatique.Foundations.Text.Templating.Razor.IRazorTextTemplateRenderer, PosInformatique.Foundations.Text.Templating.Razor");
14+
private static readonly Type RazorTextTemplateRendererClass = Type.GetType("PosInformatique.Foundations.Text.Templating.Razor.RazorTextTemplateRenderer, PosInformatique.Foundations.Text.Templating.Razor");
15+
16+
[Fact]
17+
public void UseRazorEmailTemplates()
18+
{
19+
var serviceCollection = new ServiceCollection();
20+
var emailingBuilder = new EmailingBuilder(serviceCollection);
21+
22+
emailingBuilder.UseRazorEmailTemplates().Should().BeSameAs(emailingBuilder);
23+
24+
var sp = serviceCollection.BuildServiceProvider();
25+
26+
sp.GetRequiredService(IRazorTextTemplateRendererInterface).Should().BeOfType(RazorTextTemplateRendererClass);
27+
sp.GetRequiredService<ILogger<string>>().Should().NotBeNull();
28+
}
29+
30+
[Fact]
31+
public void UseRazorEmailTemplates_WithBuilderArgumentNull()
32+
{
33+
var act = () =>
34+
{
35+
RazorEmailTemplateServiceCollectionExtensions.UseRazorEmailTemplates(null);
36+
};
37+
38+
act.Should().ThrowExactly<ArgumentNullException>()
39+
.WithParameterName("builder");
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)