ActionResult<IEnumerable<T>> has to return a List<T>
Asked Answered
L

2

30

Take the following code using ASP.NET Core 2.1:

[HttpGet("/unresolved")]
public async Task<ActionResult<IEnumerable<UnresolvedIdentity>>> GetUnresolvedIdentities()
{
   var results = await _identities.GetUnresolvedIdentities().ConfigureAwait(false);
   return results.ToList();
}

I would have thought since GetUnresolvedIdentities() returns IEnumerable<UnresolvedIdentity> that I could just return

return await _identities.GetUnresolvedIdentities().ConfigureAwait(false);

Except I can't, as I get this error:

CS0029 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<Data.Infrastructure.Models.UnresolvedIdentity>' to 'Microsoft.AspNetCore.Mvc.ActionResult<System.Collections.Generic.IEnumerable<Data.Infrastructure.Models.UnresolvedIdentity>>'

I need the .ToList(), which is annoying as it's 2 lines rather than 1.

Why can't ActionResult<T> figure out that GetUnresolvedIdentities() returns an IEnumerable<> and just return that?

The signature of GetUnresolvedIdentities is:

Task<IEnumerable<UnresolvedIdentity>> GetUnresolvedIdentities();
Lazare answered 8/8, 2018 at 8:55 Comment(7)
Because IEnumerable is different than IEnumerable<T>. Either change _identities.GetUnresolvedIdentities return type or your controller return type.Selvage
Why not return await _identities.GetUnresolvedIdentities().ConfigureAwait(false).ToList();, if the "two lines" is the only thing bothering you?Littman
@Littman because you can't task.ToList(). (await task).ToList() would work thoughArtois
@VladiPavelka - yes, of course, thank you. ^_^Littman
You can wrap it around in ActionTask with the Ok helper method: return Ok(await _identities.GetUnresolvedIdentities());. P.S. you shouldn't call .ConfigureAwait(false) inside the controllers, unless you're 100% certain about the consequences (even though its not that much of an issue these days as it was in legacy ASP.NET). Its advised to always use it in general purpose libraries where its unknown in which context the library will be usedCrank
@Tseng, good catch on the COnfigureAwait(false). ThanksLazare
You actually don’t need to use ConfigureAwait anywhere with ASP.NET Core since it does not have a synchronization context.Bellinger
C
36

Take this documentation from msdn: https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.1#actionresultt-type

C# doesn't support implicit cast operators on interfaces. Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>.

Colewort answered 8/8, 2018 at 8:59 Comment(0)
S
6

You can resolve this in a relatively tidy way by using Ok(...)

[HttpGet]
public ActionResult<IEnumerable<MyDTOObject>> Get() => Ok(Repo.GetObjects());

[HttpGet]
public async Task<ActionResult<IEnumerable<MyDTOObject>>> GetAsync() => Ok(await Repo.GetObjectsAsync());

Which assuming that GetObjects() and GetObjectsAsync() return a IEnumerable<MyDTOObject> and Task<IEnumerable<MyDTOObject>> respectively - allows you to skip .ToList() or .ToListAsync().

Scruggs answered 15/2, 2022 at 16:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.