ASP.NET MVC Электронная почта
Являются ли они решением для создания шаблона электронной почты с использованием ASP.NET MVC View без необходимости переходить через обручи.
Позвольте мне разработать прыжки через обручи.
var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
var oldContext = HttpContext.Current;
HttpContext.Current = fakeContext;
var html = new HtmlHelper(new ViewContext(fakeControllerContext,
new FakeView(), viewDataDictionary, new TempDataDictionary()),
new ViewPage());
html.RenderPartial(viewName, viewData, viewDataDictionary);
HttpContext.Current = oldContext;
Приведенный выше код использует текущий HttpContext для подделки нового контекста и визуализации страницы с помощью RenderPartial, нам не нужно этого делать.
Еще одно очень подробное решение с использованием ControllerContext и.Render: ( IEmailTemplateService, Headers / Postback WorkAround), но в значительной степени делает то же самое с гораздо большим количеством кода.
Я, с другой стороны, ищу что-то, что просто визуализирует View без необходимости POST/GET и генерирует мне простую строку, которую я могу отправить через мой код электронной почты. Что-то, что не сталкивается с ошибками, такими как публикация заголовков дважды или подделка некоторой части данных.
EX:
//code which does not fire Render, RenderPartial... etc
var email = emailFramework.Create(viewData, view);
Смотрите мое решение ниже или перейдите по этой ссылке:
Мое решение с использованием spark: (30.12.2009) ASP.NET MVC Email Template Solution
7 ответов
Это то, что я хотел сделать ASP.NET MVC ViewEngine, но это в Spark, просто перейдите по последней ссылке прямо ниже,
Обновление (30.12.2009) Более чистая версия: ASP.NET MVC Email Template Solution
(16.11.2009) Или, версия консольного приложения Луи ДеДжардена:
using System;
using Spark;
using Spark.FileSystem;
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class EmailView : AbstractSparkView
{
public User user { get; set; }
}
class Program
{
static void Main(string[] args)
{
// following are one-time steps
// create engine
var settings = new SparkSettings()
.SetPageBaseType(typeof(EmailView));
var templates = new InMemoryViewFolder();
var engine = new SparkViewEngine(settings)
{
ViewFolder = templates
};
// add templates
templates.Add("sample.spark", @"Dear ${user.Name}, This is an email.Sincerely, Spark View Engine http://constanto.org/unsubscribe/${user.Id}");
// following are per-render steps
// render template
var descriptor = new SparkViewDescriptor()
.AddTemplate("sample.spark");
var view = (EmailView)engine.CreateInstance(descriptor);
view.user = new User { Id = 655321, Name = "Alex" };
view.RenderView(Console.Out);
Console.ReadLine();
}
}
Я решил использовать этот метод, потому что кажется, что он все делает правильно:
- Не использует HttpContext/ControllerContext и не связывается с данными маршрутизации!
- Он может реализовать верхний / нижний колонтитул, чтобы разрешить шаблоны!
- Вы можете использовать циклы, условные выражения и т.д...
- Это чистый, легкий вес, особенно если вы планируете полностью перейти на двигатель с искровым обзором!
Пожалуйста, обязательно прочитайте эти посты. Все заслуги Луи ДеДжардина смотрите в его уроках:): Использование Spark в качестве движка шаблонов общего назначения!, Шаблоны электронной почты повторно
Зачем вам нужно создавать электронную почту из представления? Почему бы не использовать простой старый файл шаблона? Я делаю это все время - я делаю шаблон и использую движок NVelocity из проекта замка (не путать с движком nvelocity VIEW) для визуализации шаблона.
Пример:
var nvEngine = new NVelocityEngine();
nvEngine.Context.Add("FullName", fullName);
nvEngine.Context.Add("MallName", voucher.Mall.Name);
nvEngine.Context.Add("ConfirmationCode", voucher.ConfirmationCode);
nvEngine.Context.Add("BasePath", basePath);
nvEngine.Context.Add("TermsLink", termsLink);
nvEngine.Context.Add("LogoFilename", voucher.Mall.LogoFilename);
var htmlTemplate = System.IO.File.ReadAllText(
Request.MapPath("~/App_Data/Templates/Voucher.html"));
var email = nvEngine.Render(htmlTemplate);
Класс NVelocityEngine - это оболочка, которую я написал для порта NVelocity, предоставленного проектом Castle, как показано ниже:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NVelocity;
using NVelocity.App;
namespace MyProgram
{
/// <summary>
/// A wrapper for the NVelocity template processor
/// </summary>
public class NVelocityEngine : VelocityEngine
{
Hashtable context = new Hashtable();
/// <summary>
/// A list of values to be merged with the template
/// </summary>
public Hashtable Context
{
get { return context; }
}
/// <summary>
/// Default constructor
/// </summary>
public NVelocityEngine()
{
base.Init();
}
/// <summary>
/// Renders a template by merging it with the context items
/// </summary>
public string Render(string template)
{
VelocityContext nvContext;
nvContext = new VelocityContext(context);
using (StringWriter writer = new StringWriter())
{
this.Evaluate(nvContext, writer, "template", template);
return writer.ToString();
}
}
}
}
Таким образом, вам вообще не нужно вмешиваться в движок представления, и вы можете теоретически связать его с движком представления ASP.NET, если хотите, как я сделал в следующем методе контроллера:
public ActionResult ViewVoucher(string e)
{
e = e.Replace(' ', '+');
var decryptedEmail = CryptoHelper.Decrypt(e);
var voucher = Voucher.FindByEmail(decryptedEmail);
if (voucher == null) return View("Error", new Exception("Voucher not found."));
var basePath = new Uri(Request.Url, Url.Content("~/")).ToString();
var termsLink = new Uri(Request.Url, Url.Action("TermsGC", "Legal")).ToString();
basePath = basePath.Substring(0, basePath.Length - 1);
var fullName = voucher.FirstName;
if (!string.IsNullOrEmpty(voucher.LastName))
fullName += " " + voucher.LastName;
var nvEngine = new NVelocityEngine();
nvEngine.Context.Add("FullName", fullName);
nvEngine.Context.Add("MallName", voucher.Mall.Name);
nvEngine.Context.Add("ConfirmationCode", voucher.ConfirmationCode);
nvEngine.Context.Add("BasePath", basePath);
nvEngine.Context.Add("TermsLink", termsLink);
nvEngine.Context.Add("LogoFilename", voucher.Mall.LogoFilename);
var htmlTemplate = System.IO.File.ReadAllText(
Request.MapPath("~/App_Data/Templates/Voucher.html"));
return Content(nvEngine.Render(htmlTemplate));
}
Попробуйте использовать движок Spark View ( http://www.sparkviewengine.com/). Он прост в использовании, лучше стандартного движка и не требует фальсификации контекста.
Вы также можете использовать функцию из этого ответа. Отобразить представление в виде строки, но для этого требуется поддельный контекст. Так работает стандартный движок представления, и с этим ничего не поделаешь.
Это мой класс расширения, который используется для генерации представлений в строку. Первый для стандартного вида движка, второй для Spark:
public static class ControllerHelper
{
/// <summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
string viewName, object viewData)
{
//Getting current response
var response = HttpContext.Current.Response;
//Flushing
response.Flush();
//Finding rendered view
var view = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName).View;
//Creating view context
var viewContext = new ViewContext(controller.ControllerContext, view,
controller.ViewData, controller.TempData);
//Since RenderView goes straight to HttpContext.Current, we have to filter and cut out our view
var oldFilter = response.Filter;
Stream filter = new MemoryStream(); ;
try
{
response.Filter = filter;
viewContext.View.Render(viewContext, null);
response.Flush();
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
return reader.ReadToEnd();
}
finally
{
filter.Dispose();
response.Filter = oldFilter;
}
}
/// <summary>Renders a view to string.</summary>
public static string RenderSparkToString(this Controller controller,
string viewName, object viewData)
{
var view = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName).View;
//Creating view context
var viewContext = new ViewContext(controller.ControllerContext, view,
controller.ViewData, controller.TempData);
var sb = new StringBuilder();
var writer = new StringWriter(sb);
viewContext.View.Render(viewContext, writer);
writer.Flush();
return sb.ToString();
}
}
Если вам нужны простые замены текста, в.NET есть что-то для этого:
ListDictionary replacements = new ListDictionary();
// Replace hard coded values with objects values
replacements.Add("{USERNAME}", "NewUser");
replacements.Add("{SITE_URL}", "http://yourwebsite.com");
replacements.Add("{SITE_NAME}", "My site's name");
string FromEmail= "from@yourwebsite.com";
string ToEmail = "newuser@gmail.com";
//Create MailDefinition
MailDefinition md = new MailDefinition();
//specify the location of template
md.BodyFileName = "~/Templates/Email/Welcome.txt";
md.IsBodyHtml = true;
md.From = FromEmail;
md.Subject = "Welcome to youwebsite.com ";
System.Web.UI.Control ctrl = new System.Web.UI.Control { ID = "IDontKnowWhyThisIsRequiredButItWorks" };
MailMessage message = md.CreateMailMessage(ToEmail , replacements, ctrl);
//Send the message
SmtpClient client = new SmtpClient();
client.Send(message);
И файл Welcome.txt
Welcome - {SITE_NAME}<br />
<br />
Thank you for registering at {SITE_NAME}<br />
<br />
Your account is activated and ready to go! <br />
To login, visit <a href="{SITE_URL}">{SITE_NAME}</a> and use the following credentials:
<br />
username: <b>{USERNAME}</b><br />
password: use the password you registered with
<br />
<br />
- {SITE_NAME} Team
Опять же, это хорошо только для простых замен строк. Если вы планируете отправлять больше данных по электронной почте, вам необходимо правильно отформатировать их и заменить.
Вы можете рассмотреть возможность использования MvcMailer NuGet - он делает именно то, что вы ищете, и делает это чисто. Смотрите пакет NuGet здесь и проектную документацию
Надеюсь, поможет!
Я создал перегрузку для метода RenderSparkToString от LukLed, который позволяет вам использовать макет искры вместе с вашим представлением:
public static string RenderSparkToString(this Controller controller,
string viewName, string masterName, object viewData)
{
var view = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, masterName).View;
//Creating view context
var viewContext = new ViewContext(controller.ControllerContext, view,
controller.ViewData, controller.TempData);
var sb = new StringBuilder();
var writer = new StringWriter(sb);
viewContext.View.Render(viewContext, writer);
writer.Flush();
return sb.ToString();
}
Я согласен с Эндрю, хотя. Хотелось бы, чтобы был более простой способ сделать это с помощью механизма просмотра веб-форм.
Хотя это немного старая тема, я бы посоветовал вам взглянуть на пакет MvcMailer NuGet - он значительно упрощает все и заставляет почтовик вести себя