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

ASP.NET Core MVC中单选按钮选项无法渲染问题排查

ASP.NET Core MVC单选按钮无法从配置渲染问题

我正在开发一个带有单选按钮的ASP.NET Core MVC应用,该应用从appsettings.json文件中获取DocSource选项。运行应用时,控制器已能正确读取配置中的对应值,但这些值似乎无法正确传递到视图,导致单选按钮选项未正常渲染。以下是相关代码信息:

appsettings.json配置

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
        }
    },
    "AllowedHosts": "*",
    "DocumentSources": [
        {
            "DocSource": "Supplier",
            "DocumentTypes": [
                "Ocean Bill of Lading",
                "Container Packing List",
                "Suppliers Invoice",
                "Required USDA Information",
                "Spur Note",
                "Arrival Notice",
                "Freight Invoice",
                "Other"
            ]
        },
        {
            "DocSource": "Customer",
            "DocumentTypes": [
                "Purchase Order",
                "Correspondence",
                "Remittance Notice"
            ]
        },
        {
            "DocSource": "Vendor",
            "DocumentTypes": [
                "Action Invoice",
                "Rhody Invoice",
                "Vendor Invoice",
                "Product / Service Quote",
                "Order Confirmation"
            ]
        },
        {
            "DocSource": "Other",
            "DocumentTypes": [
                "See Description"
            ]
        }
    ]
}

模型类代码

namespace RLPDocumentUpload.Models
{
    public class Document
    {
        public int Id { get; set; }
        public DateTime DocumentDate { get; set; }
        public string DocumentDesc { get; set; } = string.Empty;
        public string DocumentSource { get; set; } = string.Empty;
        public string DocumentType { get; set; } = string.Empty;
        public string FilePath { get; set; } = string.Empty;
    }

    public class DocumentSettings
    {
        public List<string> DocumentSources { get; set; }
    }
}

视图代码

@{ 
    var documentSources = ViewBag.DocumentSources as List<DocumentSource>;
}

<!DOCTYPE html>
<html>
<head>
    <title>Upload Document</title>
    <link rel="stylesheet" type="text/css" href="/css/site.css" />
    <script src="/js/site.js"></script>
</head>
<body>
    <div class="form-group" style="padding-top: 10px;">
        <table width="100%">
            <tbody>
                <tr>
                    <td style="width: 31.489%;">
                        <img src="https://rlpritchard.com/wp-content/uploads/2020/03/ship.jpg" alt="RLP Logo" width="228" height="141" />
                    </td>
                    <td style="width: 65.511%;">
                        <h1 style="text-align: center;"><strong>RL Pritchard &amp; Co., Inc.</strong></h1>
                    </td>
                </tr>
                <tr>
                    <td>&nbsp;</td>
                    <td style="color: #007bff; text-align: center;"><h2>Document Upload</h2></td>
                </tr>
            </tbody>
        </table>
    </div>

    <form action="/Document/Upload" method="post" enctype="multipart/form-data">
        <div class="form-group">
            <label for="DocumentDesc" style="font-weight: bold; color: #3264a8;">Document Description</label>
            <input type="text" id="DocumentDesc" name="DocumentDesc" class="form-control" />
            <span class="text-danger"></span>
        </div>

        <div class="form-group" style="padding-top: 10px;">
            <label for="DocSource" style="font-weight: bold; color: #3264a8;">Document Source</label>
            <div id="documentSourceGroup" style="padding-left: 15px;">
                <!-- Radio buttons will be populated here by JavaScript -->
            </div>
            <span class="text-danger"></span>
        </div>

        <div class="form-group" style="padding-top: 10px;">
            <label for="DocumentType" style="font-weight: bold; color: #3264a8;">Document Type</label>
            <select id="documentTypeDropdown" name="DocumentType" class="form-control">
                <!-- Options will be populated here by JavaScript -->
            </select>
            <span class="text-danger"></span>
        </div>

        <div class="form-group" style="padding-top: 10px;">
            <label for="DocumentDate" style="font-weight: bold; color: #3264a8;">Document Date</label>
            <input type="date" id="DocumentDate" name="DocumentDate" class="form-control" />
            <span class="text-danger"></span>
        </div>

        <div class="form-group" style="padding-top: 10px;">
            <label for="upload" style="font-weight: bold; color: #3264a8;">Upload File</label>
            <input type="file" name="upload" class="form-control" />
        </div>

        <button type="submit" class="btn btn-primary" style="margin-top: 15px;">Upload</button>
    </form>

    @if (ViewBag.SuccessMessage != null)
    {
        <script>
            alert('@ViewBag.SuccessMessage');
            window.location.href = '/Document/Upload';
        </script>
    }

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const documentSources = @Html.Raw(Json.Serialize(ViewBag.DocumentSources));
            const documentSourceGroup = document.getElementById('documentSourceGroup');
            const documentTypeDropdown = document.getElementById('documentTypeDropdown');

            function populateDocumentSources() {
                documentSources.forEach(source => {
                    const radio = document.createElement('input');
                    radio.type = 'radio';
                    radio.name = 'DocSource';
                    radio.value = source.DocSource;
                    radio.id = source.DocSource;
                    if (source.DocSource === 'Supplier') {
                        radio.checked = true;
                    }

                    const label = document.createElement('label');
                    label.htmlFor = source.DocSource;
                    label.textContent = source.DocSource;
                    label.style.color = '#3264a8';

                    const div = document.createElement('div');
                    div.appendChild(radio);
                    div.appendChild(label);

                    documentSourceGroup.appendChild(div);
                });
            }

            function populateDocumentTypes(selectedSource) {
                documentTypeDropdown.innerHTML = '';
                const source = documentSources.find(s => s.DocSource === selectedSource);
                source.DocumentTypes.forEach(type => {
                    const option = document.createElement('option');
                    option.value = type;
                    option.textContent = type;
                    documentTypeDropdown.appendChild(option);
                });
            }

            documentSourceGroup.addEventListener('change', function (event) {
                if (event.target.name === 'DocSource') {
                    populateDocumentTypes(event.target.value);
                }
            });

            populateDocumentSources();
            populateDocumentTypes('Supplier');
        });
    </script>
</body>
</html>

控制器代码

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using RLPDocumentUpload.Models;
using System.Collections.Generic;

public class DocumentController : Controller
{
    private readonly IConfiguration _configuration;

    public DocumentController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public IActionResult Upload()
    {
        var documentSources = _configuration.GetSection("DocumentSources").Get<List<DocumentSource>>();
        ViewBag.DocumentSources = documentSources;
        return View();
    }

    [HttpPost]
    public IActionResult Upload(DocumentUploadModel model)
    {
        if (ModelState.IsValid)
        {
            // Handle the file upload
            ViewBag.SuccessMessage = "Document uploaded successfully!";
        }

        return View();
    }

    [HttpGet]
    public IActionResult GetDocumentSources()
    {
        var documentSources = _configuration.GetSection("DocumentSources").Get<List<DocumentSource>>();
        return Json(documentSources);
    }
}

public class DocumentSource
{
    public string DocSource { get; set; } = string.Empty;
    public List<string> DocumentTypes { get; set; } = new List<string>();
}

public class DocumentUploadModel
{
    public string DocumentDesc { get; set; }
    public string DocSource { get; set; }
    public string DocumentType { get; set; }
    public DateTime DocumentDate { get; set; }
    public IFormFile? Upload { get; set; } // Made nullable
}

Startup.cs代码

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using RLPDocumentUpload.Models;

public class Startup
{
    private readonly IConfiguration Configuration;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.Configure<DocumentSettings>(Configuration.GetSection("DocumentSources"));
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Document}/{action=Upload}/{id?}");
        });
    }
}

Program.cs代码

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// Access configuration settings
var documentSources = builder.Configuration.GetSection("DocumentSources").Get<List<DocumentSource>>();

// Register the configuration settings as a singleton service
builder.Services.AddSingleton(documentSources);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Document}/{action=Upload}/{id?}");

app.Run();

渲染效果

渲染效果截图


问题原因及修复方案

1. 命名空间不匹配导致类型转换失败

控制器中定义的DocumentSource和DocumentUploadModel未归属到RLPDocumentUpload.Models命名空间,视图默认引用该命名空间,导致ViewBag.DocumentSources转换为List<DocumentSource>时返回null,JavaScript无法获取数据生成单选按钮。

修复:将这两个类移到RLPDocumentUpload.Models命名空间下:

namespace RLPDocumentUpload.Models
{
    public class DocumentSource
    {
        public string DocSource { get; set; } = string.Empty;
        public List<string> DocumentTypes { get; set; } = new List<string>();
    }

    public class DocumentUploadModel
    {
        public string DocumentDesc { get; set; }
        public string DocSource { get; set; }
        public string DocumentType { get; set; }
        public DateTime DocumentDate { get; set; }
        public IFormFile? Upload { get; set; }
    }
}

2. 修正视图中的类型转换

更新视图顶部的类型转换代码,指定完整命名空间:

@{ 
    var documentSources = ViewBag.DocumentSources as List<RLPDocumentUpload.Models.DocumentSource>;
}

3. 修复Post请求后的数据回显

当前Post方法返回视图时未重新设置ViewBag.DocumentSources,提交后单选按钮会消失。修改Post方法:

[HttpPost]
public IActionResult Upload(DocumentUploadModel model)
{
    if (ModelState.IsValid)
    {
        // 处理文件上传逻辑
        ViewBag.SuccessMessage = "文档上传成功!";
    }
    // 重新加载配置数据到ViewBag
    var documentSources = _configuration.GetSection("DocumentSources").Get<List<DocumentSource>>();
    ViewBag.DocumentSources = documentSources;
    return View(model);
}

4. 优化配置读取(可选)

既然已在Program.cs中注册List<DocumentSource>为单例,可直接注入控制器,避免重复读取配置:

private readonly List<DocumentSource> _documentSources;

public DocumentController(List<DocumentSource> documentSources)
{
    _documentSources = documentSources;
}

public IActionResult Upload()
{
    ViewBag.DocumentSources = _documentSources;
    return View();
}

5. 验证数据传递

在浏览器开发者工具中查看页面源码,确认@Html.Raw(Json.Serialize(ViewBag.DocumentSources))输出了正确的JSON数组,确保JavaScript能正常读取数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:54:53