I am using Asp.Net MVC 5 and am trying to wire up my dependencies for a web api controller but it doesnt work and says the controller needs a parameter less constructor.
I have updated unity container to v4 which meant updating some other references, namely unity.abstractions is also v4.
I am using unity.mvc not unity.mvc5.
In UnityConfig I have
public static class UnityConfig
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(InitialiseContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static IUnityContainer ConfiguredContainer()
{
return Container.Value;
}
private static IUnityContainer InitialiseContainer()
{
var container = new UnityContainer();
//DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
//GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
// Auth
container.RegisterType<IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType<ApplicationUserManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()));
container.RegisterType<IUserStore<LiApplicationUser>> (new InjectionFactory(c => new UserStore<LiApplicationUser>(new ApplicationIdentityDbContext())));
// Repository
container.RegisterType<LeisureInsureEntities>(new InjectionFactory(c => ContextFactory.Context()));
container.RegisterType<ICar, Volvo>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
}
I commented out the unity.mvc5 code is no longer needed, so its removed. That seemed to require unity.abstractions v2, and doesn't accept 4.
As I am trying to inject into a webapi controller do I also need Unity.WebAPI? that gives the same problem as Unity.Mvc5 and is developed by the same person, ie it doesnt like my later version of unity.abstractions.
In my webapi controller I am seeing if I can wire up Volvo as a test
public class StripeController : ApiController
{
private readonly IEndpointInstance _endpoint;
private readonly ICar car;
//public StripeController(IEndpointInstance endpoint)
//{
// _endpoint = endpoint;
//}
public StripeController(ICar newcar)
{
car = newcar;
}
Thanks
You will need the Unity.AspNet.WebApi adapter to configure your ApiControllers.
Careful you don't mix up packages. Some of those are not by the same project owner (Unity.Mvc5, Unity.WebAPI). I haven't used those so I can't comment on its suitability.
I have a example https://github.com/jasenhk/MovieStar from another answer that uses Unity v5.10 and Unity.MVC as well as Unity.AspNet.WebApi.
Here is the packages.config
<package id="Unity" version="5.10.2" targetFramework="net461" />
<package id="Unity.Abstractions" version="4.1.2" targetFramework="net461" />
<package id="Unity.AspNet.WebApi" version="5.10.0" targetFramework="net461" />
<package id="Unity.Container" version="5.10.2" targetFramework="net461" />
<package id="Unity.Mvc" version="5.10.0" targetFramework="net461" />
Related
In the ASP.net MVC 5 project, use Nuget to install Nlog, Nlog.config, Nlog.schema Packages.
Target xsi:type="MethodCall" in the NLog.config file
NLog.config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<targets>
<target name="mc" xsi:type="MethodCall" className="NlogMethodCallWebApp.Models.NLogHelper, NlogMethodCallWebApp" methodName="LogMethod">
<parameter layout="${longdate}" />
<parameter layout="${uppercase:${level}}" />
<parameter layout="${message}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace,Debug,Info,Warn,Error,Fatal" writeTo="mc" />
</rules>
</nlog>
Execute Debug HomeController Index Action Method
HomeController.cs
using NLog;
using System.Web.Mvc;
namespace NlogMethodCallWebApp.Controllers
{
public class HomeController : Controller
{
private static Logger logger = NLog.LogManager.GetCurrentClassLogger();
public ActionResult Index()
{
logger.Trace("This is Trace");
logger.Debug("This is Debug");
logger.Info("This is Info");
logger.Warn("This is Warn");
logger.Error("This is Error");
logger.Fatal("This is Fatal");
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
LogMethod set breakpoint in class NLogHelper has no effect
NLogHelper.cs
using System;
using System.Diagnostics;
namespace NlogMethodCallWebApp.Models
{
public class NLogHelper
{
/// <summary>
/// c - NLog
/// </summary>
public static void LogMethod(string longdate, string level, string message)
{
Trace.WriteLine(string.Format("D:{0} L:{1} M:{2}", longdate, level, message));
}
}
}
NLog does not execute LogMethod method. Where is the problem?
You loglevel is wrong.
There a multiple possibilities:
minlevel="Trace,Debug,Info,Warn,Error,Fatal" <-- Yours, that wrong
change to:
levels="Trace,Debug,Info,Warn,Error,Fatal"
or
minlevel="Trace"
or you can also use minlevel and maxlevel
Details:
https://github.com/NLog/NLog/wiki/Configuration-file#log-levels
Also check that the assembly is inside your output directory (your project must reference this assembly)
I have the following account controller
public class AccountController : Controller
{
public IMembershipService MembershipService { get; set; }
protected override void Initialize(RequestContext requestContext)
{
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
}
public AccountController(IMembershipService membership)
{
MembershipService = membership;
}
[HttpPost]
public ActionResult Login(LoginModel model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.EmailorUserName, model.Password))
{
.....
}
}
}
from my unit testing project I want to simulate a login
public class AccountControllerTest2
{
[Test]
public void Login_UserCanLogin()
{
string returnUrl = "/Home/Index";
string userName = "user1";
string password = "password1";
Mock<AccountMembershipService> Membership = new Mock<AccountMembershipService>();
AccountController Controller = new AccountController(Membership.Object);
var model = new LoginModel
{
EmailorUserName = userName,
Password = password
};
var result = Controller.Login(model, returnUrl) as RedirectResult;
Assert.NotNull(result);
Assert.AreEqual(returnUrl, result.Url);
}
}
my web config in my main application uses custommembership provider
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear />
<add name="CustomMembershipProvider" type="QUBBasketballMVC.Infrastructure.CustomMembershipProvider" connectionStringName="UsersContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
I keep getting this error
QUBBasketballMVC.Tests.Controllers.AccountControllerTest.Login_UserCanLogin:
System.Web.Management.SqlExecutionException : An error occurred during the execution of the SQL file 'InstallCommon.sql'. The SQL error number is 5123 and the SqlException message is: CREATE FILE encountered operating system error 5(Access is denied.) while attempting to open or create the physical file 'C:\PROGRAM FILES (X86)\NUNIT 2.6.3\BIN\APP_DATA\ASPNETDB_TMP.MDF'.
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
Creating the ASPNETDB_7b94db5a0b5b4fbbbe22fa8e91e4cc68 database...
It seems that you are still initializing the real membership database, meaning that the MembershipService hasn't been completely mocked out. You shouldn't need to add the membership config to your unit tests, given that you intend mocking it out completely.
You almost certainly want to mock the Interface to your service abstraction IMembershipService, viz:
Mock<IMembershipService> Membership = new Mock<IMembershipService>();
As an aside, the lazy initialization code
if (MembershipService == null)
MembershipService = new AccountMembershipService();
isn't ideal from a testing point of view, given that it means that the controller has 2 modes of operation, whereby it can either create the MembershipService itself, or accept one as a constructor dependency.
As an alternative, you might consider an IoC framework here to manage dependency lifespans, and this way there is only one set of code to be tested.
According to this article description custom-membership-provider-with-repository-injection
I implement the custom Membership provide with inject.
Custom Membership provider
using Ninject;
public class CustomMembershipProvider : MembershipProvider
{
[Inject]
public IUserRepository UserRepository { get; set; }
[...]
Custom Role Provider
using Ninject;
public class CustomRoleProvider : RoleProvider
{
[Inject]
public IUserRoleRepository UserRoleRepository { get; set; }
[...]
within Web.Config
<membership defaultProvider="CustomsMembershipProvider">
<providers>
<clear/>
<add name="CustomsMembershipProvider" type="namespace.CustomsMembershipProvider"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="customRoleProvider">
<providers>
<clear/>
<add name="customRoleProvider" type="namespace.customRoleProvider"/>
</providers>
</roleManager>
Now within NinjectWebCommon
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
[...]
kernel.Bind<IUserRepository>().To<UserRepository>();
kernel.Bind<IUserRoleRepository>().To<UserRoleRepository>();
// Inject user & role repository into our custom membership & role providers.
kernel.Inject(Membership.Provider);
kernel.Inject(Roles.Provider);
}
when I run application I got error
This method cannot be called during the application's pre-start
initialization stage.
from kernel.Inject(Membership.Provider); this line
But If I Kernel setting put within Application_Start
I got bellow Error
Error activating IUserRepository No matching bindings are available,
and the type is not self-bindable. Activation path: 2) Injection of
dependency IUserRepository into property UserRepository of type
CustomMembershipProvider 1) Request for CustomeMembershipProvider
How to solve that. ??
The result is always null. why? because asp.net has it's own static property for membership.
which is membership.provider. and this instance is not part of instance ninject management.
to workaround it , you need to use kernel.inject . but on the generate aspnetmvc.cs you would see that it's injection on PreApplicationStart event and won't let you.
here is the soloution by cipto that solve the problem for me. add this to your NinjectWebCommon
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
}
Link to article: Ninject and customMembership asp.net mvc 3
I had a lot of trouble trying this and ended up adding a method that gets me a repository
using System.Web.Mvc; //Used to access dependency resolver
private IUserRepository GetUserRepository()
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
I then call this in the methods that require it
I was able to get the repository to become injected using constructor injection but as soon as I went to use the repository the object had been disposed. I found the above to be the simplest alternative.
However, I guess you could also use the Initialize() method
IUserRepository userRepository;
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
this.userRepository = DependencyResolver.Current.GetService<IUserRepository>();
}
Or another way would be to use a property
public IUserRepository UserRepository
{
get
{
return DependencyResolver.Current.GetService<IUserRepository>();
}
}
Since a custom RoleProvider often comes along with the custom MembershipProvider, in that case it is useful to add an injection for the Role Provider class. I used the ramon22's solution with an additional line.
[assembly: WebActivator.PreApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(TopRankFantasy.App_Start.NinjectMVC3), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(TopRankFantasy.App_Start.NinjectMVC3), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
bootstrapper.Kernel.Inject(Roles.Provider);
}
I am trying to use Unity 2.0 for my current project with MVC and having trouble configuring paramter injection in the web.config file.
Here's what I have:
1) A Home Controller:
public class HomeController : Controller
{
IRepository repository = null;
public HomeController()
{
// Always calls this constructor. Why?
// Should be calling the constructor below that takes IRepository.
}
public HomeController(IRepository repository)
{
// Should be calling this constructor!!!
this.repository = repository;
}
public ActionResult Index()
{
List<int> intList = this.repository.GetInts();
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
A basic controller with two constructors. The 1st one takes no arguments, and the 2nd one takes IRepository as an argument (that's supposed to be injected by Unity)
2) SQL Repository
public class SQLRepository : IRepository
{
private string connectionString = null;
public SQLRepository(string connectionString)
{
this.connectionString = connectionString;
}
#region IRepository Members
public List<int> GetInts()
{
return new List<int>() { 1, 2, 3, 4, 5 };
}
#endregion
}
A future to be SQL repository, but for now it just implements 1 member of the IRepository interface, namely GetInts() and returns a list of integers.
3) IRepository Interace
public interface IRepository
{
List<int> GetInts();
}
An interface.
4) Application_Start() Event in my Global.asax file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
This is used to read the Unity 2.0 configuration from the web.config file in order to register and map types etc.
6) The Unity 2.0 Configuration Section in web.config
<unity>
<typeAliases>
<typeAlias alias="string" type="System.String, mscorlib" />
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="IRepository" type="NewMVCApp.Interfaces.IRepository, NewMVCApp" />
<typeAlias alias="SQLRepository" type="NewMVCApp.Repository.SQLRepository, NewMVCApp" />
</typeAliases>
<containers>
<container name="Default">
<types>
<type type="IRepository" mapTo="SQLRepository">
<lifetime type="singleton" />
<constructor>
<param name="connectionString">
<value value="ApplicationServices" />
</param>
</constructor>
</type>
</types>
</container>
</containers>
This is Unity 2.0 configuration section that I use. As you can see It typeAlias for both my IRepository and my SQLRepository classes and then maps IRepository to SQLRepository. So that anytime IRepository is requested, SQLRepository instance will be supplied. Also, I want to pass a connection string via the constructor to my SQLRepository.
5) So, what am I trying to do?
I am trying to use Unity 2.0 to pass in the instance of IRepository (SQLRepository) to my HomeController. But for some reason the default, parameterless constructor, for the HomeController() gets invoked. But HomeController(IRepository repository) never gets called. I am pretty sure that I did not set things up properly in the web.config file. But I am not sure how do set things up properly so the correct constructor on the HomeController gets called. Please help:)
&Thank you:)
Your Unity configuration looks fine. The problem is that you haven't hooked up Unity to the MVC framework, so the framework isn't using the container to create your controller, instead MVC is using the default logic, which calls the default constructor.
You need two things. First, an implementation of IControllerFactory. I usually use this one:
public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if(controllerType != null)
return container.Resolve(controllerType) as IController;
return base.GetControllerInstance(requestContext, controllerType);
}
}
Second, you need to tell the MVC framework to use this controller factory instead of it's default one. You do this in your Application_Start handler. Do this:
ControllerBuilder.Current.SetControllerFactory(
new UnityControllerFactory(container));
Once you've done that, your controllers will be created through the container and everything should start working.
Thank you so much Chris!! That was it! Here's the how the Application_Start() event should look like in MVC2 using Unity 2.0:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
IUnityContainer container = new UnityContainer();
IControllerFactory controllerFactory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
// Do the line below only if you want to Register IoC programatically
//container.RegisterType<IRepository, SQLRepository>(new ContainerControlledLifetimeManager());
UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(container, "Default");
}
Try with Unity.Mvc nuget packages. You can use container.LoadConfiguration(); in UnityConfig class.
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.LoadConfiguration();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Then you can update web.config as below.
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity configSource="unity.config" />
Complete article can be found # MVC 5 with Unity for Dependency Injection.
My web app solution consists of 3 projects:
Web App (ASP.NET MVC)
Business Logic Layer (Class Library)
Database Layer (Entity Framework)
I want to use Ninject to manage the lifetime of the DataContext generated by the Entity Framework in the Database Layer.
The Business Logic layer consists of classes which reference repositories (located in the database layer) and my ASP.NET MVC app references the business logic layer's service classes to run code. Each repository creates an instance of the MyDataContext object from the Entity Framework
Repository
public class MyRepository
{
private MyDataContext db;
public MyRepository
{
this.db = new MyDataContext();
}
// methods
}
Business Logic Classes
public class BizLogicClass
{
private MyRepository repos;
public MyRepository
{
this.repos = new MyRepository();
}
// do stuff with the repos
}
Will Ninject handle the lifetime of MyDataContext despite the lengthy dependency chain from the Web App to the Data Layer?
EDIT
I has some problems with it some time ago, but now it seems to work:
Bind<CamelTrapEntities>().To<CamelTrapEntities>().Using<OnePerRequestBehavior>();
Instead of using HttpModule, you can use OnePerRequestBehavior and it will take care of handling context in current request.
EDIT 2
OnePerRequestBehavior needs to be registered in web.config, because it depends on HttpModule too:
In IIS6:
<system.web>
<httpModules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</httpModules>
</system.web>
With IIS7:
<system.webServer>
<modules>
<add name="OnePerRequestModule" type="Ninject.Core.Behavior.OnePerRequestModule, Ninject.Core"/>
</modules>
</system.webServer>
PREVIOUS ANSWER
It is your responsibility to dispose context when it is not needed. Most popular way in ASP.NET is to have one ObjectContext per request. I do it by having HttpModule:
public class CamelTrapEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
((CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
HttpContext.Current.Items[#"CamelTrapEntities"] = new CamelTrapEntities();
}
}
This is injection rule:
Bind<CamelTrapEntities>().ToMethod(c => (CamelTrapEntities) HttpContext.Current.Items[#"CamelTrapEntities"]);
My Repository takes ObjectContext in constructor:
public Repository(CamelTrapEntities ctx)
{
_ctx = ctx;
}
Just want to mention that Autofac with the ASP.Net integration have the request lifetime support built-in. Resolve instances in the RequestContainer and they will be disposed (if implementing IDisposable) at the end of the request.
You should make your classes DI friendly though:
public class MyRepository
{
private MyDataContext db;
public MyRepository(MyDataContext context)
{
this.db = context;
}
// methods
}
public class BizLogicClass
{
private MyRepository repos;
public BizLogicClass(MyRepository repository)
{
this.repos = repository;
}
// do stuff with the repos
}