This is what i want to be able to do (passing interface(s) to Controllers):
public class TestController : Controller
{
// GET: Test
[HttpGet]
public ActionResult Index(ITestService service)
{
var test = new TestModel();
test.Greeting = "yo" + service.GetString();
test.Name = "nils";
return View(test);
}
}
This is what i have put in Global.asax.cs in the Application_Start() to try to make that work:
// Create a new Unity dependency injection container
var unity = new UnityContainer();
unity.RegisterType<ITestService,TestService>();
// Finally, override the default dependency resolver with Unity
DependencyResolver.SetResolver(new IoCContainer(unity));
I have also, as you can see, created an IoCContainer class which looks as follows:
public class IoCContainer : IDependencyResolver
{
private readonly IUnityContainer _container;
public IoCContainer(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
return _container.Resolve(serviceType);
return null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (_container.IsRegistered(serviceType))
return _container.ResolveAll(serviceType);
return new List<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
When i try to access the "http://humptidumptiurl/Test" it tells me:
A public action method 'Login' was not found on controller 'Companyname.Product.Web.Controllers.TestController'.
Now... i thought it should resolve the ITestService.. not bother about a completely different Controller? other controllers that does not use Unity yet, work as they have always done....
Inputs on how i could achieve my desired solution would be greatly appriciated
EDIT:
Thank you! Of course it injects through the constructor... I should have thought of that... but now it gives me this error message:
{"An error occurred when trying to create a controller of type 'Stimline.Xplorer.Web.Controllers.TestController'. Make sure that the controller has a parameterless public constructor."}
Edited testController:
public class TestController : Controller
{
private readonly ITestService _testService;
public TestController(ITestService service)
{
_testService = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo" + _testService.GetString();
test.Name = "nils";
return View(test);
}
}
You're injecting your dependency into your action method.
When using IDependencyResolver in this manner you tend to inject dependencies into your constructor.
Try changing controller to look something like this:
public class TestController : Controller
{
private readonly ITestService service;
public TestController(ITestService service)
{
this.service = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo";
test.Name = "nils";
// TODO do something with ITestService
// this.service.DoSomethingCool()
return View(test);
}
}
Declare it like this :
public class TestController : Controller
{
private ITestService service;
public TestController(ITestService service)
{
this.service = service;
}
// GET: Test
[HttpGet]
public ActionResult Index()
{
var test = new TestModel();
test.Greeting = "yo";
test.Name = "nils";
return View(test);
}
}
Please inject your dependencies inside your constructor. You by mistake passed it to your action method.
Related
I have an MVC application that contains a static class providing a boolean value to the rest of the program. My issue is that I want the boolean to reset with each call to the back-end. I want it to be "stateless", getting initialized to false for each and every back-end call. I'll then set it to true as needed. For instance, consider the following where from the Index view we load the About view and then afterwards load the Contact view ...
public static class BooleanProvider
{
public static bool theBool = false;
}
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
BooleanProvider.theBool = true;
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
//I want BooleanProvider.theBool to be false here, since it's a different call, even though we set it to true in the About() method
return View();
}
}
When I check BooleanProvider.theBool at the commented line, it's set to true. Is there a way to "re-initialize" the boolean with every call? I'd rather not make the class instantiable and have to new it up with each controller call, but maybe there is no other way?
Thank you in advance!
You have to use Dependency injection for that.
dotnetcore solution
Scoped Lifetime is exactly what you needed.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#scoped
At your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<BooleanProvider>();
// ...
}
and at your HomeController
public class HomeController : Controller
{
private readonly BooleanProvider _booleanProvider;
public HomeController (BooleanProvider booleanProvider){
_booleanProvider = booleanProvider;
// ...
}
// ...
}
not core solution
Here is a guide if you do not use dotnetcore https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection
PerRequestLifetimeManager is what you needed here
Install-Package Unity.Mvc3
At Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Bootstrapper.Initialise();
}
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
Func<LifetimeManager> LM = () => { return new PerRequestLifetimeManager(); };
container.RegisterType<IBooleanProvider, BooleanProvider>(LM());
return container;
}
}
public class HomeController : Controller
{
private readonly IBooleanProvider _booleanProvider;
public HomeController (IBooleanProvider booleanProvider){
_booleanProvider = booleanProvider;
// ...
}
// ...
}
In Startup:
services.AddTransient<IMyService, MyService>()
Controller method:
[HttpGet]
public JsonResult GetSomething()
{
Helper helper = new Helper(new MyService()); // works but looking better solution
return Ok("");
}
Helper class:
public class Helper
{
private readonly IMyService myService;
public Helper(IMyService myService)
{
this.myService = myService;
}
public Helper()
{
this.myService = ?;
}
}
I want to instantiate Helper class without inject the dependency manually with new MyService().
The MyService() class should be the class in startup.
I also want to place the the Helper class in another assembly.
I see some code with
var service = (IFooService)serviceProvider.GetService(typeof(IMyService));
but i don't know how to get a serviceProvider instance without injecting it to the helper.
Add the helper to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<Helper>(sp => new Helper(sp.GetRequiredService<IMyService>()));
And explicitly inject it into the controller
public class MyController: Controller {
private readonly Helper helper;
public MyController(Helper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
Ideally the helper should be derived from an abstraction as well
public class Helper : IHelper {
private readonly IMyService myService;
public Helper(IMyService myService) {
this.myService = myService;
}
//...
}
And added accordingly to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<IHelper, Helper>();
to avoid the controller having tight coupling to concretions (implementation concerns).
public class MyController: Controller {
private readonly IHelper helper;
public MyController(IHelper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
A way to properly resolve the service via DI:
[HttpGet]
public JsonResult GetSomething([FromServices] IMyService myService)
{
Helper helper = new Helper(myService);
return Ok("");
}
Or you inject it via ctor and use it in the method.
I am trying to start a new web project and I am new to asp.net mvc. Everytime I debug the following code, the error appears stating
the current type, BBNepal.Repository.Interface.IUnitOfWork, is an interface and cannot be constructed.
Are you missing a type mapping?'
Where did I go wrong?
This is my controller
public class RegisterController : Controller
{
private IRegisterService registerService;
public RegisterController(IRegisterService _registerService)
{
registerService = _registerService;
}
// GET: Register
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Create(RegisterDTO registerDTO)
{
try
{
bool isSaved;
if (registerDTO.Id == 0)
isSaved = registerService.Create(registerDTO);
else
return View();
}
This is my service layer
public interface IRegisterService
{
bool Create(RegisterDTO registerDTO);
}
#endregion
#region Implementation
public class RegisterService : IRegisterService
{
private IUnitOfWork unitOfWork;
public RegisterService(IUnitOfWork _unitOfWork)
{
unitOfWork = _unitOfWork ?? new UnitOfWork();
}
public bool Create(RegisterDTO registerDTO)
{
Register register = registerDTO.Convert();
unitOfWork.RegisterRepository.Insert(register);
unitOfWork.Save();
return true;
}
}
This is my interfaced repository
public interface IUnitOfWork
{
#region Core Method
int Save();
Task<int> SaveAsync();
#endregion
IRepository<Register> RegisterRepository { get; }
}
This is my repository
private IRepository<Register> _registerRepository;
public IRepository<Register> RegisterRepository
{
get
{
return _registerRepository ?? (_registerRepository = new RepositoryBase<Register>(_context));
}
}
My DI registrations are:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IRegisterService, RegisterService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
You need to update the registrations, and include one for IUnitOfWork as it is passed into the constructor of class RegisterService.
It should be something like:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IRegisterService, RegisterService>();
container.RegisterType<IUnitOfWork, UnitOfWork>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
I'm trying to mock SignalR broadcasting present in ApiController(WebApi), but unable to complete test case, below is my code
SignalRHub
public class HubServer : Hub { }
ApiControllerWithHub
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub
{
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
protected IHubContext Hub
{
get { return hub.Value; }
}
}
Controller (Method to Mock)
public class NotificationController : ApiControllerWithHubController<HubServer>
{
[HttpPost]
public HttpResponseMessage SendNotification(NotificationInput notification)
{
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
}
}
I'm writing following unit test with the help of Mock SignalR Post, I'm stuck here because this is SignalR call from controller not from SignalR Hub.
MockTest
public interface IClientContract
{
void BroadcastCustomerGreeting(string message);
}
[TestMethod]
public void SendNotificationTest()
{
NotificationInput notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
// Arrange
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
var mockGroups = new Mock<IClientContract>();
// Act.
mockGroups.Setup(_ => _.BroadcastCustomerGreeting("notification")).Verifiable();
mockClients.Setup(_ => _.Group("GroupName")).Returns(mockGroups.Object);
// I'm stuck here
var controller = new NotificationController();
// Act
HttpResponseMessage actionResult = controller.SendNotification(notificationInput);
}
Any help is appreciated to complete/correct this unit test.
Redesign needed. Base ApiController tightly coupled to static accessor of the hub context. This needs to be refactored out into its own service to allow for more flexibility via constructor injection.
public interface IHubContextProvider {
IHubContext Hub { get; }
}
public class HubContextProvider<THub> : IHubContextProvider where THub : IHub {
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
public IHubContext Hub {
get { return hub.Value; }
}
}
Controllers now need to be refactored to explicitly expose its dependencies.
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub {
private readonly IHubContext hub;
public ApiControllerWithHubController(IHubContextProvider context) {
this.hub = context.Hub;
}
protected IHubContext Hub {
get { return hub; }
}
}
public class NotificationController : ApiControllerWithHubController<HubServer> {
public NotificationController(IHubContextProvider context)
: base(context) {
}
[HttpPost]
public IHttpActionResult SendNotification(NotificationInput notification) {
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
return Ok();
}
}
Test can now be exercised with necessary mocks of dependencies.
[TestMethod]
public void _SendNotificationTest() {
// Arrange
var notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
var groupName = "GroupName";
var message = "notification";
var mockGroups = new Mock<IClientContract>();
mockGroups.Setup(_ => _.BroadcastCustomerGreeting(message)).Verifiable();
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
mockClients.Setup(_ => _.Group(groupName)).Returns(mockGroups.Object).Verifiable();
var mockHub = new Mock<IHubContext>();
mockHub.Setup(_ => _.Clients).Returns(mockClients.Object).Verifiable();
var mockHubProvider = new Mock<IHubContextProvider>();
mockHubProvider.Setup(_ => _.Hub).Returns(mockHub.Object);
var controller = new NotificationController(mockHubProvider.Object);
// Act
var actionResult = controller.SendNotification(notificationInput);
//Assert
mockClients.Verify();
mockGroups.Verify();
mockHub.Verify();
}
Just make sure to register new service with DI container so that it can be injected into dependent controllers.
With the redesign the base controller can be removed all together and the hub provider used directly. This is assuming that there was not any other reason to have the base controller.
I have the below code that is returning null when I try and return Sales Data. It works if I remove the other constructor for employee, so I believe it is a constructor injection issue.
How do I handle this injection?
Repository: Located in a seperate Project
public class CompanyRepository : ICompanyRepository, IDisposable
{
public CompanyRepository()
{
}
private readonly IEmployeeRepository _employeeRepository;
public CompanyRepository(IEmployeeRepository parameter)
{
_employeeRepository = parameter;
}
//fails never hits this
private readonly ISalesRepository _salesRepository;
public CompanyRepository(ISalesRepository parameter)
{
_salesRepository = parameter;
}
}
MVC 5 Controller:
[HttpGet]
public ActionResult Create()
{
//works
var a = _CompanyRepository.GetCompanyData();
//works
var b = _CompanyRepository.GetEmployeeData();
//fails
var c = _CompanyRepository.GetSalesData();
//return view etc
}
App_Start Unity.Config
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
container.RegisterType<ICompanyRepository, CompanyRepository>();
//this one is failing
container.RegisterType<ICompanyRepository, CompanyRepository>(new InjectionConstructor(new ResolvedParameter<SalesRepository>()));
container.RegisterType<ICompanyRepository, CompanyRepository>(new InjectionConstructor(typeof(EmployeeRepository)));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
I was just using but it is not working either
container.RegisterType<ICompanyRepository, CompanyRepository>(new InjectionConstructor(typeof(SalesRepository)));
container.RegisterType<ICompanyRepository, CompanyRepository>(new InjectionConstructor(typeof(EmployeeRepository)));
You should name your InjectionConstructor registrations
container.RegisterType<ICompanyRepository, CompanyRepository>("salesRep", new InjectionConstructor(new ResolvedParameter<SalesRepository>()));
container.RegisterType<ICompanyRepository, CompanyRepository>("employeeRep",new InjectionConstructor(new ResolvedParameter<EmployeeRepository>()));
And then resolve like this
var salesRep = container.Resolve<ICompanyRepository>( "salesRep" );
var employeeRep = container.Resolve<ICompanyRepository>( "employeeRep" );
An alternative to resolving is to change your constructors to
public CompanyRepository([Dependency("employeeRep")]IEmployeeRepository parameter)
public CompanyRepository([Dependency("salesRep")]ISalesRepository parameter)
and then use the DependencyResolver