13

フープをジャンプすることなく、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;

上記のコードは、現在の HttpContext を使用して新しい Context を偽装し、RenderPartial でページをレンダリングしていますが、これを行う必要はありません。

ControllerContext と .Render を使用した別の非常に詳細なソリューション: ( IEmailTemplateService, Headers/Postback WorkAround ) しかし、より多くのコードでほとんど同じことを行っています。

一方、私は、POST/GET を使用せずにビューをレンダリングするだけで、電子メール コードを介して送信できる単純な文字列を生成するものを探しています。ヘッダーを 2 回投稿したり、一部のデータを偽造したりするなどのエラーが発生しないもの。

元:

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

以下の私の解決策を参照するか、このリンクをたどってください:

spark を使用した私のソリューション: (12/30/2009) ASP.NET MVC 電子メール テンプレート ソリューション

4

7 に答える 7

8

ビューからメールを作成する必要があるのはなぜですか?昔ながらのテンプレートファイルを使ってみませんか?私はいつもこれを行っています-私はテンプレートを作成し、城プロジェクトの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クラスは、以下に示すように、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ビューエンジンでこれをチェーンできます。

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));
}
于 2009-11-13T19:45:49.363 に答える
7

Spark ビュー エンジン ( http://www.sparkviewengine.com/ ) を使用してみてください。使いやすく、標準のエンジンより優れており、コンテキストを偽造する必要はありません。

この回答Render a view as a string の関数を使用することもできますが、偽のコンテキストが必要です。これは、標準のビュー エンジンが機能する方法であり、それについては何もできません。

これは、文字列へのビューを生成するために使用される私の拡張クラスです。1 つ目は標準のビュー エンジン用で、2 つ目は 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();
    }
}
于 2009-11-13T16:24:28.557 に答える
4

単純なテキスト置換が必要な場合、.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

繰り返しますが、これは単純な文字列置換にのみ適しています。より多くのデータを電子メールで送信する予定がある場合は、適切にフォーマットしてから置き換える必要があります。

于 2009-11-15T08:16:07.440 に答える
3

MvcMailer NuGet の使用を検討できます。これは、探していることだけを実行し、クリーンに実行します。こちらの NuGet パッケージとプロジェクト ドキュメントを参照してください。

それが役に立てば幸い!

于 2011-03-09T04:34:48.657 に答える
1

ビューと共にスパーク レイアウトを使用できるようにする、LukLed の RenderSparkToString メソッドへのオーバーロードを作成しました。

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 フォーム ビュー エンジンを使用してこれを行う簡単な方法があればいいのにと思います。

于 2009-11-13T19:36:22.720 に答える
0

これは少し古いスレッドですが、MvcMailer NuGet パッケージを確認することをお勧めします。これにより、全体が大幅に簡素化され、メーラーの動作がスムーズになります。

于 2011-01-12T23:28:08.647 に答える