19

私はこのようなかみそりエンジンを使用します:

public class EmailService : IService
{
    private readonly ITemplateService templateService;

    public EmailService(ITemplateService templateService)
    {
        if (templateService == null)
        {
            throw new ArgumentNullException("templateService");
        }
        this.templateService = templateService;
    }

    public string GetEmailTemplate(string templateName)
    {
        if (templateName == null)
        {
            throw new ArgumentNullException("templateName");
        }
        Assembly assembly = Assembly.GetAssembly(typeof(EmailTemplate));
        Stream stream = assembly.GetManifestResourceStream(typeof(EmailTemplate), "{0}.cshtml".FormatWith(templateName));
        string template = stream.ReadFully();
        return template;
    }

    public string GetEmailBody(string templateName, object model = null)
    {
        if (templateName == null)
        {
            throw new ArgumentNullException("templateName");
        }
        string template = GetEmailTemplate(templateName);
        string emailBody = templateService.Parse(template, model, null, null);
        return emailBody;
    }
}

私が使用しているテンプレート サービスはインジェクトされていますが、これは単なるデフォルトの実装です。

    internal ITemplateService InstanceDefaultTemplateService()
    {
        ITemplateServiceConfiguration configuration = new TemplateServiceConfiguration();
        ITemplateService service = new TemplateService(configuration);
        return service;
    }

この場合は特に、これらのテンプレートからメールを作成します。@sectionメールの件名とメール本文のさまざまなセクションに sを使用できるようにしたいのですが、メール構造全体に共通のスタイルを指定するレイアウトを使用します (これはMailChimpのいずれかのようになります)。おそらく)。

質問は 2 つあります。

  • でレイアウトを指定するにはどうすればよいRazorEngineですか?
  • これらのレイアウトを文字列 (またはストリーム) から指定するにはどうすればよいですか? ご覧のとおり、埋め込みリソースを使用して剃刀メール テンプレートを保存しています。

アップデート

明確ではなかったかもしれませんが、RazorEngineライブラリについて言及しています。

4

3 に答える 3

17

レイアウトがサポートされていることを掘り下げた結果、_Layout代わりにで宣言する必要がありますLayout

組み込みリソースの問題については、以下を実装しましたITemplateResolver

using System;
using System.IO;
using System.Reflection;
using Bruttissimo.Common;
using RazorEngine.Templating;

namespace Website.Extensions.RazorEngine
{
    /// <summary>
    /// Resolves templates embedded as resources in a target assembly.
    /// </summary>
    public class EmbeddedTemplateResolver : ITemplateResolver
    {
        private readonly Assembly assembly;
        private readonly Type type;
        private readonly string templateNamespace;

        /// <summary>
        /// Specify an assembly and the template namespace manually.
        /// </summary>
        /// <param name="assembly">The assembly where the templates are embedded.</param>
        /// <param name="templateNamespace"></param>
        public EmbeddedTemplateResolver(Assembly assembly, string templateNamespace)
        {
            if (assembly == null)
            {
                throw new ArgumentNullException("assembly");
            }
            if (templateNamespace == null)
            {
                throw new ArgumentNullException("templateNamespace");
            }
            this.assembly = assembly;
            this.templateNamespace = templateNamespace;
        }

        /// <summary>
        /// Uses a type reference to resolve the assembly and namespace where the template resources are embedded.
        /// </summary>
        /// <param name="type">The type whose namespace is used to scope the manifest resource name.</param>
        public EmbeddedTemplateResolver(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            this.assembly = Assembly.GetAssembly(type);
            this.type = type;
        }

        public string Resolve(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            Stream stream;
            if (templateNamespace == null)
            {
                stream = assembly.GetManifestResourceStream(type, "{0}.cshtml".FormatWith(name));
            }
            else
            {
                stream = assembly.GetManifestResourceStream("{0}.{1}.cshtml".FormatWith(templateNamespace, name));
            }
            if (stream == null)
            {
                throw new ArgumentException("EmbeddedResourceNotFound");
            }
            string template = stream.ReadFully();
            return template;
        }
    }
}

次に、次のように配線します。

    internal static ITemplateService InstanceTemplateService()
    {
        TemplateServiceConfiguration configuration = new TemplateServiceConfiguration
        {
            Resolver = new EmbeddedTemplateResolver(typeof(EmailTemplate))
        };
        ITemplateService service = new TemplateService(configuration);
        return service;
    }

渡すタイプは、リソースが埋め込まれているアセンブリと名前空間を参照するためだけのものです。

namespace Website.Domain.Logic.Email.Template
{
    /// <summary>
    /// The purpose of this class is to expose the namespace of razor engine templates in order to
    /// avoid having to hard-code it when retrieving the templates embedded as resources.
    /// </summary>
    public sealed class EmailTemplate
    {
    }
}

最後に、リゾルバーでテンプレートを解決するには、次のように解決する必要があります。

ITemplate template = templateService.Resolve(templateName, model);
string body = template.Run();
return body;

.Runの用途が見つからないため、これは単純な拡張メソッドViewBagです。

public static class ITemplateExtensions
{
    public static string Run(this ITemplate template)
    {
        ExecuteContext context = new ExecuteContext();
        string result = template.Run(context);
        return result;
    }
}

アップデート

不足している拡張機能は次のとおりです

    public static string FormatWith(this string text, params object[] args)
    {
        return string.Format(text, args);
    }

    public static string ReadFully(this Stream stream)
    {
        using (StreamReader reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
于 2012-05-12T18:13:35.670 に答える
5

独自のレイアウトを文字列またはファイル名として指定する必要がありました。これを解決した方法は次のとおりです(このブログ投稿に基づく)

public static class RazorEngineConfigurator
{
    public static void Configure()
    {
        var templateConfig = new TemplateServiceConfiguration
            {
                Resolver = new DelegateTemplateResolver(name =>
                    {
                        //no caching cause RazorEngine handles that itself
                        var emailsTemplatesFolder = HttpContext.Current.Server.MapPath(Properties.Settings.Default.EmailTemplatesLocation);
                        var templatePath = Path.Combine(emailsTemplatesFolder, name);
                        using (var reader = new StreamReader(templatePath)) // let it throw if doesn't exist
                        {
                            return reader.ReadToEnd();
                        }
                    })
            };
        RazorEngine.Razor.SetTemplateService(new TemplateService(templateConfig));
    }
}

次に、Global.asax.cs で RazorEngineConfigurator.Configure() を呼び出し、準備完了です。

テンプレートへのパスは Properties.Settings.Default.EmailTemplatesLocation にあります

私の見解では、これがあります:

@{ Layout = "_layout.html";}

_layout.html は emailTemplatesFolder にあります

これは、 @RenderBody() 呼び出しが中間にあるかなり標準的な HTML です。

私の知る限り、RazorEngine はテンプレート名 (この場合は「_layout.html」) をキャッシュのキーとして使用するため、コンフィギュレーターのデリゲートはテンプレートごとに 1 回だけ呼び出されます。

(まだ)知らないすべてのテンプレート名にそのリゾルバーを使用していると思います。

于 2013-05-07T07:57:29.823 に答える
3

他の誰かがあなたのためにそれを解決したようです。

https://github.com/aqueduct/Appia/blob/master/src/Aqueduct.Appia.Razor/RazorViewEngine.cs

必要なコードは、2番目のExecuteViewメソッドにあります。彼らは独自のビューエンジンを作成していますが、代わりに独自のカスタムテンプレートソリューションを作成して、同様のものを使用することができます。基本的に、彼らはテンプレートのLayoutプロパティを探しており、それが存在する場合は、レイアウトからコンテンツを検索して置き換えます。

RazorEngineのカスタムテンプレートへのリンクは次のとおりです。

http://razorengine.codeplex.com/wikipage?title=Building%20Custom%20Base%20Templates&referringTitle=Documentation

これが私があなたの解決策を見つけたところです:

.NETRazorエンジン-レイアウトの実装

于 2012-05-08T19:46:16.587 に答える