如何使 Blazor HTTP Get JSON ASYNC 请求?

how to make Blazor HTTP Get JSON ASYNC request?

我正在尝试在示例应用程序中实现一个小的 crud。

我在应用程序中使用 blazor,但发现服务器调用存在一些问题。

我创建了一个简单的 API 控制器,其名称为 Employee 和带有 HTTP 动词的方法。

 [ApiController]
    [Route("[controller]")]
    public class EmployeeController : ControllerBase
    {
        EmployeeRepository objemployee = new EmployeeRepository();   
        [HttpGet]
        [Route("api/Employee/Index")]
        public IEnumerable<Employee> Index()
        {
            return objemployee.GetAllEmployees();
        }
   }  

empList = await Http.GetJsonAsync<Employee[]>("/api/Employee/Index"); 

line 报告了一个问题,我对此一无所知,因为我是 blazor 的新手。我应该在我的代码中做什么?

使用 asp 构建的应用程序。网络核心 3.0", "blazor preview 9".

输出: 我尝试遵循指南并查找示例实现,但无法解决问题。

我收到以下异常:

  WASM: Unhandled exception rendering component:
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM: 
    System.Text.Json.JsonException: 
    '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0. ---> 
    System.Text.Json.JsonReaderException: '<' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
d.printErr @ blazor.webassembly.js:1
    blazor.webassembly.js:1 WASM:   at.    System.Text.Json.ThrowHelper.ThrowJsonReaderException (System.Text.Json.Utf8JsonReader& json, System.Text.Json.ExceptionResource resource, System.Byte nextByte, System.ReadOnlySpan`1[T] bytes) <0x2398fc8 + 0x00020> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.Utf8JsonReader.ConsumeValue (System.Byte marker) <0x1fa7718 + 0x0028e> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.Utf8JsonReader.ReadFirstToken (System.Byte first) <0x1fa6d60 + 0x001ec> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.Utf8JsonReader.ReadSingleSegment () <0x1fa6618 + 0x00234> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.Utf8JsonReader.Read () <0x1fa61d0 + 0x00012> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x1fa5b40 + 0x00062> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:    --- End of inner exception stack trace ---
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.ThrowHelper.ReThrowWithPath (System.Text.Json.ReadStack& readStack, System.Text.Json.JsonReaderException ex) <0x23e6bc8 + 0x00116> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.JsonSerializer.ReadCore (System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader, System.Text.Json.ReadStack& readStack) <0x1fa5b40 + 0x002a8> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.JsonSerializer.ReadCore (System.Type returnType, System.Text.Json.JsonSerializerOptions options, System.Text.Json.Utf8JsonReader& reader) <0x1fa4e70 + 0x0003e> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.JsonSerializer.ParseCore (System.String json, System.Type returnType, System.Text.Json.JsonSerializerOptions options) <0x1fa1698 + 0x00086> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at System.Text.Json.JsonSerializer.Deserialize[TValue] (System.String json, System.Text.Json.JsonSerializerOptions options) <0x2398808 + 0x00022> in <81e9245ca982431695a55cc67ffb3b86>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.GetJsonAsync[T] (System.Net.Http.HttpClient httpClient, System.String requestUri) <0x2270e18 + 0x000fa> in <900d091618e14952821fd2fc9b26598c>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at EMS.Client.Pages.FetchEmployee.OnInitializedAsync () [0x0002a] in C:\ES\Client\Pages\FetchEmployee.razor:51 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync () <0x1f4ed10 + 0x00176> in <cc81133ac6304aada69282c517e2b811>:0 
d.printErr @ blazor.webassembly.js:1
blazor.webassembly.js:1 WASM:   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask (System.Threading.Tasks.Task taskToHandle) <0x224b4e8 + 0x000f4> in <cc81133ac6304aada69282c517e2b811>:0 
 `

我猜问题与您的 Web Api 有关,其中 returns Html 而不是 JSON。 GetJsonAsync 方法运行良好,JSON 解析器也运行良好。也许员工模型有问题...

尝试使用这个:

[ApiController]
public class EmployeeController: ControllerBase
{
   EmployeeRepository objemployee = new EmployeeRepository();   
        [HttpGet("/")]
        public IEnumerable<Employee> Index()
        {
            return objemployee.GetAllEmployees();
        }

}

然后像这样调用 Web Api:

empList = await Http.GetJsonAsync<Employee[]>("api/Employee"); 

请注意删除了 url 中的前导“/”。这可能是问题的根源。

  • 在您的代码中使用异步编程可能是个好主意
  • 在您的应用程序中注入总是比创建对象更好,例如 EmployeeRepository

看来您要求的 API 分不对。只需检查您的终点返回 json 而不是 html:打开导航器并转到 http://localhost:5000/api/Employee/Index.

看你的代码,建议你修改:

Route("[controller]"...

作者:

Route("/api/[controller]"...

我认为这不是 Blazor 问题,我假设您使用的是 Blazor WebAssembly 托管模板?

如果您尝试通过在浏览器中导航到您的 API 端点来加载它,您会看到什么?我猜是 404 未找到还是 500 错误?

我认为问题在于您如何在 API 控制器上定义路线。尝试以下设置。

[ApiController]
[Route("[controller]")]
public class EmployeeController : ControllerBase
{
    EmployeeRepository objemployee = new EmployeeRepository();  

    [HttpGet]
    public IEnumerable<Employee> Index()
    {
        return objemployee.GetAllEmployees().ToArray();
    }

}

然后打个电话employees = await Http.GetJsonAsync<Employee[]>("Employee");,如果一切顺利,你应该会得到你的员工名单。

我遇到了错误

System.Text.Json.JsonReaderException: '<' is an invalid start of a value

在我对 return 类型的控制器方法进行有效代码更改后出现几次,只是为了错误似乎无缘无故地停止发生,即使没有进行进一步的代码更改。

我猜测发生了某种缓存,有一段时间 Blazor WASM 客户端正在寻找现在需要不同参数或 return 不同对象类型的控制器端点。

我试过重新启动 VS,删除 obj、bin 和 .vs 文件等都没有帮助,所以我猜这可能是 Chrome 缓存问题,或者某种原因在 Blazor WebAssembly 创建的调试电路上缓存。

因此,如果您进行这些检查:

  • 您控制器上的路由属性是否与客户端中使用的 requestUri 匹配?所以例如如果你的路线是 [Route("api/[controller]")] 那么你使用的 requestUri 也需要有 api\
  • 控制器的名称(减去 'Controller')是否与您在客户端中调用的 requestUri 匹配?
  • 如果您使用 Http.GetFromJsonAsync<YourType>
  • ,控制器方法的 return 类型是否与您反序列化的目标相匹配

一切都如预期的那样,那么可能值得终止 Chrome 的进程,甚至重新启动您的 PC 以查看是否清除了异常,然后再花太多时间追查可能是幻影的错误.

解决方案是将所有 Nuget 包更新到 5.0.4。另外,请确保将 Visual Studio 2019 更新到最新版本。此外,您必须确保您的证书有效,即自签名 PFX。您不必使用 dot-net dev-certs,但您需要一份正式注册的证书才能使 HTTPS 正常运行。这是 Web 和 YouTube 上有据可查的程序。此外,您可能希望将日志记录代码添加到相关的服务器端位置,以便查看发生了什么。

下面显示的是来自控制台的 Kestrel HTTPS 启动,作为我的输出功能的证据。学习很好很有趣-赞美耶稣!

服务器端代码现在可见并且断点正在运行。在我将所有附加的 Nuget 包更新到 5.0.4 之后,这一切就在今天,即 2021 年 3 月 25 日星期二开始工作。请参阅最底部的创建脚本。

您还会看到各种 Console.Writeline 指令的输出,注释为 'First Hit'、'Second Hit' 等。这些是查看最新情况的方法。日志记录技术也开始发挥作用,但您需要学习如何附加它并自行输出。

..\dotnet watch --verbose run -c Debug
watch : Evaluating dotnet-watch file set.
watch : Running MSBuild target 'GenerateWatchList' on 'C:\Beachgoo.Authority\Server\Authority.Server.csproj'
watch : Started 'C:\Program Files\dotnet\dotnet.exe' 'msbuild /nologo C:\Beachgoo.Authority\Server\Authority.Server.csproj /p:_DotNetWatchListFile=D:\Global_TMP\h4f00m3z.2oq /nologo /v:n /t:GenerateWatchList /p:DotNetWatchBuild=true /p:DesignTimeBuild=true "/p:CustomAfterMicrosoftCommonTargets=C:\Program Files\dotnet\sdk.0.201\DotnetTools\dotnet-watch.0.201-servicing.21123.24\tools\net5.0\any\DotNetWatch.targets" "/p:CustomAfterMicrosoftCommonCrossTargetingTargets=C:\Program Files\dotnet\sdk.0.201\DotnetTools\dotnet-watch.0.201-servicing.21123.24\tools\net5.0\any\DotNetWatch.targets"' with process id 10188
watch : Process id 10188 ran for 3629ms
watch : Watching 39 file(s) for changes
watch : Watch command can be configured to use --no-restore.
watch : No restore arguments: run --no-restore -c Debug
watch : dotnet-watch is configured to launch a browser on ASP.NET Core application startup.
watch : Refresh server running at ws://127.0.0.1:23993.
watch : Started 'C:\Program Files\dotnet\dotnet.exe' 'run -c Debug' with process id 9768
watch : Running dotnet with the following arguments: run -c Debug
watch : Started
Building...
First hit: now in Server Program.Main() method of Program.cs
Second hit: IPAddress.Parse
Third hit: now in ConfigureKestrel() => listopt lambda
Certificate Path is: /wwwroot/<yourssc>.pfx, <yourpassword>
Fourth Hit: Added WebAssemblyDebugging in development should be: True
Fifth Hit: Inside the UseEndoints Lambda in Startup.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://192.168.2.3:5000
watch : Launching browser.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://192.168.2.3:5001
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Beachgoo.Authority\Server
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside constructor for ApiController ResortQualitiesController. This type is: Authority.Server.Controllers.ResortQualitiesController
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside HTTP Get(), on server side Kestrel.
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside constructor for ApiController ResortQualitiesController. This type is: Authority.Server.Controllers.ResortQualitiesController
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside HTTP Get(), on server side Kestrel.
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside constructor for ApiController ResortQualitiesController. This type is: Authority.Server.Controllers.ResortQualitiesController
trce: Authority.Server.Controllers.ResortQualitiesController[0]
      Inside HTTP Get(), on server side Kestrel.

我的创作脚本在这里。我也玩过坚持,但你可以刮一下。

@ECHO OFF
@CLS
@REM Rename / create the word <Trial> as you need.
@REM C:\Trial.bat
@ECHO -------------------------
@ECHO  Trial System Build
@ECHO -------------------------
@ECHO.
C:
CD C:\
@ECHO ------Build WASM---------
dotnet new blazorwasm -lang "C#" -o <your.folder.<Trial> -n <Trial> -f net5.0 -ho -p
@ECHO ----Create Persistence----
cd C:\<yourfolder.<Trial>
dotnet new classlib -lang "C#" -n Persistent -f net5.0
dotnet add .\Persistent\Persistent.csproj package Microsoft.EntityFrameworkCore --version 5.0.4
dotnet add .\Persistent\Persistent.csproj package Microsoft.AspNetCore.Identity.UI --version 5.0.4
dotnet add .\Persistent\Persistent.csproj package Microsoft.Extensions.Configuration --version 5.0.0
dotnet add .\Persistent\Persistent.csproj package Microsoft.EntityFrameworkCore.Tools --version 5.0.4
dotnet add .\Persistent\Persistent.csproj package Microsoft.EntityFrameworkCore.SqlServer --version 5.0.4
dotnet add .\Persistent\Persistent.csproj package Microsoft.AspNetCore.Identity.EntityFrameworkCore --version 5.0.4
dotnet add .\Persistent\Persistent.csproj package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore --version 5.0.4
@ECHO.
@ECHO -----Combine Projects-----
dotnet sln <Trial>.sln add .\Persistent\Persistent.csproj
@ECHO.
CD \
@ECHO.
@ECHO Done! Completed <Trial> Solution Build.