ServiceLocator does not exist in Ninject? - ninject

I am trying to use Ninject with Common Service Locator in my asp.net mvc3 project. I've added Ninject.dll and CommonServiceLocator.NinjectAdapter.dll to the project.
I wrote following code in my global.asax.cs file.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(CreateKernel()));
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
private static IKernel CreateKernel()
{
IKernel kernel = new StandardKernel();
kernel.Bind(typeof(IUserService)).To(typeof(UserService));
return kernel;
}
But it does not compile because it couldn't find ServiceLocator and giving me the error
"The name 'ServiceLocator' does not exist in the current context"
What am I doing wrong here? Am I missing a reference?

I think you won't get an answer to your question because using the Common ServiceLocator is very uncommon especially for MVC3. The service locator anti-pattern you seem to use is considered bad practice.
Almost everyone is using some IDependencyResolver implementation instead. See https://github.com/ninject/ninject.web.mvc/wiki/MVC3

Related

The DbContext of type cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions

I am trying to upgrade our current .Net Core application from 1.1 to 2.0 and am getting this runtime error: "The DbContext of type 'CoreContext' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions".
It is caused by using the new IServiceCollection.AddDbContextPool<> function. When I use IServiceCollection.AddDbContext<> it still works.
This application is DB-First, so I generate all our contexts using 'Scaffold-DbContext'. Due to that, and the need to inject other services I have an extension on every context like this:
public partial class CoreContext
{
public CoreContext(
DbContextOptions<CoreContext> options,
IUserService userService,
IAuditRepository auditRepository
) : base(options) {...}
}
Whenever I run the Scaffold-DbContext I just remove the autogenerated Constructor from CoreContext, but even if I put it in there I still get this error.
public partial class CoreContext : DbContext
{
public CoreContext(DbContextOptions<CoreContext> options) : base(options) {}
}
I've already updated Program.cs to the new style:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
And the Startup.cs is pretty straightforward:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
...
services.AddDbContextPool<CoreContext>(options => options.UseSqlServer(absConnectionString));
...
}
I am using Autofac for DI if that helps. For now I'll default back to the non-Pooling alternative, but it would be nice to take advantage of this feature.
When using DbContext Pooling, your own state (e.g. private fields) in your derived DbContext class will be preserved. Which means the lifetime of your services is now singleton. That's why you shouldn't have other injected services here.
But it's possible to query the required services this way:
First we should use the UseInternalServiceProvider method on DbContextOptionsBuilder to tell EF which service provider to use for its services. This service provider must have all the services configured for EF and any providers. So we should register EF Services manually:
services.AddEntityFrameworkSqlServer();
And then introduce the application's services provider which now includes the EF Services too:
services.AddDbContextPool<ApplicationDbContext>((serviceProvider, optionsBuilder) =>
{
optionsBuilder.UseSqlServer("...");
optionsBuilder.UseInternalServiceProvider(serviceProvider);
});
After that define these namespaces:
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
And now you can access the registered services in the application within the
ApplicationDbContext class using the following methods
var siteSettings = this.GetService<IOptionsSnapshot<SiteSettings>>();
Or
var siteSettings = this.GetInfrastructure().GetRequiredService<IOptionsSnapshot<SiteSettings>>();
this is the current instance of the DbContext.
Remove the default constructor in the DbContext class, this worked for me
"because it does not have a single public constructor accepting a
single parameter of type DbContextOptions"
If you have any public constructors apart from one that accepts DbContextOptions, you need to remove them or make them non-public in order to use context pooling.
Also, there are restrictions on what can be done by overriding the OnConfiguring method. This is referenced in the documentation here but it isn't explicit about what those restrictions are: https://learn.microsoft.com/en-us/ef/core/what-is-new/index#dbcontext-pooling
This issue is mostly encountered when you "Scaffold-Dbcontext" and two constructors are generated.
Simple Solutions:
AddDbContextPool:
If you want to use AddDbContextPool, remove your empty constructor and maintain the one with the DbContextOptionsBuilder. Note that in this case you might have to provide the options, as suggested in the previous posts.
AddDbContext:
With AddDbContext, you can have both constructors/Overloads
Note: AddDbContextPool is preferred for performance reasons!
Try to use AddDbContext instead of AddDbContextPool. This helped me in the same situation.
services.AddDbContext<CoreContext>(options => options.UseSqlServer(absConnectionString));
in some case need to
remove the constractor with zero parameter
//public MyContext()
//{
//}
or use
"AddDbContext"
instead of
"AddDbContextPool"
in startup.cs => ConfigureServices()
services.AddDbContext(options =>
options.UseSqlServer(absConnectionString));

Use Ninject in both main and referenced projects

I have MVC4 website project and WCF project, both using Ninject.
I want to use class from WCF project in website project. I add reference to project and get both NinjectWebCommon.Start() executing (with "The static container already has a kernel associated with it!" error).
Is there way to make what I want?
Solved this using this startup in referenced project
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return new StandardKernel(new ServiceModule());
}
}

Global.asax's Application_Start method doesn't get called

I have a WCF web service hosted on my Local IIS (not Express). I've included a Global.asax in its root directory, where it is supposed to be. Since I'm using Ninject with WCF extensions, the class Global extends NinjectHttpApplication instead of HttpApplication (as seen here).
Also, I'm using the AutoMapper library in order to circumvent writing boring boilerplate code.
The problem arises because a static method I defined for configuring AutoMapper isn't being called causing AutoMapper to throw exceptions when I call Mapper.Map(). That static method's call is defined in Global.asax's Application_Start() method since I want these mappings to be performed once per the web service's lifetime.
Ninject's CreateKernel() method gets called just fine, by the way.
Am I missing something here? I've tried debugging it, it doesn't hit the breakpoint even though I've attached the debugger to w3wp.exe and also tried putting an explicit Debugger.Break() call in its body.
This is how it looks like so far:
Global.asax
<%# Application Codebehind="Global.asax.cs" Inherits="MyApp.WebHost.Global" Language="C#" %>
Global.asax.cs
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel();
/* various bindings */
return kernel;
}
protected void Application_Start(object sender, EventArgs e)
{
AutoMapperConfig.RegisterMappings();
}
/* rest of Global.asax methods (Session_Start, Application_BeginRequest, etc.) with empty bodies */
RegisterMappings method
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
/* multiple calls to Mapper.CreateMap() */
Mapper.AssertConfigurationIsValid();
}
}
Svc file markup
<%# ServiceHost Language="C#"
Debug="true"
Service="MyApp.Services.MyAppService"
Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>
Everything else works, I've already created a test client (a simple console app) and added a service reference. Service methods get called just fine, it is just that these mappings are a bit problematic since AutoMapper keeps throwing AutoMapperMappingException exceptions ("Missing type map configuration or unsupported mapping.") for the obvious reasons.
The application's app pool is DefaultAppPool. Should I create a separate one?
I really don't understand the problem here. Thank you in advance.
Well, it required some additional searching but I found the answer here - https://groups.google.com/forum/#!topic/ninject/wRy3ELSV4bU
The problem was that NinjectHttpApplication class itself implements the Application_Startup method so it is impossible to implement it in your own derived class (Global class).
To simulate such behavior one needs to override the OnApplicationStarted Ninject's method.
This is how it looks like regarding my particular problem:
protected override void OnApplicationStarted()
{
AutoMapperConfig.RegisterMappings();
}

Upgrading Ninject/Ninject WCF Extensions to the latest version 3.0.0.5

I am currently using Ninject (2.2.1.4) and Ninject.Extensions.Wcf (2.2.0.4) with my WCF service. I would like to upgrade to Ninject (3.0.0.15) and Ninject.Extensions.Wcf (3.0.0.5) and it doesn't look like I can use my current approach anymore. Can anyone point me to some samples or posts on how to get the latest version of Ninject working with a WCF project.
My current approach:
I wrote a module:
public class NinjectDependencyResolver : NinjectModule
{
public override void Load()
{
// Declare bindings
}
}
I added the Factory Attribute to my .svc file
Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"
I added a Global.asax to the WCF project
public class Global : NinjectWcfApplication
{
protected override IKernel CreateKernel()
{
return new StandardKernel(new NinjectDependencyResolver());
}
}
Now I can modify the default constructor in my service and use constructor injection.
Any pointers on how I could upgrade are appreciated.
Thanks
Add Ninject.Web.Common and derive from NinjectHttpApplication or use the App_Start file that comes with the NuGet package.

Using the Ninject NLogModule Logger in global.asax

I'm using Ninject for DI in my asp.net application, so my Global class inherits from NinjectHttpApplication.
In my CreateKernel(), I'm creating my custom modules and DI is working fine for me.
However, I notice that there is a Logger property in the NinjectHttpApplication class, so I'm trying to use this in Application_Error whenever an exception is not caught.
I think I'm creating the nlog module correctly for Ninject, but my logger is always null. Here's my CreateKernel:
protected override Ninject.Core.IKernel CreateKernel()
{
IKernel kernel = new StandardKernel(new NLogModule(), new NinjectRepositoryModule());
return kernel;
}
But in the following method, Logger is always null.
protected void Application_Error(object sender, EventArgs e)
{
Exception lastException = Server.GetLastError().GetBaseException();
Logger.Error(lastException, "An exception was caught in Global.asax");
}
To clarify, Logger is a property on NinjectHttpApplication of type ILogger and has the [Inject] attribute
Any idea how to inject correctly into Logger?
Download the latest version from GitHub. The logging was removed. The reason you are not seeing the logger injected is that Ninject isn't creating the HttpApplication class, so it doesn't know to inject it, you have to assign it manually. Ninject can only initialize components activated by the kernel.
Are you actually wiring up an ILogger in your NLogModule? If not then Ninject probably won't know what to use when you use the Logger of your implemented NinjectHttpApplication class.
I would check what is in your NLogModule, and I would also suggest putting it in your question. I think it might help us to solve your problem.