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

如何在ASP.NET Core Razor应用中调用ASP.NET API并展示页面数据

核心问题说明

你当前的实现存在3个直接导致报错、功能异常的问题:

  • HttpClient使用方式错误:每次调用都新建实例极易触发套接字耗尽,且你使用的52189是IIS Express随机分配的临时端口,项目重启后端口大概率变化,同时开发环境自签名HTTPS证书未做适配也会触发连接拒绝,最终抛出Cannot assign requested address异常。
  • Razor Pages生命周期逻辑错误:在PageModel构造函数中调用async void类型的异步方法,构造函数不会等待异步任务执行完成,页面开始渲染时数据往往还未拉取完成,同时async void会导致异步异常无法被框架捕获,直接触发进程级错误。
  • 职责划分错误:不应该在MVC控制器中编写静态方法供Razor Pages调用,控制器的职责是处理入站HTTP请求,跨服务调用逻辑应该独立抽离,硬编码API地址的方式也会大幅提升后续维护成本。
落地实现步骤

1. 固定API端口、注册HttpClient实例

首先进入API项目的Properties/launchSettings.json文件,将applicationUrl配置的端口固定为一个不常用的固定值(比如https://localhost:7001),避免每次启动端口随机变化。
然后在Razor Pages Web项目的Program.cs中,使用IHttpClientFactory注册专用的HTTP客户端,彻底解决手动new HttpClient导致的套接字耗尽问题:

// 注册调用Incident接口专用的HttpClient
builder.Services.AddHttpClient("IncidentApiClient", client =>
{
    client.BaseAddress = new Uri("https://localhost:7001/");
    // 仅开发环境使用,用于绕过自签名证书验证,生产环境必须删除此行
    client.ServerCertificateCustomValidationCallback = (_, _, _, _) => true;
});

2. 抽离独立的API调用服务

不要把API调用逻辑写在控制器中,在Web项目下新建Services文件夹,添加专门的事件服务类处理接口调用:

// Services/IncidentService.cs
public class IncidentService
{
    private readonly IHttpClientFactory _clientFactory;

    public IncidentService(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public async Task<List<IncidentModel>> GetAllIncidentsAsync()
    {
        var client = _clientFactory.CreateClient("IncidentApiClient");
        var response = await client.GetAsync("api/incident");
        // 先验证接口请求状态,避免接口报错时反序列化空内容抛出异常
        response.EnsureSuccessStatusCode();
        var resultStr = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<List<IncidentModel>>(resultStr);
    }
}

回到Program.cs将服务注册到依赖注入容器:

builder.Services.AddScoped<IncidentService>();

3. 修正PageModel的异步调用逻辑

删除构造函数中的业务调用,使用Razor Pages原生提供的OnGetAsync生命周期方法处理页面加载时的异步数据拉取,框架会自动等待该方法执行完成后再渲染页面:

// Pages/Index.cshtml.cs
public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    private readonly IncidentService _incidentService;
    // 使用明确的强类型代替dynamic,避免视图渲染时出现动态类型解析错误
    public List<IncidentModel> IncidentList { get; set; }

    public IndexModel(ILogger<IndexModel> logger, IncidentService incidentService)   
    {
        _logger = logger;
        _incidentService = incidentService;
    }

    public async Task OnGetAsync()
    {
        IncidentList = await _incidentService.GetAllIncidentsAsync();
    }
}

4. Razor页面渲染数据

在Index.cshtml中通过Model访问拉取到的列表数据,遍历渲染即可:

@page
@model IndexModel
@{
    ViewData["Title"] = "事件列表";
}

<h1>事件列表</h1>
<table class="table table-bordered">
    <thead>
        <tr>
            <th>事件ID</th>
            <th>事件标题</th>
            <th>创建时间</th>
        </tr>
    </thead>
    <tbody>
        @if (Model.IncidentList != null && Model.IncidentList.Any())
        {
            @foreach (var item in Model.IncidentList)
            {
                <tr>
                    <td>@item.Id</td>
                    <td>@item.Title</td>
                    <td>@item.CreateTime.ToString("yyyy-MM-dd HH:mm")</td>
                </tr>
            }
        }
        else
        {
            <tr>
                <td colspan="3" class="text-center">暂无数据</td>
            </tr>
        }
    </tbody>
</table>
验证注意事项
  • 调试时需要同时启动API项目和Razor Pages Web项目,确保API端口有服务正常监听,启动后先手动在浏览器访问API地址,确认能正常返回JSON数据再调试Web项目。
  • 检查本机防火墙、代理软件规则,确保没有拦截localhost对应端口的请求。
  • 除了事件处理场景,不要在ASP.NET Core中使用async void编写异步方法,所有业务异步方法都要返回Task或Task<T>类型,避免异常逃逸、执行顺序混乱的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 23:18:25