Issue with Simple Injector while using with Web API - asp.net-web-api

I am having issue using Simple Injector with WebAPI project that gets created default with VS 2015.
I am having the AccountController having the below constructor
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
In order to register these I used the below code in Simple Injector
// Create the container.
var apiContainer = new Container();
apiContainer.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
apiContainer.Options.ConstructorResolutionBehavior = new ConstructorBehavior();
//register the classes that we are going to use for dependency injection
apiContainer.Register<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>(new ApplicationDbContext()),Lifestyle.Scoped);
apiContainer.Register<IDataProtector>(() => new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider().Create("ASP.NET Identity"),Lifestyle.Transient);
apiContainer.Register<ISecureDataFormat<AuthenticationTicket>, SecureDataFormat<AuthenticationTicket>>(Lifestyle.Transient);
apiContainer.Register<ITextEncoder, Base64UrlTextEncoder>(Lifestyle.Scoped);
apiContainer.Register<IDataSerializer<AuthenticationTicket>, TicketSerializer>(Lifestyle.Scoped);
//apiContainer.RegisterCommonClasses();
//register the webapi controller
apiContainer.RegisterWebApiControllers(configuration);
but after this I am getting the warning message that says
[Disposable Transient Component] ApplicationUserManager is registered as transient, but implements IDisposable.
Can someone Please help me with this how to resolve this ? With Default Web api project with VS 2015 it adds Account controller and that use ApplicationUserManager and has below details
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
Another issue I am getting as below
The constructor of type HttpConfiguration contains the parameter with name 'routes' and type HttpRouteCollection that is not registered. Please ensure HttpRouteCollection is registered, or change the constructor of HttpConfiguration.
This is with the HelpController as it uses the below details:
public HelpController()
: this(GlobalConfiguration.Configuration)
{
}
public HelpController(HttpConfiguration config)
{
Configuration = config;
}

Related

Replace default IoC container in MvvmCross

Since MvvmCross v7 sticks on its own IoC container, I would like to replace it with the .NET Core one in order to have an easier life when registering third party libraries such as IHttpClientFactory, Polly, Automapper, etc. through already built-in extensions methods.
To achieve this, I've successfully created a class that implementas MvxSingleton<IMvxIoCProvider> described as follow:
public class HostingAdapter : MvxSingleton<IMvxIoCProvider>, IMvxIoCProvider
{
private IServiceProvider ServiceProvider;
private IServiceCollection ServiceCollection;
public HostingAdapter()
{
var host = Host
.ConfigureServices((context, serviceCollection) =>
{
// Configure local services
ConfigureServices(context, serviceCollection);
ServiceCollection = serviceCollection;
ServiceProvider = ServiceCollection.BuildServiceProvider();
})
.Build();
}
public void RegisterType<TFrom, TTo>() where TFrom : class where TTo : class, TFrom
{
ServiceCollection.AddTransient<TFrom, TTo>();
ServiceProvider = ServiceCollection.BuildServiceProvider();
}
public T GetSingleton<T>() where T : class
{
return ServiceProvider.GetRequiredService<T>();
}
public object GetSingleton(Type type)
{
return ServiceProvider.GetRequiredService(type);
}
.. and all the required methods requested by the interface.
Then on the platform specific side I override the IoC creation as follow:
protected override IMvxIoCProvider CreateIocProvider()
{
var hostingAdapter = new HostingAdapter();
return hostingAdapter;
}
The code seems to work but as soon as the app starts Mvx registers its own "extra" services such as the IMvxLoggerProvider, IMvxSettings and so on. And here issues come:
ServiceProvider = ServiceCollection.BuildServiceProvider(); is called during the Host initialization but Mvx still continue to register services after that. This means IServiceProvider is not 'in sync' with IServiceCollection and a new ServiceCollection.BuildServiceProvider(); call is needed. I temporarily solved updating the provider at each collection registration (like the code above) but I'm aware this affects performances. Anyone knows how to workaround this?
There are plenty of Mvx services that are not registered so the app fails to start. These are the IMvxLogProvider, IMvxAndroidLifetimeMonitor, IIMvxSettings, IMvxStart, etc. I just wonder, why? How can let Mvx handle the registration in my container of all what it needs to start? I partially solved some of them such as the logger thing replacing the default with a custom one, but other callbacks like InitializeLifetimeMonitor are called too late for being registered.
Do I need to change anything in my MvxApplication than the most standard implementation?
Am I really forced to replace the standard IoC container? How can I handle the IServiceCollection's extension methods that 3rd party libraries expose like services.AddHttpClient();?
If it needs, I am on Xamarin classic using the Droid platform. Thanks
Deliberately inspired by Unity.Microsoft.DependencyInjection repository I've workarounded this approaching the problem the other way round: instead of replacing the default IoC container, I manually initialize an IServiceCollection instance and I add it to the Mvx's IoC provider.
To achieve this, I've used the following code:
public class App : MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitializeServiceCollection();
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<HomeViewModel>();
}
private static void InitializeServiceCollection()
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
MapServiceCollectionToMvx(serviceProvider, serviceCollection);
}
private static void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddHttpClient();
}
private static void MapServiceCollectionToMvx(IServiceProvider serviceProvider,
IServiceCollection serviceCollection)
{
foreach (var serviceDescriptor in serviceCollection)
{
if (serviceDescriptor.ImplementationType != null)
{
Mvx.IoCProvider.RegisterType(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationType);
}
else if (serviceDescriptor.ImplementationFactory != null)
{
var instance = serviceDescriptor.ImplementationFactory(serviceProvider);
Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, instance);
}
else if (serviceDescriptor.ImplementationInstance != null)
{
Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationInstance);
}
else
{
throw new InvalidOperationException("Unsupported registration type");
}
}
}
}

Asp.net Identity, Generate WebApi token OAuthGrantResourceOwnerCredentialsContext - no access to UserManager using Unity

I am trying to setup a project structure so that I have a WebApi, WebUI and Domain layer. I have moved all the Asp.Net.Identity objects into the Domain layer and have also setup the ApplicationContext here too (inheriting from IdentityContext).
(I have used this tutorial and package as a base which is excellent. http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/)
In the WebAPI layer I am able to use the Account controller correctly to login and register. However, I cannot generate an access token.
The OAuthGrantResourceOwnerCredentialsContext method internally uses
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
This works fine but doesnt give me the same context as my Account Controller as I am using Unity constructor injection in this to use my ApplicationUserManager from the domain.
I have tried injecting the OAuth class but I never seem to get the instance back.
Any advice?
Edit, this is what I have in Startup class in a default WebApi project.
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
So the ApplicationOAuthProvider seems to be used when getting an access token.
--
More info.
UnityConfig.cs
container.RegisterType<ApplicationDbContext>(); //this is referencing my domain layer
Startup.Auth.cs
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
ApplicationOAuthProvider.cs
Have injected constructor as below
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
private ApplicationUserManager userManager;
public ApplicationOAuthProvider(ApplicationUserManager userManager)
{
this.userManager = userManager;
}
public ApplicationOAuthProvider(string publicClientId)
{
//this.userManager = userManager;
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); //PROBLEM LINE!!!
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
}
}
The problem line is shown above. This method gets called when requesting a token, and the userManager is always null.
Edit to show UnityWebApiActivator.cs
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
// Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
// var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
I have just create pure WebApi project with Identity, checked over the classes and not sure I understand your question correctly.
The standard VS2013 template contains this in Startup.Auth.cs:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// blah - other stuff
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
Provider = new ApplicationOAuthProvider(PublicClientId),
// another blah
};
app.UseOAuthBearerTokens(OAuthOptions);
//blah-blah-blah
}
}
I have checked and ApplicationOAuthProvider is not used anywhere else. So no need to inject it.
Inside of this class, as you say, it calls for context.OwinContext.GetUserManager<ApplicationUserManager>() to get user manager. If you get an incorrect instance of ApplicationDbContext there, then you inject incorrect instance of ApplicationUserManager into Owin context. Do you still have a line with this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Go replace it with this:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
This should do the job - would be the best solution.
Alternatively in ApplicationOAuthProvider replace line where you get the ApplicationUserManager from OWIN context with this:
var userManager = DependencyResolver.Current.GetService<ApplicationUserManager>()
This should resolve your user manager from Unity, giving you correct DbContext.

Autofac, Owin, Webapi and injecting to AuthorizationServerProvider

After reading questions and articles about using autofac with owin and webapi, I came across a solution to inject services but it does not work. Here is my code:
public class StartUp
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
var builder = new ContainerBuilder(); // Create the container builder.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the Web API controllers.
var authcontext = new AuthContext();
builder.RegisterInstance(authcontext).AsSelf().SingleInstance();
//Updated
//var simpleauth = new SimpleAuthorizationServerProvider();
//Updated
// builder.RegisterInstance(simpleauth).SingleInstance().AsSelf().PropertiesAutowired();
builder.Register(x => new UserStore<IdentityUser>(authcontext)).As<IUserStore<IdentityUser>>();
//updated
builder.Register(x =>
{
var p = new SimpleAuthorizationServerProvider();
var userStore = x.Resolve<IUserStore<IdentityUser>>();
p.userManager = new UserManager<IdentityUser>(userStore);
return p;
}).AsSelf().PropertiesAutowired();
builder.RegisterType<AuthRepository>().As<IAuthRepository>().InstancePerRequest().PropertiesAutowired();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container); // Create an assign a dependency resolver for Web API to use.
config.DependencyResolver = resolver;
app.UseAutofacMiddleware(container);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
ConfigureOAuth(app, resolver);
}
public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
//updated
Provider = new SimpleAuthorizationServerProvider()
//resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
But in SimpleAuthorizationServerProvider class, when a method like ValidateClientAuthentication is begin called, all the services are null, here is the code:
public readonly IAuthRepository repository;
public readonly UserManager<IdentityUser> userManager;
public readonly AuthContext dbContext;
public SimpleAuthorizationServerProvider()
{
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
if (context.TryGetFormCredentials(out clientId, out clientSecret))
{
try
{
Client client = await repository.FindClientById(clientId);
}
}
}
Would you help me please ?
Updated
If in ConfigureOAuth method I use the following approach:
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
I get error:
An exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll but was not handled in user code
Additional information: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested 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 you register an instance of an object rather than a type, even if you specify PropertiesAutowired that will not take effect because Autofac assumes you've done all the work you want when you create the instance. If you want properties wired in, you need to do that in an OnActivated handler.
There are actually a lot of things at play in this sample code that will not work.
The values in SimpleAuthorizationServerProvider are fields not properties so PropertiesAutowired won't work on them.
The fields are marked readonly and they're never set.
You have UserManager<IdentityUser> registered as a lambda but also have PropertiesAutowired which won't work - you can only use PropertiesAutowired on a reflection-based component (e.g., RegisterType<T>).
Consider registering a lambda for your provider and set everything in the lambda:
builder.Register(c => {
var p = new SimpleAuthorizationServerProvider();
p.repository = c.Resolve<UserManager<IdentityUser>>();
// ...and so on
return p;
}).AsSelf().SingleInstance();
Also, keep in mind that if you register an instance (or register something as SingleInstance the properties will be resolved one time and that's it. So if you have some dependencies that are InstancePerDependency or InstancePerRequest, that's not going to work the way you think - they'll be resolved one time and effectively be singletons after that.
Update 1
Based on the original and updated code, it occurs to me that it would be good if you could check out some of the Autofac doc to understand better how it works. For example, the use of fields in SimpleAuthorizationServerProvider shows you may not totally get how injection works in Autofac or how to properly register things so Autofac can do the work for you.
Registration concepts
Web API integration
Working with per-request lifetime
For example, looking at the updates...
You now have a lambda registered for the SimpleAuthorizationServerProvider but I don't see where you set the repository field there.
You don't need PropertiesAutowired on the SimpleAuthorizationServerProvider registration because you're registering a lambda and the properties will not be autowired (as noted earlier).
The only component I see as being registered InstancePerRequest is the AuthRepository but, like I said, I don't see where that's being resolved or set - and that's the only thing that would generate the exception you noted. There is an FAQ on dealing with that exact exception that you should look into.
Also, you are showing two different versions of the OAuthServerOptions being initialized and it's hard to tell which one is "real."
I would recommend a fairly major refactoring to enable things to actually use DI correctly.
Change the SimpleAuthorizationServerProvider to stop using public fields and add them as constructor parameters so Autofac can wire the stuff up for you.
public class SimpleAuthorizationServerProvider
{
public IAuthRepository Repository { get; private set; }
public UserManager<IdentityUser> UserManager {get; private set; }
public AuthContext Context { get; private set; }
public SimpleAuthorizationServerProvider(
IAuthRepository repository,
UserManager<IdentityUser> userManager,
AuthContext context)
{
this.Repository = repository;
this.UserManager = userManager;
this.AuthContext = context;
}
}
During startup, fix your registrations to remove extraneous stuff and take advantage of the Autofac auto-wiring goodness.
public class StartUp
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config);
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register the auth context instance but skip
// the extra .AsSelf() and .SingleInstance() because
// it's implicit.
builder.RegisterInstance(new AuthContext());
// Use the lambda to resolve the auth context rather
// than making a closure over an instance.
builder.Register(c => new UserStore<IdentityUser>(c.Resolve<AuthContext>()))
.As<IUserStore<IdentityUser>>();
// Just register the provider type and let Autofac
// do the work without all this manual stuff. Skip
// the .AsSelf() because it's implicit if you don't
// specify other interfaces and don't auto-wire properties
// because you don't need it.
builder.RegisterType<SimpleAuthorizationProvider>();
// This is fine, but I can't tell where it's used - if
// you are using it at app startup or OUTSIDE a request,
// you will get that exception you noted. Also, unless
// you're actually using property injection, lose the
// .PropertiesAutowired() call.
builder.RegisterType<AuthRepository>()
.As<IAuthRepository>()
.InstancePerRequest()
.PropertiesAutowired();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
app.UseAutofacMiddleware(container);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
ConfigureOAuth(app, resolver);
}
public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver)
{
var options = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
// If you want the values to be wired up, you have
// to do a resolve. Note, however, that since you're
// doing this wire-up at app startup, there's no request
// scope, so if something in here is registered `InstancePerRequest`
// you will get an exception.
Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
Under the assumption that's all the code you should be OK. If things aren't set - like one of the SimpleAuthorizationServerProvider properties comes through as null, or if you get an exception because it's missing a dependency, or if you get the exception about there being no request scope... then there's something else going on that you haven't put in your question.
Again, please take the time to check out the docs and familiarize yourself with Autofac. I think many of the troubles you're running into are the result of some misunderstanding on how things get wired up.

Structure Map parameterless constructor error

I am trying to set up structure map ver 3.0.5.0 with Web API 2.
I have followed this implementation: Configuring dependency injection with ASP.NET Web API 2.1
However, I am getting this error when doing a get against my ComplexesController:
An error occurred when trying to create a controller of type 'ComplexesController'. Make sure that the controller has a parameterless public constructor.
Can anyone see what is wrong with my structuremap config? The Create method never gets called.
This is my implementation:
public class StructureMapControllerActivator : IHttpControllerActivator
{
private readonly IContainer _container;
public StructureMapControllerActivator(IContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
try
{
var scopedContainer = _container.GetNestedContainer();
scopedContainer.Inject(typeof(HttpRequestMessage), request);
request.RegisterForDispose(scopedContainer);
return (IHttpController)scopedContainer.GetInstance(controllerType);
}
catch (Exception e)
{
// TODO : Logging
throw e;
}
}
}
This method is in my startup...
public void InitializeContainer()
{
// STRUCTURE MAP
Container container = new Container();
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new StructureMapControllerActivator(container));
container.Configure(x => x.For<IForumRepository>().Use<ForumRepository>());
container.Configure(x => x.For<IComplexRepository>().Use<ComplexRepository>());
}
.. and this is the controller:
public class ComplexesController : ApiController
{
private IComplexRepository _repo;
public ComplexesController(IComplexRepository repo)
{
_repo = repo;
}
// GET: api/Complexes
public IList<Complex> GetComplexes()
{
var complexes = _repo.GetList();
return complexes;
}
...
My full Startup class
[assembly: OwinStartup(typeof(AngularJSAuthentication.API.Startup))]
namespace AngularJSAuthentication.API
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
}
The problem here is that you are registering your service activator with a GlobalConfiguration object and not your HttpConfiguration object. In this scenario The GlobalConfiguration object is never used as it is replaced by the HttpConfiguration object. In order to solve your issue you should replace your InitializeContainer() method with the following.
public void InitializeContainer(HttpConfiguration config)
    {
        // STRUCTURE MAP
        Container container = new Container();
        config.Services.Replace(typeof(IHttpControllerActivator), new StructureMapControllerActivator(container));
        container.Configure(x => x.For<IForumRepository>().Use<ForumRepository>());
        container.Configure(x => x.For<IComplexRepository>().Use<ComplexRepository>());        
    }
you should then pass the HttpConfiguration object from your Startup class to the new InitializeContainer() method.
Hope this helps.
-B
I am trying to gain a solid understanding of the complete lifecycle. I think my setup may be slightly different to the above. Here is what worked for me.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
var container = IocConfig.Setup();
// Allow a controller to be declared without a parameterless constructor
config.DependencyResolver = new DependencyResolver(container);
config.Services.Add( typeof(IExceptionLogger), new GlobalExceptionLogger( container.GetInstance<ILoggingService>()));
// Web API routes
config.MapHttpAttributeRoutes();
// Setup Authentication
ConfigureOAuth(app, container);
var corsOptions = CorsOptions.AllowAll;
app.UseCors(corsOptions);
// Add ASP.Net Web API to OWIN pipeline
app.UseWebApi(config);
}
}
It worked after I added this line:
// Allow a controller to be declared without a parameterless constructor
config.DependencyResolver = new DependencyResolver(container);
You have to get that my var container loads from a static class called IocConfig with a static Setup method. This is where the interfaces are mapped to their concrete implementations.
Also, you can probably ignore the GlobalExceptionLogger line if you want to use my complete example.

Autofac, ASP.NET MVC 3 httpRequest scope and AutoMapper: No scope with a Tag matching 'httpRequest' is visible

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.
#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.)
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);
});
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.

Resources