We are createing a Web.Api application of a angularjs application. The Web.Api returns a json result.
Step one was getting the data:
public List
You need to move the async data fetch out of the Map call:
var data = await dataRepository.GetDataAsync();
return Mapper.Map<List<DataItem>>(data);
Alternatively, you can use AutoMapper LINQ projections:
var data = await dbContext.Data.ProjectTo<DataItem>().ToListAsync();
I don't know if your repository exposes IQueryable directly (we don't use repositories). Our apps use the second version pretty much exclusively these days.
You can also add a couple of Task Extension Methods that will do this for you:
public static Task<TReturn> Convert<T, TReturn>(this Task<T> task)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
var tcs = new TaskCompletionSource<TReturn>();
task.ContinueWith(t => tcs.TrySetCanceled(), TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(t =>
{
tcs.TrySetResult(Mapper.Map<T, TReturn>(t.Result));
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => tcs.TrySetException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
return tcs.Task;
}
public static Task<List<TReturn>> ConvertEach<T, TReturn>(this Task<List<T>> task)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
var tcs = new TaskCompletionSource<List<TReturn>>();
task.ContinueWith(t => tcs.TrySetCanceled(), TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(t =>
{
tcs.TrySetResult(t.Result.Select(Mapper.Map<T, TReturn>).ToList());
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(t => tcs.TrySetException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
return tcs.Task;
}
Jose's solution proved quite useful to me. I did, however, re-target the extension method to extend IMapper which allowed me to remove the singleton Mapper reference.
public static class MapperExtensions
{
public static Task<TResult> MapAsync<TSource, TResult>(this IMapper mapper, Task<TSource> task)
{
if (task == null)
{
throw new ArgumentNullException(nameof(task));
}
var tcs = new TaskCompletionSource<TResult>();
task
.ContinueWith(t => tcs.TrySetCanceled(), TaskContinuationOptions.OnlyOnCanceled);
task
.ContinueWith
(
t =>
{
tcs.TrySetResult(mapper.Map<TSource, TResult>(t.Result));
},
TaskContinuationOptions.OnlyOnRanToCompletion
);
task
.ContinueWith
(
t => tcs.TrySetException(t.Exception),
TaskContinuationOptions.OnlyOnFaulted
);
return tcs.Task;
}
}