You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于工厂模式在ASP.NET MVC中动态生成表单控件的技术问询

基于工厂模式实现MVC表单视图生成方案

核心结论

必须为LongAnswerText和MultipleChoice分别创建对应的ConcreteStrategy类,这是实现类型与渲染逻辑解耦、可扩展的关键。

实现思路拆解

1. 定义统一的策略接口

先创建一个IPollingQuestionRenderer接口,规定所有问题类型必须实现的渲染方法:

public interface IPollingQuestionRenderer
{
    HtmlString Render(MeetingPollingQuestion question);
}

2. 实现两种类型的ConcreteStrategy类

分别针对两种问题类型编写控件渲染逻辑:

  • LongAnswerTextRenderer(对应标签+文本框)
public class LongAnswerTextRenderer : IPollingQuestionRenderer
{
    public HtmlString Render(MeetingPollingQuestion question)
    {
        var container = new TagBuilder("div");
        // 生成问题标签
        var label = new TagBuilder("label");
        label.Attributes["for"] = $"Q_{question.Id}";
        label.InnerHtml.Append(question.Title);
        container.InnerHtml.AppendHtml(label);
        
        // 生成文本框
        var textBox = new TagBuilder("textarea");
        textBox.Attributes["id"] = $"Q_{question.Id}";
        textBox.Attributes["name"] = $"PollAnswers[{question.Id}]";
        textBox.Attributes["rows"] = "5";
        container.InnerHtml.AppendHtml(textBox);
        
        return new HtmlString(container.ToString());
    }
}
  • MultipleChoiceRenderer(对应标签+单选按钮组)
public class MultipleChoiceRenderer : IPollingQuestionRenderer
{
    public HtmlString Render(MeetingPollingQuestion question)
    {
        var container = new TagBuilder("div");
        // 生成问题标签
        var label = new TagBuilder("label");
        label.InnerHtml.Append(question.Title);
        container.InnerHtml.AppendHtml(label);
        
        // 生成单选按钮组
        var options = question.PartsValues.Cast<ChoiceOption>();
        foreach (var option in options)
        {
            var optionContainer = new TagBuilder("div");
            
            var radioBtn = new TagBuilder("input");
            radioBtn.Attributes["type"] = "radio";
            radioBtn.Attributes["id"] = $"Q_{question.Id}_Opt_{option.Id}";
            radioBtn.Attributes["name"] = $"PollAnswers[{question.Id}]";
            radioBtn.Attributes["value"] = option.Value;
            optionContainer.InnerHtml.AppendHtml(radioBtn);
            
            var optionLabel = new TagBuilder("label");
            optionLabel.Attributes["for"] = $"Q_{question.Id}_Opt_{option.Id}";
            optionLabel.InnerHtml.Append(option.Text);
            optionContainer.InnerHtml.AppendHtml(optionLabel);
            
            container.InnerHtml.AppendHtml(optionContainer);
        }
        
        return new HtmlString(container.ToString());
    }
}

3. 实现工厂类封装类型判断

创建PollingRendererFactory,根据问题类型返回对应渲染器:

public static class PollingRendererFactory
{
    public static IPollingQuestionRenderer GetRenderer(MeetingPollingQuestionType type)
    {
        return type switch
        {
            MeetingPollingQuestionType.LongAnswerText => new LongAnswerTextRenderer(),
            MeetingPollingQuestionType.MultipleChoice => new MultipleChoiceRenderer(),
            _ => throw new NotSupportedException($"不支持的问题类型:{type}")
        };
    }
}

4. 在MVC视图中调用工厂生成表单

在Razor视图中遍历解析后的JSON数据,通过工厂生成对应控件:

@model List<MeetingPollingQuestion>

<form asp-action="SubmitPoll" method="post">
    @foreach (var question in Model)
    {
        var renderer = PollingRendererFactory.GetRenderer(question.Type);
        @renderer.Render(question)
    }
    <button type="submit">提交问卷</button>
</form>

方案优势

  • 解耦逻辑:新增问题类型时,只需添加新的Renderer类和工厂分支,无需修改现有代码
  • 可维护性:每种类型的渲染逻辑独立,便于调试和修改
  • 符合开闭原则:对扩展开放,对修改关闭

注意事项

  • 确保JSON解析后的MeetingPollingQuestion模型包含Id、Title、Type及对应类型的PartsValues(比如多选题的选项列表)
  • 渲染器中要正确设置表单控件的name属性,保证MVC模型绑定能正确接收提交的答案

内容的提问来源于stack exchange,提问作者Jefferson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 01:15:43