Ninject Creating an Extra Instance when using NinjectHttpModule - c#

For some reason Ninject is creating an additional instance of my object when I use NinjectHttpModule in my MVC 4 app.
If I use NinjectHttpModule (the Ninject.MVC3 default) but do not actually have any IHttpModule classes that require constructor injection, it works fine. But as soon as I create a class that implements IHttpModule and that requires constructor injection, Ninject for some reason creates two instances of my object.
I added some tracking code to the class that is being duplicated to verify that it was being duplicated. Every time an instance is created, the static count variable is incremented:
namespace Trigger.Events
{
public class TriggerEventRegistry : ITriggerRegistry
{
private static int count;
public TriggerEventRegistry()
{
TriggerEventRegistry.count++;
}
}
}
Here is my IHttpModule:
namespace TriggerDevelopment.ApplicationTriggers
{
public class RegisterTriggerComponentsHttpModule : IHttpModule
{
ITriggerEventRegistry eventRegistry;
public RegisterTriggerComponentsHttpModule(ITriggerEventRegistry eventRegistry)
{
this.eventRegistry = eventRegistry;
}
}
....
}
By the time a TriggerEventRegistry is injected into my controller (on the same request), the TriggerEventRegistry.count equals 2. If I comment out the constructor on RegisterTriggerComponentsHttpModule, then the value of TriggerEventRegistry.count equals 1 (which is should since there should only be one instance/request).
Here is the binding code:
Bind<ITriggerEventRegistry>().To<TriggerEventRegistry>().InRequestScope();
Any help on this would be greatly appreciated!
Note
I even made a request to my app using curl to avoid multiple HTTP requests being made by the browser looking for assets, a favicon or something like that. Still no joy.
Update
Upon further investigation, I'm also seeing that the ctor and the Init method of RegisterTriggerComponentsHttpModule is being called twice.

It's going to call your HttpModule as many times as there are requests. For instance, most web browsers submit at least two requests, the page request and a favicon request. Try adding something like an image to the page, and see if you get three requests...

Related

MVC Page Load instantiate several controllers with shared resources

I have detected, that during loading the main page several controllers are instantiated (I think because the main page is built from several parts). The controllers instantiate the API classes to query some data through them. I was wondering how and where I could share the same API class instance between them.
I can imagine such a code:
class HomeController : Controller
{
private MyApi Api;
public HomeController()
{
this.Api = get the pervious MyApi instance form somewhere
if (this.Api == null) // 1st time
{
this.Api = new MyApi();
put this instance to somewhere to share between controllers
}
This "somewhere" is not a session, because next page load needs another MyApi instance. It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated. It must be really a simple thing, but I really don't know where it is :( Could somebody help me?
You can consider using Microsoft Unity Framework in your application.
Using Unity Dependency Injector you will be able to inject instances of MyApi class into the any controller and avoid writing " if (this.Api == null) " these types of checks and also managing instances of it in some Session or Application level variables, which makes code dirty.
For this specific problem "It must go to an object property which remains intact during the whole page load process, but is dismissed when the html result is generated", You can configure Unity Injected object to have a life time of "Scoped". Meaning, the object will be created once per request.
Here's is a link on configuring Unity in an asp.net core application
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2

Passing object of class defined in assembly1 to assembly2, without changing assembly1

I am trying to create tools for a game to learn, as well as improve my own playing experience.
The primary .NET assembly, csass.dll, that controls the client is heavily obfuscated, and I have no control over this .dll-file at all and reading it's code is very time consuming. The game also includes a mainapi.dll which handles the communication between server and client. I have full control over this assembly and I can listen to the servers responses and send my own requests, which already gives me some pretty nice functionality, however there are some limitations I'd like to work around.
csass.dll references mainapi.dll, by default mainapi does not reference csass. In csass.dll there is a class, let's call it clickHandler, that has a public, non-static method ClickObj() of return type void. I want to call this method from within mainapi.dll, but I have no idea how to go about this, given that I have to leave csass.dll untouched.
Are there any feasible ways to 'retrieve' a clickHandler object (to then call its ClickObj() method) from within the mainapi assembly, without making any changes in csass.dll? Appreciate any and all input!
Create an interface:
public interface IClickHandler
{
void ClickObject();
}
Now create a helper class implementing that interface:
using CsAss;
public class ObjectClicker : IClickHandler
{
CsAss _csass;
public ObjectClicker(CsAss csass)
{
_csass = csass;
}
public void ClickObject()
{
_csass.clickObject();
}
}
Add a dependency on an instance of the interface into your MainAPI class:
public class MainApi
{
IClickHandler _clickHandler;
public MainApi(IClickHandler clickHandler)
{
_clickHandler = clickHandler;
// Now you have a class that can call the click handler for you
}
}
Now wire it all up:
public void StartupMethod()
{
var csass = new CsAss();
IClickHandler clickHandler = new ObjectClicker(csass);
var main = new MainApi(clickHandler);
// TODO: Start your app now that MainApi is properly configured
}
That last step is the only potentially tricky part, depending on your project layout. You need something that can create an instance of CsAss, MainApi and ObjectClicker. Normally I would solve that with the dependency injection (DI) pattern, either using a framework such as Autofac or so-called "poor man's DI" by manually instantiating from a central startup method. That gets a little more difficult with Unity since there isn't an easily accessible startup point. You could start looking into https://github.com/svermeulen/Zenject and go from there for options.

Is changing contextLifetime to Singleton a correct solution to fix the following error?

I am using Asp.net Core 2. Consider the following classes:
public class BlogDbContext: DbContext
{
.....
}
public interface IBlogData { ... }
public class BlogData : IBlogData
{
private BlogDbContext _context;
public BlogData(BlogDbContext context) { ... }
.......
}
When I used the default value contextLifetime: ServiceLifetime.Scoped as follows,
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddDbContext<BlogDbContext>(...);
.....
services.AddSingleton<IBlogData, BlogData>();
}
Compilation, first migration and first database update were performed without any error. But I got the following error when visiting the page for the first time.
InvalidOperationException: Cannot consume scoped service 'MyProject.Data.BlogDbContext' from singleton 'MyProject.Services.IBlogData'.
Question
Is it correct if I fix the error by changing contextLifetime as follows ?
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddDbContext<BlogDbContext>(...,contextLifetime: ServiceLifetime.Singleton);
.....
services.AddSingleton<IBlogData, BlogData>();
}
Note: this problem is specific to Asp.Net Core 2.0.
It's because you are trying to use a scoped service from a singleton service.
This is new to asp.net core 2.0. Only singleton services can be consumed by a
signleton service.
You need to add BlogData as Scoped.
No, you should generally always used scoped for DbContext in asp.net core that way it gets created once per request and is automatically disposed for you at the end of the request.
You are not really showing the code where the error is happening, but my guess is it is happening because you are running some code in startup to run the migrations. If you confirm that or show the code where the error is actually happening I could offer more help
Old question without a great answer.
The reason you get this error is because a scoped service has to be recreated every time a new page request is made (Atleast within ASP.net). How it does that is everytime a service is "requested" by way of injection (For example within a constructor), it caches the first time it's requested, then for subsequent requests, it simply returns that same instance. At the end of the page load, it trashes this instance.
Now a singleton is instead cached that first time it's requested, but it's never disposed. Every request ever made for the service will return the exact same instance.
The problem is if you have a parent service that is singleton that then references a child service that is scoped. That first request, the parent and child are created. The second request, well the parent is a singleton so it isn't recreated. Now we have a problem, because the child service is scoped, how can it be created for each request if the thing that is requesting it (And thus kicking off the DI), is a singleton? It can't. So an exception is thrown.
Interestingly, it is more about saving yourself from hanging yourself more than anything. For example, if you replace the scoped instance with a transient one, you will still have the same "problem", but it won't throw an exception.
More info here if you need further examples : https://dotnetcoretutorials.com/2018/03/20/cannot-consume-scoped-service-from-singleton-a-lesson-in-asp-net-core-di-scopes/

State in ApiController

I need to provide an api to a long running windows service which does a bunch of processing and retains a memory of that history. An api is required to provide status on current activity levels of the system (records processed, records waiting to be processed, etc).
I was wanting to use a self-hosted Owin ApiController to provide a nice interface to the system. However, the ApiController is completely stateless and there is no method (after searching dozens of IoC posts) for injecting an already active instance into the controller.
Is there a way to provide a class instance to an ApiController?
I don't think you can inject an old instance of the controller, because you get a new instance every time you perform a request.
However you can create a singleton object with a collection inside, and you can inject it into the controller constructor and use in every request.
You can also use some sort of persistence such as DB, that you can run on your device.
Here is an example for a singleton class:
using System;
public class Singleton
{
public Dictionary<string,object> State {get; private set;}
private static Singleton instance;
private Singleton() {
State = new Dictionary<string,object>();
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Even though you can get Session state in web api controller, it is going to be questionable solution, instead, I would recommend going the following way:
include Hangfire as dependancy and use it for long running tasks
Use signal-r to to push state of background task
return JobID from your API method and use it on the client to subscribe to signal-r hub

How to dynamically create and inject services in ASP.NET 5?

I'm in a situation where the classic functionality of vnext's DI container is not enough to provide me with the correct functionality. Let's say I have a DataService that gets data from a database like this:
public class DataService : IDataService, IDisposable {
public List<MyObject> GetMyObjects()
{
// do something to fetch the data...
return myObjects;
}
}
I can then register this service in the DI container during the configuration phase in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IDataService), typeof(DataService));
}
This ensures the correct lifecylce of the service (one per request scope), however, I need the service to access a different database when a different request is made. For simplicity reasons, let's say the following scenario applies:
when a request to my Web API is made, the DataService will access the currently logged in user, which contains a claim called Database which contains the information which database to use.
the DataService is then instantiated with the correct database connection.
In order to get the second step to work, I have created a constructor for the DataService like this:
public DataService(IHttpContextAccessor accessor)
{
// get the information from HttpContext
var currentUser = accessor.HttpContext.User;
var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
if (databaseClaim != null)
{
var databaseId = databaseClaim.Value;
// and use this information to create the correct database connection
this.database = new Database(databaseId);
}
}
By using the currently logged in user and his claims, I can ensure that my own authentication middleware takes care of providing the necessary information to prevent attackers from trying to access the wrong database.
Of course adding the IDisposable implementation is required to cleanup any database connections (and gets called correctly using the scope lifecycle).
I can then inject the DataService into a controller like this
public MyController : Controller
{
private IDataService dataService;
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
This all works fine so far.
My questions now are:
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Is this method really safe? Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
What you have is fine.
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Not really. You can use delegate registration but it's the same problem.
Is this method really safe?
Yes
Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
Nope. The IHttpContextAcessor uses AsyncLocal (http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to provide access to the "current" http context.

Categories