Рендеринг объектов C# в Html
у нас есть куча объектов домена, которые должны быть отображены в формате html, который показывает их детали во всплывающем окне.
Я был бы рад сделать что-то вроде этого:
Product product = new Product(...);
product.ToHtml(); // or: HtmlRenderer.Render(Product);
но моя главная проблема заключается в том, как это делать Сзади. У меня есть 3 разных ответа:
1. Рендеринг По Коду:
Я могу просто написать свой код для рендеринга Html внутри метода ToHtml (C#) - проблема в том, что это слишком статический. если вы хотите немного переместить заголовок в середину, вы должны изменить код. кроме того, очень трудно прочитать отступ Html В C#.
2. Использование XSL:
xsl-файлы могут легко управлять HTML-шаблоном и с помощью XSLT я могу преобразовать XML-файл в нужное место документов. парсер уже написан кем-то другим (просто нужно изучать синтаксис) ** для этого нам нужно, чтобы каждый объект можно сериализовать в Xml. и если объект изменен - > Xml будет изменен -> xslt также необходимо изменить ** это также даст мне возможность легко отступить html, например: добавление возможностей css иили изменить дизайн html
3. использование другого движка шаблонов:
напишите мой собственный C# -> html template Engine, чтобы он прочитал шаблон из файла (*.template) и вставит нужное свойство в нужное место шаблона, используя отражение. ** в это решение у нас есть много проблем, которые мы можем придумать, например: как должен быть синтаксис? это нормально? %Name% %описание% и как мы можем обрабатывать массивы? ** может быть, мы можем использовать существующий движок (Brail или T4-Templating)?
что вы предпочитаете? вы знаете хороший двигатель? пока я предпочитаю второе решение, но оно будет очень медленным.
спасибо
7 ответов
Я не могу согласиться с Джоном Feminella. Интеграция HTML-рендеринга непосредственно в объекты домена-это ужасное загрязнение вашего домена совершенно произвольной и внешней заботой. Как сказал Джон, сделав это, вы сделаете свои сущности очень хрупкими и нарушите оба критических правила: разделение забот и Единую ответственность.
из вариантов, которые вы дали, #3 ближе всего к соответствующему способу сделать это. Вам не нужно писать свой собственный шаблон двигатель. В сети есть много бесплатных и готовых шаблонных движков, которые сделают работу более чем адекватно (NVelocity, StringTemplate, Brail и т. д. так далее.)
продолжайте рендеринг, где он принадлежит...в вашей презентации / представлении, и не загрязняйте свой домен проблемами более высокого уровня.
когда-то мне нужно было отобразить коллекцию любого типа в таблицу Html. Я создал метод расширения на IEnumerable
http://crazorsharp.blogspot.com/2009/03/cool-ienumberable-extension-method_25.html
Он использует отражение, чтобы получить все свойства объекта, а также оказывает хороший столик. Посмотрим, сработает ли это для тебя.
[System.Runtime.CompilerServices.Extension()]
public string ToHtmlTable<T>(IEnumerable<T> list, string propertiesToIncludeAsColumns = "")
{
return ToHtmlTable(list, string.Empty, string.Empty, string.Empty, string.Empty, propertiesToIncludeAsColumns);
}
[System.Runtime.CompilerServices.Extension()]
public string ToHtmlTable<T>(IEnumerable<T> list, string tableSyle, string headerStyle, string rowStyle, string alternateRowStyle, string propertiesToIncludeAsColumns = "")
{
dynamic result = new StringBuilder();
if (String.IsNullOrEmpty(tableSyle)) {
result.Append("<table id=\"" + typeof(T).Name + "Table\">");
} else {
result.Append((Convert.ToString("<table id=\"" + typeof(T).Name + "Table\" class=\"") + tableSyle) + "\">");
}
dynamic propertyArray = typeof(T).GetProperties();
foreach (object prop in propertyArray) {
if (string.IsNullOrEmpty(propertiesToIncludeAsColumns) || propertiesToIncludeAsColumns.Contains(prop.Name + ",")) {
if (String.IsNullOrEmpty(headerStyle)) {
result.AppendFormat("<th>{0}</th>", prop.Name);
} else {
result.AppendFormat("<th class=\"{0}\">{1}</th>", headerStyle, prop.Name);
}
}
}
for (int i = 0; i <= list.Count() - 1; i++) {
if (!String.IsNullOrEmpty(rowStyle) && !String.IsNullOrEmpty(alternateRowStyle)) {
result.AppendFormat("<tr class=\"{0}\">", i % 2 == 0 ? rowStyle : alternateRowStyle);
} else {
result.AppendFormat("<tr>");
}
foreach (object prop in propertyArray) {
if (string.IsNullOrEmpty(propertiesToIncludeAsColumns) || propertiesToIncludeAsColumns.Contains(prop.Name + ",")) {
object value = prop.GetValue(list.ElementAt(i), null);
result.AppendFormat("<td>{0}</td>", value ?? String.Empty);
}
}
result.AppendLine("</tr>");
}
result.Append("</table>");
return result.ToString();
}
Это работа вашего представления, а не ваши контроллеры или модели. Как вы подозреваете, использование метода (1) сделает ваши изменения очень хрупкими. Вместо этого напишите фрагмент представления для каждого способа, в котором вы хотите отобразить определенную сущность домена. Затем просто потяните соответствующие представления, чтобы создать свою последнюю страницу.
Я искренне предпочитаю метод A. HTML уже является стандартом, поэтому вы не должны слишком сильно избивать себя промежуточными форматами, такими как XML (через XSL - Метод 2) или пользовательский формат (метод 3).
Если запись в / для ASP.NET MVC вы можете, однако, построить .ASCX (пользовательский элемент управления), который будет принимать объект вашего типа и отображать соответствующий HTML. И вы не получите неприятный отступ C# и никакой подсветки или автозаполнения.
вы также можете написать несколько пользовательских представлений для размещения различных сценариев для одного типа объекта.
после немного исследований я сделал свою собственную функцию для преобразования любого объекта toHtmlString.
VB .Net код:
Public Function ToHtmlString(ByVal fObj As Object) As String
Dim pType = fObj.GetType()
Dim props As IList(Of PropertyInfo) = pType.GetProperties()
Dim value As Object = Nothing
Dim htmlString As String = "<html><body><form>"
For Each p In props
value = p.GetValue(fObj, Nothing)
If value <> Nothing Then
htmlString += String.Format("<input type=""hidden"" name=""{0}"" id=""{0}"" value=""{1}""/>", p.Name, value)
End If
Next
htmlString += "</form></body></html>"
Return htmlString.ToString()
он получит имя свойства и значение от конкретного объекта. вы можете манипулировать HTML на основе вашего
лично я бы объединил метод два и три: просто создайте общий XML-документ, используя отражение, скажем:
<object type="xxxx">
<property name="ttt" value="vvv"/>
...
</object>
и используйте таблицу стилей XSTL для создания фактического HTML из этого.
почему вы не хотите создать пользовательский элемент управления .ascx-файл, который принимает объект объектов домена в качестве аргумента, а затем вы можете сделать gui любым способом. Таким образом, вы можете динамически добавлять элементы управления на страницу и просто устанавливать свойство для их заполнения.
Edit 1: Просто визуализируйте элемент управления HTMLTextWriter вместо размещения его на странице.
StringBuilder outString = new StringBuilder();
StringWriter outWriter = new StringWriter(outString);
HtmlTextWriter htmlText = new HtmlTextWriter(outWriter);
System.Web.UI.WebControls.Label lbl1 = new System.Web.UI.WebControls.Label();
lbl1.Text = "This is just a test!";
lbl1.ToolTip = "Really";
lbl1.RenderControl(htmlText);
ViewData["Output"] = outString.ToString();
выход
<span title="Really">This is just a test!</span>
конечно, используйте свой пользовательский элемент управления вместо встроенного управления, но это была быстрая и простая демонстрация.