I am using the MvcContrib library with Castle Windsor and I am having a problem
with setting a parameter when I register a component.
I have the following interfaces for classes that wrap a DataContext. I want
to be able to specify which DataContext to use for different services because
I am connecting to several databases to retrieve data.
public interface IDataContext
{
DataContext Context { get; }
}
public interface IReportingDC : IDataContext
{
}
public class Repository<T> : IRepository<T> where T : class
{
public IDataContext DC { get; set; }
public Repository(IDataContext dataContext)
{
DC = dataContext;
}
}
Here are the registration lines from my global.asax.cs.
container.AddComponentLifeStyle<IDataContext, MainDataContext>(Castle.Core.LifestyleType.PerWebRequest);
container.AddComponentLifeStyle<IReportingDC, ReportingDC>(Castle.Core.LifestyleType.PerWebRequest);
container.Register(Component.For<IRepository<ReportingTotals>>()
.ImplementedBy<Repository<ReportingTotals>>()
.Parameters(Parameter.ForKey("dataContext").Eq("IReportingDC"))
.LifeStyle.PerWebRequest
);
When I try and load the page I get the following error.
"Key invalid for parameter dataContext. Thus the kernel was unable to
override the service dependency"
Name your component and use ServiceOverrides instead of Parameters:
Component.For<IReportingDC>()
.ImplementedBy<ReportingDC>()
.Named("IReporting")
.LifeStyle.PerWebRequest
and
Component.For<IRepository<ReportingTotals>>()
.ImplementedBy<Repository<ReportingTotals>>()
.ServiceOverrides(ServiceOverride.ForKey("dataContext").Eq("IReporting"))
See the fluent API docs for reference.
Related
The package Blazored.LocalStorage is:
a library to provide access to local storage in Blazor applications
Injecting the service into a component is easy:
#inject Blazored.LocalStorage.ILocalStorageService localStorage
and if we want to inject it into the code behind:
[Inject]
private ILocalStorageService localStorage { get; set; }
But suppose I want to inject it into another service (let say for centralizing the control):
public class StorageManagement
{
public StorageManagement(LocalStorageService localStorage)
{
//How to initialize it here?
}
}
I do not know how to initialize an instance of the service in the constructor of StorageManagement and also how to set the parameters of constructor of StorageManagement in Program.cs :
builder.Services.AddSingleton(e => new StorageManagement(//?));
Just builder.Services.AddBlazoredLocalStorage(); or builder.Services.AddBlazoredLocalStorage(config => config.JsonSerializerOptions.WriteIndented = true); as it's explain in README.
Then builder.Services.AddScoped<StorageManagement>(); or builder.Services.AddScoped(p => new StorageManagement(p.GetRequiredSerice<ILocalStorageService>()));
But your service should take a ILocalStorageService not a LocalStorageService instance :
public class StorageManagement
{
public StorageManagement(ILocalStorageService localStorage)
{
//How to initialize it here?
}
}
You are not using the Interface ILocalStorageServer in your constructor, it should be
public class StorageManagement
{
private readonly ILocalStorageService LocalStorage;
public StorageManagement(ILocalStorageService localStorage)
{
LocalStorage = localStorage;
}
}
I'm trying to use SimpleInjector 2.7.3 (IoC container) within an Asp.Net MVC + Web API application.
I've had a couple of problems trying to set it up for both MVC and Web API on the same project until I found this link:
http://methoddev.com/blg/let-s-talk-software/310/simple-injector-in-asp-net-mvc-webapi
After following the link's example, here's what I got:
One of my Web API controllers:
public class UserController : BaseApiController
{
private readonly IUserService service;
public UserController(IUserService userService)
{
// I should point that IUserService is being injected correctly here
this.service = userService;
}
public IHttpActionResult Post(CreateUserRequest request)
{
return Ok();
}
}
The problem happens when I try to execute the Post operation. The CreateUserRequest class itself has a dependency.
public class CreateUserRequest : IValidatableObject
{
private readonly IValidator<CreateUserRequest> validator;
public CreateUserRequest(IValidator<CreateUserRequest> _validator)
{
// _validator is not being injected, I'm getting null here
validator = _validator;
}
public string SomeProperty { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// My validation logic here must call the validator injected
// when the object was created.
return null;
}
}
I should point that IValidator is an interface from the FluentValidator package.
Anyway, when CreateUserRequest is instantiated the validator is null, which means it's not being injected.
When I'm creating the SimpleInjector Container I can see the type correctly registered, so I don't think that is a problem.
I did the following change to CreateUserRequest class:
public class CreateUserRequest : IValidatableObject
{
private readonly CreateUserRequestValidator validator;
// Changed here to the concrete class
public CreateUserRequest(CreateUserRequestValidator _validator)
{
validator = _validator;
}
// ...
}
So, I changed the interface to a concrete class and I'm still receiving a null there.
The only thing I can imagine is that this is somehow related to the custom dependency resolver suggested by the aforementioned link. I needed to use that in order to have the same dependency resolution logic for both MVC and Web API. Here's the code:
public class SimpleInjectorDependencyResolver : System.Web.Mvc.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyScope
{
public SimpleInjectorDependencyResolver(Container container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.Container = container;
}
public Container Container { get; private set; }
public object GetService(Type serviceType)
{
if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
{
return this.Container.GetInstance(serviceType);
}
return ((IServiceProvider)this.Container).GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
IDependencyScope System.Web.Http.Dependencies.IDependencyResolver.BeginScope()
{
return this;
}
object IDependencyScope.GetService(Type serviceType)
{
return ((IServiceProvider)this.Container).GetService(serviceType);
}
IEnumerable<object> IDependencyScope.GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
void IDisposable.Dispose()
{
}
}
I don't really know a lot of the plumbing behind MVC and Web API (specially the custom dependency resolver feature), so, I'm really stuck on this one.
I appreciate any help figuring that out. Thanks.
--UPDATE--
In addition to the answer given by Steven, I would like to leave a link to whoever falls into the same problem. It's a great resource:
https://brettedotnet.wordpress.com/2014/07/16/web-api-and-interface-parameters/
The reason why your view model object isn't auto-wired by Simple Injector is because both MVC and Web API don't build view model objects using the IDependencyResolver. So creating a special dependency resolver won't work. If you want to let your view models to be auto-wired, you will have to override the default model binder in MVC and Web API.
But I urge you not to do this. In my opinion, a model binder should just do data conversion and a view model should be a plain DTO. Although it is fine to mark view models with validation attributes, letting them have behavior using services that might even trigger any database communication is a big no-no in my book. This can complicate development tremendously.
This however means that this validator should be injected elsewhere. Without making any changes to your architecture, this basically means you will have to inject that validator in the controller instead:
public class UserController : BaseApiController
{
private readonly IUserService service;
private readonly IValidator<CreateUserRequest> validator;
public UserController(IUserService userService,
IValidator<CreateUserRequest> validator)
{
this.service = userService;
this.validator = validator;
}
}
Obviously this can easily complicate your controllers with extra dependencies and logic, but that's because validation is a cross-cutting concern that you would like to probably keep out of your controllers.
If you try to address this, you will eventually end up with a message passing architecture such as described here.
I would like to have my own injection attribute so that I am not coupling my code to a particular IOC framework. I have a custom injection attribute that my code uses to denote that a property should be injected.
public class CustomInjectAttribute : Attribute {}
Fictitious example below...
public class Robot : IRobot
{
[CustomInject]
public ILaser Zap { get; set; }
...
}
In Ninject, you can setup an injection Heuristic to find that attribute, and inject like;
public class NinjectInjectionHeuristic : NinjectComponent, IInjectionHeuristic, INinjectComponent, IDisposable
{
public new bool ShouldInject(MemberInfo member)
{
return member.IsDefined(typeof(CustomInjectAttribute), true);
}
}
and then register the heuristic with the kernel.
Kernel.Components.Get<ISelector>().InjectionHeuristics.Add(new NinjectInjectionHeuristic());
How would I go about achieving this with StructureMap. I know StructureMap has its own SetterProperties and attributes, but I'm looking for a way to decouple from that as you can with Ninject in the above example.
Use the SetAllProperties() method in your ObjectFactory or Container configuration. For example:
new Container(x =>
{
x.SetAllProperties(by =>
{
by.Matching(prop => prop.HasAttribute<CustomInjectAttribute>());
});
});
This makes use of a handy extension method (that should be in the BCL):
public static bool HasAttribute<T>(this ICustomAttributeProvider provider) where T : Attribute
{
return provider.GetCustomAttributes(typeof (T), true).Any();
}
I'm a newbie when it comes to DI and ninject and I'm struggling a bit
about when the actual injection should happen and how to start the
binding.
I'm using it already in my web application and it working fine there,
but now I want to use injection in a class library.
Say I have a class like this:
public class TestClass
{
[Inject]
public IRoleRepository RoleRepository { get; set; }
[Inject]
public ISiteRepository SiteRepository { get; set; }
[Inject]
public IUserRepository UserRepository { get; set; }
private readonly string _fileName;
public TestClass(string fileName)
{
_fileName = fileName;
}
public void ImportData()
{
var user = UserRepository.GetByUserName("myname");
var role = RoleRepository.GetByRoleName("myname");
var site = SiteRepository.GetByID(15);
// Use file etc
}
}
I want to use property injection here because I need to pass in a
filename in my constructor. Am I correct in saying that if I need to
pass in a constructor parameter, I cannot use constructor injection?
If I can use constructor injection with additional parameters, how do
I pass those parameters in?
I have a console app that consumes by Test class that looks as
follows:
class Program
{
static void Main(string[] args)
{
// NinjectRepositoryModule Binds my IRoleRepository etc to concrete
// types and works fine as I'm using it in my web app without any
// problems
IKernel kernel = new StandardKernel(new NinjectRepositoryModule());
var test = new TestClass("filename");
test.ImportData();
}
}
My problem is that when I call test.ImportData() my repositories are null - nothing has been injected into them. I have tried creating another module and calling
Bind<TestClass>().ToSelf();
as I thought this might resolve all injection properties in TestClass but I'm getting nowhere.
I'm sure this is a trivial problem, but I just can't seem to find out
how to go about this.
You are directly newing TestClass, which Ninject has no way of intercepting - remember there's no magic like code transformation intercepting your news etc.
You should be doing kernel.Get<TestClass> instead.
Failing that, you can inject it after you new it with a kernel.Inject( test);
I think there's an article in the wiki that talks about Inject vs Get etc.
Note that in general, direct Get or Inject calls are a Doing It Wrong smell of Service Location, which is an antipattern. In the case of your web app, the NinjectHttpModule and PageBase are the hook that intercepts object creation - there are similar interceptors / logical places to intercept in other styles of app.
Re your Bind<TestClass>().ToSelf(), generally a StandardKernel has ImplicitSelfBinding = true which would make that unnecessary (unless you want to influence its Scope to be something other than .InTransientScope()).
A final style point:- you're using property injection. There are rarely good reasons for this, so you should be using constructor injection instead.
And do go buy Dependency Injection in .NET by #Mark Seemann, who has stacks of excellent posts around here which cover lots of important but subtle considerations in and around the Dependency Injection area.
OK,
I've found out how to do what I need, thanks in part to your comments Ruben. I've created a new module that basically holds the configuration that I use in the class library. Within this module I can either Bind using a placeholder Interface or I can add a constructor parameter to the CustomerLoader.
Below is the code from a dummy console app to demonstrating both ways.
This might help someone else getting started with Ninject!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Core;
using Ninject.Core.Behavior;
namespace NinjectTest
{
public class Program
{
public static void Main(string[] args)
{
var kernel = new StandardKernel(new RepositoryModule(), new ProgramModule());
var loader = kernel.Get<CustomerLoader>();
loader.LoadCustomer();
Console.ReadKey();
}
}
public class ProgramModule : StandardModule
{
public override void Load()
{
// To get ninject to add the constructor parameter uncomment the line below
//Bind<CustomerLoader>().ToSelf().WithArgument("fileName", "string argument file name");
Bind<LiveFileName>().To<LiveFileName>();
}
}
public class RepositoryModule : StandardModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>().Using<SingletonBehavior>();
}
}
public interface IFileNameContainer
{
string FileName { get; }
}
public class LiveFileName : IFileNameContainer
{
public string FileName
{
get { return "live file name"; }
}
}
public class CustomerLoader
{
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
private string _fileName;
// To get ninject to add the constructor parameter uncomment the line below
//public CustomerLoader(string fileName)
//{
// _fileName = fileName;
//}
public CustomerLoader(IFileNameContainer fileNameContainer)
{
_fileName = fileNameContainer.FileName;
}
public void LoadCustomer()
{
Customer c = CustomerRepository.GetCustomer();
Console.WriteLine(string.Format("Name:{0}\nAge:{1}\nFile name is:{2}", c.Name, c.Age, _fileName));
}
}
public interface ICustomerRepository
{
Customer GetCustomer();
}
public class CustomerRepository : ICustomerRepository
{
public Customer GetCustomer()
{
return new Customer() { Name = "Ciaran", Age = 29 };
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
}
I just started working with dependency injection for the first time and I am using as Ninject 2.0 as my IoC container in an ASP.NET MVC 2 website and I'm hitting an activation error that I am not sure how to react to. I am sure it's simple so hopefully someone can point me in the right direction without too much thought.
I have a property on my class BaseController which takes an IWebsiteSettings and is flagged with the [Inject] attribute. In my StandardKernel I load a module with the following code:
public class WebModule : Module
{
public override void Load()
{
Bind<IWebsiteSettings>()
.ToProvider(new WebsiteSettingsProvider(WebConfigurationManager.AppSettings))
.InSingletonScope();
}
}
public class WebsiteSettingsProvider : Provider<WebsiteSettings>
{
private const string WebsiteNameKey = "Website.Name";
private const string ContactFormEmailSubjectKey = "ContactForm.EmailSubject";
private const string ProductImageDirectoryKey = "Products.ImageDirectory";
private const string UploadTempDirectoryKey = "Uploads.TempDirectory";
protected NameValueCollection Settings { get; set; }
public WebsiteSettingsProvider(NameValueCollection settings)
{
Settings = settings;
}
protected override WebsiteSettings CreateInstance(IContext context)
{
return new WebsiteSettings
{
WebsiteName = Settings[WebsiteNameKey] ?? string.Empty,
ContactFormEmailSubject = Settings[ContactFormEmailSubjectKey] ?? string.Empty,
ProductImageDirectory = Settings[ProductImageDirectoryKey] ?? string.Empty,
UploadsTemporaryDirectory = Settings[UploadTempDirectoryKey] ?? string.Empty
};
}
}
This is fairly straightforward- I'm trying to load some data from the web.config file and store it in a singleton object for use across my controllers. The call to Bind seems to function exactly as it should and the Settings property in my provider is correctly initialized with the AppSettings collection in the config file. Still, when the application loads the first time:
Server Error in '/' Application.
Error activating SByte* using implicit self-binding of SByte*
No constructor was available to create an instance of the implementation type.
Activation path:
4) Injection of dependency SByte* into parameter value of constructor of type string
3) Injection of dependency string into property WebsiteName of type WebsiteSettings
2) Injection of dependency IWebsiteSettings into property WebsiteSettings of type HomeController
1) Request for HomeController
Suggestions:
1) Ensure that the implementation type has a public constructor.
2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
Interestingly, if I refresh the page I don't get the exception and a call to Kernel.Get() returns the correct object.
Any advice?
(We talked about this on IRC, but I'm putting it here in case someone else runs into this problem as well.)
WebsiteSettings has [Inject] attributes on its properties, so Ninject is trying to resolve a binding from System.String to inject a value into the properties. Since you're using a custom provider to activate WebsiteSettings instances, you don't need [Inject] attributes on its properties.
The offending code was actually in the class WebsiteSettings where I was doing this:
public class WebsiteSettings : IWebsiteSettings
{
[Ninject.Inject]
public string WebsiteName
{
get; set;
}
[Ninject.Inject]
public string UploadsTemporaryDirectory
{
get; set;
}
[Ninject.Inject]
public string ContactFormEmailSubject
{
get; set;
}
[Ninject.Inject]
public string ProductImageDirectory
{
get; set;
}
}
By placing the Inject attribute on my properties I was causing Ninject to try to assign values that I never bound. Because I am using a Provider to load my type I do not need to include the Inject attribute.