Map async result with automapper

前端 未结 3 520
夕颜
夕颜 2021-02-01 07:14

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

        
相关标签:
3条回答
  • 2021-02-01 07:34

    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.

    0 讨论(0)
  • 2021-02-01 07:44

    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;
        }
    
    0 讨论(0)
  • 2021-02-01 07:52

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题