C# ASP.NET MVC电子邮件

C# ASP.NET MVC电子邮件,c#,asp.net-mvc,email,templates,spark-view-engine,C#,Asp.net Mvc,Email,Templates,Spark View Engine,他们的解决方案是使用ASP.NET MVC视图生成电子邮件模板,而无需跳转 var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse); var oldContext = HttpContext.Current; HttpContext.Current = fakeContext; var html = new HtmlHelper(new ViewContext(fakeControllerConte

他们的解决方案是使用ASP.NET MVC视图生成电子邮件模板,而无需跳转

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;
让我来详细说明一下跳环

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的另一个非常详细的解决方案: ()但是用更多的代码做同样的事情

另一方面,我正在寻找一种只渲染视图而不必发布/获取的东西,并生成一个简单的字符串,我可以通过电子邮件代码发送。 不会出现错误的东西,比如两次发布标题或伪造数据

EX:

//code which does not fire Render, RenderPartial... etc
var email = emailFramework.Create(viewData, view); 

请参阅下面的“我的解决方案”或点击此链接:


使用spark的我的解决方案:(12/30/2009)尝试使用spark view引擎()。它易于使用,比标准引擎更好,并且不需要伪造上下文

您也可以使用这个答案中的函数,但它需要伪造上下文。这是标准视图引擎的工作方式,对此您无能为力

这是我的扩展类,用于生成要字符串的视图。第一个用于标准视图引擎,第二个用于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();
    }
}
公共静态类控制器帮助器
{
///将视图渲染为字符串。
公共静态字符串RenderViewToString(此控制器,
字符串viewName,对象viewData)
{
//获取当前响应
var response=HttpContext.Current.response;
//冲洗
response.Flush();
//查找渲染视图
var视图=ViewEngines.Engines.FindPartialView(controller.ControllerContext,viewName).view;
//创建视图上下文
var viewContext=新的viewContext(controller.ControllerContext,视图,
controller.ViewData、controller.TempData);
//由于RenderView直接进入HttpContext.Current,我们必须过滤并删除视图
var oldFilter=response.Filter;
流过滤器=新内存流();
尝试
{
响应。过滤器=过滤器;
viewContext.View.Render(viewContext,null);
response.Flush();
过滤器。位置=0;
var reader=newstreamreader(过滤器、响应、内容编码);
返回reader.ReadToEnd();
}
最后
{
filter.Dispose();
响应。过滤器=旧过滤器;
} 
}
///将视图渲染为字符串。
公共静态字符串RenderSparkToString(此控制器,
字符串viewName,对象viewData)
{
var视图=ViewEngines.Engines.FindPartialView(controller.ControllerContext,viewName).view;
//创建视图上下文
var viewContext=新的viewContext(controller.ControllerContext,视图,
controller.ViewData、controller.TempData);
var sb=新的StringBuilder();
var编写器=新的StringWriter(sb);
viewContext.View.Render(viewContext,writer);
writer.Flush();
使某人返回字符串();
}
}

我为LukLed的RenderSparkToString方法创建了一个重载,允许您在视图中使用spark布局:

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();
}

不过我同意安德鲁的观点。我希望有一种更简单的方式使用web表单视图引擎来实现这一点。

为什么需要从视图创建电子邮件?为什么不使用普通的旧模板文件?我一直都在这样做——我制作一个模板,并使用castle项目中的NVelocity引擎(不要与NVelocity视图引擎混淆)来渲染模板

例如:

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类是我围绕Castle项目提供的NVelocity端口编写的包装,如下所示:

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 MVC ViewEngine所做的,但它是Spark中的,只需按照下面最新的链接进行操作

更新(2009年12月30日)清洁版:


(2009年11月16日)或Louis DeJardin控制台应用程序版本:

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或混乱路由数据
  • 它可以实现页眉/页脚来允许模板
  • 您可以使用循环、条件等
  • 它干净,重量轻,特别是如果你打算完全转移到火花查看引擎
请务必阅读这些帖子。所有这些都归功于路易斯·德贾丁(见他的教程:):

如果您需要简单的文本替换,.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
Welcome-{SITE\u NAME}

感谢您在{SITE\u NAME}注册

您的帐户已激活并准备就绪
要登录,请访问并使用以下凭据:
用户名:{username}
密码:使用您注册的密码

-{SITE_NAME}团队

同样,这只适用于简单的字符串替换。如果您计划通过电子邮件发送更多数据,则需要正确格式化数据,然后将其替换。

虽然这是一个有点旧的线程,我会鼓励你看看MVCMALNER NuGET包——它大大简化了整个事情,使邮件程序的行为为LI/P>< P>你可以考虑使用MVCMALULUGET——它只做你正在寻找的并且干净的。请参阅NuGet包和


希望有帮助

您好,LukLed,我熟悉Spark View引擎,以前也考虑过这个解决方案,您可能是对的,因为这最终将是最好的方式。最终我可能会被迫走上这条路。然而,我觉得在我的项目中添加第二个视图引擎只会增加