I use this startup class in asp.net MVC 5 (using Microsoft.Extensions.DependencyInjection)
[assembly: OwinStartupAttribute(typeof(MVC5.Startup))]
namespace MVC5
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var services = new ServiceCollection();
// configure all of the services required for DI
ConfigureServices(services);
// Create a new resolver from our own default implementation
var resolver = new MyDependencyResolver(services.BuildServiceProvider());
// Set the application resolver to our default resolver. This comes from "System.Web.Mvc"
//Other services may be added elsewhere through time
DependencyResolver.SetResolver(resolver);
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersAsServices(new[]
{ typeof(HomeController), typeof(AccountController), typeof(ManageController)});
services.AddTransient<AppDbContext>();
//====================================================
// ApplicationUserManager
//====================================================
// instantiation requires the following instance of the Identity database
services.AddTransient(typeof(IUserStore<ApplicationUser>), p => new UserStore<ApplicationUser>(new IdentityContext()));
// with the above defined, we can add the user manager class as a type
services.AddTransient<ApplicationUserManager>();
//====================================================
// ApplicationSignInManager
//====================================================
// instantiation requires two parameters, [ApplicationUserManager] (defined above) and [IAuthenticationManager]
services.AddTransient(typeof(Microsoft.Owin.Security.IAuthenticationManager), p => new OwinContext().Authentication);
services.AddTransient<ApplicationSignInManager>();
//====================================================
// ApplicationRoleManager
//====================================================
// Maps the rolemanager of identity role to the concrete role manager type
services.AddTransient<RoleManager<IdentityRole>>();
// Maps the role store role to the implemented type
services.AddTransient<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>();
}
/// <summary>
/// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods.
/// This is combined dependency resolver for MVC and WebAPI usage.
/// </summary>
public class MyDependencyResolver : System.Web.Mvc.IDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
{
protected IServiceProvider serviceProvider;
protected IServiceScope scope = null;
public MyDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public MyDependencyResolver(IServiceScope scope)
{
this.scope = scope;
this.serviceProvider = scope.ServiceProvider;
}
public IDependencyScope BeginScope()
{
return new MyDependencyResolver(serviceProvider.CreateScope());
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
scope?.Dispose();
}
public object GetService(Type serviceType)
{
var ser = this.serviceProvider.GetService(serviceType);
return ser;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
}
}
public static class ServiceProviderExtensions
{
public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> serviceTypes)
{
foreach (var type in serviceTypes)
{
services.AddTransient(type);
}
return services;
}
}
In ManageController all services are injected and Action method is ready to run, but due to its Base Controller that has ValueProvider is NULL, The controller is disposed before doing any job. Why controller's valueprovider is null and how to solve this?
I changed, ApplicationUserManager and ApplicationSignInManager and RoleManager injections to the code bellow and now, everything works:
...
services.AddTransient<ApplicationUserManager>(p => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>());
...
services.AddTransient<ApplicationSignInManager>(p => HttpContext.Current.GetOwinContext().Get<ApplicationSignInManager>());
...
services.AddTransient<RoleManager<IdentityRole>>(p =>
HttpContext.Current.GetOwinContext().Get<RoleManager<IdentityRole>>());
...
Related
In my repository level I'm trying to use ServiceProvider.GetService() and it is returning null. I'm not able to resolve these.
public static void ConfigureServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<IUserUnitofWork, UserUnitofWork>();
}
now I have user detail class and I'm trying to access the
public class UserDetail
{
private IserviceProvider _serviceProvider;
UserDetail(IserviceProvider serviceProvider)
{
_serviceProvider = serviceProvider
}
public addUser()
{
using (var scope = _serviceProvider.CreateScope())
{
var uow = (IUserUnitofWork)scope.ServiceProvider.GetService(typeof(IUserUnitofWork));
isCreateSuccess = uow.addData(userlist);
// above code is throwing null error
}
}
}
I have some problems with EF-Core that I'm trying to figure out.
I use the startup code in the MVC Core application to initalize the db context.
This is my DB context:
public class AccountsDBContext : DbContext
{
public AccountsDBContext(DbContextOptions<AccountsDBContext> options)
:base(options)
{
}
// ...
}
And startup code:
public void ConfigureServices(IServiceCollection services)
{
// Inject the account db
services.AddDbContext<AccountsDBContext>(options =>
options.UseMySQL(Configuration.GetConnectionString("AccountsStore")));
// ...
In all the exampes I see the DB Context is a delivered via the constructor to the controller (I assume by dependency injection) and from there on to other entities\ layers.
[Route("api/[controller]")]
public class AccountsController : Controller
{
private AccountsDBContext _db;
public AccountsController(AccountsDBContext context)
{
this._db = context;
}
However, I'm not very fond of the idea that the db context will be a member at the controller.
I really prefer to get a hold of the db context in the data access layer instead of getting it passed into the repositories classes.
Is there a way to get the context inside the data access layer? (There is no IServiceCollection, IApplicationBuilder, IServiceScopeFactory there as far as I know)
I Understand what you are trying to do. I have done exactly that. The key is to Create a static class in your DAL that uses the IServiceCollection. then in here you add your context here's mine and it works a treat My front end doesn't even know about entity framework, nethier does my business layer:
public static IServiceCollection RegisterRepositoryServices(this IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole<int>>(
config => { config.User.RequireUniqueEmail = true;
config.Cookies.ApplicationCookie.LoginPath = "/Account/Login";
config.Cookies.ApplicationCookie.AuthenticationScheme = "Cookie";
config.Cookies.ApplicationCookie.AutomaticAuthenticate = false;
config.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
{
OnRedirectToLogin = async ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/visualjobs") && ctx.Response.StatusCode == 200)
{
ctx.Response.StatusCode = 401;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
await Task.Yield();
}
};
}).AddEntityFrameworkStores<VisualJobsDbContext, int>()
.AddDefaultTokenProviders();
services.AddEntityFramework().AddDbContext<VisualJobsDbContext>();
services.AddScoped<IRecruiterRepository, RecruiterRepository>();
services.AddSingleton<IAccountRepository, AccountRepository>();
return services;
}
then in my service layer I have another static class. My service layer has a reference to the repository layer and I register the repository services here (bootstrapping the repository into the service layer), like so and then I do the same again in the UI:
Service layer code:
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterServices(this IServiceCollection services)
{
services.RegisterRepositoryServices();
services.AddScoped<IRecruiterService, RecruiterService>();
services.AddSingleton<IAccountService, AccountService>();
return services;
}
}
The Magic in the Repository Layer:
public partial class VisualJobsDbContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
private IConfigurationRoot _config;
public VisualJobsDbContext() { }
public VisualJobsDbContext(IConfigurationRoot config, DbContextOptions<VisualJobsDbContext> options) : base(options)
{
_config = config;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(#_config["ConnectionStrings:VisualJobsContextConnection"]);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{....
Inject your repository/DAL implementation into the controller and have the DbContext injected into the repo constructor. The DI container will hook it all up as long as the appropriate classes are registered
How about this?
DALAccount.cs
public class DALAccount
{
private AccountsDBContext _db;
public DALAccount(AccountsDBContext db)
{
_db = db;
}
public IQueryable<User> Get()
=> _db.User.AsQueryable();
}
Your Api
public class AccountsController : Controller
{
private AccountsDBContext _db;
public AccountsController(AccountsDBContext context)
{
this._db = context;
}
public IActionResult Index()
{
DALAccount dal = new DALAccount(_db);
var list = dal.Get();
}
}
I have an Asp.NET MVC5 application in which I registre my types using Autofac in Startup class in this way:
public class Startup
{
public void Configuration(IAppBuilder app)
{
IContainer container = null;
var builder = new ContainerBuilder();
// Register Services
builder.RegisterType<SalesRepository>().As<ISalesRepository>().InstancePerRequest();
builder.RegisterType<SalesService>().As<ISalesService>().InstancePerRequest();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IHandle<>))
.AsImplementedInterfaces()
.InstancePerRequest();
builder.Register<IAppEvents>(_ => new AppEvents(container)).InstancePerRequest();
// Register MVC Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
These are my services (this is a simplified scenario, only for demonstration).
The SalesService class receives a ISalesRepository interface as dependency . In addition I have an AppEvents class where I want to resolve IHandle types:
public interface ISalesRepository { }
public class SalesRepository : ISalesRepository
{
public SalesRepository() { }
}
public interface ISalesService { }
public class SalesService : ISalesService
{
ISalesRepository _repo;
public SalesService(ISalesRepository repo)
{
_repo = repo;
}
}
public interface IHandle<T>
{
void Handle();
}
public class SalesActionHandle : IHandle<string>
{
ISalesRepository _repo;
public SalesActionHandle(ISalesRepository repo)
{
_repo = repo;
}
public void Handle() { }
}
public interface IAppEvents
{
void Raise<T>();
}
public class AppEvents : IAppEvents
{
private readonly IContainer _container;
public AppEvents(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public void Raise<T>()
{
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>(); // Runtime error here
foreach (var handler in handlers)
handler.Handle();
}
}
And this is my only (simplified) controller:
public class HomeController : Controller
{
ISalesService _service;
IAppEvents _events;
public HomeController(ISalesService service, IAppEvents events)
{
_service = service;
_events= events;
}
public ActionResult Index()
{
_events.Raise<string>();
return View();
}
}
The problem I have is that I get an error at this line when it is executed:
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>();
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.
I resolve it by doing this:
public void Raise<T>()
{
using (var scope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var handlers = scope.Resolve<IEnumerable<IHandle<T>>>();
foreach (var handler in handlers)
handler.Handle();
}
}
But in this case, when IHandle is resolved (with SalesActionHandle instance), a new instance of SalesRepository is passed as parameter in SalesActionHandle constructor. What I want is to "reuse" the same instance that SalesService is using (it was created when ISalesService was resolved. I want the same SalesRepository instance for the request)
Is there any way to achieve this behaviour?
The sample code is avaible in Github: https://github.com/josmonver/AutofacTest
You may want to use
AutofacDependencyResolver.Current.RequestLifetimeScope
to match your current request scope, but not to create a new request scope.
I am struggling to make this work. I've got Unity and Unity.AspNet.WebApi packages (v 3.5.1404) installed and below activation code which came with the packages
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityHierarchicalDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
// DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
and my type registration looks like this:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IAuditService, AuditService>(
new PerThreadLifetimeManager(),
new InjectionConstructor(new SecurityDbContext()));
}
So far I've tried PerThreadLifetimeManager and TransientLifetimeManager with no success. I've also got the Unity.Mvc package and tried using the PerRequestLifetimeManager as suggested by msdn but no luck. It always gives me the same instance of dbcontex.
I rather do not include any MVC dependency as this is purely WebApi but when I try to use Unity.Mvc, I ended up some http runtime errors too.
Anyone has a good suggestion/example to resolve dbcontext per request with Unity in WebApi, preferably without any mvc dependency?
The way I was injecting db context was the problem here. Unity remembers the instance created and injects the same instance for all new AuditService instance created. I simply needed to resolve the db context as below.
container.RegisterType<DbContext, SecurityDbContext>(new PerThreadLifetimeManager());
PerThreadLifetimeManager did the work and it should be fine considering each web requests will be served by a different thread.
I managed to resolve per request by declaring my custom UnityResolver's class within the WebApiConfig class. The UnityResolver class uses the HttpConfiguration class assuming you're using an OWIN context.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var _container = new UnityContainer();
DependencyConfiguration.ConfigureContainer(_container);
config.DependencyResolver = new UnityResolver(_container);
}
The ConfigureContainer class is simply a class where I declare my IOC dependencies as shown below:
private static void RegisterReleaseEnv(IUnityContainer container)
{
//Repository Registration
container
.RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());
}
It is very important that you use the HierarchicalLifetimeManager lifetime manager so that you get a new instance per request.
The UnityResolver class then looks like this:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
I then get a new DB Context using a Generic Repistory as shown below:
public class GenericRepository<TEntity> : IRepository<TEntity>, IDisposable where TEntity : class
{
internal BackendContainer context;
internal DbSet<TEntity> dbSet;
public GenericRepository(BackendContainer context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public GenericRepository()
: this(new BackendContainer())
{
}
public virtual IQueryable<TEntity> All()
{
return dbSet.AsQueryable();
}
}
Because of the Unity Resolver, the Generic Repository is instantiated per request and so is the DbContext (BackendContainer).
I hope this helps.
For more information: http://www.asp.net/web-api/overview/advanced/dependency-injection
Before I set up the question you should know that I got my current code from this page:
http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/
I'm trying to use ASP.NET Web API and Ninject in my application by using an IDependencyResolver adapter found on the site above.
I created all the code just like it shows on the site and it works but when I load up my appication my regular controllers fail and show this error:
[MissingMethodException: No parameterless constructor defined for this object.]
[InvalidOperationException: An error occurred when trying to create a controller of type 'AccountManager.Controllers.HomeController'...
So, it seems like I can use Ninject with regular controllers or Web API controllers but not both. :(
Here is my code:
NinjectResolver.cs
public class NinjectResolver : NinjectScope, IDependencyResolver
{
private IKernel _kernel;
public NinjectResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
NinjectScope.cs
public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;
public NinjectScope(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).SingleOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).ToList();
}
public void Dispose()
{
IDisposable disposable = (IDisposable)resolutionRoot;
if (disposable != null) disposable.Dispose();
resolutionRoot = null;
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
private void SetupDependencyInjection()
{
//create Ninject DI Kernel
IKernel kernel = new StandardKernel();
//register services with Ninject DI container
RegisterServices(kernel);
//tell asp.net mvc to use our Ninject DI Container
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
}
}
AccountingController.cs
public class AccountingController : ApiController
{
private ICustomerService _customerService;
public AccountingController(ICustomerService service)
{
_customerService = service;
}
// GET /api/<controller>/5
public string Get(int id)
{
return "value";
}
}
Insert the following line of code into the CreateKernel() method before the call to the RegisterServices(kernel); is made.
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
You will also need to use the below code, I prefer to have it defined in the same class.
public class NinjectResolver : NinjectScope, IDependencyResolver
{
private IKernel _kernel;
public NinjectResolver(IKernel kernel) : base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;
public NinjectScope(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).SingleOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).ToList();
}
public void Dispose()
{
IDisposable disposable = (IDisposable)resolutionRoot;
if (disposable != null) disposable.Dispose();
resolutionRoot = null;
}
}
Run it, and it should work. This worked for me, I hope it does for you too.
Further Reading :
Using Ninject – Dependency Injection with ASP.NET Web API controllers
I have a Web API project working using exactly the same solution as you from strathweb, so I just added a normal controller to the project, and it does work. Not a great help on it's own for you, so I'll detail the setup I've got:
I have the following packages installed (on the IOC side of things):
Ninject 3.0.1.10
Ninject MVC 3.0.0.6
Ninject.Web.Common 3.0.0.7
WebActivator 1.5.1
I have absolutely nothing in my Global.asax.cs file regarding Ninject, instead using the NinjectWebCommon.cs file that is automatically created in App_Start when you install Ninject. I don't know if by having code in your Global file that means that Ninject hasn't set itself up correctly in your project?
Here is the code in NinjectWebCommon.cs:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserRepository>().To<UserRepository>().InSingletonScope();
kernel.Bind<IUserManager>().To<UserManager>();
}
}
Here's the other difference I can see between our code, where I create the Kernel, my code declares two bindings to the kernel.
Here's the code for my test controller, I can set a breakpoint in the constructor and it gets it:
public class TestController : Controller
{
IUserManager _userManager;
public TestController(IUserManager userManager)
{
_userManager = userManager;
}
//
// GET: /Test/
public ActionResult Index()
{
return View();
}
}
This works with both my Controller and my APIControllers.