使用 MailKit 中的结果 razor 视图发送电子邮件
Sending email using resulted razor view in MailKit
希望我能用简单的方式解释我的要求:
在 .Net Core 中,我们可以在使用 View(FileName, Model)
发送模型数据后显示 .cshtml
视图。
有没有办法将 Model
发送到 .cshtml
文件,这样我就不会显示生成的视图,而是使用 Mailkit
[=15= 通过电子邮件发送附件]
感谢Paris Polyzos and his article。
我找到了解决方案,所以喜欢分享它,可能有人会从中受益,或者改进它。
首先:我们需要创建service
来将Rasor转换成String,代码Razor2String.cs
如下:
using System
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
namespace Project.Utilities
{
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
}
其次:我们需要将"preserveCompilationContext": true
添加到buildOptions
,所以project.json
变成:
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"MailKit":"1.10.0"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
}
},
"imports": "dnxcore50"
}
}
}
第三:我们需要在Startup
class中的ConfigureServices
中加入service
,这样Startup.cs
文件就变成了:
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Project.Utilities;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Add application services.
services.AddScoped<IViewRenderService, ViewRenderService>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
"Hello World of the last resort. The Time is: " +
DateTime.Now.ToString("hh:mm:ss tt"));
});
}
}
第四:定义你的Model
,比如users.cs
:
namespace myApp
{
public class users {
public string UserId {get; set;}
public string UserName {get; set;}
}
}
第五步:在Views
文件夹中创建View
模板,类似于Views/Razor2String.cshtml
:
Hello
<hr/>
@{
ViewData["Title"] = "Contact";
}
<h2>@ViewData["Title"].</h2>
<h3>user id: @Model.UserId</h3>
第六:Program.cs
就是:
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace myApp
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseKestrel()
.UseUrls("http://localhost:50000")
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
第七:正文,'Email.cs':
using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Project.Utilities;
using System.Threading.Tasks;
using MailKit.Net.Smtp; // for SmtpClient
using MimeKit; // for MimeMessage, MailboxAddress and MailboxAddress
namespace myApp
{
[Route("api")]
public class RenderController : Controller
{
private readonly IViewRenderService _viewRenderService;
public RenderController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}
[Route("sendEmail")]
public async Task sendEmail()
{
var viewModel = new users
{
UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
UserName = "iggy",
};
// Get the generated Razor view as String
var result = await _viewRenderService.RenderToStringAsync("Razor2String", viewModel);
MemoryStream stream = new MemoryStream ();
StreamWriter writer = new StreamWriter(stream);
writer.Write((String)result);
writer.Flush();
stream.Position = 0;
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Hasan Yousef", "mySelf@gmail.com"));
message.To.Add(new MailboxAddress("Personal", "myPersonalEmail@gmail.com"));
message.Subject = "Email Test";
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = @"<div>HTML email body</Div>";
bodyBuilder.Attachments.Add ("msg.html", stream);
message.Body = bodyBuilder.ToMessageBody();
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 587);
client.AuthenticationMechanisms.Remove("XOAUTH2"); // due to enabling less secure apps access
Console.WriteLine("Prepairing the Email");
try{
client.Authenticate("mySelf@gmail.com", "myPSWD");
Console.WriteLine("Auth Completed");
}
catch (Exception e){
Console.WriteLine("ERROR Auth");
}
try{
client.Send(message);
Console.WriteLine("Email had been sent");
}
catch (Exception e){
Console.WriteLine("ERROR");
}
client.Disconnect(true);
}
}
}
}
如果您需要为浏览器发送回字符串,您可以使用:
[Route("returnView")]
public async Task<IActionResult> returnView()
{
var viewModel = new users
{
UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
UserName = "iggy",
};
// Get the generated Razor view as String
var result = await _viewRenderService.RenderToStringAsync("Razor2String", viewModel);
return Content(result);
}
如果你需要将结果发送到AJAX请求,你可以使用类似:
public async Task<String> RenderInviteView()
{
.
.
.
return result;
}
如果你想像GenerateStreamFromString(result)
那样使用单独的方法将字符串转换为流,那么你可以使用using (Stream stream = GenerateStreamFromString(result)){ }
调用它
希望我能用简单的方式解释我的要求:
在 .Net Core 中,我们可以在使用 View(FileName, Model)
发送模型数据后显示 .cshtml
视图。
有没有办法将 Model
发送到 .cshtml
文件,这样我就不会显示生成的视图,而是使用 Mailkit
[=15= 通过电子邮件发送附件]
感谢Paris Polyzos and his article。
我找到了解决方案,所以喜欢分享它,可能有人会从中受益,或者改进它。
首先:我们需要创建service
来将Rasor转换成String,代码Razor2String.cs
如下:
using System
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
namespace Project.Utilities
{
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
}
其次:我们需要将"preserveCompilationContext": true
添加到buildOptions
,所以project.json
变成:
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"MailKit":"1.10.0"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
}
},
"imports": "dnxcore50"
}
}
}
第三:我们需要在Startup
class中的ConfigureServices
中加入service
,这样Startup.cs
文件就变成了:
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Project.Utilities;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Add application services.
services.AddScoped<IViewRenderService, ViewRenderService>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync(
"Hello World of the last resort. The Time is: " +
DateTime.Now.ToString("hh:mm:ss tt"));
});
}
}
第四:定义你的Model
,比如users.cs
:
namespace myApp
{
public class users {
public string UserId {get; set;}
public string UserName {get; set;}
}
}
第五步:在Views
文件夹中创建View
模板,类似于Views/Razor2String.cshtml
:
Hello
<hr/>
@{
ViewData["Title"] = "Contact";
}
<h2>@ViewData["Title"].</h2>
<h3>user id: @Model.UserId</h3>
第六:Program.cs
就是:
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace myApp
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseKestrel()
.UseUrls("http://localhost:50000")
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
第七:正文,'Email.cs':
using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Project.Utilities;
using System.Threading.Tasks;
using MailKit.Net.Smtp; // for SmtpClient
using MimeKit; // for MimeMessage, MailboxAddress and MailboxAddress
namespace myApp
{
[Route("api")]
public class RenderController : Controller
{
private readonly IViewRenderService _viewRenderService;
public RenderController(IViewRenderService viewRenderService)
{
_viewRenderService = viewRenderService;
}
[Route("sendEmail")]
public async Task sendEmail()
{
var viewModel = new users
{
UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
UserName = "iggy",
};
// Get the generated Razor view as String
var result = await _viewRenderService.RenderToStringAsync("Razor2String", viewModel);
MemoryStream stream = new MemoryStream ();
StreamWriter writer = new StreamWriter(stream);
writer.Write((String)result);
writer.Flush();
stream.Position = 0;
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Hasan Yousef", "mySelf@gmail.com"));
message.To.Add(new MailboxAddress("Personal", "myPersonalEmail@gmail.com"));
message.Subject = "Email Test";
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = @"<div>HTML email body</Div>";
bodyBuilder.Attachments.Add ("msg.html", stream);
message.Body = bodyBuilder.ToMessageBody();
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 587);
client.AuthenticationMechanisms.Remove("XOAUTH2"); // due to enabling less secure apps access
Console.WriteLine("Prepairing the Email");
try{
client.Authenticate("mySelf@gmail.com", "myPSWD");
Console.WriteLine("Auth Completed");
}
catch (Exception e){
Console.WriteLine("ERROR Auth");
}
try{
client.Send(message);
Console.WriteLine("Email had been sent");
}
catch (Exception e){
Console.WriteLine("ERROR");
}
client.Disconnect(true);
}
}
}
}
如果您需要为浏览器发送回字符串,您可以使用:
[Route("returnView")]
public async Task<IActionResult> returnView()
{
var viewModel = new users
{
UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
UserName = "iggy",
};
// Get the generated Razor view as String
var result = await _viewRenderService.RenderToStringAsync("Razor2String", viewModel);
return Content(result);
}
如果你需要将结果发送到AJAX请求,你可以使用类似:
public async Task<String> RenderInviteView()
{
.
.
.
return result;
}
如果你想像GenerateStreamFromString(result)
那样使用单独的方法将字符串转换为流,那么你可以使用using (Stream stream = GenerateStreamFromString(result)){ }