Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该如何生成HTML来表示类及其属性?_C#_Asp.net - Fatal编程技术网

C# 我应该如何生成HTML来表示类及其属性?

C# 我应该如何生成HTML来表示类及其属性?,c#,asp.net,C#,Asp.net,目前,我有一个表示文档的类。此文档需要显示为HTML。我希望有一个方法可以调用,比如GetHTML(),然后对需要呈现的文档的任何属性/部分调用GetHTML()。我最初考虑使用linq和XElement,但我想知道这是否会导致HTML中的某些标记出现问题。我是否最好使用HtmlTextWriter?对于这种情况,我愿意接受任何建议或最佳实践。谢谢 我认为您所说的是拥有一个能够以HTML呈现自身的数据模型,并且您希望确保合成中具有保真度,并且它能够递归地发现和呈现子对象 “经典”ASP.net在

目前,我有一个表示文档的类。此文档需要显示为HTML。我希望有一个方法可以调用,比如
GetHTML()
,然后对需要呈现的文档的任何属性/部分调用
GetHTML()
。我最初考虑使用linq和
XElement
,但我想知道这是否会导致HTML中的某些标记出现问题。我是否最好使用
HtmlTextWriter
?对于这种情况,我愿意接受任何建议或最佳实践。谢谢

我认为您所说的是拥有一个能够以HTML呈现自身的数据模型,并且您希望确保合成中具有保真度,并且它能够递归地发现和呈现子对象

“经典”ASP.net在其呈现模型中是如何做到这一点的,就是一切都是一个控件,每个控件都有一个呈现(HtmlTextWriter)方法。包含子控件(复合控件、用户控件、页面等)的控件具有逻辑,可以在其自身的上下文中递归呈现其每个子控件。例如,复合控件的Render方法调用RenderBeginTag,然后调用RenderChildren,然后调用RenderEndTag,同时传递对用于呈现整个响应的同一HtmlTextWriter的引用。像页面和用户控件这样的东西甚至有点复杂,因为它们也解析模板(aspx),但归根结底,这些模板只是一个呈现方法的处方

好吧,问题是,从分离关注点的角度来看,它很糟糕。为什么数据文档需要包含所有代码才能以HTML呈现自身?我也不喜欢GetHtml()的想法,因为它(对我)意味着你要重新发明一些已经发明出来的东西。在这里重用MVC ViewEngine可能是一个好主意:它有很多特性,与HtmlTextWriter之类的东西相比易于开发

无论如何。我的建议是为文档类创建一个新接口;让我们称之为“iRenderable”。这个接口的唯一要求是一个名为“ViewName”的字符串

如果要将文档(模型)转换为HTML,只需调用RenderPartial(Model.ViewName,Model)。如果该文档具有iRenderable子元素,那么(从该视图中),再次调用RenderPartial(model.SomeChild.ViewName,model.SomeChild)

好了。MVC使用模板来完成繁重的工作,你也不用在数据模型中烘焙一堆额外的程序渲染垃圾

interface IRenderable
{
    string ViewName
    {
        get;
    }
}

public class Table : IRenderable
{
    public string ViewName
    {
        get
        {
            return "Table";
        }
    }

    public List<Row> Rows { get; set; }
}

public class Row : IRenderable
{
    public string ViewName
    {
        get
        {
            return "Row";
        }
    }

    public string Value { get; set; }
}
接口IRenderable
{
字符串视图名
{
得到;
}
}
公共类表:IRenderable
{
公共字符串视图名
{
得到
{
返回“表”;
}
}
公共列表行{get;set;}
}
公共类行:IRenderable
{
公共字符串视图名
{
得到
{
返回“行”;
}
}
公共字符串值{get;set;}
}

您可能会问,如果表知道它包含行,为什么还要费心处理接口?因为在某些情况下,您可能有一个要渲染的对象(或对象集合),而您的父视图不知道该类型。您仍然可以通过尝试强制转换为IRenderable来渲染对象

如果您自己创建了DOM,那么您可以查看访问者模式。它将允许您避免在DOM本身中使用特定的代码来创建HTML文档。我不久前也做过同样的事情,但仍然找到了使用这种方式向DOM类添加新功能的新方法。以下是一些例子:

interface IVisitable {
    void Assign(IVisitor);
}

interface IVisitor {
    void Visit(Document document);
    void Visit(Section section);
    void Visit(Paragraph paragraph);
}

class Element : IVisitable {
    void IVisitable.Assign(IVisitor visitor) {
        this.Assign(visitor);
    }
    protected abstract void Assign(IVisitor visitor);
}

abstract class Block : Element { }
abstract class Inline : Element { }
abstract class BlockContainer<TElement> : Block, ICollection<TElement> { }
abstract class ElementContainer<TElement> : Element, ICollection<TElement> { }
abstract class InlineContainer<TElement> : Inline, ICollection<TElement> { }

class Paragraph : BlockContainer<Inline> {
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); }
}

class Section : BlockContainer<Block> {
    public string Title { get; set; }
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); }
}

class Document : ElementContainer<Block> {
    protected override void Assign(IVisitor visitor) { visitor.Visit(this); }
}
这个方法提供了一个实现,在这个实现中,您可以只覆盖您感兴趣的那些元素,如果您不覆盖这些方法中的任何一个,那么将引入更通用的访问方法,它只针对元素的ICollection部分(正如我前面所说的,访问者模式要求您了解所有关于可访问元素的信息)

要使用此实现创建某种深度优先搜索行为,将引入另一个访问者:

abstract class SearchVisitor : Visitor {
    protected override Visit(ICollection<Block> container) {
        this.AssignAll(container);
    }
    protected override Visit(ICollection<Inline> container) {
        this.AssignAll(container);
    }
    protected override Visit(ICollection<Element> container) {
        this.AssignAll(container);
    }
    private void AssignAll<TElement>(IEnumerable<TElement> container) {
        foreach (IVisitable element in container) {
            element.Assign(this);
        }
    }
}
我在这个“布局”上花了很多时间,所以我可以很快地复制它,但它可能会产生一些开销。如果您想了解这方面的更多详细信息,请告诉我。

一些代码示例(无论多么简短)可能会有所帮助。
abstract class SearchVisitor : Visitor {
    protected override Visit(ICollection<Block> container) {
        this.AssignAll(container);
    }
    protected override Visit(ICollection<Inline> container) {
        this.AssignAll(container);
    }
    protected override Visit(ICollection<Element> container) {
        this.AssignAll(container);
    }
    private void AssignAll<TElement>(IEnumerable<TElement> container) {
        foreach (IVisitable element in container) {
            element.Assign(this);
        }
    }
}
class HtmlMarkupRenderer : SearchVisitor {
    private readonly XmlWriter writer;
    private int sectionDepth = 0;
    public HtmlMarkupRenderer(TextWriter textWriter) {
        this.writer = XmlWriter.Create(textWriter, new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment });

    public override void Visit(Section section) {
        this.sectionDepth++;
        string headingElement = String.Concat("h", Math.Max(this.sectionDepth, 6));
        this.writer.WriteElementString(headingElement, section.Title);
        // The base implementation will assign this visitor to all childs of section.
        base.Visit(section);
        this.sectionDepth--;
    }

    public override void Visit(Paragraph paragraph) {
        this.writer.WriteStartElement("p");
        base.Visit(paragraph);
        this.writer.WriteEndElement();
    }
}