Using Razor outside of web project

2019-03-16 06:26发布

问题:

I would like to generate emails using the Razor view engine.

From what I've read, I can use these OS projects to do that from my website:

  • Postal
  • ActionMailer.Net
  • MvcMailer

However, all these use example where the user submits a form and an email is sent from the contoller. When creating the email a ControllerContext seems to be required. I am hoping to do the generating within my "Service" layer at periodic intervals, so I doubt I have access to the ControllerContext.

Is this doable?

回答1:

Check this out. I'm using it with templates as embedded resources like this (but can be modified to locate templates anywhere):

public static class MailSender
{
    static MailSender()
    {
        CompilerServiceFactory = new DefaultCompilerServiceFactory();
        TemplateService = new TemplateService(CompilerServiceFactory.CreateCompilerService(), typeof(MailTemplate<>));
    }

    private static ICompilerServiceFactory CompilerServiceFactory { get; set; }
    private static TemplateService TemplateService { get; set; }

    private static ITemplate<T> GetTemplate<T>(T model)
    {
        string path = typeof(T).FullName;

        var assembly = Assembly.GetExecutingAssembly();

        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path))
        {
            if (stream == null)
                throw new FileNotFoundException("Mail template not found");

            using (var reader = new StreamReader(stream))
            {
                string source = reader.ReadToEnd();

                return TemplateService.GetTemplate<T>(source, model);
            }
        }
    }

    public static void Send<T>(string to, T model)
    {
        Send(new string[] { to }, new string[] { }, new string[] { }, model);
    }
    public static void Send<T>(string to, string cc, string bcc, T model)
    {
        Send(new string[] { to }, new string[] { cc }, new string[] { bcc }, model);
    }
    public static void Send<T>(string[] to, string[] cc, string[] bcc, T model)
    {
        var template = (MailTemplate<T>)GetTemplate<T>(model);

        template.Execute();

        Trace.WriteLine(string.Format("To: {0} Subject: {1}{3}Body: {2}", string.Join(",", to), template.Subject, template.Result, Environment.NewLine), "Mail");
#if !LOCAL
        using (var message = new MailMessage())
        using (var client = new SmtpClient())
        {
            if (!string.IsNullOrWhiteSpace(template.From))
                message.From = new MailAddress(template.From);

            message.To.Add(string.Join(",", to));

            if (cc != null && cc.Length > 0)
                message.CC.Add(string.Join(",", cc));

            if (bcc != null && bcc.Length > 0)
                message.Bcc.Add(string.Join(",", bcc));

            message.Subject = template.Subject;

            message.Body = template.Result;
            message.IsBodyHtml = true;

            client.Send(message);
        }
#endif
    }
}

public abstract class MailTemplate<TModel> : TemplateBase<TModel>
{
    public string From { get; set; }
    public string Subject { get; set; }
}

model:

public class Contact
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Text { get; set; }
}

template:

@inherits Feedback.Lib.Mail.MailTemplate<Feedback.Lib.Mail.Templates.Contact>
@{
    From = string.Format("{0} <{1}>", Model.Name, Model.Email);
    Subject = "Contact request - " + From; 
}

@Model.Text

I have for each template it's own model, so its easy to locate them via class name. Also I was unable to make intellisense work.



回答2:

so what i use to get razor outside asp.net is the razor engine found on codeplex: RazorEngine