Каков хороший способ создания шаблонов строк в .NET?

Мне нужно отправить уведомления по электронной почте пользователям, и я должен разрешить администратору предоставить шаблон для тела сообщения (и, возможно, заголовки тоже).

Мне нужно что-то вроде string.Format который позволяет мне string.Format строки с заменой, поэтому шаблон может выглядеть так:

 Dear {User}, Your job finished at {FinishTime} and your file is available for download at {FileURL}. Regards, -- {Signature} 

Какой самый простой способ сделать это?

Используйте шаблонный двигатель. StringTemplate – один из тех, и их много.

Вот версия для тех из вас, кто может использовать новую версию 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}." 

В строке – теперь это полностью поддерживаемая языковая функция (строчная интерполяция).

SmartFormat – довольно простая библиотека, которая отвечает всем вашим требованиям. Он ориентирован на составление текста «естественного языка» и отлично подходит для генерации данных из списков или применения условной логики.

Синтаксис очень похож на String.Format и очень прост и прост в освоении и использовании. Вот пример синтаксиса из документации:

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

Библиотека имеет отличные возможности обработки ошибок (игнорировать ошибки, выводить ошибки, ошибки броска). Очевидно, это будет работать идеально для вашего примера.

Библиотека с открытым исходным кодом и легко расширяемая, поэтому вы также можете улучшить ее с помощью дополнительных функций.

Вы можете использовать метод 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); 

Это позволяет вам изменять контент в будущем и дружелюбен для локализации.

Вы можете использовать string.Replace (…), в конце концов, для каждого из всех ключевых слов. Если есть несколько ключевых слов, вы можете использовать их в строке следующим образом:

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

Или вы можете использовать Regex.Replace (…), если вам нужно что-то более мощное и с большим количеством опций.

Прочтите эту статью на codeproject, чтобы узнать, какая опция замены строки для вас самая быстрая.

На самом деле вы можете использовать XSLT. Вы создаете простой XML-шаблон:

    

Dear , Your job finished at and your file is available for download at . Regards, --

Затем создайте XmlDocument для выполнения преобразования: 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); 

После этого примените преобразование:

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

Реализация собственного пользовательского форматирования может быть хорошей идеей.

Вот как вы это делаете. Во-первых, создайте тип, определяющий материал, который вы хотите ввести в ваше сообщение. Примечание. Я собираюсь проиллюстрировать это с пользовательской частью вашего шаблона …

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

Затем реализуем простой пользовательский форматтер …

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

Наконец, используйте его вот так …

 string template = "Dear {0:User}. Your job finished..."; JobDetails job = new JobDetails() { User = "Martin Peck" }; string message = string.Format(new ExampleFormatter(), template, job); 

… который будет генерировать текст «Дорогой Мартин Пек. Ваша работа закончена …».

На этом есть хорошая история с реализацией в блоге Фила Хаака: http://haacked.com/archive/2009/01/14/named-formats-redux.aspx

Очень простое решение на основе регулярных выражений. Поддерживает \n стильные одиночные escape-последовательности символов и {Name} -истовые имена переменных.

Источник

 class Template { /// Map of replacements for characters prefixed with a backward slash private static readonly Dictionary EscapeChars = new Dictionary { ['r'] = "\r", ['n'] = "\n", ['\\'] = "\\", ['{'] = "{", }; /// Pre-compiled regular expression used during the rendering process private static readonly Regex RenderExpr = new Regex(@"\\.|{([a-z0-9_.\-]+)}", RegexOptions.IgnoreCase | RegexOptions.Compiled); /// Template string associated with the instance public string TemplateString { get; } /// Create a new instance with the specified template string /// Template string associated with the instance public Template(string TemplateString) { if (TemplateString == null) { throw new ArgumentNullException(nameof(TemplateString)); } this.TemplateString = TemplateString; } /// Render the template using the supplied variable values /// Variables that can be substituted in the template string /// The rendered template string public string Render(Dictionary Variables) { return Render(this.TemplateString, Variables); } /// Render the supplied template string using the supplied variable values /// The template string to render /// Variables that can be substituted in the template string /// The rendered template string public static string Render(string TemplateString, Dictionary 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; }); } } 

Применение

 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 { ["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 

Заметки

  • Я только определил \n , \r , \\ и \{ escape-последовательности и жестко закодировал их. Вы можете легко добавить больше или сделать их определяемыми потребителем.
  • Я сделал переменные имена без учета регистра, так как такие вещи часто представлены конечным пользователям / не-программистам, и я лично не считаю, что чувствительность к регистру имеет смысл в этом прецеденте – это еще одна вещь, которую они может ошибиться и позвонить вам, чтобы жаловаться (плюс, в общем, если вы считаете, что вам нужны имена символов, чувствительных к регистру, то, что вам действительно нужно, – это лучшие имена символов). Чтобы сделать их чувствительными к регистру, просто удалите флаг RegexOptions.IgnoreCase .
  • Я удаляю неверные имена переменных и escape-последовательности из строки результата. Чтобы оставить их неповрежденными, верните Match.Value вместо пустой строки в конце обратного вызова Regex.Replace . Вы также можете сделать исключение.
  • Я использовал синтаксис {var} , но это может помешать встроенному синтаксису синтаксиса. Если вы хотите определить шаблоны в строковых литералах в вашем коде, может быть целесообразно изменить разделители переменных, например, %var% (regex \\.|%([a-z0-9_.\-]+)% ) или другой синтаксис по вашему выбору, который более подходит для использования.

Основываясь на ответе Бенджамина Грюнбаума, в C # версии 6 вы можете добавить @ с помощью $ и в значительной степени использовать свой код так, как он есть, например:

 var text = [email protected]"Dear {User}, Your job finished at {FinishTime} and your file is available for download at {FileURL}. Regards, -- {Signature} "; 

Если вам нужно что-то очень мощное ( но на самом деле не самый простой способ ), вы можете разместить ASP.NET и использовать его в качестве шаблона.

Вы будете иметь всю мощь ASP.NET для форматирования тела вашего сообщения.

Если вы кодируете в VB.NET, вы можете использовать литералы XML. Если вы кодируете на C #, вы можете использовать ShartDevelop для хранения файлов в VB.NET в том же проекте, что и код C #.

Interesting Posts
Давайте будем гением компьютера.