Can't get Ninject to dispose object in Request Scope - c#

I can't seem to get Ninject to dispose objects in request scope in an ASP.NET MVC application with web API no matter what I do.
What I am doing:
Create a new ASP.NET Web Application with Visual Studio 2013. I select the MVC template and add a Web API to it (it also has ASP.NET Identity in the package by default)
I install Ninject.MVC5 package via nuget (install-package Ninject.MVC5)
I add a the following class to my application:
public class SomeDisposable : IDisposable
{
public void Dispose()
{
System.Diagnostics.Debug.WriteLine("test");
}
}
I add the following binding in NinjectWebCommon RegisterServices method
kernel.Bind().ToSelf().InRequestScope();
I add an object of the type SomeDisposable to the Home controller
public HomeController(SomeDisposable some)
{
}
I run the application and place a breakpoint in the HomeController constructor and the Dispose method of the SomeDisposable class. The controller receives an object (presumably from Ninject), the page loads but the Dispose method is never called.
At this point things are already broken but I add a Web API controller, install Ninject.WebApi packaged and repeat the experiment with the WebAPI controller and I get the same result.
I have read a bunch of questions including this one - Ninject doesn't call Dispose on objects when out of scope and the Ninject documentation https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope and they both indicate that due to the fact that Ninject.Web.Common includes a registration for the OnePerRequestHttpModule (yes it is there) the disposal should just work but it doesn't. I also tried adding the PerRequest module in the web.config and got an error saying that I can't have this section in integrated mode.
At this point I am lost. I suspect either integrated mode or OWIN have something to do with this but I have no idea how to debug it or what to do to fix it. Any suggestions?

The object not being disposed was a problem in Ninject.Web.Common before version 3.2.2, as discussed here: InRequestScope is failing to dispose objects
As you have been installing Ninject via nuget, you probably installed the oldest supported dependencies. This can be avoided by using:
Install-Packages Ninject.MVC5 -DependencyVersion Highest
Please verify that you are using the current version of all Ninject packages.

Related

'AddEntityFramework*' was called on the service provider, but 'UseInternalServiceProvider' wasn't called in the DbContext options configuration

I'm upgrading an ASP.NET Core application from Framework 2.2 to 3.1. It also uses Entity Framework Core.
In the Startup.ConfigureServices method, there is this code:
services.AddEntityFrameworkNpgsql()
.AddDbContext<MainDbContext>(options => options
.UseNpgsql(Configuration.GetConnectionString("MainDbContext")));
Everything was fine with .NET Core 2.2. With .NET Core 3.1, I get this warning on every application start:
'AddEntityFramework*' was called on the service provider, but 'UseInternalServiceProvider' wasn't called in the DbContext options configuration. Remove the 'AddEntityFramework*' call as in most cases it's not needed and might cause conflicts with other products and services registered in the same service provider.
Looking up the UseInternalServiceProvider method, it looks like that should be called on the options to pass on the main service provider. Unfortunately, at this point, the service provider does not exist yet. It is just about to be built.
I don't understand what the problem is and what this warning wants to tell me, but failed to do. How can I make that warning go away? The web doesn't know about this message yet.
Remove AddEntityFrameworkNpgsql. The docs explain that :
Calling this method is no longer necessary when building most applications, including those that use dependency injection in ASP.NET or elsewhere. It is only needed when building the internal service provider for use with the method. This is not recommend other than for some advanced scenarios.
The actual Getting Started page For Npgsql shows there's no need for anything extra :
simply place the following in your ConfigureServices method in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Other DI initializations
services.AddDbContext<BloggingContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("BloggingContext")));
}

Refreshing loaded Assemblies during WebApi runtime

I have a C# Owin WebApi Selfhost Project and the controllers I use are implemented in separate assemblies.
I´m finding these assemblies by naming conventions before I start up the WebApp and load them into the AppDomain. Then when the Api starts, the controllers are accessible. There is another approach which involves a custom IAssemblyResolver-class which replaces the default one in the Config.Services
config.Services.Replace(typeof(IAssembliesResolver), new MyAssembliesResolver());
This also works, all my seperate controller-assemblies are found, loaded and accessible.
Now to the problem: It may occur, that a new controller-assembly appears in my executing directory. My Api has an "AssembliesController" which can be told to look for new assemblies in the executing directory and load them
during runtime. This also works, but the problem is: the controllers in the newly loaded assembly aren´t accessible until I restart my Api.
It appears that the Api just asks once for assemblies (IAssembliesResolver) and available controller types (IHttpControllerTypeResolver) on startup and works with the results until the end. But in my case I want to add assemblies/controllers during runtime without restarting the Api. Can somebody help me please? How do I get the Api to refresh the assemblies/controllers?
You need to overwrite the DefaultHttpControllerSelector.
Here is a very nice article on the subject: link
Enjoy!

asp net core 1 RC2 AccountController injection

I created a asp.net core rc2 web application with user identity, however i'm confused how the account controller class is getting it's arguments, usermanager, signinmanager? Where are they being passed in from? I follow the call stack and I get external code, what external code is passing in these objects? Help me understand, how these 2 objects are being initialized.
In your Startup.cs you will see a call to this method
services.AddIdentity<ApplicationUser, IdentityRole>()
Afte reading the links on dependency injection suggested by #AndrésRobinet you can actually see where the services are being wired up.
This extension method lives in `IdentityServiceCollectionExtensions - You can then go and look at the source code for this method call (.NET core is on github):
line 67 of the AddIdentity method
services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();
what external code is passing in these objects?
Right-click on External code and click Show External Code - now you can get an idea of what is happening under the hood. the code down to and including the Kestrel webserver is also browsable/downloadable on github
image truncated

Configuring Entity Framework In ASP.NET 5 using a DAL

I'm trying to completely separate the repository / data access later whilst still using configuration in the main project (through appsettings.json)
My current solution is either to hard code the connection string in the OnConfiguring method in the DbContext which is not ideal. Or perhaps create a config file just for the repository layer and read from that.
I would like the main project (web service in this case) to be completely independent of the data access layer (as I will be communicating to it using a service layer anyway), but be able to configure it at start-up using the default appsettings.json
Is there a good approach of doing this? Or must the main project have a reference to the repository layer.
Project layout:
Project.WebService
- Startup.cs
- EmployeeController.cs
- appsettings.json
Project.Service
- EmployeeService.cs
- EmployeeDTO.cs
Project.DAL
- DbContext.cs
- EmployeeRepository.cs
Project.Entities
- Employee.cs
The WebService references the Service, the Service references the DAL and the DAL references the Entities / POCOs
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string connString = Configuration["AppSettings:ConnectionString"];
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options => options.UseSqlServer(connString));
}
The above doesn't work anyway with the DbContext being in another class library. The following exception gets thrown.
An exception of type 'System.InvalidOperationException' occurred in
EntityFramework.Core.dll but was not handled in user code
Additional information: No database providers are configured.
Configure a database provider by overriding OnConfiguring in your
DbContext class or in the AddDbContext method when setting up
services.
Which is one reason why I hard-coded the connection string into the OnConfiguring method.
Does anyone have any good approaches / solutions for this or am I missing something? The web service doesn't need to know what database it is talking to, or have any reference to it at all. It simply calls a service, a receives a DTO or, sends a DTO.
Hook up all dependencies:
If you really insist on your webservice not having a reference to your DAL, you could always try an 'IT ops' layer.
Some infrastructure layer (which you can call for instance "InfratructureService", which has a reference to all your projects (webservice, Service, DAL, Entities). In this infrastructure layer you create the container which every project is going to use.
Then all your projects should have a class which is called "ConfigureMe" or something, with 1 method called "Configure" for instance. That method takes as parameter an instance of the container which was build in InfratructureService. At startup your Webservice is going to give "InfratructureService" a sign to build the container and call every "Configure" method of every "ConfigureMe" class of every project it references.
In those "Configure" methods each project can ofcourse register their own depedencies in the container. And voila, all dependencies are known in the container without making unnecessary references and ready to be resolved via constructor injection.
The connectionstring problem:
Now as for your hardcoded connectionstring, you know about configuration in asp.net core right? Once you've set up your configuration as described here you can insert via dependency injection the IOptions anywhere you want. That means also in your DAL.
Let me know if anything is unclear or you can't figure it out.

How to configure Web Api 2 to look for Controllers in a separate project? (just like I used to do in Web Api)

I used to place my controllers into a separate Class Library project in Mvc Web Api. I used to add the following line in my web api project's global.asax to look for controllers in the separate project:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
I never had to do any other configuration, except for adding the above line. This has always worked fine for me.
However I am unable to use the above method to do the same in WebApi2. It just doesn't work. The WebApi2 project still tries to find the controllers in its own project's controllers folder.
-- Giving little summary update after 2 months (As I started bounty on this):
I have created a WebApiOne solution, it has 2 projects, the first one is WebApi project, and the second is a class library for controllers. If I add the reference to the controllers class library project into the WebApi project, all works as expected. i.e. if i go to http://mydevdomain.com/api/values i can see the correct output.
I have now create a second project called WebApiTwo, it has 2 projects, the first one is WebApi2 project, and the second is a class library for controllers. If I add the reference to the controllers class library project to the WebApi2 project, it doest NOT work as expected. i.e. if i go to http://mydevdomain.com/api/values i get "No type was found that matches the controller named 'values'."
for the first project i am not doing any custom settings at all, i do NOT have:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
in my global.asax, and i have not implemented any custom solutions proposed by StrathWeb in two of his blog posts, as i think its not applicable any more; because all works just by adding the reference of the controller project to the WebApi project.
So i would expect all to work same for WebApi2 ... but its not. Has anyone really tried doing this in WebAPi2 ?
I have just confirmed that this works fine. Things to check:
References: Does your main Web API project reference the external class library?
Routing: Have you set up any routes that might interfere with the external controllers?
Protection Level: Are the controllers in the external library public?
Inheritance: Do the controllers in the external library inherit from ApiController?
Versioning: Are both your Web API project and class library using the same version of the Web API libraries?
If it helps, I can package up my test solution and make it available to you.
Also, as a point to note, you don't need to tell Web API to find the controllers with the line you added to Global.asax, the system finds the controllers automatically provided you have them referenced.
It should work as is. Checklist
Inherit ApiController
End controller name with Controller. E.g. ValuesController
Make sure WebApi project and class library project reference same WebApi assemblies
Try to force routes using attribute routing
Clean the solution, manually remove bin folders and rebuild
Delete Temporary ASP.NET Files folders. WebApi and MVC cache controller lookup result
Call `config.MapHttpAttributeRoutes(); to ensure framework takes attribute routes into consideration
Make sure that the method you are calling is made to handle correct HTTP Verb (if it is a GET web method, you can call via browser URL, if it is POST you have to otherwise craft a web request)
This controller:
[RoutePrefix("MyValues")]
public class AbcController : ApiController
{
[HttpGet]
[Route("Get")]
public string Get()
{
return "Ok!";
}
}
matches this url:
http://localhost/MyValues/Get (note there is no /api/ in route because it wasn't specified in RoutePrefix.
Controller lookup caching:
This is default controller resolver. You will see in the source code that it caches lookup result.
/// <summary>
/// Returns a list of controllers available for the application.
/// </summary>
/// <returns>An <see cref="ICollection{Type}" /> of controllers.</returns>
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
HttpControllerTypeCacheSerializer serializer = new HttpControllerTypeCacheSerializer();
// First, try reading from the cache on disk
List<Type> matchingTypes = ReadTypesFromCache(TypeCacheName, IsControllerTypePredicate, serializer);
if (matchingTypes != null)
{
return matchingTypes;
}
...
}
Was running into same scenario and #justmara set me on the right path. Here's how to accomplish the force loading of the dependent assemblies from #justmara's answer:
1) Override the DefaultAssembliesResolver class
public class MyNewAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
var controllersAssembly = Assembly.LoadFrom(#"Path_to_Controller_DLL");
baseAssemblies.Add(controllersAssembly);
return baseAssemblies;
}
}
2) In the configuration section, replace the default with the new implementation
config.Services.Replace(typeof(IAssembliesResolver), new MyNewAssembliesResolver());
I cobbled this syntax together using pointers from this blog:
http://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/
As others have said, you know if you are running into this issue if you force the controller to load by directly referencing it. Another way is to example the results of CurrentDomain.GetAssemblies() and see if your assembly is in the list.
Also: If you are self-hosting using OWIN components you WILL run into this. When testing keep in mind that the DefaultAssembliesResolver will NOT kick in until the first WebAPI request is submitted (it took me awhile to realize that).
Are you sure that your referenced assembly was loaded BEFORE IAssembliesResolver service called?
Try to insert some dummy code in your application, something like
var a = new MyClassLibraryProject.Controllers.MyClass();
in configuration method (but don`t forget, that compiler can "optimize" this code and totally remove it, if "a" is never used).
I've had similar issue with assembly loading order. Ended up with force loading dependent assemblies on startup.
You need to tell webapi/mvc to load your referrenced assembly. You do that with the compilation/assemblies section in your web.config.
<compilation debug="true" targetFramework="4.5.2">
<assemblies>
<add assembly="XYZ.SomeAssembly" />
</assemblies>
</compilation>
Simple as that. You can do it with code the way #user1821052 suggested, but this web.config version will have the same effect.
Apart from what has been said already:
Make sure you don't have two controllers of the same name in different namespaces.
Just had the case where one controller (foo.UserApiController) should be partially migrated to a new namespace (bar.UserApiController) and URI. The old controller was mapped by convention to /userapi, the new one was attribute-routed via RoutePrefix["api/users"]. The new controller didn't work until I renamed it to bar.UserFooApiController.
When using AttributeRouting it is easily forgettable to decorate your methods with the Route Attribute, especially when you are using the RoutePrefix Attribute on your controller class. It seems like your controller assembly wasn't picked up by the web api pipeline then.
If your class library is built with EF then make sure you have the connection string specified in the App.config for the class library project, AND in the Web.config for your Web API MVC project.

Categories

Resources