IFeatureCollection has been disposed. Object name: 'Collection'. going from controller to view

3.9k Views Asked by At

I am new to all of this, and am in the early stages of making this web application. This is just for my personal use. I am trying to display the results of a web api call in a view. The api call works fine. I can see the data coming back from services and being placed in the DTO fine. It goes from the services to the controller but I am not sure why every time I try to send data from the controller to the view I get the same exception:

IFeatureCollection has been disposed. Object name: 'Collection'.

Can anyone tell me what does it mean and how do I fix the issue?

Here is my Startup.cs


public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("mapQUrl", client => { client.BaseAddress = new Uri("https://www.mapquestapi.com/geocoding/v1/address?"); });
    services.AddHttpClient("climaUrl", client => { client.BaseAddress = new Uri("https://api.climacell.co/v3/weather/nowcast?"); });
    services.AddControllersWithViews();
    services.AddScoped<IServices, Services>();

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

This is my services:

public async Task<List<ClimaCellDto>> GetTemp(MapQuestFlatDto loc)
{
    List<ClimaCellDto> dataObjects = new List<ClimaCellDto>();
    
    var client = _clientFactory.CreateClient("climaUrl");
    string attr = "unit_system=us&timestep=5&start_time=now&fields=temp&";
    var url = client.BaseAddress + attr + climaUrlParameters;

    // Add an Accept header for JSON format.
    client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = await client.GetAsync(url);  // Blocking call! Program will wait here until a response is received or a timeout occurs.
    if (response.IsSuccessStatusCode)
    {
        // Parse the response body.
        var strContent = await response.Content.ReadAsStringAsync();  //Make sure to add a reference to System.Net.Http.Formatting.dll

        dataObjects = JsonConvert.DeserializeObject<List<ClimaCellDto>>(strContent);
        return dataObjects;
    }
    else
    {
        Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
    }

    return dataObjects;
}

This is the controller method that is receiving the data from the service and sending it to the view:

[HttpPost]
public async void getLoc ([FromBody]ZipDto obj)
{    
    var zip = Int32.Parse(obj.zip);
    var location = await _services.GetLatLng(zip);
    var climate =  await _services.GetTemp(location);
    ShowResults(climate);
}

public IActionResult ShowResults(List<ClimaCellDto> data)
{
    try
    {
        return View(data);
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

and this is the view:

    @model IEnumerable<Weather_web_app.DTOs.ClimaCellDto>

@{
    ViewData["Title"] = "ShowResults";
}

<h1>ShowResults</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.lat)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.lon)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.observation_time.value)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.temp.value)
            </td>
        </tr>
}
    </tbody>
</table>

This is the call stack:

at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ThrowContextDisposed()
    at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ContextDisposed()
    at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.Fetch[TFeature,TState](TFeature& cached, TState state, Func`2 factory)
    at Microsoft.AspNetCore.Http.DefaultHttpContext.get_RequestServices()
    at Microsoft.AspNetCore.Mvc.Controller.get_TempData()
    at Microsoft.AspNetCore.Mvc.Controller.View(String viewName, Object model)
    at Microsoft.AspNetCore.Mvc.Controller.View(Object model)

I have looked online for hours for someone having a similar issue but I have not found anything. Any help is greatly appreciated. Thanks in advance.

1

There are 1 best solutions below

0
On BEST ANSWER

It seems like you're not using the controller method correctly. You need to return the view form the endpoint method itself. At the moment you're only returning from the ShowResults method which is not being propagated up. Try this (look at the return types):

[HttpPost]
public async Task<IActionResult> getLoc ([FromBody]ZipDto obj)
{    
    var zip = Int32.Parse(obj.zip);
    var location = await _services.GetLatLng(zip);
    var climate =  await _services.GetTemp(location);
    return ShowResults(climate);
}

public IActionResult ShowResults(List<ClimaCellDto> data)
{
    try
    {
        return View(data);
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Also, one more thing I would recommend is to redirect to a GET method rather than returning a view from a POST endpoint directly.