Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper IValueResolver: Cannot access a disposed object. Object name: 'IServiceProvider'

I want to use IValueResolver in AutoMapper to map two class, and one value will be take from HttpRequest Context, so I want to use IValueResolver

CreateMap<Dto, ViewModel>().ForMember(x=>x.MemberID, opt=>opt.Mapfrom<SpecialResolver>())

and Resolver is simple

public string Resolve(ViewModel viewModel, Dto dto, string destMember, ResolutionContext context)
{
  return "test";
}

inside startup class i put this:

services.AddAutoMapper(typeof(Startup));

but every time I map them for MemberID will throw out error say IServiceProvider been disposed. so how to make these work? I tried inject this SpecialResolver in startup but also not work. BTW, I'm use .net core 3.0

like image 761
BeiBei ZHU Avatar asked Oct 15 '25 20:10

BeiBei ZHU


1 Answers

I'm strongly convinced that a bug has crept in your code somewhere and hence your problems. On my side, everything works just fine. I tried to recrete what you are trying to do, based on your question and comments. It will surely differ more or less, but you should be able to grasp the idea and get it going on your own.

I'm starting with a mapping profile, where I'm explicitly specifying usage of HttpContextValueResolver for MemberId property of ViewModel class:

public class MyMappingProfile : Profile
{
    public MyMappingProfile()
    {
        CreateMap<Dto, ViewModel>()
            .ForMember(x => x.MemberId, opt => opt.MapFrom<HttpContextValueResolver>());
    }
}

Then the value resolver:

public class HttpContextValueResolver : IValueResolver<Dto, ViewModel, string>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpContextValueResolver(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string Resolve(Dto source, ViewModel destination, string destMember, ResolutionContext context)
    {
        // Obtain whatever you need from HTTP context.
        // Warning! HTTP context may be null.

        return _httpContextAccessor.HttpContext?.Request.Path;
    }
}

To acess HttpContext outside a controller I used a dedicated for that purpose service called IHttpContextAccessor. Read more about it in the docs.

It isn't automatically available, so I need to register it in Startup alongside with the AutoMapper:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddAutoMapper(typeof(Startup));

    services.AddHttpContextAccessor();
}

Take notice that registering AutoMapper while passing just one type (of Startup), requires that all mapping profiles need to be in the same assembly (project) as the Startup. With mapping profiles in more than one assembly, you need to specify those assemblies or types with a suitable overload of the AddAutoMapper() method.

And finally usage in an example controller:

public class HomeController : Controller
{
    private readonly IMapper mapper;

    public HomeController(IMapper mapper)
    {
        this.mapper = mapper;
    }

    public IActionResult Index()
    {
        var source = new Dto
        {
            MemberID = "123",
        };
        var result = mapper.Map<ViewModel>(source);

        return View();
    }
}

And here are the dto and view model I used:

public class Dto
{
    public string MemberID { get; set; }
}
public class ViewModel
{
    public string MemberId { get; set; }
}
like image 197
Prolog Avatar answered Oct 18 '25 11:10

Prolog



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!