admin管理员组

文章数量:1353256

I have my web app calling an external API. That API then calls another external API.

All three items are separate and unconnected. I can call either API from my web app with no issues, but when I call my second API from my first API from my web app, I run into problems.

The error I get is

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: '[MyDbContext]'

All the calls are awaited, but it seems that the completion of the second API also completed the first one. The second API completes successfully and returns the expected result.

It not a problem I've run into before and I don't see a similar solution, anything I found close to this problem both calls in the the same app/api.

I kinda get whats going on but what I can't understand is why. Any help would be appreciated.

There is quite a lot of code to post here, so let me try and summarise

Web app

HttpClient client = new HttpClient();

List<string> payload = new() { "One", "Two", "Three", "Four" };

var result = await client.PostAsJsonAsync(";, payload);

var SomeObject so = JsonConvert.DeserializeObject<SomeObject>(result);

API #1:

[HttpPost("dostuff")]
public async Task<SomeOtherObject>DoStuff([FromBody]List<string> thePayload)
{
    // try and find my thing in my local database
    var SomeOtherObject soo = await _context.DbStuff.FirstOrDefaultAsync(c => c.Id == thePayload.Id);

    // not in my local db so go get is from the external service
    if (soo == null)
    {
        HttpClient client = new HttpClient();
        List<string> payload = new(){ "One", "Two", "Three", "Four" };

        // The problem happens here, this completion also completes the original API call
        var result = await client.PostAsJsonAsync(";, thePayload)

        soo = JsonConvert.DeserializeObject<SomeOtherObject>(result);

        // I do an object transform here, but you get my drift
        _context.DbStuff.Add(soo)
        await _context.SaveChangesAsync();
    }

    return soo;
}

API #2 is an external 3rd party API that returns successfully with the correct results

UPDATE
Minimal API doesn't work

app.MapPost("/url1.dostuff" ...

Controller works

    [HttpPost("/api/dostuff")]
    public async Task<List<SomeObject>> DoStuff([FromBody] List<string> payload)
    {
        // ...
    }

UPDATE Minimal API (original) sorry for the pseudo code but I'm trying not to give stuff away :)

        public static void RegisterStuffEndpoints(this WebApplication app)
        {
            var stuffGroup = app.MapGroup("api/dostuff").WithTags("DoStuff");
            // These are the endpoints that are used to get the data
            stuffGroup.MapPost("/dostuff", ([FromBody] List<string> source, StuffService service) => await TypedResults.Ok(service.DoStuff(source)));
        }

I have my web app calling an external API. That API then calls another external API.

All three items are separate and unconnected. I can call either API from my web app with no issues, but when I call my second API from my first API from my web app, I run into problems.

The error I get is

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: '[MyDbContext]'

All the calls are awaited, but it seems that the completion of the second API also completed the first one. The second API completes successfully and returns the expected result.

It not a problem I've run into before and I don't see a similar solution, anything I found close to this problem both calls in the the same app/api.

I kinda get whats going on but what I can't understand is why. Any help would be appreciated.

There is quite a lot of code to post here, so let me try and summarise

Web app

HttpClient client = new HttpClient();

List<string> payload = new() { "One", "Two", "Three", "Four" };

var result = await client.PostAsJsonAsync("http://url.ap1/dostuff", payload);

var SomeObject so = JsonConvert.DeserializeObject<SomeObject>(result);

API #1:

[HttpPost("dostuff")]
public async Task<SomeOtherObject>DoStuff([FromBody]List<string> thePayload)
{
    // try and find my thing in my local database
    var SomeOtherObject soo = await _context.DbStuff.FirstOrDefaultAsync(c => c.Id == thePayload.Id);

    // not in my local db so go get is from the external service
    if (soo == null)
    {
        HttpClient client = new HttpClient();
        List<string> payload = new(){ "One", "Two", "Three", "Four" };

        // The problem happens here, this completion also completes the original API call
        var result = await client.PostAsJsonAsync("http://url.ap2/dootherstuff", thePayload)

        soo = JsonConvert.DeserializeObject<SomeOtherObject>(result);

        // I do an object transform here, but you get my drift
        _context.DbStuff.Add(soo)
        await _context.SaveChangesAsync();
    }

    return soo;
}

API #2 is an external 3rd party API that returns successfully with the correct results

UPDATE
Minimal API doesn't work

app.MapPost("/url1.dostuff" ...

Controller works

    [HttpPost("/api/dostuff")]
    public async Task<List<SomeObject>> DoStuff([FromBody] List<string> payload)
    {
        // ...
    }

UPDATE Minimal API (original) sorry for the pseudo code but I'm trying not to give stuff away :)

        public static void RegisterStuffEndpoints(this WebApplication app)
        {
            var stuffGroup = app.MapGroup("api/dostuff").WithTags("DoStuff");
            // These are the endpoints that are used to get the data
            stuffGroup.MapPost("/dostuff", ([FromBody] List<string> source, StuffService service) => await TypedResults.Ok(service.DoStuff(source)));
        }

Share Improve this question edited Apr 2 at 8:06 DarkBee 15.5k8 gold badges72 silver badges117 bronze badges asked Apr 1 at 19:58 djack109djack109 1,3832 gold badges29 silver badges45 bronze badges 5
  • 2 Sounds like you are missing an await somewhere in your code. Or you have some async void shenanigans going on somewhere. How do you inject _context? Do you have a full minimal reproducible example you can share? – Guru Stron Commented Apr 1 at 20:05
  • Thanks for the pointer, there was indeed some shenanigans going on. I'm using minimal API and I have over 100 endpoints that work just fine, however this one (the newest) does not – djack109 Commented Apr 1 at 20:30
  • 2 Can you please post the full minimal API version? – Guru Stron Commented Apr 1 at 20:39
  • await TypedResults.Ok looks suspiciously uncompilable to me TBH =) – Guru Stron Commented Apr 1 at 21:02
  • You are correct, it isnt, with or without the await this minimal API implementation doesn't work for this use case. Good old controller saves the day lol – djack109 Commented Apr 1 at 21:05
Add a comment  | 

2 Answers 2

Reset to default 0

Quite simple when you think about it. I was thinking too far left field.

        public static void RegisterStuffEndpoints(this WebApplication app)
        {
            var stuffGroup = app.MapGroup("api/dostuff").WithTags("DoStuff");
            // These are the endpoints that are used to get the data
            stuffGroup.MapPost("/dostuff", async ([FromBody] List<string> source, StuffService service) => TypedResults.Ok(await service.DoStuff(source)));
        }

The problem is that your DbContext was probably disposed of too soon while you were waiting for the first API to submit the second API request. Avoid encapsulating the context in using statements or outright discarding it to correct this. Permit the dependency injection lifecycle to be managed. Additionally, make sure that every HTTP request and answer is appropriately awaited. This will enable smooth chaining across APIs and avoid the "disposed context" problem.

本文标签: cHow to call an external api from another external apiStack Overflow