2015-04-22 12 views
8

Mam aplikację MVC 4, która wysyła wiele wiadomości e-mail. Na przykład mam szablon wiadomości e-mail do przesyłania zamówienia, szablon do anulowania zamówienia itp.Błąd RazorEngine podczas próby wysłania wiadomości e-mail

Mam Email Service z wieloma metodami. Mój kontroler wywołuje metodę Send który wygląda tak:

public virtual void Send(List<string> recipients, string subject, string template, object data) 
{ 
    ... 
    string html = GetContent(template, data); 
    ... 
} 

Sposób Send wzywa GetContent, która to metoda powoduje problem:

private string GetContent(string template, object data) 
{ 
    string path = Path.Combine(BaseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml")); 
    string content = File.ReadAllText(path); 
    return Engine.Razor.RunCompile(content, "htmlTemplate", null, data); 
} 

Otrzymuję błąd:

The same key was already used for another template!

W mojej metodzie GetContent należy dodać nowy parametr dla TemplateKey i użyć tej zmiennej zamiast zamiast zawsze używać htmlTemplate? Następnie new order email template może mieć newOrderKey i CancelOrderKey dla szablonu e-mail używanego do anulowania zamówienia?

Odpowiedz

16

Wyjaśnienie

Dzieje się tak dlatego, że korzystają z tego samego klucza szablonu ("htmlTemplate") dla wielu różnych szablonów. Należy zauważyć, że sposób, w jaki obecnie wdrożyły GetContent można uruchomić na kilka problemów:

  • Nawet jeśli używasz unikalny klucz, na przykład zmienną template, będzie powodować wyjątku, gdy szablony są edytowane na dysku .

  • Wydajność: czytasz plik szablonu za każdym razem, nawet gdy szablon jest już zapisany w pamięci podręcznej.

Rozwiązanie:

Wdrożenie interfejsu ITemplateManager zarządzać szablony:

public class MyTemplateManager : ITemplateManager 
{ 
    private readonly string baseTemplatePath; 
    public MyTemplateManager(string basePath) { 
     baseTemplatePath = basePath; 
    } 

    public ITemplateSource Resolve(ITemplateKey key) 
    { 
     string template = key.Name; 
     string path = Path.Combine(baseTemplatePath, string.Format("{0}{1}", template, ".html.cshtml")); 
     string content = File.ReadAllText(path); 
     return new LoadedTemplateSource(content, path); 
    } 

    public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context) 
    { 
     return new NameOnlyTemplateKey(name, resolveType, context); 
    } 

    public void AddDynamic(ITemplateKey key, ITemplateSource source) 
    { 
     throw new NotImplementedException("dynamic templates are not supported!"); 
    } 
} 

Setup na starcie:

var config = new TemplateServiceConfiguration(); 
config.Debug = true; 
config.TemplateManager = new MyTemplateManager(BaseTemplatePath); 
Engine.Razor = RazorEngineService.Create(config); 

i używać go:

// You don't really need this method anymore. 
private string GetContent(string template, object data) 
{ 
    return Engine.Razor.RunCompile(template, null, data); 
} 

RazorEngine naprawi wszystkie wyżej wymienione problemy wewnętrznie. Zwróć uwagę, jak dobrze jest używać nazwy szablonu jako klucza, jeśli w twoim scenariuszu nazwa jest wszystkim, czego potrzebujesz do identyfikacji szablonu (w przeciwnym razie nie będziesz mógł użyć NameOnlyTemplateKey i musisz podać własną implementację).

Mam nadzieję, że to pomoże. (Disclaimer: Dostawca RazorEngine)

+0

Dziękuję bardzo, to bardzo pomaga! Zaimplementowałem interfejs 'ITemplateManager' i usunąłem metodę" GetContent ", tak jak powiedziałeś. Czy powyższa sekcja 'setup on startup' działa w' Send() '? – Andrew

+0

Powinien przejść do konfiguracji aplikacji, w której jest wykonywany 'once' i' before' przy użyciu właściwości 'Engine.Razor'.Jednak konkretna lokalizacja zależy od twojej aplikacji: na przykład użyj statycznego konstruktora lub dodaj go na początku 'Main' w aplikacji konsolowej – matthid

+0

Ahh w porządku, to jest coś, co myślałem po tym, jak opuściłem komentarz. Umieszczę go w metodzie 'Application_Start()' w moim projekcie MVC. Nadal utrzymuję linię 'Engine.Razor.RunCompile' w' GetContent() ', poprawne? – Andrew

Powiązane problemy