Domanda

Ho bisogno di inviare notifiche e-mail agli utenti e ho bisogno per consentire all'amministratore di fornire un modello per il corpo del messaggio (e, eventualmente, le intestazioni, troppo).

Mi piacerebbe qualcosa di simile string.Format che mi permette di dare stringhe di sostituzione di nome, in modo che il modello può apparire così:

Dear {User},

Your job finished at {FinishTime} and your file is available for download at {FileURL}.

Regards,

-- 
{Signature}

Qual è il modo più semplice per me di fare questo?

È stato utile?

Soluzione

Usa un motore di template. StringTemplate è uno di quelli, e sono tanti.

Altri suggerimenti

Ecco la versione per quelli di voi che possono utilizzare una nuova versione di C #:

// add $ at start to mark string as template
var template = $"Your job finished at {FinishTime} and your file is available for download at {FileURL}."

In una linea -. Questa è ora una caratteristica del linguaggio pienamente supportato (stringa interpolazione)

È possibile utilizzare il metodo "string.Format":

var user = GetUser();
var finishTime = GetFinishTime();
var fileUrl = GetFileUrl();
var signature = GetSignature();
string msg =
@"Dear {0},

Your job finished at {1} and your file is available for download at {2}.

Regards,

--
{3}";
msg = string.Format(msg, user, finishTime, fileUrl, signature);

E 'consente di modificare il contenuto in futuro ed è adatto per la localizzazione.

SmartFormat è un piuttosto semplice libreria che soddisfa tutte le vostre esigenze. Essa si concentra sulla composizione del testo "linguaggio naturale", ed è ottimo per la generazione di dati di elenchi, o applicando la logica condizionale.

La sintassi è estremamente simile a String.Format, ed è molto semplice e facile da imparare e da usare. Ecco un esempio della sintassi dalla documentazione:

Smart.Format("{Name}'s friends: {Friends:{Name}|, |, and}", user)
// Result: "Scott's friends: Michael, Jim, Pam, and Dwight"

La biblioteca dispone di grandi opzioni di gestione degli errori (ignorare gli errori, errori di output, gettare gli errori). Ovviamente, questo dovrebbe funzionare perfetto per il vostro esempio.

La biblioteca è open source e facilmente estendibile, in modo da poter anche migliorare con funzionalità aggiuntive troppo.

Si potrebbe utilizzare String.Replace (...), infine in una for-each attraverso tutte le parole chiave. Se ci sono solo un paio di parole chiave che li può avere su una riga come questa:

string myString = template.Replace("FirstName", "John").Replace("LastName", "Smith").Replace("FinishTime", DateTime.Now.ToShortDateString());

In alternativa è possibile utilizzare Regex.Replace (...), se avete bisogno di qualcosa di un po 'più potente e con più opzioni.

su CodeProject per vedere che la sostituzione di stringa opzione è più veloce per voi.

Sulla risposta di Benjamin Gruenbaum, in C # versione 6 è possibile aggiungere un @ con il $ e praticamente utilizzare il codice come è, per esempio:.

var text = $@"Dear {User},

Your job finished at {FinishTime} and your file is available for download at {FileURL}.

Regards,

-- 
{Signature}
";

Il $ è per interpolazione stringa: https: //docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated

Il @ è l'identificatore testualmente: https: //docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim

... ed è possibile utilizzare questi in combinazione.

: o)

In realtà, è possibile utilizzare XSLT. Si crea un semplice template XML:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:template match="TETT">
    <p>
       Dear <xsl:variable name="USERNAME" select="XML_PATH" />,

       Your job finished at <xsl:variable name="FINISH_TIME" select="XML_PATH" /> and your file is available for download at <xsl:variable name="FILE_URL" select="XML_PATH" />.

       Regards,
        -- 
       <xsl:variable name="SIGNATURE" select="XML_PATH" />
    </p>
</xsl:template>

Quindi creare un XmlDocument per eseguire la trasformazione contro:             XmlDocument xmlDoc = new XmlDocument ();

        XmlNode xmlNode = xmlDoc .CreateNode(XmlNodeType.Element, "EMAIL", null);
        XmlElement xmlElement= xmlDoc.CreateElement("USERNAME");
        xmlElement.InnerXml = username;
        xmlNode .AppendChild(xmlElement); ///repeat the same thing for all the required fields

        xmlDoc.AppendChild(xmlNode);

Dopo di che, applicare la trasformazione:

        XPathNavigator xPathNavigator = xmlDocument.DocumentElement.CreateNavigator();
        StringBuilder sb = new StringBuilder();
        StringWriter sw = new StringWriter(sb);
        XmlTextWriter xmlWriter = new XmlTextWriter(sw);
        your_xslt_transformation.Transform(xPathNavigator, null, xmlWriter);
        return sb.ToString();

L'implementazione il proprio formattazione personalizzata potrebbe essere una buona idea.

Ecco come si fa. In primo luogo, creare un tipo che definisce la roba che si desidera iniettare nel messaggio. Nota: Sto solo andando a illustrare questo con la parte utente del modello ...

class JobDetails
{
    public string User 
    { 
        get;
        set; 
    }        
}

Avanti, implementare un semplice formattazione personalizzata ...

class ExampleFormatter : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        return this;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        // make this more robust
        JobDetails job = (JobDetails)arg;

        switch (format)
        {
            case "User":
            {
                return job.User;
            }
            default:
            {
                // this should be replaced with logic to cover the other formats you need
                return String.Empty;
            }
        }
    }
}

Infine, usare in questo modo ...

string template = "Dear {0:User}. Your job finished...";

JobDetails job = new JobDetails()
                     {
                             User = "Martin Peck"
                     };

string message = string.Format(new ExampleFormatter(), template, job);

... che genererà il testo "Caro Martin Peck. Il vostro lavoro finito ...".

Una soluzione molto semplice regex-based. Supporta \n stile singolo carattere sequenze di escape e {Name} stile denominate variabili.

sorgente

class Template
{
    /// <summary>Map of replacements for characters prefixed with a backward slash</summary>
    private static readonly Dictionary<char, string> EscapeChars
        = new Dictionary<char, string>
        {
            ['r'] = "\r",
            ['n'] = "\n",
            ['\\'] = "\\",
            ['{'] = "{",
        };

    /// <summary>Pre-compiled regular expression used during the rendering process</summary>
    private static readonly Regex RenderExpr = new Regex(@"\\.|{([a-z0-9_.\-]+)}",
        RegexOptions.IgnoreCase | RegexOptions.Compiled);

    /// <summary>Template string associated with the instance</summary>
    public string TemplateString { get; }

    /// <summary>Create a new instance with the specified template string</summary>
    /// <param name="TemplateString">Template string associated with the instance</param>
    public Template(string TemplateString)
    {
        if (TemplateString == null) {
            throw new ArgumentNullException(nameof(TemplateString));
        }

        this.TemplateString = TemplateString;
    }

    /// <summary>Render the template using the supplied variable values</summary>
    /// <param name="Variables">Variables that can be substituted in the template string</param>
    /// <returns>The rendered template string</returns>
    public string Render(Dictionary<string, object> Variables)
    {
        return Render(this.TemplateString, Variables);
    }

    /// <summary>Render the supplied template string using the supplied variable values</summary>
    /// <param name="TemplateString">The template string to render</param>
    /// <param name="Variables">Variables that can be substituted in the template string</param>
    /// <returns>The rendered template string</returns>
    public static string Render(string TemplateString, Dictionary<string, object> Variables)
    {
        if (TemplateString == null) {
            throw new ArgumentNullException(nameof(TemplateString));
        }

        return RenderExpr.Replace(TemplateString, Match => {
            switch (Match.Value[0]) {
                case '\\':
                    if (EscapeChars.ContainsKey(Match.Value[1])) {
                        return EscapeChars[Match.Value[1]];
                    }
                    break;

                case '{':
                    if (Variables.ContainsKey(Match.Groups[1].Value)) {
                        return Variables[Match.Groups[1].Value].ToString();
                    }
                    break;
            }

            return string.Empty;
        });
    }
}

Uso

var tplStr1 = @"Hello {Name},\nNice to meet you!";
var tplStr2 = @"This {Type} \{contains} \\ some things \\n that shouldn't be rendered";
var variableValues = new Dictionary<string, object>
{
    ["Name"] = "Bob",
    ["Type"] = "string",
};

Console.Write(Template.Render(tplStr1, variableValues));
// Hello Bob,
// Nice to meet you!

var template = new Template(tplStr2);
Console.Write(template.Render(variableValues));
// This string {contains} \ some things \n that shouldn't be rendered

Note

  • Ho sempre e solo definito \n, \r, \\ e \{ sequenze di escape e loro hard-coded. Si potrebbe facilmente aggiungere più o renderli definibile da parte del consumatore.
  • Ho fatto i nomi delle variabili maiuscole e minuscole, come le cose come questa sono spesso presentati a / non-programmatori utenti finali e non mi Personalmente ritengo che maiuscole e minuscole ha senso in questo caso d'uso - è solo uno ancora una cosa che possono ottenere sbagliato e telefono fino a lamentarsi (più in generale, se pensi di aver bisogno nomi dei simboli sensibili caso ciò che si ha realmente bisogno sono i nomi dei simboli migliori). Per renderli tra maiuscole e minuscole, è sufficiente rimuovere il flag RegexOptions.IgnoreCase.
  • la spoglierò nomi delle variabili non valide e sequenze di escape dalla stringa risultato. Lasciarli intatti, restituire Match.Value invece che la stringa vuota alla fine della richiamata Regex.Replace. Si potrebbe anche un'eccezione.
  • ho usato la sintassi {var}, ma questo può interferire con la sintassi della stringa interpolata nativo. Se si desidera definire modelli in stringhe letterali in te codice, potrebbe essere consigliabile cambiare i delimitatori variabili per esempio %var% (\\.|%([a-z0-9_.\-]+)% regex) o qualche altra sintassi tua scelta che è più appropriato al caso d'uso.

Se avete bisogno di qualcosa di molto potente ( ma in realtà non è il modo più semplice ) è possibile ospitare ASP.NET e utilizzarlo come motore di template.

Avrete tutta la potenza di ASP.NET per formattare il corpo del messaggio.

Se si esegue la codifica in VB.NET è possibile utilizzare letterali XML. Se si esegue la codifica in C # è possibile utilizzare ShartDevelop avere i file in VB.NET nello stesso progetto di codice C #.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top