Blazor WebAssembly FetchData 无法在 SQL Server 上运行

Posted

技术标签:

【中文标题】Blazor WebAssembly FetchData 无法在 SQL Server 上运行【英文标题】:Blazor WebAssembly FetchData Will Not Work On SQL Server 【发布时间】:2021-10-20 12:42:10 【问题描述】:

我正在开发 Blazor WebAssembly 应用程序。我的目标是 .NET 5.0,通过 VS 2019 发布到文件夹。我的 Web 服务器是 Windows Server 2012 R2 上的 IIS 8。如果重要,该应用只能在我们的公司内部网中访问。

应用程序的当前状态是它具有默认计数器和天气预报,尽管我已将天气预报更改为查询 SQL 数据库。这个天气预报查询是通过 HTTP 请求完成的,如this Youtube tutorial 所示(下面包含一些相关代码)。我添加了第二组数据用于查询,也是通过 HTTP 请求执行的。

我的问题是,当我从 VS 2019 中启动应用程序并且 SQL 服务器托管在同一个开发工作站上时,我可以很好地获取数据(并对其进行 CRUD)。但是,当我发布到 IIS 时,我遇到了问题。

具体来说,如果 SQL Server 在我的开发工作站上,我会收到异常“响应状态代码不指示成功:404(未找到)”。查看控制台的网络部分,我在 http://[我的 IIS 服务器的网络可访问名称]:5001/api/weatherforecast 上看到 404。在我的开发机器上从 VS 2019 启动时,该特定页面加载正常。

我的一个想法是,这可能是 SQL Server Express 的身份验证问题。当指向我的本地工作站时,它通过以下连接字符串使用 Windows 身份验证:

"Default": "Data Source = [my development workstation's name]; Initial Catalog = blazorTest; Integrated Security = True; MultipleActiveResultSets = True"

为了测试这一点,我在虚拟服务器上设置了 SQL Server Express 2012(使用混合模式身份验证),并将连接字符串更改为:

"Data Source=[virtual server's name]; Initial Catalog=blazorTest; User Id=sa; Password=[super-secure password]"

现在,我在尝试访问天气预报时遇到了另一个错误,具体来说:

"Failed to load resource: the server responded with a status of 400 ()"

奇怪的是,这似乎是一个未捕获的异常,而不是我之前看到的 Console.Writeline(ex.Message)。未捕获的异常引用 /api/weatherforecast。

这是天气预报 API 的代码(CART 是应用程序的名称):

using CART.Server.Data_Access_Layer;
using CART.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CART.Server.Controllers

[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase

    private readonly ILogger<WeatherForecastController> _logger;
    private readonly WeatherDbContext _context;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, WeatherDbContext context)
    
        _logger = logger;
        _context = context;
    

    [HttpGet]
    public async Task<IActionResult> Get()
                
        try
        
            List<WeatherForecast> forecasts = await _context.Forecasts.ToListAsync();
            return Ok(forecasts);
        

        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
        

        return BadRequest();
    

    [HttpGet]
    [Route("id")]
    public async Task<IActionResult> GetById(int id)
    
        try
        
            WeatherForecast forecast = await _context.Forecasts.Where(f => f.Id == id).FirstOrDefaultAsync();
            return Ok(forecast);
        

        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
        

        return BadRequest();
        
    

    [HttpPost]
    public async Task<IActionResult> Create([FromBody] WeatherForecast forecast)
    
        try
        
            _context.Forecasts.Add(forecast);
            await _context.SaveChangesAsync();
            return Ok(forecast);
        

        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
        

        return BadRequest();            
    

    [HttpPut]
    [Route("id")]
    public async Task<IActionResult> Update(int id, WeatherForecast updatedForecast)
    
        try
        
            _context.Forecasts.Update(updatedForecast);
            await _context.SaveChangesAsync();

            return Ok(updatedForecast);
        

        catch (Exception ex)
        
            Console.WriteLine(ex.Message);
        

        return BadRequest();            
    

    [HttpDelete]
    [Route("id")]
    public async Task<IActionResult> Delete(int id)
    
        try
        
            WeatherForecast forecast = await _context.Forecasts.Where(f => f.Id == id).FirstOrDefaultAsync();
            _context.Forecasts.Remove(forecast);
            await _context.SaveChangesAsync();
            return Ok(forecast);
        
        
        catch (Exception ex) 
        
            Console.WriteLine(ex.Message); 
        

        return BadRequest();
    


因此,在我看来,没有任何尝试引发异常(因为在这种情况下我会看到 Console.WriteLine(ex.message)),但尚未达到尝试中的返回。相反,正在达到返回 BadRequest,这导致其他代码中的异常。但怎么可能呢?我怀疑我在这里误解了一些东西。

同样重要的是,我需要更改/调查哪些内容才能使其正常工作?

ETA:事实证明,虚拟服务器上的 SQL Server 未配置为允许远程连接。在 this link's answers 之后,我能够在 Visual Studio 中重新获取数据的基本 SQL 数据,并与远程 SQL Server 进行通信。但是,当我发布到虚拟服务器时,我继续得到"Response status code does not indicate success: 404 (Not Found)。此外,http://[虚拟服务器名称]:5001/api/weatherforecast 的 URL 得到 404。

【问题讨论】:

1) 在 IIS 上你不应该有 :5001 部分 2) 400 并不表示未处理的异常,而是 500。 3) 在 IIS 上,检查运行应用程序池的帐户。那应该可以访问数据库。 Re 1),我们在该虚拟服务器上同时运行 Apache 和 IIS,所以我确实需要指定端口,否则我最终将由 Apache 提供服务。 Re 2),我相信我收到的 400 来自我的“return BadRequest()”。由于它们位于 try-catch 之外,它表明发生了异常(以避免“返回 Ok()”),但不知何故没有被捕获。我可能在这方面有误。Re 3),我更新了应用程序的帐户Pool运行在我的Windows用户名下。我已经确认我的用户名可以通过Management Studio登录到数据库。但是错误仍然存​​在:-/。 如何将运行应用程序池的帐户更新为 windows 用户名?通常,IIS 上的应用程序想要连接到 sql server。需要将应用池添加到sql登录组。 【参考方案1】:

事实证明,虚拟服务器上的 SQL Server 未配置为允许远程连接。在this link's answers 之后,我能够让基本的 SQL 数据获取再次工作。

但是,我遇到了另一个问题,即 api/weatherforecast 无法在 IIS 8.5 或 Apache 2.4(在虚拟服务器的不同端口上运行的两个 Web 服务器)下路由。该页面将在 IIS Express 10 或 Kestrel(可以在 Visual Studio 中启动的两个 Web 服务器)下成功路由。

所以,我决定使用 Kestrel 作为虚拟服务器上的 Web 服务器。

我在 Server 项目的 Program.cs 中添加了 UseKestrel 和 UseUrls 行:

public class Program

    public static void Main(string[] args)
    
        CreateHostBuilder(args).Build().Run();
        

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            
                webBuilder.UseKestrel();
                webBuilder.UseUrls("http://localhost:5000", "http://[virtual server's network name]:5000");
                webBuilder.UseStartup<Startup>();
            );

然后我将整个解决方案复制到虚拟服务器上的 C:\inetpub 中。 (不过,我怀疑我可以使用任何目录。)然后我在虚拟服务器上安装了 .NET 5.0 SDK,在虚拟服务器上打开命令提示符,并在 C:\inetpub\Server 中运行 dotnet run(也就是我的 Blazor 解决方案的服务器部分所在的文件夹)。

那时我终于能够从虚拟服务器访问我的应用程序并让它从虚拟服务器上的 SQL 服务器检索 SQL 数据!

【讨论】:

以上是关于Blazor WebAssembly FetchData 无法在 SQL Server 上运行的主要内容,如果未能解决你的问题,请参考以下文章

明晚7点半 | Blazor + WebAssembly开启Web开发新体验

Blazor WebAssembly + Grpc Web = 未来?

Blazor WebAssembly 3.2 正式发布

「译」 用 Blazor WebAssembly 实现微前端

一起学Blazor WebAssembly 开发

通过 Serverless 加速 Blazor WebAssembly