Skip to content
This repository has been archived by the owner on May 25, 2023. It is now read-only.

FYI, how to use AutoMapper in custom ResultFilterAttribute #69

Closed
dylanwa opened this issue Sep 9, 2018 · 9 comments
Closed

FYI, how to use AutoMapper in custom ResultFilterAttribute #69

dylanwa opened this issue Sep 9, 2018 · 9 comments

Comments

@dylanwa
Copy link

dylanwa commented Sep 9, 2018

Please check comments in
https://app.pluralsight.com/library/courses/building-async-api-aspdotnet-core/discussion
this function broken in v5.0.1 and works in v4.0.1

@dylanwa
Copy link
Author

dylanwa commented Sep 9, 2018

Using v4.0.1, add this in ConfigureServices, works
Service.AddAutoMapper()

Using v5.0.1, add this in ConfigureServices, get error "Mapper not initialized"
Service.AddAutoMapper()
must add explicit initialization to make it work:
services.AddAutoMapper();
Mapper.Initialize(cfg => cfg.AddProfile());

@dylanwa
Copy link
Author

dylanwa commented Sep 10, 2018

Thanks for the link.
It seems the static Map function is not recommended in v5.0.1 now.

Could you please give me an idea how to use _mapper.Map in a custom ResultFilterAttribute?

https://github.com/KevinDockx/BuildingAsyncAPIAspNetCore/blob/master/Finished%20sample/Books/Books.Api/Filters/BookResultFilterAttribute.cs

@lbargaoanu
Copy link
Member

I would change the question to how do you do DI in general in a custom ResultFilterAttribute. I don't have an answer to that, but surely it's possible somehow.

@jbogard
Copy link
Member

jbogard commented Sep 10, 2018

With any filter, they don't want you to do constructor injection. Filters typically have a singleton lifecycle. Instead, core ASP.NET extensions pass in a context parameter that then gives you access to an IServiceProvider. So that example should be:

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Books.Api.Filters
{
    public class BookResultFilterAttribute : ResultFilterAttribute
    {
        public override async Task OnResultExecutionAsync(ResultExecutingContext context, 
            ResultExecutionDelegate next)
        {
            var resultFromAction = context.Result as ObjectResult;
            if (resultFromAction?.Value == null
               || resultFromAction.StatusCode < 200
               || resultFromAction.StatusCode >= 300)
            {
                await next();
                return;
            }
            
            var mapper = context.HttpContext.RequestServices.GetService<IMapper>();
            resultFromAction.Value = mapper.Map<Models.Book>(resultFromAction.Value);

            await next();
        }
    }
}

@dylanwa
Copy link
Author

dylanwa commented Sep 11, 2018

Awesome, thanks Jimmy, that's what I want!

Just a small change on your code and it works!

var mapper = (IMapper) context.HttpContext.RequestServices.GetService(typeof(IMapper)); resultFromAction.Value = mapper.Map<Models.Book>(resultFromAction.Value);

@jbogard
Copy link
Member

jbogard commented Sep 11, 2018

FYI that GetService<T>() method is an extension method in the Microsoft.Extensions.DependencyInjection namespace.

@dylanwa
Copy link
Author

dylanwa commented Sep 13, 2018

You're right! 💯

@dylanwa dylanwa changed the title Service.AddAutoMapper() breaks when using v5.0.1 FYI, how to use AutoMapper in custom ResultFilterAttribute Sep 13, 2018
@lock
Copy link

lock bot commented Jun 3, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants