如何根据第一个API的响应获取第二个API的数据?

huangapple go评论66阅读模式
英文:

How to fetch a second API based on the response of a first API?

问题

I don't understand why my C# code isn't working.

Basically I want to fetch a URL, and once I get the response I want to use that response and fetch another URL.

For this, I have two methods:

TestSuiteModel TestSuites;
public async Task GetTestSuites()
{

string url = "https://dev.azure.com/XXX/_apis/test/Plans/12/suites?api-version=5.0";
TestSuites = await TestSuiteService.GetTestSuites(url);

if (TestSuites != null)
{
    foreach (var ts in TestSuites.value)
    {
        await this.GetTestCasess(ts.url);
    }
}

}

TestCasesModel TestCases;
private async Task GetTestCasess(string url)
{
TestCases = await TestCasesService.GetTestCases(url);
}

and then I try to render the result like this:

@if (TestSuites != null)
{

    @foreach (var ts in TestSuites.value)
    {

  • @ts.name
  • }

}

@if (TestCases.value != null)
{

    @foreach (var ts in TestCases.value)
    {

  • @ts.testCase.webUrl
  • }

}

The first foreach works, but the second one throws this error:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

TestCases was null.

It is always the same error no matter how I rewrite the logic.

The second URL has no issues.

Basically, there are no issues with the URLs, Models, Services. The problem has something to do with async/await that I haven't figured out yet.

For context, this is how I am calling my Models, Services, and OnInitializedAsync:

@page "/";
@using BlazorTest.Models.TestSuiteModel;
@using BlazorTest.Models.TestCasesModel;

@inject BlazorTest.Services.TestSuiteService TestSuiteService;
@inject BlazorTest.Services.TestCasesService TestCasesService;

protected override async Task OnInitializedAsync()
{

await this.GetTestSuites();
await base.OnInitializedAsync();

}

英文:

I don't understand why my C# code isn't working.

Basically I want to fetch a URL, and once I get the response I want to use that reponse and fetch another URL.

For this, I have two methods:

TestSuiteModel TestSuites;
public async Task GetTestSuites()
{

    string url = "https://dev.azure.com/XXX/_apis/test/Plans/12/suites?api-version=5.0";
    TestSuites = await TestSuiteService.GetTestSuites(url);


    if(TestSuites != null)
    {
        foreach (var ts in TestSuites.value)
        {
            await this.GetTestCasess(ts.url); 
        }
    }
}

TestCasesModel TestCases; 
private async Task GetTestCasess(string url)
{
    TestCases = await TestCasesService.GetTestCases(url);
}

and then I try to render the result like this:

@if(TestSuites != null)
{
<ul>
    @foreach (var ts in TestSuites.value)
    {
        <li> @ts.name </li>
    }
</ul>
}



@if (TestCases.value != null)
{
    <ul>
        @foreach (var ts in TestCases.value)
        {
             <li> @ts.testCase.webUrl </li>
        }
    </ul>
}

The first foreach works, but the second one throws this error:

> System.NullReferenceException: 'Object reference not set to an
> instance of an object.'
>
> TestCases was null.

It is always the same error no matter how re-write the logic.

The second URL has no issues.

Basically there is no issues with the URLs, Models, Services. The problem has something to do with async/await I haven't figured out yet.

For context, this is how I am calling my Models, Services and OnInitializedAsync

@page "/"; 


@using BlazorTest.Models.TestSuiteModel; 
@using BlazorTest.Models.TestCasesModel;

@inject BlazorTest.Services.TestSuiteService TestSuiteService;
@inject BlazorTest.Services.TestCasesService TestCasesService;

protected override async Task OnInitializedAsync()
{

    await this.GetTestSuites();
    await base.OnInitializedAsync();

}

答案1

得分: 1

我假设错误与任何请求或特定逻辑无关。


错误消息是:

System.NullReferenceException: '未将对象引用设置到对象的实例。'

TestCases为null。

它表示TestCases的值为空。

我在你的代码中看到了这一行:

@if (TestCases.value != null)

你应该将它改为(注意 ?):

@if (TestCases?.value != null)

它会检查TestCases是否不为空,或者TestCases.value是否不为空。


?. – 一个空值条件运算符,只有在其操作数评估为非空时才对其进行成员访问操作;否则,它返回 null

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-

英文:

> I assume, the error is not relevant to any requests or specific logic


Error message is:

> System.NullReferenceException: 'Object reference not set to an instance of an object.'
>
> TestCases was null.

It says: value of the TestCases is null.

It means that you are trying to do something with value of TestCases.

I see this line in your code:

> @if (TestCases.value != null)

You should change it to (notice the ?):

> @if (TestCases?.value != null)

It will check if TestCases is not null or TestCases.value is not null.


> ?. – a null-conditional operator applies a member access operation to its operand only if that operand evaluates to non-null; otherwise, it returns null
>
> https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-

答案2

得分: 1

@Vlad DX 是正确的。

原因是因为第一个异步调用会将线程控制返回给组件代码,从而触发渲染事件。在这一点上,`TestCases` 是空的。

以下是您问题的最小复现代码示例。

我假设您要么在项目中禁用了 `Nullable`,要么忽略了警告???
英文:

@Vlad DX is correct.

The reason is because the first async call yields thread control back to Component code which runs a render event. At which point TestCases is null.

Here's a minimum reproduction code sample of your issue.

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

@if(TestSuiteModel is not null)
{
    <div>display</div>
}

@*Will Work*@
@*@if (TestCaseModel?.Value is not null)
{
    <div>display</div>
}
*@

@if (TestCaseModel.Value is not null)
{
    <div>display</div>
}


@code {
    TestSuite? TestSuiteModel;
    TestCase? TestCaseModel;

    protected async override Task OnInitializedAsync()
        => await GetData();

    private async ValueTask GetData()
    {
        // fake an async call to an API/Db
        await Task.Delay(1000);
        // First render of the component occurs here
        TestSuiteModel = new(Enumerable.Empty<string>());
        // fake an async call to an API/Db
        await Task.Delay(1000);
        TestCaseModel = new(Enumerable.Empty<string>());
    }

    public record TestSuite(IEnumerable<string> Value);
    public record TestCase(IEnumerable<string> Value);
}

I'm assuming you either have Nullable disabled on the project or are ignoring the warnings???

huangapple
  • 本文由 发表于 2023年2月16日 04:05:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464937.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定