2

When I use a web type registered with autofac from an automapper mapping, I get this error:

No scope with a Tag matching 'httpRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.

When another type is resolved in the mapping it works. When a web type is resolved from the controller it works.

Why doesnt web (or any other httprequest scoped?) types get successfully resolved in my mapping?

    protected void Application_Start()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<AutofacWebTypesModule>();
        builder.RegisterControllers(Assembly.GetExecutingAssembly());
        builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
        builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .AssignableTo<Profile>()
            .As<Profile>()
            ;
        builder.Register(c => Mapper.Engine)
            .As<IMappingEngine>();
        builder.RegisterType<AnotherType>()
            .As<IAnotherType>();
        var container = builder.Build();

        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        var profiles = container.Resolve<IEnumerable<Profile>>();
        Mapper.Initialize(c => profiles.ToList().ForEach(c.AddProfile));

        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

public class HomeController : Controller
{
    private readonly IMappingEngine _mapper;
    private readonly Func<HttpContextBase> _httpContext;

    public HomeController(IMappingEngine mapper, Func<HttpContextBase> httpContext)
    {
        _mapper = mapper;
        _httpContext = httpContext;
    }

    public ActionResult Index()
    {
        var test = _httpContext.Invoke();
        return View(_mapper.Map<Model, ViewModel>(new Model()));
    }

}

public class MyProfile : Profile
{
    private readonly Func<HttpContextBase> _httpContext;
    private readonly Func<IAnotherType> _anotherType;

    public MyProfile(Func<HttpContextBase> httpContext, Func<IAnotherType> anotherType)
    {
        _httpContext = httpContext;
        _anotherType = anotherType;
    }

    protected override void Configure()
    {
        CreateMap<Model, ViewModel>()
            .ForMember(d => d.Url, o => o.ResolveUsing(s =>
                                                    {
                                                        var test = _anotherType.Invoke().GetAValue();
                                                        return _httpContext.Invoke().Request.Url;
                                                    }))
            ;
    }
}

public interface IAnotherType
{
    string GetAValue();
}

public class AnotherType : IAnotherType
{
    public string GetAValue() { return "a value"; }
}

public class ViewModel
{
    public string Url { get; set; }
}

public class Model
{
}

EDIT: Its easy to create an empty MVC project, paste the code and try it out and see for yourself.

EDIT: Removed the ConstructServicesUsing call because its not required by the example. No services are resolved through AutoMapper in the example.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
MatteS
  • 1,542
  • 1
  • 16
  • 35

3 Answers3

2

@rene_r above is on the right track; adapting his answer:

c.ConstructServicesUsing(t => DependencyResolver.Current.GetService(t))

Still might not compile but should get you close.

The requirement is that the call to DependencyResolver.Current is deferred until the service is requested (not kept as the value returned by Current when the mapper was initialised.)

Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
  • Removed the call completely because however its made it doesnt make a difference, and I dont think it really matters because no services are resolved through automapper in the example. – MatteS Nov 24 '11 at 12:43
  • `var profiles = container.Resolve>();` won't work - `MyProfile` depends on `HttpContext` which is a per-request type (`Func` doesn't alter this). – Nicholas Blumhardt Nov 24 '11 at 21:21
  • Hmm, I followed an example somewhere on how to pass dependencies to mappings, maybe obviously that doesnt work in this case. How would you suggest I provide dependencies for my mappings if not this way? – MatteS Nov 25 '11 at 12:43
  • Where you able to get this working? I'm having similar problems – tamaslnagy Jul 17 '12 at 20:30
0

I recently had a similar problem and it turned out to be a bad setup in my bootstrapper function. The following autofac setup did it for me.

builder.Register(c => new ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers))
    .AsImplementedInterfaces()
    .SingleInstance();

builder.Register(c => Mapper.Engine)
    .As<IMappingEngine>()
    .SingleInstance();

builder.RegisterType<TypeMapFactory>()
    .As<ITypeMapFactory>()
    .SingleInstance();

I did not have to specify resolver in the Mapper.Initialize() function. Just called

Mapper.Initialize(x => 
            {
                x.AddProfile<DomainToDTOMappingProfile>(); 
            });

after the bootstrapped and it works fine for me.

0

I think you should use DependencyResolver.Current.Resolve instead of container.Resolve in

Mapper.Initialize(c =>
                {                               
                   c.ConstructServicesUsing(DependencyResolver.Current);
                   profiles.ToList().ForEach(c.AddProfile);
                 });
rene_r
  • 936
  • 1
  • 6
  • 15
  • That doesnt even compile, but changing it to c.ConstructServicesUsing(DependencyResolver.Current.GetService); it compiles, but its still the same problem. – MatteS Nov 23 '11 at 20:53