Error during InSingletonScope() with Ninject - c#

I have some problem with InSingletonScope().
My interface:
public interface ISettingsManager
{
ApplicationSettings Application { get; }
}
and my class:
public class SettingsManager : ISettingsManager
{
private readonly IConfigurationService _configurationService;
private readonly Lazy<ApplicationSettings> _applicationSettings;
public ApplicationSettings Application { get { return _applicationSettings.Value; } }
private SettingsManager(IConfigurationService context)
{
_configurationService = context;
_applicationSettings = new Lazy<ApplicationSettings>(() => new ApplicationSettings(context));
}
}
and standard binding in NinjectWebCommon looks like this:
kernel.Bind<ISettingsManager>().To<SettingsManager>().InSingletonScope();
kernel.Bind<IConfigurationService >().To<ConfigurationService>().InRequestScope();
And when I use constructor injection or property injection in HomeController:
[Inject]
public ISettingsManager SettingsManager { private get;}
Then I get an error:
An error occurred when trying to create a controller of type 'Web.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.
Where is the problem? What is wrong with my Singleton?
I use in my project dependency injection and when I inject one interface in constructor, everything work fine. When I add ISettingsManagers I have many problems.

I know what was wrong. The private constructor was the main problem. When I change it to:
public SettingsManager(IConfigurationService context)
then it works like a charm.

The Error it self says its the home controller that needs to be parameterless, however if ninject is setup correctly that is not true, and the bug can be nested down to a single class that does not have the bindings needed.
However, there is one thing that might go wrong in what you show here.
Your configuration is in request scope and your settings is in singleton scope.
This means it might run fine the first time, however in the second attempt, its a new request and the configuration, could be disposed inside your singleton settings, and would proberbly break something.

Related

Blazor: Unable to resolve service for type xx while attempting to activate yyy

I have read many other SO questions on the same topic, but none of the answers that I found applies to my case.
I have successfully added 4 services in my Startup.cs, and it was working fine before. I then added the 5th, and now I realize that something is broken - none of the services work. Even if I remove the 5th completely, the other ones are now also broken with the same error.
Unable to resolve service for type xx while attempting to activate
This is my Startup.cs ConfigureServices.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddStorage();
services.AddSingleton<IMyLocalStorage, MyLocalStorage>();
services.AddSingleton<IFrontEndService, FrontEndService>();
services.AddSingleton<ISystemProvider, SystemProviderService>();
services.AddSingleton<IAuthenticationService, AuthenticationService>();
}
It's the last AuthenticationService that I noticed the error, but even the older previously working services fails now.
public interface IAuthenticationService
{
// ...
}
public class AuthenticationService : IAuthenticationService
{
private readonly FrontEndService frontEndService;
private readonly MyLocalStorage myLocalStorage;
public AuthenticationService(FrontEndService frontEndService, MyLocalStorage myLocalStorage)
{
this.frontEndService = frontEndService;
this.myLocalStorage = myLocalStorage;
}
// ...
}
The services are simple; one interface, one implementation of that interface, and then adding in Startup.cs. I can't figure out why it stopped working.
So if I remove IAuthenticationService, then the error instead shows up in FrontEndService, then complaining on the MyLocalStorage:
public interface IFrontEndService
{
Task<T> GetAsync<T>(string requestUri);
}
public class FrontEndService : IFrontEndService
{
private readonly HttpClient client;
private readonly MyLocalStorage myLocalStorage;
public FrontEndService(HttpClient client, MyLocalStorage myLocalStorage)
{
// ...
}
}
and
public class MyLocalStorage : IMyLocalStorage
{
public MyLocalStorage(LocalStorage storage)
{
this.storage = storage;
}
}
What am I missing here?
When you call methods on IServiceCollection such as .AddSingleton<IFrontEndService, FrontEndService>(), you're saying to the container, "Whenever you see an IFrontEndService dependency, inject an instance of FrontEndService." Now if you take a look at your AuthenticationService:
public class AuthenticationService : IAuthenticationService
{
private readonly FrontEndService frontEndService;
private readonly MyLocalStorage myLocalStorage;
public AuthenticationService(FrontEndService frontEndService, MyLocalStorage myLocalStorage)
{
this.frontEndService = frontEndService;
this.myLocalStorage = myLocalStorage;
}
// ...
}
Notice how you're passing in dependencies of FrontEndService and MyLocalStorage, rather than the interfaces you registered. That means the container doesn't recognise them, so it doesn't know how to fulfil the dependency graph.
You need to change the service to depend on the interfaces, as those are what you've registered with the container:
public class AuthenticationService : IAuthenticationService
{
private readonly IFrontEndService frontEndService;
private readonly IMyLocalStorage myLocalStorage;
public AuthenticationService(IFrontEndService frontEndService, IMyLocalStorage myLocalStorage)
{
this.frontEndService = frontEndService;
this.myLocalStorage = myLocalStorage;
}
// ...
}
#Ted,
Do you remember a question of yours from a couple of weeks ago, in which you used LocalStorage in a service ? At that service you had a constructor with IStorage parameter, but this caused an error, the reason of which was that though the LocalStorage class implements the IStorage interface, the creators of this library added the LocalStorage to the DI container as a concrete class like this:
public static IServiceCollection AddStorage(this IServiceCollection services)
{
return services.AddSingleton<SessionStorage>()
.AddSingleton<LocalStorage>();
}
And therefore, you had to use
(LocalStorage storage)
instead of
(IStorage storage)
The extension method above, could be rewritten thus:
public static IServiceCollection AddStorage(this IServiceCollection services)
{
return services.AddSingleton<IStorage, SessionStorage>()
.AddSingleton<IStorage, LocalStorage>();
}
In which case, you could use the IStorage interface in your constructor.
Now you may form a general rule, and act accordingly.
Ted says:
Thats odd, cause I have used exactly this approach before, and it
worked fine. If you read the docs, Microsoft also uses the concrete
class, not the interface
HttpClient derives from HttpMessageInvoker. It does not implement any interface.
This code-snippet shows how the HttpClient is added to the service container, and made available for injection in your client-side Blazor:
services.AddSingleton<HttpClient>(s =>
{
// Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
var uriHelper = s.GetRequiredService<IUriHelper>();
return new HttpClient
{
BaseAddress = new Uri(WebAssemblyUriHelper.Instance.GetBaseUri())
};
});
Hope this helps...

Using Ninject with Owin and InRequestScope

We are trying to use Ninject within an Owin with WebAPI pipeline. We have everything setup according to this documentation, but we cannot get InRequestScope() to work.
Here's the significant part of the startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
// Ninject Setup
app.UseNinjectMiddleware(NinjectConfig.CreateKernel);
app.UseNinjectWebApi(config);
}
}
NinjectConfig looks something like this:
public sealed class NinjectConfig
{
public static IKernel CreateKernel()
{
var kernel = new StandardKernel();
INinjectModule[] modules =
{
new ApplicationModule()
};
instance.Load(modules);
// Do we still need to do this wtih Owin?
instance.Bind<IHttpModule>().To<OnePerRequestHttpModule>();
}
}
Our ApplicationModule lives in a separate infrastructure project with access to all of our different layers, for handling DI & Mapping:
public class ApplicationModule: NinjectModule
{
public override void Load()
{
// IUnitOfWork / EF Setups
Bind<ApplicationContext>().ToSelf().InRequestScope();
Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<ApplicationContext>()});
Bind<ApplicationContext>().ToMethod(ctx => ctx.Kernel.Get<ChromLimsContext>()}).WhenInjectedInto<IDal>();
// other bindings for dals and business objects, etc.
}
}
Then we have a couple interfaces:
public interface IUnitOfWork()
{
void SaveChanges();
Task SaveChangesAsync();
}
and
public interface IDal()
{
// Crud operations, Sync and Async
}
then our actual classes using these:
public class SomeBusinessObject
{
private IUnitOfWork _uow;
private IDal _someDal;
public SomeBusinessObject(IUnitOfWork uow, IDal someDal)
{
_uow = uow;
_someDal = someDal;
}
public Task<SomeResult> SaveSomething(Something something)
{
_someDal.Save(something);
_uow.SaveChanges();
}
}
Some Dal
public class SomeDal : IDal {
private ApplicationContext _applicationContext;
public SomeDal(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public void Save(Something something)
{
_applicationContext.Somethings.Add(something);
}
}
Our EF DbContext
public class ApplicationContext : DbContext, IUnitOfWork
{
// EF DBSet Definitions
public void SaveChanges()
{
base.SaveChanges();
}
}
The expectation is that for every request, a single instance of ApplicationContext is created and injected into the business objects as an IUnitOfWork implementation and into the IDals as an ApplicationContext.
Instead what is happening is that a new instance of ApplicationContext is being created for every single class that uses it. If I switch the scope from InRequestScope to InSingletonScope, then (as expected) exactly 1 instance is created for the entire application, and injected properly into the specified classes. Since that works, I'm assuming this isn't a binding issue, but instead an issue with the InRequestScope extension.
The only issue I could find similar to what I'm experiencing is this one, but unfortunately the solution did not work. I'm already referencing all of the packages he specified in both the WebApi and Infrastructure projects, and I double checked to make sure they are being copied to the build directory.
What am I doing wrong?
Edit:
Some additional information. Looking at the Ninject source code in both Ninject.Web.WebApi.OwinHost and Ninject.Web.Common.OwinHost, it appears that the Owin Middleware adds the OwinWebApiRequestScopeProvider as the IWebApiRequestScopeProvider. This provider is then used in the InRequestScope() extension method to return a named scope called "Ninject_WebApiScope". This will be present until the target class that being injected into switches. The named scope then disappears, and a new scope is created. I think this may be what #BatteryBackupUnit was referring to in their comment, but I don't know how to correct it.
This thread is related to this issue...
https://github.com/ninject/Ninject.Web.WebApi/issues/17
I've found that behavior of InRequestScope seems to change depending on how you inject them. For example...
public ValuesController(IValuesProvider valuesProvider1, IValuesProvider valuesProvider2)
{
this.valuesProvider1 = valuesProvider1;
this.valuesProvider2 = valuesProvider2;
}
Ninject will create and inject the same instance of IValuesProvider. However if the method were written as...
/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// </summary>
/// <param name="valuesProvider">The values provider.</param>
public Values2Controller(IKernel kernel)
{
this.valuesProvider1 = kernel.Get<IValuesProvider>();
this.valuesProvider2 = kernel.Get<IValuesProvider>();
}
...this will create two new instances.
Based on the information in the link in #Mick's post I ended up adding my own extension method like this. I am not sure about the downsides.
public static class CustomRequestScope
{
public static Ninject.Syntax.IBindingNamedWithOrOnSyntax<T> InCustomRequestScope<T>(this Ninject.Syntax.IBindingInSyntax<T> syntax)
{
return syntax.InScope(ctx => HttpContext.Current.Handler == null ? null : HttpContext.Current.Request);
}
}
I do consider switching to another container because of this issue.

How to set connection string to DbContext after user has login with Unity container?

I am building an MVC application that connect to diferent databases depending on the user that has log in.
For this i have 3 projects DAL using entity framework(DataBaseFirst) where i have extended the dbcontext so that i can pass the connectionstring like this:
public partial class ARACultivoEntities
{
public ARACultivoEntities(string nameOfConnectionString)
: base(nameOfConnectionString)
{
}
}
Note: I have the connections strings defined in the web.config of the mvc project.
There is also another project, Services where i have a genericService from where other service can inherit this like this:
public class GenericService<T> : IGenericService<T>
where T : class
{
protected ARACultivoEntities Db;
protected DbSet<T> Table;
public GenericService(string nameConnectionString)
{
if (string.IsNullOrEmpty(nameConnectionString))
{
throw new ArgumentNullException("nameConnectionString");
}
Db = new ARACultivoEntities(nameConnectionString);
Table = Db.Set<T>();
}
Now i save the name of the connection string in the user claims when he logs in and in the controllers i have something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> service;
public DeduccionController()
{
service = ServiceFactoryGeneric<Deducciones>.InitGenericService(GetClaimsUser.Cadena);
//GetClaimsUser.Cadena has the name of the connectionString
//ServiceFactoryGeneric<Deducciones>.InitGenericService do this:
// return new GenericService<T>(connectionString);
}
now i want to instead of having my own factories i want to use an Ioc Container and i have chosen unity for this, i am new to this, i've read some articles and i think i undsertand the basics but i dont know how to pass the connection string after the user has log in because my RegisterTypes hapen at the application start
public static void RegisterTypes(IUnityContainer container)
{
// this happen at application start
// string nameOfConnectionString = *user is still not loged in*
container.RegisterType<IGenericService<T>, GenericService<T>>(
new InjectionConstructor(nameOfConnectionString));
}
i been thinkin to try to tweet the code to register my types after the user has loged in but i dont think this a good idea..
i also have been thinking about adding a public method to my IGenericService so that i can set my connectionString after the service is constructed and implemented something like this:
public void SetConnectionString(string nameOfConnectionString)
{
Db.Database.Connection.ConnectionString = nameOfConnectionString;
//not sure if this actually works
}
then my controller will be something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> _service;
public DeduccionController(IGenericService<Deducciones> service)
{
_service = service;
_service.SetConnectionString(GetUserClaims.Cadena);
}
and let my RegisterTypes just with the:
container.RegisterType<IGenericService<T>, GenericService<T>>()
but since i new to this world of IoCs i am not sure if this is the best way
What would be the correct way to do this using Unity?
Thank you for reading.
I am sorry for my english not my first languague.
I recently had to do something similar by swapping connection strings based on a route parameter specifying a geo-location.
I would recommend building your own Unity LifetimeManager that acts in a instance per session scope. Register an object that acts as a configuration container for the connection string property.
[See Unity Lifetime Manager: http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.lifetimemanager(v=pandp.30).aspx]
Then you could inject that singleton instance of this configuration object into your controller and set the connection string property once a user has logged in. You could then inject that same singleton instance into a DbContext factory that instantiates your DbContext using the connection string specified in your configuration object.
Like I said, it may not be the most elegant solution, but I liked it better than having to pass a connection string through the many tiers of your application stack. Hope this helps.

IoC setup and issue with inherited class

I'm fairly new to the IoC pattern and I've hit an issue on the way the following should be setup.
I've got a Service class which has the following constructor:
public BookingService(IBookingRepository bookingRepository, IUnitRepository unitRepository, IRateRepository rateRepository, IDiscountRepository discountRepository, IUnitOfWork unitOfWork)
{
this.bookingRepository = bookingRepository;
this.unitRepository = unitRepository;
this.rateRepository = rateRepository;
this.discountRepository = discountRepository;
this.unitOfWork = unitOfWork;
}
Now I've got this working with my controllers like so:
private IBookingService _bookingService;
public AdminBookingSurfaceController(IBookingService bookingService)
{
_bookingService = bookingService;
}
Where I've got stuck is when using the BookingService in an inherited class from a Third Party framework (Umbraco).
This is the current constructor:
public class Freedom2BookTree : umbraco.cms.presentation.Trees.BaseTree
{
public Freedom2BookTree(string application)
: base(application)
{
}
I wasn't sure how IoC would work with this, I tried like this but it didn't work:
As in, when I add the additional parameter the constructor never gets hit/called
public class Freedom2BookTree : umbraco.cms.presentation.Trees.BaseTree
{
private IBookingService _bookingService;
public Freedom2BookTree(string application, IBookingService bookingService)
: base(application)
{
_bookingService = bookingService;
}
If anyone could lend some advice on how this should be done or if I'm looking at it in the wrong way, that would great :)
Many Thanks,
Tom
Maybe that framework only executes a constructor with specific parameters.
You can make the IBookingService a property on the Freedom2BookTree and assign it outside of the constructor.

How do I use AutoMapper with Ninject.Web.Mvc?

Setup
I have an AutoMapperConfiguration static class that sets up the AutoMapper mappings:
static class AutoMapperConfiguration()
{
internal static void SetupMappings()
{
Mapper.CreateMap<long, Category>.ConvertUsing<IdToEntityConverter<Category>>();
}
}
where IdToEntityConverter<T> is a custom ITypeConverter that looks like this:
class IdToEntityConverter<T> : ITypeConverter<long, T> where T : Entity
{
private readonly IRepository _repo;
public IdToEntityConverter(IRepository repo)
{
_repo = repo;
}
public T Convert(ResolutionContext context)
{
return _repo.GetSingle<T>(context.SourceValue);
}
}
IdToEntityConverter takes an IRepository in its constructor in order to convert an ID back to the actual entity by hitting up the database. Notice how it doesn't have a default constructor.
In my ASP.NET's Global.asax, this is what I have for OnApplicationStarted() and CreateKernel():
protected override void OnApplicationStarted()
{
// stuff that's required by MVC
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
// our setup stuff
AutoMapperConfiguration.SetupMappings();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<NHibRepository>();
return kernel;
}
So OnApplicationCreated() will call AutoMapperConfiguration.SetupMappings() to set up the mappings and CreateKernel() will bind an instance of NHibRepository to the IRepository interface.
Problem
Whenever I run this code and try to get AutoMapper to convert a category ID back to a category entity, I get an AutoMapperMappingException that says no default constructor exists on IdToEntityConverter.
Attempts
Added a default constructor to IdToEntityConverter. Now I get a NullReferenceException, which indicates to me that the injection isn't working.
Made the private _repo field into a public property and added the [Inject] attribute. Still getting NullReferenceException.
Added the [Inject] attribute on the constructor that takes an IRepository. Still getting NullReferenceException.
Thinking that perhaps Ninject can't intercept the AutoMapperConfiguration.SetupMappings() call in OnApplicationStarted(), I moved it to something that I know is injecting correctly, one of my controllers, like so:
public class RepositoryController : Controller
{
static RepositoryController()
{
AutoMapperConfiguration.SetupMappings();
}
}
Still getting NullReferenceException.
Question
My question is, how do I get Ninject to inject an IRepository into IdToEntityConverter?
#ozczecho's answer is spot-on, but I'm posting the Ninject version of the code because it has one little caveat that caught us for a while:
IKernel kernel = null; // Make sure your kernel is initialized here
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => kernel.Get(t));
});
You can't just pass in kernel.Get to map.ConstructServicesUsing because that method has a params parameter in addition to the Type. But since params are optional, you can just create the lambda expression to generate an anonymous function to get you what you need.
You have to give AutoMapper access to the DI container. We use StructureMap, but I guess the below should work with any DI.
We use this (in one of our Bootstrapper tasks)...
private IContainer _container; //Structuremap container
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(_container.GetInstance);
map.AddProfile<MyMapperProfile>();
}

Categories

Resources