Ninject not injecting service into Web Forms page - c#

I've trying to use Ninject for DI in a combined ASP.NET Web Forms and MVC project. I installed the following packages (and their dependencies) via NuGet:
Ninject.MVC5 3.2.1.0
Ninject.Web 3.2.1.0
In ~/App_Start/NinjectWebCommon.cs I register services:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ITermusRepository>().To<TermusOracleRepository>();
}
In MVC controllers, I use constructor injection to retrieve my ITermusRepository implementation:
public class Appraisal2013_2014FullController : Controller
{
ITermusRepository repo { get; set; }
public Appraisal2013_2014FullController(ITermusRepository Repo)
{
repo = Repo;
}
}
MVC works great, I use the repo later in my action methods to successfully retrieve data. All is well there.
In Web Forms, I use attribute injection.
public partial class _2013_2014_TERMUS_PaperTermus : BasePage
{
[Inject]
ITermusRepository repo { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var appraisal = repo.LoadByTermusId<Termus2013_2014EndYear>(Request.QueryString["TERMUSID"]);
}
}
However, repo.LoadByTermusId() call fails with a NullReferenceException because repo is null.
System.NullReferenceException: Object reference not set to an instance
of an object.
Clearly Ninject is set up correctly at least for MVC. I don't understand why my implementation of ITermusRepository isn't getting injected into my Web Forms code behind. What can I do to get it to inject it properly?
I used Jason's answer from How can I implement Ninject or DI on asp.net Web Forms? as my pattern for getting this working. I don't want to use Joe's answer, as it requires modifying the base class of the global application class, pages, master pages, ASMX services, generic handlers etc. And that appears unnecessary in the current version of Ninject.

[Inject]
ITermusRepository repo { get; set; }
needed to be
[Inject]
public ITermusRepository repo { get; set; }
That fixed the problems with my .aspx Web Forms pages. But it wasn't injecting them into my .ashx generic handlers. Since I don't have many of those, I created a constructor in my handler class and retrieved the service from the kernel.
ITermusRepository repo { get; set;}
public GetPDF()
{
var kernel = TERMUS.App_Start.NinjectWebCommon.CreateKernel();
repo = kernel.Get<ITermusRepository>();
}

Related

Constructor Injection in Xamarin Froms .xaml.cs file classes

I want to take advantage of dependency injection in my Xamarin project but can't get constructor injection to work in C# classes behind XAML views. Is there any way to do it ?
I've seen guides how to setup dependency injections in View Models, to later use them as repositories but that doesn't work for me.
So far I tried Ninject and Unity.
Code:
This is the service I want to use inside of my PCL project:
public class MyService : IMyService
{
public void Add(string myNote)
{
//Add Note logic
}
}
Interface:
public interface IMyService
{
void Add(string myNote);
}
Unity setup in App.Xaml:
public App ()
{
InitializeComponent();
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IMyService, MyService>();
var unityServiceLocator = new UnityServiceLocator(unityContainer);
ServiceLocator.SetLocatorProvider(() => unityServiceLocator);
MainPage = new MainMasterMenu(); //<-- feel that I'm missing something here as I shouldn't be creating class instances with DI, right ?
}
Usage that I'd like to see. This is .CS file behind a XAML starting page:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainMasterMenu : MasterDetailPage
{
private IMyService _myService;
public MainMasterMenu(IMyService myService)
{
_myService = myService
}
private void SomeFormControlClickEvent(object sender, ItemChangedEventArgs e)
{
_myService.Add("hi");
}
}
For that simple example creating the MainMasterMenu directly would be no issue, but you would have to pass the reference to your service
MainPage = new MainMasterMenu(unityContainer.Resolve<IMyService>());
But this would mean that you'll have to change that line every time the constructor of MainMasterMenu changes. You could circumvent this by registering the MainMasterMenu, too.
unityContainer.RegisterType<MainMasterMenu>();
...
MainPage = unityContainer.Resolve<MainMasterPage>();
Anyway, anytime you want to navigate to another page, which needs any dependency registered with unity, you'll have to make sure to resolve its dependencies properly, which requires (at least indirect) access to the unity container. You could pass a wrapper that encapsules the access to unity
interface IPageResolver
{
T ResolvePage<T>()
where T : Page;
}
and then implement that resolver with unity
public class UnityPageResolver
{
private IUnityContainer unityContainer;
public UnityPageResolver(IUnityContainer unityContainer)
{
this.unityContainer = unityContainer;
}
public T ResolvePage<T>()
where T : Page // do we need this restriction here?
{
return unityContainer.Resolve<T>();
}
}
This gets registered with unity
unityContainer.RegisterInstance<IUnityContainer>(this);
unityContainer.RegisterType<IPageResolver, UnityPageResolver>();
But you should have a look at the Prism library (see here) that solves many of the issues (e.g. it provides an INavigationService that lets you navigate to other pages without caring about the dependencies and it provides facilities to resolve viewmodels automatically, including dependencies).

DBContext dependency injection within Web Api using repositories [duplicate]

I am trying to use Ninject and OpenAccess for the first time. Please help me with the following. Here is what my project looks like...
public class ContentController : Controller
{
private ContentService contentSvc;
public ContentController(ContentService contentSvc)
{
this.contentSvc = contentSvc;
}
}
The following class is under a folder in my web app.
public class ContentService
{
private IContentRepository contentRepository;
public ContentService(IContentRepository contentRepository)
{
this.contentRepository = contentRepository;
}
public void InsertContent(Content content)
{
contentRepository.InsertContent(content);
}
}
The following repository belongs to a separate assembly.
public class ContentRepository : IContentRepository
{
DBContext db;
public ContentRepository(DBContext _db)
{
db = _db;
}
public void InsertContent(Content content)
{
db.Add(content);
}
}
Here is what Ninject binding look like..
kernel.Bind<ContentService>().To<ContentService>().InRequestScope();
kernel.Bind<IContentRepository>().To<ContentRepository>().InRequestScope().WithConstructorArgument("_db", new DBContext());
Everything works fine if I fetch one page at a time. I am using a simple tool 'XENU' to fetch multiple pages simultaneously. This is when I get errors with DBContext by fetching multiple pages at a time.
I am not sure if Ninject is dosposing the DBContext in each REQUEST?? I get different errors, e.g. 'Object reference not set to an instance of an object.', OR 'ExecuteReader requires an open and available Connection. The connection's current state is open.'
P.S.
I have ContentService under a folder in my MVC web app. ContentRepository is a separate assembly. I will be adding business logic in ContentService and use 'ContentRepository' only for CRUD operations. Also, please let me know if this architecture is okay or is there a better way to create services and repositories.
Here's how I would do your Ninject bindings,
kernel.Bind<DBContext>().ToSelf().InRequestScope();
kernel.Bind<ContentService>().ToSelf().InRequestScope();
kernel.Bind<IContentRepository>().To<ContentRepository>().InRequestScope();
This pattern should work fine in the example above with EF and Ninject.

Autofac attribute injection failing on attributes

I've found a few questions on this, but they tend to point to the exact documentation I'm following... but it's still not working.
I'm building a fairly simple ASP.NET MVC 4 site, and the plan is to use ActionFilterAttribute-based logging. I have a DataAccessProvider class which opens transactions with the database and provides unit-of-work instances, and I'm trying to inject it into the filter attribute.
The documentation says that it's enough to just call RegisterFilterProvider(), and ensure that the relevant types are registered. It specifically says that there is no need to register the attribute, but I've tried both with and without. My code currently looks something like this:
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(x => new EntityAccessProvider())
.As<IDataAccessProvider>()
.InstancePerHttpRequest();
builder.RegisterType<DebugLogAttribute>().PropertiesAutowired();
// ^ I've tried it with and without this line
builder.RegisterFilterProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
The example in the docs then just places a property on the filter, so I've done the same:
public class DebugLogAttribute : ActionFilterAttribute
{
private IDataAccessProvider DataAccess { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) { ... }
public override void OnActionExecuted(ActionExecutedContext filterContext) { ... }
}
The docs say that's all is required - not even a constructor to inject into; it's done by property injection. When I run this code, however, The DataAccess property is always null; Autofac seems to ignore it. I know the registration works properly because it's correctly injecting EntityAccessProvider into my controllers, but it's not working for attributes. What am I missing?
Your property of type IDataAccessProvider has to be public for injection to work. You can still mark DebugLogAttribute, IDataAccessProvider and it's implementation as internal if you prefer.
[DebugLogAttribute]
public class HOmeController : Controller
{
public ActionResult Index()
{
return View();
}
}
internal class DebugLogAttribute : ActionFilterAttribute
{
public IDataAccessProvider DataAccess { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Debugger.Break();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Debugger.Break();
}
}
internal interface IDataAccessProvider {}
internal class DataAccessProvider:IDataAccessProvider {}
I've been having the same issue in asp dotnet core but the current solution (making it public) doesn't seem to work. What I find odd is that the comment below is regarding a web-api but I'm using a normal ASP.NET Core MVC (MVC6). So if anyone has the same problem, try out the solution below.
https://docs.autofac.org/en/latest/integration/webapi.html#standard-web-api-filter-attributes-are-singletons
Unlike the filter provider in MVC, the one in Web API does not allow you to specify that the filter instances should not be cached. This means that all filter attributes in Web API are effectively singleton instances that exist for the entire lifetime of the application.
public override async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
MyService = context.HttpContext.
RequestServices.GetService(typeof(IMyService)) as IMyService;
}

Ninject + ASP.NET Web Forms Not Working

I've successfully implemented Ninject in an MVC3 application, but am running into some trouble doing the same thing with ASP.NET Web Forms. I'm getting null references every time I try to access an injected property in my business layer. After setting breakpoints within the CreateKernel method, as well as several places within the ServiceLocator class, it looks like none of them are ever getting hit, so it's not even loading.
I'm sure I'm just approaching this wrong, but there is very little documentation or info out there for wiring up Ninject in a Web Forms application.
Basically here's what I have so far:
code behind
public class ReviewManager
{
[Inject] private IReviewRepository _reviewRepository { get; set; }
public ReviewManager() { }
public ReviewManager(IReviewRepository reviewRepository)
{
_reviewRepository = reviewRepository;
}
public Review GetById(int id)
{
if (id <= 0) throw new ArgumentException("ID must be greater than zero");
**I get a null reference exception on the next line. _reviewRepository is null**
return _reviewRepository.GetById(id);
}
}
global.asax.cs
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return ServiceLocator.Kernel;
}
// deleted for brevity
}
ServiceLocator.cs (edited for brevity, the relevant parts are here)
public static class ServiceLocator
{
public static IKernel Kernel { get; set; }
public static ILogger Logger { get; set; }
static ServiceLocator()
{
Kernel = new StandardKernel(new INinjectModule[] {
new LoggerBindings(),
new DataBindings()
});
if (Logger == null)
Logger = Kernel.Get<ILogger>();
}
}
public class LoggerBindings : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<NLogLogger>();
}
}
public class DataBindings : NinjectModule
{
public override void Load()
{
Bind<IReviewRepository>().To<ReviewRepository>();
}
}
ASP.Net via WebForms does not allow you to manage the lifecycle of all object instances (like MVC does). For example, the framework instantiates page objects. This means you probably can't implement DI in quite the same way as you would in MVC/WPF/Silverlight (the same problem is present in WinForms IIRC). You will likely have to initiate the dependency graph directly in each of your code behinds.
Translation: you will want to call ServiceLocator.Kernel.Get<IReviewRepository> when your page loads (or as lazy-init on the property).
The cool thing about MVC ist that it can run side a side of ASP.NET WebForm pages in the same application. In my opinion the best way to extend ASP.NET WebForms websites is to create new pages using MVC3 and to refactor every page that needs major changes to MVC3.
If this is no option go and use the Ninject.Web extension. It contains a IHttpModule that property injects all web pages and controlls after they are initialized. That way you can property inject the services als have them created by Ninject.
A potential workaround, by changing your DataBindings class as follows:
public class DataBindings : NinjectModule
{
public override void Load()
{
Bind<IReviewRepository>().To<ReviewRepository>();
Bind<ReviewManager>().ToSelf();
}
}
And within your caller, instead of
var rm = new ReviewManager();
Try using
var rm = ServiceLocator.Kernel.Get<ReviewManager>();
I havent tested this code, but i think it'll solve your null reference problem.
I use property injection for pages, masterpages and usercontrols. All my pages, for example, inherit from a base class that overrides RequestActivation method with the following code:
''' <summary>
''' Asks the kernel to inject this instance.
''' </summary>
Protected Overridable Sub RequestActivation()
ServiceLocator.Kernel.Inject(Me)
End Sub
And in each page I declare injectable properties:
<Inject()>
Property repo As IMyRepository

Database injection into a validation attribute with ASP MVC and Castle Windsor

I need some help - I am trying to use a custom validation attribute in an ASP.NET MVC web project that needs to make a database call.
I have windsor successfully working for the controllers and the IRepository interface is injected normally. The problem arrises when I need to inject the repository into the attribute class.
The attribute class has the following code:
public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
private readonly string message;
private readonly IArticleRepository articleRepository;
public ValidateUniqueUrlNodeAttribute(string message)
{
this.message = message;
}
public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
{
this.articleRepository = articleRepository;
}
public override IValidator Build()
{
var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };
ConfigureValidatorMessage(validator);
return validator;
}
My problem is that I cannot seem to make Windsor intercept the contruction of the attribute to pass in the IArticleRepository
The current code in my global.asax file is as follows:
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
container
.RegisterControllers(Assembly.GetExecutingAssembly())
.AddComponent<IArticleRepository, ArticleRepository>()
.AddComponent<ValidateUniqueUrlNodeAttribute>();
Any help would be greatly appreciated.
AFAIK no dependency injection container can directly manage an attribute, since it's instantiated by the runtime and there's no way to intercept that.
However, they can cheat by either:
Using a static gateway to the container (example), or
Using a "BuildUp" feature that injects whatever dependencies are found within an already-constructed object. This is called BuildUp in Unity or InjectProperties in Autofac.
Windsor doesn't support #2 (ref1, ref2), so you can either:
Try one of the hacks to make Windsor support #2 (hack1, hack2)
Use a static gateway
Implement your own IValidatorBuilder and make it use Windsor to create validators. I'm sure this is implemented somewhere but I can't find it right now...
Don't know if this helps, but I subclassed ValidationAttribute to expose a Resolve<T>() method like so:
public abstract class IocValidationAttribute : ValidationAttribute
{
protected T Resolve<T>()
{
return IocHelper.Container().Resolve<T>();
}
}
Then it can be used in any custom ValidatorAttribute that needs to hit a database:
public class UniqueEmailAttribute : IocValidationAttribute
{
public override bool IsValid(object value)
{
ICustomerRepository customerRepository = Resolve<ICustomerRepository>();
return customerRepository.FindByEmail(value.ToString()) == null;
}
}
I think it's a variation of the 'Static Gateway' approach mentioned by Mauricio Scheffer. I don't know if this is a good design or not. I'm not a huge fan of it, I'd rather the dependency was injected more 'elegantly', though I can't use constructor injection obviously, I'd like to use Property injection but can't work out a way to hook into the ASP.NET MVC framework code to do this (I've even pored though the MVC2 source code).
I was able to wire it up [using Autofac as it happens, but it's just constructor injection via the ASP.NET MVC DependencyResolver] in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
Hmm.
Can you test the effect of removing the (string message) ctor, and see if that at least forces Castle to use the ctor with the Repostiory ?
Otherwise we call AddComponent(name, type, type). Other than that it really should work...
Also does this hint at my first idea ? How do I use Windsor to inject dependencies into ActionFilterAttributes

Categories