【问题标题】:.NET Core - Confirming asset has been included with production build.NET Core - 确认资产已包含在生产版本中
【发布时间】:2022-01-18 03:23:49
【问题描述】:

我有一个包含多个项目的 .NET Core Web API 解决方案,我将在下面发布结构和必要的路径。

我有一个电子邮件服务,它从同一项目的路径中提取模板,对其进行解析并通过电子邮件发送。

Solution -
   Core (Project Models, Context and Interfaces)
   MainProject (Executed Project) -
      Controllers -
          EmailController.cs
   Repository
   Services -
      Email -
         templates -
            ContactEmailTemplate.html
         EmailService.cs

电子邮件服务如下所示:

using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using Core.Email.Services;
using Core.Email.Services.Models;
using Core.Services.Response;

namespace Services.Email
{
    public class EmailService : IEmailService
    {
        private const string SmtpAddress = "smtp.gmail.com";
        private const int PortNumber = 587;
        private const bool EnableSsl = true;
        private const string EmailFromAddress = ""; //Sender Email Address  
        private const string Password = ""; //Sender Password  
        private const string EmailToAddress = ""; //Receiver Email Address  
        private const string Subject = "New Email From...";

        public ServicesResponse<bool> SendEmail(EmailRequest emailRequest)
        {
            try
            {
                var mail = CreateMailMessage(emailRequest);
                
                using var smtp = new SmtpClient(SmtpAddress, PortNumber);
                smtp.Credentials = new NetworkCredential(EmailFromAddress, Password);
                smtp.EnableSsl = EnableSsl;
                smtp.Send(mail);

                return new ServicesResponse<bool>
                {
                    Data = true,
                    Exception = null,
                    HasError = false
                };   
            }
            catch (Exception exception)
            {
                return ServicesResponse<bool>.FromException(exception);
            }
        }

        private static MailMessage CreateMailMessage(EmailRequest request)
        {
            return new MailMessage
            {
                From = new MailAddress(EmailFromAddress),
                To = { EmailToAddress },
                Body = CreateMailMessageFromHtml(request),
                IsBodyHtml = true,
                Subject = Subject
            };
        }

        private static string CreateMailMessageFromHtml(EmailRequest request)
        {
            string body;
            
            using (var reader = new StreamReader(Path.Combine(AppContext.BaseDirectory, "../../../../Services/Email/templates/ContactEmailTemplate.html"))) /* <--- Is this even going to work in prod? ???? */
            {
                body = reader.ReadToEnd();
            }

            body = body.Replace("{Name}", request.Name);
            body = body.Replace("{Message}", request.Message);

            return body;
        }
    }

一切正常,我在我的收件箱中看到了调试版本的电子邮件。不过,我对这段代码完全没有信心:

using (var reader = new StreamReader(Path.Combine(AppContext.BaseDirectory, "../../../../Services/Email/templates/ContactEmailTemplate.html"))) /* <--- Is this even going to work in prod? ???? */

我担心一旦进入生产版本就会爆炸,感觉很脏。

我如何确认像 ContactEmailTemplate.html 这样的资产包含在生产版本中?

它会包含在Services 项目的.dll 捆绑包中吗?

编辑:我已将 ContactEmailTemplate.html 作为嵌入资源添加到项目中,并将 CreateMailMessageFromHtml 重构为以下内容

 private static string CreateMailMessageFromHtml(EmailRequest request)
        {
            string body;
            var assembly = Assembly.GetCallingAssembly();
// tried the following to get the template
            var resourceStream = assembly.GetManifestResourceStream("EmbeddedResource/Email/templates/ContactEmailTemplate.html");
var resourceStream = assembly.GetManifestResourceStream("EmbeddedResource.Email.templates.ContactEmailTemplate.html");
assembly.GetManifestResourceStream("Email\\templates\\ContactEmailTemplate.html");
            using (var reader = new StreamReader(resourceStream, Encoding.UTF8))
            {
                body = reader.ReadToEnd();
            }

            body = body.Replace("{Name}", request.Name);
            body = body.Replace("{Message}", request.Message);

            return body;
        }

但是当我打开流时一切都返回 null

【问题讨论】:

    标签: c# .net email dev-to-production


    【解决方案1】:

    如果您将 HTML 文件添加到项目并在解决方案资源管理器中单击该文件,您可以在属性窗口中看到一个名为 Build Action 的属性。如果您将其更改为嵌入式资源,该文件将(一旦编译)存在于 DLL 中,因此始终可用。

    确定作为嵌入式资源交付的所有文件(并获取您的全名)

    var allResourceNames = assembly.GetManifestResourceNames();

    我为你创建了一个示例项目来演示用法: https://github.com/nikneem/embedded-resource-example

    通过流打开文件:

    using (var stream = assembly.GetManifestResourceStream(resourceName))

    【讨论】:

    • 我已将电子邮件模板添加为嵌入式资源,并且似乎已成功添加:Services.scproj &lt;ItemGroup&gt; &lt;None Remove="Email\templates\ContactEmailTemplate.html" /&gt; &lt;EmbeddedResource Include="Email\templates\ContactEmailTemplate.html"&gt; &lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt; &lt;/EmbeddedResource&gt; &lt;/ItemGroup&gt; 但是当我使用 assembly.GetManifestResourceStream 打开一个新流时,我返回 null。我将更新我的问题以显示我尝试过的内容
    • 你的意思是它不适合你吗?或者你的问题解决了吗。查看您的代码,我可以看到您使用 Assembly.GetCallingAssembly 可能不是包含您的 HTML 文件的程序集。如果你使用 typeof(AnyClassInYourAssembly).Assembly 你会得到正确的程序集。
    • 我已经更新了答案,它现在包含一个示例项目
    • 我认为问题已经解决,但是,我想尝试一下您的建议,看看是否可行,因为我希望对我的代码有信心。
    【解决方案2】:

    我关注了@Eduard Keilhoz 的回答。我嵌入了 HTML 文件,并将其添加到我的 .csproj 文件中:

     <ItemGroup>
       <None Remove="Email\templates\ContactEmailTemplate.html" />
       <EmbeddedResource Include="Email\templates\ContactEmailTemplate.html">
         <CopyToOutputDirectory>Always</CopyToOutputDirectory>
       </EmbeddedResource>
    </ItemGroup>
    

    然后将CreateMailMessageFromHtml 更新为以下内容:

     private static string CreateMailMessageFromHtml(EmailRequest request)
     {
         string body;
         var assembly = Assembly.GetCallingAssembly();
         using (var reader = new StreamReader(assembly.GetManifestResourceStream("Services.Email.templates.ContactEmailTemplate.html") ?? throw new InvalidOperationException()))
         {
             body = reader.ReadToEnd();
         }
    
         body = body.Replace("{Name}", request.Name);
         body = body.Replace("{Message}", request.Message);
    
         return body;
     }
    
    

    这是给.NET Core 5.0,如果有人感兴趣的话

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-31
      • 2023-03-13
      • 2016-07-14
      相关资源
      最近更新 更多