Automapper + EF4 + ASP.NET MVC - getting a "context" error (I know why, but how to fix it?)

I have this really basic code in an MVC controller action. It maps the model class Operationto the base model class OperationVM.

public class OperationVM: Operation 
{
    public CategoryVM CategoryVM { get; set; }
}

I need to download a complete list of categories to create an instance of CategoryVM.
Here's how I (try) to create List<OperationVM>to display in the view.

public class OperationsController : Controller {

    private SomeContext context = new SomeContext ();

    public ViewResult Index()
    {
        var ops = context.Operations.Include("blah...").ToList();
        Mapper.CreateMap<Operation, OperationVM>()
            .ForMember(
                dest => dest.CategoryVM, 
                opt => opt.MapFrom(
                    src => CreateCatVM(src.Category, context.Categories)
                    //  trouble here ----------------^^^^^^^
                )
            );
        var opVMs = ops.Select(op => Mapper.Map<Operation, OperationVM>(op))
                       .ToList();

        return View(opVMs);
    }
}

Everything works great the first time I got to the page. The problem is that the mapper object is static. Therefore, when called, an Mapper.CreateMap()instance of the current one is DbContextsaved in the closure specified by CreateMap ().

, , , , , DbContext.

:

The operation cannot be completed because the DbContext has been disposed.

: AutoMapper ?

"" automapper Mapper? , ? .

, . ?

+5
3

, . Ninject .

AutoMapper TypeConverters. , . CategoryVM , TypeConverter, :

using System;
using AutoMapper;

public class CategoryToCategoryVMConverter : 
        TypeConverter<Category, CategoryVM>
{
    public CategoryToCategoryVMConverter(DbContext context)
    {
        this.Context = context;
    }

    private DbContext Context { get; set; }

    protected override CategoryVM ConvertCore(Category source)
    {
        // use this.Context to lookup whatever you need
        return CreateCatVM(source, this.Context.Categories);
    }
}

AutoMapper :

Mapper.CreateMap<Category, CategoryVM>().ConvertUsing<CategoryToCategoryVMConverter>();

. AutoMapper , , DbContext . Ninject , DbContext . , DbContext , AutoMapper. Ninject :

Bind<DbContext>().To<SomeContext>().InRequestScope();

, , - factory, DbContext , .

, - .

+7

, . , AutoMapper , .

:

public class OperationsController : Controller {

    private SomeContext context = new SomeContext ();

    public ViewResult Index()
    {
        var ops = context.Operations.Include("blah...").ToList();
        Mapper.CreateMap<Operation, OperationVM>()
            .ForMember(dest => dest.CategoryVM, opt => opt.Ignore());

        var opVMs = ops.Select(
            op => {
                var opVM = Mapper.Map<Operation, OperationVM>(op);
                opVM.CategoryVM = CreateCatVM(op.Category, context.Categories);
                return opVM;
            })
            .ToList();

        return View(opVMs);
    }
}

- , AutoMapper...

+2

The answer from @LeffeBrune is perfect. However, I want to have the same behavior, but I do not want to display each property on my own. Basically, I just wanted to override "ConstructUsing".

Here is what I came up with.

public static class AutoMapperExtension
{
    public static void ConstructUsingService<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExression, Type typeConverterType)
    {
        mappingExression.ConstructUsing((ResolutionContext ctx) =>
        {
            var constructor = (IConstructorWithService<TSource, TDestination>)ctx.Options.ServiceCtor.Invoke(typeConverterType);
            return constructor.Construct((TSource)ctx.SourceValue);
        });
    }
}

public class CategoryToCategoryVMConstructor : IConstructorWithService<Category, CategoryVM>
{
    private DbContext dbContext;

    public DTOSiteToHBTISiteConverter(DbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public CategoryVM Construct(Category category)
    {
        // Some commands here
        if (category.Id > 0)
        {
            var vmCategory = dbContext.Categories.FirstOrDefault(m => m.Id == category.Id);
            if (vmCategory == null)
            {
                throw new NotAllowedException();
            }

            return vmCategory;
        }

        return new CategoryVM();
    }
}

// Initialization
Mapper.Initialize(cfg =>
{
    cfg.ConstructServicesUsing(type => nInjectKernelForInstance.Get(type));
    cfg.CreateMap<Category, CategoryVM>().ConstructUsingService(typeof(CategoryToCategoryVMConstructor));
};
0
source

All Articles