diff --git a/src/Postal.AspNetCore/Email.cs b/src/Postal.AspNetCore/Email.cs
index 646ae74..79baa2c 100644
--- a/src/Postal.AspNetCore/Email.cs
+++ b/src/Postal.AspNetCore/Email.cs
@@ -2,11 +2,13 @@
using System.Collections.Generic;
using System.Dynamic;
using System.Net.Mail;
+using System.Runtime.Serialization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Routing;
using Postal.AspNetCore;
namespace Postal
@@ -17,6 +19,7 @@ namespace Postal
/// ViewBag property of a Controller. Any dynamic property access is mapped to the
/// view data dictionary.
///
+ [DataContract]
public class Email : DynamicObject, IViewData
{
/// Create an Email where the ViewName is derived from the name of the class.
@@ -25,9 +28,8 @@ protected Email()
{
Attachments = new List();
ViewName = DeriveViewNameFromClassName();
- ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
- ViewData.Model = this;
- ImageEmbedder = new ImageEmbedder();
+ ViewData = new Dictionary();
+ RequestPath = new RequestPath();
}
///
@@ -38,16 +40,10 @@ protected Email()
{
}
- public Email(string viewName, IModelMetadataProvider modelMetadataProvider)
+ public Email(string viewName, IModelMetadataProvider modelMetadataProvider): this()
{
if (viewName == null) throw new ArgumentNullException(nameof(viewName));
if (string.IsNullOrWhiteSpace(viewName)) throw new ArgumentException("View name cannot be empty.", "viewName");
-
- Attachments = new List();
- ViewName = viewName;
- ViewData = new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary());
- ViewData.Model = this;
- ImageEmbedder = new ImageEmbedder();
}
///
@@ -63,24 +59,29 @@ public Email(string viewName, string areaName, IModelMetadataProvider modelMetad
///
/// The name of the view containing the email template.
///
+ [DataMember]
public string ViewName { get; set; }
///
/// The name of the area containing the email template.
///
- public string AreaName { get; set; }
+ [DataMember]
+ public string? AreaName { get; set; }
///
/// The view data to pass to the view.
///
- public ViewDataDictionary ViewData { get; set; }
+ [DataMember]
+ public Dictionary ViewData { get; set; }
///
/// The attachments to send with the email.
///
+ [DataMember]
public List Attachments { get; set; }
- internal ImageEmbedder ImageEmbedder { get; private set; }
+ [DataMember]
+ public RequestPath RequestPath { get; set; }
///
/// Adds an attachment to the email.
@@ -132,16 +133,13 @@ string DeriveViewNameFromClassName()
return viewName;
}
- public RequestPath RequestPath { get; set; }
- internal HttpContextData HttpContextData { get; private set; }
public void CaptureHttpContext(HttpContext httpContext)
{
- var endpoint = httpContext.GetEndpoint();
var routeValues = httpContext.Features.Get()?.RouteValues;
- HttpContextData = new HttpContextData { Endpoint = endpoint, RouteValues = routeValues };
RequestPath = new RequestPath();
+ RequestPath.Path = httpContext.Request.Path.ToString();
RequestPath.PathBase = httpContext.Request.PathBase.ToString();
RequestPath.Host = httpContext.Request.Host.ToString();
RequestPath.IsHttps = httpContext.Request.IsHttps;
diff --git a/src/Postal.AspNetCore/EmailParser.cs b/src/Postal.AspNetCore/EmailParser.cs
index bc1006c..a44aca0 100644
--- a/src/Postal.AspNetCore/EmailParser.cs
+++ b/src/Postal.AspNetCore/EmailParser.cs
@@ -32,14 +32,14 @@ public EmailParser(IEmailViewRender alternativeViewRenderer)
/// The email view output.
/// The used to generate the output.
/// A containing the email headers and content.
- public async Task ParseAsync(string emailViewOutput, Email email)
+ public async Task ParseAsync(string emailViewOutput, Email email, ImageEmbedder? imageEmbedder = null)
{
var message = new MailMessage();
- await InitializeMailMessageAsync(message, emailViewOutput, email);
+ await InitializeMailMessageAsync(message, emailViewOutput, email, imageEmbedder);
return message;
}
- private async Task InitializeMailMessageAsync(MailMessage message, string emailViewOutput, Email email)
+ private async Task InitializeMailMessageAsync(MailMessage message, string emailViewOutput, Email email, ImageEmbedder? imageEmbedder = null)
{
if (string.IsNullOrWhiteSpace(emailViewOutput))
{
@@ -47,15 +47,15 @@ private async Task InitializeMailMessageAsync(MailMessage message, string emailV
}
using (var reader = new StringReader(emailViewOutput))
{
- await ParserUtils.ParseHeadersAsync(reader, (key, value) => ProcessHeaderAsync(key, value, message, email));
+ await ParserUtils.ParseHeadersAsync(reader, (key, value) => ProcessHeaderAsync(key, value, message, email, imageEmbedder));
AssignCommonHeaders(message, email);
if (message.AlternateViews.Count == 0)
{
var messageBody = reader.ReadToEnd().Trim();
- if (email.ImageEmbedder.HasImages)
+ if (imageEmbedder != null && imageEmbedder.HasImages)
{
var view = AlternateView.CreateAlternateViewFromString(messageBody, new ContentType("text/html"));
- email.ImageEmbedder.AddImagesToView(view);
+ imageEmbedder.AddImagesToView(view);
message.AlternateViews.Add(view);
message.Body = "Plain text not available.";
message.IsBodyHtml = false;
@@ -112,19 +112,29 @@ private void AssignCommonHeaders(MailMessage message, Email email)
private void AssignCommonHeader(Email email, string header, Action assign)
where T : class
{
- object value;
+ object? value;
if (email.ViewData.TryGetValue(header, out value))
{
- var typedValue = value as T;
- if (typedValue != null) assign(typedValue);
+ if (value is T typedValue)
+ {
+ assign(typedValue);
+ return;
+ }
+ }
+ var foundKV = email.ViewData.Where(x => String.Equals(x.Key, header, StringComparison.OrdinalIgnoreCase) && x.Value is T typedValue);
+ if (foundKV.Any())
+ {
+ var val = foundKV.First();
+ assign((T)val.Value);
+ return;
}
}
- private async Task ProcessHeaderAsync(string key, string value, MailMessage message, Email email)
+ private async Task ProcessHeaderAsync(string key, string value, MailMessage message, Email email, ImageEmbedder? imageEmbedder)
{
if (IsAlternativeViewsHeader(key))
{
- foreach (var view in CreateAlternativeViews(value, email))
+ foreach (var view in CreateAlternativeViews(value, email, imageEmbedder))
{
message.AlternateViews.Add(await view);
}
@@ -135,17 +145,17 @@ private async Task ProcessHeaderAsync(string key, string value, MailMessage mess
}
}
- private IEnumerable> CreateAlternativeViews(string deliminatedViewNames, Email email)
+ private IEnumerable> CreateAlternativeViews(string deliminatedViewNames, Email email, ImageEmbedder? imageEmbedder)
{
var viewNames = deliminatedViewNames.Split(new[] { ',', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries);
- return viewNames.Select(v => CreateAlternativeView(email, v)).ToList();
+ return viewNames.Select(v => CreateAlternativeView(email, v, imageEmbedder)).ToList();
}
- private async Task CreateAlternativeView(Email email, string alternativeViewName)
+ private async Task CreateAlternativeView(Email email, string alternativeViewName, ImageEmbedder? imageEmbedder)
{
var fullViewName = GetAlternativeViewName(email, alternativeViewName);
- var output = await alternativeViewRenderer.RenderAsync(email, fullViewName);
- string contentType;
+ var output = await alternativeViewRenderer.RenderAsync(email, fullViewName, imageEmbedder);
+ string? contentType;
string body;
using (var reader = new StringReader(output))
{
@@ -179,7 +189,10 @@ private async Task CreateAlternativeView(Email email, string alte
// A different charset can be specified in the Content-Type header.
// e.g. Content-Type: text/html; charset=utf-8
}
- email.ImageEmbedder.AddImagesToView(alternativeView);
+ if (imageEmbedder != null)
+ {
+ imageEmbedder.AddImagesToView(alternativeView);
+ }
return alternativeView;
}
@@ -206,9 +219,9 @@ private MemoryStream CreateStreamOfBody(string body)
return stream;
}
- private string ParseHeadersForContentType(StringReader reader)
+ private string? ParseHeadersForContentType(StringReader reader)
{
- string contentType = null;
+ string? contentType = null;
ParserUtils.ParseHeaders(reader, (key, value) =>
{
if (key.Equals("content-type", StringComparison.OrdinalIgnoreCase))
diff --git a/src/Postal.AspNetCore/EmailService.cs b/src/Postal.AspNetCore/EmailService.cs
index 5c3e0b8..97752ed 100644
--- a/src/Postal.AspNetCore/EmailService.cs
+++ b/src/Postal.AspNetCore/EmailService.cs
@@ -15,18 +15,6 @@ namespace Postal
///
public class EmailService : IEmailService
{
- /// Creates a new , using the given view engines.
- [Obsolete]
- public static EmailService Create(IServiceProvider serviceProvider, Func createSmtpClient = null)
- {
- var emailViewRender = serviceProvider.GetRequiredService();
- var emailParser = serviceProvider.GetRequiredService();
- var options = Options.Create(new EmailServiceOptions() { CreateSmtpClient = createSmtpClient });
- var loggerFactory = serviceProvider.GetRequiredService();
- var logger = loggerFactory.CreateLogger();
- return new EmailService(emailViewRender, emailParser, options, logger);
- }
-
///
/// Creates a new .
///
@@ -101,13 +89,19 @@ public async Task SendAsync(MailMessage mailMessage)
/// A containing the rendered email.
public async Task CreateMailMessageAsync(Email email)
{
- var rawEmailString = await emailViewRenderer.RenderAsync(email);
+ var imageEmbedder = new ImageEmbedder();
+ var rawEmailString = await emailViewRenderer.RenderAsync(email, null, imageEmbedder);
emailParser = new EmailParser(emailViewRenderer);
- var mailMessage = await emailParser.ParseAsync(rawEmailString, email);
+ var mailMessage = await emailParser.ParseAsync(rawEmailString, email, imageEmbedder);
if ((mailMessage.From == null || mailMessage.From.Address == null) && this.options.FromAddress != null)
{
mailMessage.From = new MailAddress(this.options.FromAddress);
}
+ mailMessage.BodyTransferEncoding = System.Net.Mime.TransferEncoding.Base64;
+ if (options.BodyTransferEncoding != null)
+ {
+ mailMessage.BodyTransferEncoding = (System.Net.Mime.TransferEncoding)options.BodyTransferEncoding;
+ }
return mailMessage;
}
}
diff --git a/src/Postal.AspNetCore/EmailViewRender.cs b/src/Postal.AspNetCore/EmailViewRender.cs
index 7789b05..59b2444 100644
--- a/src/Postal.AspNetCore/EmailViewRender.cs
+++ b/src/Postal.AspNetCore/EmailViewRender.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.Extensions.Options;
using Postal.AspNetCore;
namespace Postal
@@ -17,10 +18,13 @@ public class EmailViewRender : IEmailViewRender
/// Creates a new that uses the given view engines.
///
/// The view engines to use when rendering email views.
- public EmailViewRender(ITemplateService templateService)
+ public EmailViewRender(
+ ITemplateService templateService,
+ IOptions options
+ )
{
_templateService = templateService;
- EmailViewDirectoryName = "Emails";
+ _emailViewDirectoryName = options?.Value?.EmailViewsDirectory ?? "Emails";
}
readonly ITemplateService _templateService;
@@ -29,7 +33,7 @@ public EmailViewRender(ITemplateService templateService)
/// The name of the directory in "Views" that contains the email views.
/// By default, this is "Emails".
///
- public string EmailViewDirectoryName { get; set; }
+ private string _emailViewDirectoryName;
///
/// Renders an email view.
@@ -38,7 +42,8 @@ public EmailViewRender(ITemplateService templateService)
/// The rendered email view output.
public virtual Task RenderAsync(Email email)
{
- return RenderAsync(email, null);
+ var imageEmbedder = new ImageEmbedder();
+ return RenderAsync(email, null, imageEmbedder);
}
///
@@ -47,22 +52,35 @@ public virtual Task RenderAsync(Email email)
/// The email to render.
/// Optional email view name override. If null then the email's ViewName property is used instead.
/// The rendered email view output.
- public virtual async Task RenderAsync(Email email, string viewName = null)
+ public virtual Task RenderAsync(Email email, string? viewName)
+ {
+ var imageEmbedder = new ImageEmbedder();
+ return RenderAsync(email, viewName, imageEmbedder);
+ }
+
+ ///
+ /// Renders an email view.
+ ///
+ /// The email to render.
+ /// Optional email view name override. If null then the email's ViewName property is used instead.
+ /// Optional ImageEmbedder. If null then the email cannot be generated with Image.
+ /// The rendered email view output.
+ public virtual async Task RenderAsync(Email email, string? viewName = null, ImageEmbedder? imageEmbedder = null)
{
viewName = viewName ?? email.ViewName;
var routeData = new Microsoft.AspNetCore.Routing.RouteData();
- routeData.Values["controller"] = EmailViewDirectoryName;
- routeData.Values["page"] = EmailViewDirectoryName;
+ routeData.Values["controller"] = _emailViewDirectoryName;
+ routeData.Values["page"] = _emailViewDirectoryName;
if (!string.IsNullOrWhiteSpace(email.AreaName))
{
routeData.Values["area"] = email.AreaName;
routeData.DataTokens["area"] = email.AreaName;
}
- Dictionary viewData = new Dictionary();
- viewData[ImageEmbedder.ViewDataKey] = email.ImageEmbedder;
- var viewOutput = await _templateService.RenderTemplateAsync(email.HttpContextData, routeData, viewName, email, viewData, true);
+ Dictionary viewData = new Dictionary();
+ viewData[ImageEmbedder.ViewDataKey] = imageEmbedder;
+ var viewOutput = await _templateService.RenderTemplateAsync(routeData, viewName, email, viewData, true);
viewData.Remove(ImageEmbedder.ViewDataKey);
return viewOutput;
}
diff --git a/src/Postal.AspNetCore/HttpContextData.cs b/src/Postal.AspNetCore/HttpContextData.cs
deleted file mode 100644
index 61e2aa4..0000000
--- a/src/Postal.AspNetCore/HttpContextData.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Routing;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Postal.AspNetCore
-{
- public class HttpContextData
- {
- public Endpoint Endpoint { get; internal set; }
- public RouteValueDictionary RouteValues { get; internal set; }
- }
-}
diff --git a/src/Postal.AspNetCore/InternalClass/EndpointFeature.cs b/src/Postal.AspNetCore/InternalClass/EndpointFeature.cs
deleted file mode 100644
index f2740a5..0000000
--- a/src/Postal.AspNetCore/InternalClass/EndpointFeature.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.AspNetCore.Http.Features;
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Postal.AspNetCore.InternalClass
-{
- internal sealed class EndpointFeature : IEndpointFeature
- {
- public Endpoint Endpoint { get; set; }
-
- public EndpointFeature(Endpoint endpoint)
- {
- Endpoint = endpoint;
- }
- }
-}
diff --git a/src/Postal.AspNetCore/TemplateServices/TemplateService.cs b/src/Postal.AspNetCore/TemplateServices/TemplateService.cs
index dbf0882..958493c 100644
--- a/src/Postal.AspNetCore/TemplateServices/TemplateService.cs
+++ b/src/Postal.AspNetCore/TemplateServices/TemplateService.cs
@@ -3,13 +3,15 @@
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
+using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.Logging;
-using Postal.AspNetCore.InternalClass;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -19,7 +21,7 @@
namespace Postal.AspNetCore
{
- public class TemplateService : ITemplateService
+ public partial class TemplateService : ITemplateService
{
public static readonly string ViewExtension = ".cshtml";
@@ -31,6 +33,8 @@ public class TemplateService : ITemplateService
private readonly IRazorPageActivator _pageActivator;
private readonly System.Text.Encodings.Web.HtmlEncoder _htmlEncoder;
private readonly DiagnosticListener _diagnosticListener;
+ private readonly IUrlHelperFactory _urlHelperFactory;
+
public TemplateService(
ILogger logger,
@@ -40,7 +44,8 @@ public TemplateService(
ITempDataProvider tempDataProvider,
Microsoft.Extensions.Hosting.IHostEnvironment hostingEnvironment,
System.Text.Encodings.Web.HtmlEncoder htmlEncoder,
- DiagnosticListener diagnosticListener
+ DiagnosticListener diagnosticListener,
+ IUrlHelperFactory urlHelperFactory
)
{
_logger = logger;
@@ -51,55 +56,63 @@ DiagnosticListener diagnosticListener
_pageActivator = pageActivator;
_htmlEncoder = htmlEncoder;
_diagnosticListener = diagnosticListener;
+ _urlHelperFactory = urlHelperFactory;
}
- public async Task RenderTemplateAsync(HttpContextData httpContextData, RouteData routeData,
- string viewName, TViewModel viewModel, Dictionary additonalViewDictionary = null, bool isMainPage = true) where TViewModel : IViewData
+ [LoggerMessage(
+ EventId = 1,
+ Level = LogLevel.Debug,
+ Message = "RequestPath != null\nRequestPath:{requestPath}\nHttpRequest:{request}")]
+ public partial void LogRequestPath(RequestPath requestPath, HttpRequest request);
+
+ [LoggerMessage(
+ EventId = 2,
+ Level = LogLevel.Debug,
+ Message = "_hostingEnvironment is {type} -> GetView from {property}: {value}")]
+ public partial void LogHostEnvironment(string type, string property, string value);
+
+ public async Task RenderTemplateAsync(RouteData routeData,
+ string viewName, TViewModel viewModel, Dictionary? additonalViewDictionary = null, bool isMainPage = true) where TViewModel : IViewData
{
var httpContext = new DefaultHttpContext()
{
RequestServices = _serviceProvider,
};
- if (httpContextData != null)
- {
- httpContext.Features.Set(new EndpointFeature(httpContextData.Endpoint));
- httpContext.Features.Set(new RouteValuesFeature() { RouteValues = httpContextData.RouteValues });
- }
if (viewModel.RequestPath != null)
{
httpContext.Request.Host = HostString.FromUriComponent(viewModel.RequestPath.Host);
httpContext.Request.Scheme = viewModel.RequestPath.Scheme;
+ httpContext.Request.Path = viewModel.RequestPath.Path != null ? PathString.FromUriComponent(viewModel.RequestPath.Path) : null;
httpContext.Request.PathBase = PathString.FromUriComponent(viewModel.RequestPath.PathBase);
- _logger.LogDebug($"RequestPath != null");
- _logger.LogTrace($"\tHost: {viewModel.RequestPath.Host} -> {httpContext.Request.Host}");
- _logger.LogTrace($"\tScheme: {viewModel.RequestPath.Scheme}");
- _logger.LogTrace($"\tPathBase: {viewModel.RequestPath.PathBase} -> {httpContext.Request.PathBase}");
+ this.LogRequestPath(viewModel.RequestPath, httpContext.Request);
}
var actionDescriptor = new ActionDescriptor
{
- RouteValues = routeData.Values.ToDictionary(kv => kv.Key, kv => kv.Value.ToString())
+ RouteValues = routeData.Values.ToDictionary(kv => kv.Key, kv => kv.Value!.ToString())
};
+ httpContext.SetEndpoint(new Endpoint(r => Task.CompletedTask, null, null));
var actionContext = new ActionContext(httpContext, routeData, actionDescriptor);
+ this._urlHelperFactory.GetUrlHelper(actionContext);
using (var outputWriter = new StringWriter())
{
- Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult viewResult = null;
+ Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult? viewResult = null;
RazorPageResult? razorPageResult = null;
if (IsApplicationRelativePath(viewName) || IsRelativePath(viewName))
{
_logger.LogDebug($"Relative path");
if (_hostingEnvironment is Microsoft.AspNetCore.Hosting.IWebHostEnvironment webHostEnvironment)
{
- _logger.LogDebug($"_hostingEnvironment is IWebHostEnvironment -> GetView from WebRootPath: {webHostEnvironment.WebRootPath}");
+ this.LogHostEnvironment("IWebHostEnvironment", "WebRootPath", webHostEnvironment.WebRootPath);
viewResult = _viewEngine.GetView(webHostEnvironment.WebRootPath, viewName, isMainPage);
}
else
{
- _logger.LogDebug($"_hostingEnvironment is IHostEnvironment -> GetView from ContentRootPath: {_hostingEnvironment.ContentRootPath}");
+ this.LogHostEnvironment("IHostEnvironment", "ContentRootPath", _hostingEnvironment.ContentRootPath);
viewResult = _viewEngine.GetView(_hostingEnvironment.ContentRootPath, viewName, isMainPage);
}
}
@@ -107,10 +120,27 @@ public async Task RenderTemplateAsync(HttpContextData httpCo
{
_logger.LogDebug($"Not a relative path");
viewResult = _viewEngine.FindView(actionContext, viewName, isMainPage);
- razorPageResult = _viewEngine.FindPage(actionContext, viewName);
+ }
+ razorPageResult = _viewEngine.FindPage(actionContext, viewName);
+
+ if ((viewResult == null || !viewResult.Success) && (razorPageResult == null || (razorPageResult != null && razorPageResult?.Page == null)))
+ {
+ var searchedLocations = viewResult?.SearchedLocations ?? [];
+ if (razorPageResult != null && razorPageResult?.SearchedLocations != null)
+ {
+ searchedLocations = searchedLocations.Union(razorPageResult?.SearchedLocations!);
+ }
+ _logger.LogError($"Failed to render template {viewName} because it was not found. \r\nThe following locations are searched: \r\n{string.Join("\r\n", searchedLocations)}");
+ throw new TemplateServiceException($"Failed to render template {viewName} because it was not found. \r\nThe following locations are searched: \r\n{string.Join("\r\n", searchedLocations)}");
}
- var viewDictionary = new ViewDataDictionary(viewModel.ViewData, viewModel);
+ var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
+ foreach (var kv in viewModel.ViewData)
+ {
+ viewDictionary.Add(kv.Key, kv.Value);
+ }
+ viewDictionary.Model = viewModel;
+
if (additonalViewDictionary != null)
{
_logger.LogDebug($"additonalViewDictionary count: {additonalViewDictionary.Count}");
@@ -129,20 +159,9 @@ public async Task RenderTemplateAsync(HttpContextData httpCo
var tempDataDictionary = new TempDataDictionary(httpContext, _tempDataProvider);
- if (!viewResult.Success && (razorPageResult == null || (razorPageResult != null && razorPageResult?.Page == null)))
- {
- var searchedLocations = viewResult.SearchedLocations;
- if (razorPageResult?.SearchedLocations != null)
- {
- searchedLocations = viewResult.SearchedLocations.Union(razorPageResult?.SearchedLocations);
- }
- _logger.LogError($"Failed to render template {viewName} because it was not found. \r\nThe following locations are searched: \r\n{string.Join("\r\n", searchedLocations)}");
- throw new TemplateServiceException($"Failed to render template {viewName} because it was not found. \r\nThe following locations are searched: \r\n{string.Join("\r\n", searchedLocations)}");
- }
-
try
{
- if (viewResult.Success)
+ if (viewResult!.Success)
{
_logger.LogDebug($"View template found: {viewResult.View.Path}");
var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary,
@@ -152,8 +171,8 @@ public async Task RenderTemplateAsync(HttpContextData httpCo
}
else if (razorPageResult?.Page != null)
{
- _logger.LogDebug($"Razor page found: {razorPageResult?.Page.Path}");
- var page = razorPageResult?.Page;
+ var page = razorPageResult?.Page!;
+ _logger.LogDebug($"Razor page found: {page.Path}");
var razorView = new RazorView(
_viewEngine,
_pageActivator,
@@ -166,7 +185,7 @@ public async Task RenderTemplateAsync(HttpContextData httpCo
var viewContext = new ViewContext(actionContext, razorView, viewDictionary,
tempDataDictionary, outputWriter, new HtmlHelperOptions());
- await viewResult.View.RenderAsync(viewContext);
+ await viewResult.View!.RenderAsync(viewContext);
var pageNormal = ((Page)page);
pageNormal.PageContext = new PageContext();
pageNormal.ViewContext = viewContext;
diff --git a/src/Postal.AspNetCore/TransferEncoding.cs b/src/Postal.AspNetCore/TransferEncoding.cs
new file mode 100644
index 0000000..8c63bdf
--- /dev/null
+++ b/src/Postal.AspNetCore/TransferEncoding.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Postal.AspNetCore
+{
+ //
+ // Summary:
+ // Specifies the Content-Transfer-Encoding header information for an email message
+ // attachment.
+ public enum TransferEncoding
+ {
+ //
+ // Summary:
+ // Indicates that the transfer encoding is unknown.
+ Unknown = -1,
+ //
+ // Summary:
+ // Encodes data that consists of printable characters in the US-ASCII character
+ // set. See RFC 2406 Section 6.7.
+ QuotedPrintable = 0,
+ //
+ // Summary:
+ // Encodes stream-based data. See RFC 2406 Section 6.8.
+ Base64 = 1,
+ //
+ // Summary:
+ // Used for data that is not encoded. The data is in 7-bit US-ASCII characters with
+ // a total line length of no longer than 1000 characters. See RFC2406 Section 2.7.
+ SevenBit = 2,
+ //
+ // Summary:
+ // The data is in 8-bit characters that may represent international characters with
+ // a total line length of no longer than 1000 8-bit characters. For more information
+ // about this 8-bit MIME transport extension, see IETF RFC 6152.
+ EightBit = 3
+ }
+}