I am new to Dependency Injection and currently using Ninject as my DI. I have been playing with a ASP.Net MVC 5 application and have been reading "Pro ASP.NET MVC 5". I have followed the examples in the book on how to set up and use Ninject. Below is the code for my register services:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
kernel.Bind<ICustomerUserDataRepository>().To<CustomerUserDataRepository>();
}
As for my controller I have below:
public class CustomerController : Controller
{
private ICustomerRepository customerRepository;
public CustomerController(ICustomerRepository customerRepo)
{
this.customerRepository = customerRepo;
}
// GET: Customer
public ActionResult Index(int Id = 0)
{
Customer customer = customerRepository.GetCustomer(Id).First();
return View(customer);
}
}
This works fine as expected in the book. However, I have been playing around with some other code and wanted to further use Ninject to resolve some dependencies. For example, I am working on a custom helper for one of my Razor views. In the my helper code I have the following:
using (IKernel kernel = new StandardKernel())
{
ICustomerUserDataRepository customerUserDataRepo = kernel.Get<ICustomerUserDataRepository>();
When I run this, it complains that there is no binding defined for ICustomerUserDataRepository. I am assuming this is because I am using a new kernel with no defined bindings. I read that you need to load bindings in kernels through modules. So I made the following:
public class MyBindings : NinjectModule
{
public override void Load()
{
Bind<ICustomerUserDataRepository>().To<CustomerUserDataRepository>();
}
}
I then load the module when setting my kernel below:
using (IKernel kernel = new StandardKernel(new MyBindings()))
{
ICustomerUserDataRepository customerUserDataRepo = kernel.Get<ICustomerUserDataRepository>();
This however causes a "Error loading Ninject component ICache" error message when I execute the application. I would appreciate some help on what I am doing wrong and what I am not understanding. I read that multiple defined kernels can cause this error. Am I not suppose to be using a new kernel in my helper method since one is already being used and binded under RegisterServices()? If so, am I suppose to access that existing kernel in my helper method? Or am I on the right track and need a new kernel loading the specific bindings in my module? Thank you.
Am I not suppose to be using a new kernel in my helper method since one is already being used and binded under RegisterServices()?
correct. you only want one kernel or Composition Root per application. I would suggest that instead of trying to access dependencies in a helper method, that you would create a viewmodel in your Controller (that has access to the dependency) and then pass the viewmodel into your helper method.
Related
I am making a website using ASP.NET MVC and an onion architecture. I have the following architecture:
Domain : Entities / Domain Interfaces
Repository : Generic repository (for now) using Entity Framework Code First Approach
Service : Generic Service that calls the Repository
MVC
Now I am trying to create a method in my controller to start testing the methods I have implemented in Repository and Service, and I am having a hard time as to what I am allowed to create in this controller. I want to test a simple Get method in the Repository, but to do that I need GenericService object and GenericRepository object in my controller. To demonstrate what I mean here's a snippet of my GenericRepository(I will skip the interfaces):
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly PrincipalServerContext context;
private DbSet<T> entities;
public Repository(PrincipalServerContext context)
{
this.context = context;
entities = context.Set<T>();
}
}
Now my GenericService:
public class GenericService<T> : IGenericService<T> where T : class
{
private IRepository<T> repository;
public GenericService(IRepository<T> repository)
{
this.repository = repository;
}
public T GetEntity(long id)
{
return repository.Get(id);
}
}
And finally, my question, am I allowed to create these objects in my controller as follows (using my dbcontext called PrincipalServerContext):
public class NavigationController : Controller
{
private IGenericService<DomainModelClassHere> domainService;
private IGenericRepository<DomainModelClassHere> domainRepo;
private PrincipalServerContext context;
public ActionResult MyMethod(){
context = new PrincipalServerContext();
domainRepo = new GenericRepository<DomainModelClassHere>(context);
domainService = new GenericService<DomainModelClassHere>(domainRepo);
if(domainService.GetEntity(1)==null)
return View("UserNotFound");//Just as an example
return View();
}
}
Is this allowed? According to Jeffrey Palermo, UI can depend on Service and Domain so I don't know about the Repository. Technically I am not using methods from repository, but I do need to add a reference to the project.
If I can't then how can I create a new GenericService if I don't have a GenericRepository? Is there a better way to instantiate my objects ?
EDIT I think the answer to my question resides in Startup.cs where I can put something like service.addScoped(typeof(IGenericRepository<>),typeof(GenericRepository<>));
but I 'm not sure about this, any ideas?
I'll answer this on my own if ever someone encounters the same problem. There are configuration methods we can use to create instances of classes when needed. In the Startup.cs file you have to add ConfigureServices(IServiceCollection services) method and inside there are several methods that can be applied to services to create these instances. For example you can use:
services.AddTransient(IGenericRepository, GenericRepository)
What is the difference between services.AddTransient, service.AddScope and service.AddSingleton methods in Asp.Net Core 1? (this link explains differences between methods).
AddTransient is good in my case because it creates an instance of an object through the whole lifespan of the application, which is what I need. This means UI is dependant on the rest of the solution, because Startup.cs needs to know about the Repositories as well as the Services.
A pretty good answer can be found here :Onion Architecture : Can UI depend on Domain.
I want to use DI to manually inject an IDBConnection in my api controllers. I know I can put it in the constructor:
public MyController(IDBConnection cnn) { this._Connection = cnn; }
Or I could use the [FromServices] attribute:
[FromServices]
public IDbConnection _Connection { get; set; }
And I can use it in views like this:
#inject IDbConnection cnn
What I would really like to do would be to have it in a using, and have the DI open the connection so I could do something like this:
using (var cnn = Services.Inject<IDbConnection>()) {
// do something, don't worry about opening or closing
}
I'm declaring it like this:
services.AddTransient<IDbConnection>(x =>
{
string connectionString = Configuration.Get<string>(
"Data:DefaultConnection:ConnectionString");
return new SqlConnection(connectionString);
});
Should I create a class inheriting from SqlConnection that calls Open() in it's constructor? How can I access Configuration from there? I could create it like that to inject configuration or the connect string... Is using not required? Is there basically no overhead with just creating the instance so it wouldn't matter if some actions needed multiple connections to different databases?
I recommend that you create a service layer that your controller will depend on instead of directly accessing the db connection (and you won't have to this in your views #inject IDbConnection cnn). Your views should only declare the Model that your controller method returns and you will have nice intellisense support in the view pages.
public class ProductServices(){
public ProductServices(IDbConnection conn){
...
}
public List<Product> GetProducts(){
...
}
}
using is not required. As a rule of thumb, if the instance is created via IoC container (eg. Unity, Autofac, Ninject, etc), it should also be destroyed by the IoC container.
To begin with two things.
I am trying to achieve an action filter that logs when and action begins and when it end
I am well aware of the .AsActionFilter() method in Autofac 3.0 BUT...
The project that this is using is based in Orchard 1.6 which is known to be compatible with autofac 2.6.xxx. We do not want to go through a potentially lengthy process of upgrading to Autofac 3.0 at this time so the .AsActionFilter() option is not available to us.
The other option is to set the filter (which extends ActionFilterAttribute) as an attribute on our base controller (from which all other inherit btw). The problem is that the filter itself has two dependencies:
A service of our own that holds information on the context
An implementation of an ILoggingService
What I cannot find is a way to inject these into the actual property at the head of the class. Does anyone know a way in which to achieve this either through the [Attribute] line itself of some function of Autofac during registation?
The ActionFilterAttribute:
public class GRMSActionLoggingFilter : ActionFilterAttribute {
private readonly IGRMSCoreServices _grmsCoreServices;
private readonly ILoggingService _loggingService;
public GRMSActionLoggingFilter(IGRMSCoreServices grmsCoreServices, ILoggingService loggingService) {
_grmsCoreServices = grmsCoreServices;
_loggingService = loggingService;
}
public GRMSActionLoggingFilter() { }
public override void OnActionExecuting(ActionExecutingContext actionContext) {...}
public override void OnActionExecuted(ActionExecutedContext actionContext) {...}
}
Assigning the attribute to the base controller:
// This currently compiles but will fail during run time as the IGRMSCoreSerivces and ILoggingService will both be null. Need to property inject these services somehow.
[GRMSActionLoggingFilter]
Anyone have any idea to achieve this?
You cannot (easily) inject runtime values to attributes.
This is how attributes work in C# - you can only pass constant values of certain types. You can read more about it here.
In order to achieve desired functionality in Orchard you need to split your code into two components:
a marker attribute class you put on your action
an action filter class inheriting from FilterProvider and implementing IActionFilter
The way it works is that you put an attribute on some action and then use the action filter to check existence of that attribute (using filterContext.ActionDescriptor.GetCustomAttributes(...)). If an attribute exists, do your stuff.
There are lots of examples of this technique in Orchard core. Check eg. the ThemedAttribute and ThemeFilter action filter classes.
I am using NHibernate and ninject in ASP.Net MVC, using this page as a guide. One thing I think is weird is that, in this code (half way down the page)
public class RepositoryModule : NinjectModule
{
public override void Load()
{
const string connectionString = #"Server=localhost; Port=3306; Database=trucktracker; Uid=root; Pwd='your_own_password';";
NHibernateHelper helper = new NHibernateHelper(connectionString);
Bind<ISessionFactory>().ToConstant(helper.SessionFactory).InSingletonScope();
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>().InRequestScope();
}
}
I think it's odd that you need to have this line per model:
Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>().InRequestScope();
If I have 100 different tables (and thus models) do I really need to add this line in for every class that I have? Is there not a better way where I can just declare this once and use inheritance to pass in the Type in my controller?
Use the Open Generics support:-
Bind(typeof(IIntKeyedRepository<>)).To(typeof(Repository<>)).InRequestScope();
Background
I am trying to move business logic out from the controllers into their own services.
Controller
public class AccountController : Controller
{
private readonly IAccountService _accountService;
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
....
}
I'm using Unity to inject dependencies. I'd like to use the Url.GenerateUrl() helper method within the implementation of IAccountService but Url is a property against the controller.
I looked at the MVC source to see how this is done but it requires me to access the RequestContext from outside of the controller, and I don't know how to do that.
Question
How do I access the RequestContext from outside the controller? If that won't solve my problem, how do I solve the problem given my setup?
This might not be quite right because I'm unable to test it at the moment, but I think that you can do something like this in .NET 4+:
using System.Web;
using System.Web.Mvc;
// ...
var helper = new UrlHelper(HttpContext.Current.Request.RequestContext);
string url = helper.GenerateUrl(/* ... */);
It might make more sense to pass the context from the controller to your IAccountService implementation rather than grabbing it directly from HttpContext.Current.
However i'd like to use the Url.GenerateUrl helper methods within my implementation of IAccountService
Simply pass this information as parameter. Example:
public ActionResult Index()
{
var someUrl = Url.Action("about");
_accountService.Foo(someUrl);
}
Now you no longer need UrlHelper inside your service classes. Everything that needs interacting with MVC infrastructure shouldn't be placed in your service classes. They shouldn't depend on any Request, Response, Session, ... It's the controller's responsibility to work with those objects and glue them together with your service classes.