2015-04-22 13 views
8

Possiedo un'applicazione MVC 4 che invia più e-mail. Ad esempio, ho un modello di email per l'invio di un ordine, un modello per la cancellazione di un ordine, ecc ...Errore RazorEngine durante il tentativo di inviare e-mail

Ho un Email Service con più metodi. Il mio controller chiama il metodo Send che assomiglia a questo:

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

Il metodo Send chiama GetContent, che è il metodo che causa il problema:

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

sto ricevendo l'errore:

The same key was already used for another template!

Nel mio metodo GetContent dovrei aggiungere un nuovo parametro per lo TemplateKey e usare quella variabile Le invece di usare sempre htmlTemplate? Quindi lo new order email template potrebbe avere newOrderKey e CancelOrderKey per il modello di email utilizzato per annullare un ordine?

risposta

16

Spiegazione

Questo accade perché si utilizza la stessa chiave modello ("htmlTemplate") per più modelli differenti. Si noti che il modo in cui attualmente ha implementato GetContent si incorrere in molteplici problemi:

  • Anche se si utilizza una chiave univoca, ad esempio, la variabile template, si attiverà l'eccezione quando i modelli vengono modificati su disco .

  • Prestazioni: si sta leggendo il file del modello ogni volta anche quando il modello è già memorizzato nella cache.

Soluzione:

implementare l'interfaccia ITemplateManager per gestire i vostri modelli:

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!"); 
    } 
} 

installazione all'avvio:

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

e usarlo:

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

RazorEngine ora risolverà tutti i problemi sopra menzionati internamente. Si noti come sia perfettamente corretto utilizzare il nome del modello come chiave, se nel proprio scenario il nome è tutto ciò che serve per identificare un modello (altrimenti non è possibile utilizzare NameOnlyTemplateKey e fornire la propria implementazione).

Spero che questo aiuti. (Disclaimer: Contributor of RazorEngine)

+0

Grazie mille, questo aiuta molto! Ho implementato l'interfaccia 'ITemplateManager' e ho rimosso il metodo' GetContent' come hai detto tu. La sezione "setup on startup" di cui sopra è disponibile in 'Send()'? – Andrew

+0

Dovrebbe andare nella configurazione dell'applicazione dove viene eseguito 'once' e' before' usando la proprietà 'Engine.Razor'.Tuttavia, la posizione concreta dipende dall'applicazione: Ad esempio, utilizzare un costruttore statico o aggiungerlo all'inizio di "Main" in un'applicazione console – matthid

+0

Ahh okay, è una cosa che pensavo dopo aver lasciato il commento. Lo inserirò nel metodo 'Application_Start()' nel mio progetto MVC. Continuo a mantenere la riga 'Engine.Razor.RunCompile' in' GetContent() ', corretta? – Andrew

Problemi correlati