Ninject bind all classes implementing the same interface - dependency-injection

I have an interface class:
public interface IStartUpTask
{
bool IsEnabled { get; }
void Configure();
}
I have multimple classes implementing the same interface
One of the classes looks like this:
public class Log4NetStartUpTask : IStartUpTask
{
public bool IsEnabled { get { return true; } }
public void Configure()
{
string log4netConfigFilePath = ConfigurationManager.AppSettings["log4netConfigFilePath"];
if (log4netConfigFilePath == null)
throw new Exception("log4netConfigFilePath configuration is missing");
if (File.Exists(log4netConfigFilePath) == false)
throw new Exception("Log4Net configuration file was not found");
log4net.Config.XmlConfigurator.Configure(
new System.IO.FileInfo(log4netConfigFilePath));
}
}
How can i tell Ninject that i want all the classes implementing the IStartUpTask to bind to themself automatically?
I found an example using StructureMap which does this, but i don't know how to do it in Ninject.
Scan(x => {
x.AssemblyContainingType<IStartUpTask>();
x.AddAllTypesOf<IStartUpTask>();
x.WithDefaultConventions();
});

How can i tell Ninject that i want all the classes implementing the
IStartUpTask to bind to themself automatically?
First of all, let me tell you that Ninject binds all classes to themselves automatically. You do not need to do anything special for that.
Having said that, I understand that you might want the explicit binding if you want to change scope or attach names or metadata. In this case read-on.
I do not know if it is possible to do what you are after in vanilla ninject, but you can use ninject.extensions.conventions. Using this library you can write:
Kernel.Bind(x =>
x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom<IStartUpTask>()
.BindToSelf());

you can call it explicit in your code:
...
Bind<IStartUpTask>().To<Log4NetStartUpTask>();
Bind<IStartUpTask>().To<SomeOtherStartUpTask>();
...
Use it in SomeClass
public class SomeClass
{
private readonly List<IStartUpTask> startUpTaskList;
public SomeClass(IEnumerable<IStartUpTask> startUpTaskList)
{
this.startUpTaskList = startUpTaskList;
}
foreach (var startUpTask in this.startUpTaskList)
{
...
}
}

Related

StructureMap: register as implemented interfaces like in AutoFac

Until recently I used AutoFac which had the method AsImplementedInterfaces()
which does
Register the type as providing all of its public interfaces as services (excluding IDisposable).
that means (for example a service) I have some base interface and an interface for every concerte service-class
See the simple code below:
public interface IService {}
public interface IMyService: IService
{
string Hello();
}
public class MyService: IMyService
{
public string Hello()
{
return "Hallo";
}
}
// just a dummy class to which IMyService should be injected
// (at least that's how I'd do it with AutoFac.
public class MyClass
{
public MyClass(IMyService myService) { }
}
Basically I want to inject my service's interface (so to speak) and not the concrete service.
Now I have to use StructureMap but I struggle to find what I need.
There is AddAllTypesOf<T> but this would register the concrete type.
is this even possible with StructureMap and if so how?
so, I found the answer(s)
1.
first you could use
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.RegisterConcreteTypesAgainstTheFirstInterface();
});
}
}
this will register every concrete class against the first interface which might be too broad.
2.
if so you can use the following code I adapted from http://structuremap.github.io/registration/auto-registration-and-conventions/.
I had to change Each() to foreach because of compilation errors and made the whole class generic.
public class AllInterfacesConvention<T> : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Only work on concrete types
foreach (var type in types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(x => typeof(T).IsAssignableFrom(x)))
{
if(type == typeof(NotInheritedClass))
{
continue;
}
// Register against all the interfaces implemented
// by this concrete class
foreach (var #interface in type.GetInterfaces())
{
registry.For(#interface).Use(type);
}
}
}
}
if you take the code sample from the link every concrete type would be included. With my changes only concerte classes which inherit from T will be included.
in your registry you would use it like that
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.Convention<AllInterfacesConvention<YOUR_BASE_INTERFACE>>();
});
}
}
Be aware the structuremap's GetInstance will always resolve concrete classes no matter if you previously registered them.
See here https://stackoverflow.com/a/4807950/885338

Asp.net Core options class needs class instance as parameter, what if the class uses DI references?

In startup.cs I have
services.AddAuthorization(options =>
{
options.AddPolicy("RequireSomething", policy => policy.Requirements.Add(new SomeRequirement()));
});
What if the SomeRequirement -class needs a class that is only available through dependency injection, like below. I can't/don't want to instantiate SomeRequirement.
public class SomeRequirement : AuthorizationHandler<SomeRequirement>, IAuthorizationRequirement
{
ISomething _something;
public SomeRequirement(ISomething something)
{
_something = something;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SomeRequirement requirement)
{
//TODO Do stuff
return Task.CompletedTask;
}
}
I suggest there are two solution for this.
I assume that you have concrete implementation of ISomething. If you knew that that initialize that and pass it to parameter as parameter. This is short and sweet solution.
Second solution is bit awkward.
Default DI Container available in ASP.net Core does not support property injection.
Instead of using Default DI Container try to use Autofac or some other DI Container that support property injection.
Update 1: Possible Solution. ( Using Default DI of ASP.net Core)
public class SomeRequirement : AuthorizationHandler<SomeRequirement>, IAuthorizationRequirement
{
ISomething _something;
public SomeRequirement(ISomething something)
{
_something = something;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SomeRequirement requirement)
{
//TODO Do stuff
return Task.CompletedTask;
}
}
public interface ISomething
{
}
public class Something : ISomething
{
}
And In ConfigureService
services.AddSingleton<ISomething, Something>();
services.AddScoped(typeof(SomeRequirement));
services.AddAuthorization(options =>
{
options.AddPolicy("RequireSomething", policy => policy.Requirements.Add(services.BuildServiceProvider().GetRequiredService<SomeRequirement>()));
});

Ninject constructor argument

I have this interface:
public interface IUserProfileService
{
// stuff
}
Implemented by:
public class UserProfileService : IUserProfileService
{
private readonly string m_userName;
public UserProfileService(string userName)
{
m_userName = userName;
}
}
I need this injected into a controller like this:
public class ProfilesController : BaseController
{
private readonly IUserProfileService m_profileService;
public ProfilesController(IUserProfileService profileService)
{
m_profileService = profileService;
}
}
I don't know how I can register this interface and its implementation into Ninject container so that userName param is passed in when the Ninject inits an instance of this service.
Any ideas how I can achieve this?
The technical ninject answer is to use constructor arguments like so:
Bind<IUserProfileService>().To<UserProfileService>().WithConstructorArgument("userName", "karl");
Of course you need to figure out where "karl" comes from. It really depends on your app. Maybe its a web app and it's on the HttpContex? I don't know. If it gets rather complicated then you might want to write a IProvider rather than doing a regular binding.
One alternative is to inject a factory and create your dependency using Create(string userName).
public class UserProfileServiceFactory
{
public IUserProfileService Create(string userName)
{
return new UserProfileService(userName);
}
}
It might seem off to have to create another class but the benefits mostly comes when UserProfileService takes in additional dependencies.
The trick is to not inject the username in that class. You call this class a service so it would probably work transparantly with multiple users. I see two solutions:
Inject an abstraction into the service that represents the current user:
public class UserProfileService : IUserProfileService
{
private readonly IPrincipal currentUser;
public UserProfileService(IPrincipal currentUser)
{
this.currentUser = currentUser;
}
void IUserProfileService.SomeOperation()
{
var user = this.currentUser;
// Do some nice stuff with user
}
}
Create an implementation that is specific to the technology you are working with, for instance:
public class AspNetUserProfileService : IUserProfileService
{
public AspNetUserProfileService()
{
}
void IUserProfileService.SomeOperation()
{
var user = this.CurrentUser;
// Do some nice stuff with user
}
private IPrincipal CurrentUser
{
get { return HttpContext.Current.User; }
}
}
If you can, go with option one.

How to use custom injection attribute for properties when using StructureMap?

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();
}

Inheriting from ViewPage

Is it possible to inherit from both ViewPage and ViewPage<T>?? Or do I have to implement both. Currently this is what I have for ViewPage. Do i need to repeat myself and do the same for ViewPage<T>??
public class BaseViewPage : ViewPage
{
public bool LoggedIn
{
get
{
if (ViewContext.Controller is BaseController)
return ((BaseController)ViewContext.Controller).LoggedOn;
else
return false;
}
}
}
Create both versions:
public class BaseViewPage : ViewPage
{
// put your custom code here
}
public class BaseViewPage<TModel> : BaseViewPage where TModel : class
{
// code borrowed from MVC source
private ViewDataDictionary<TModel> _viewData;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData {
get {
if (_viewData == null) {
SetViewData(new ViewDataDictionary<TModel>());
}
return _viewData;
}
set {
SetViewData(value);
}
}
protected override void SetViewData(ViewDataDictionary viewData) {
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
then
public class MyCustomView : BaseViewPage
{
}
or
public class MyCustomView : BaseViewPage<MyCustomViewData>
{
}
Depending on how you are doing things you might want to look at
ViewContext.HttpContext.Request.IsAuthenticated
it might save you some time instead of extending the ViewPage class.
If there is some other data that you are after you could maybe write an extension method to one of the classes that provides the data. E.g. if LoggedIn was stored in the session you could extend the context to give you an IsLoggedIn() in method.
Edit:
As your extending a class that is already available in the both the base and strongly typed view it will be available in both. The only other way around is to reimplement the strongly typed version as above.
I wouldn't put this in the View, instead I'd have it as a property on the ViewModel (have a BaseViewModel). It will be easier to test as well as ensuring you're not going down the slope of putting business logic into the views.

Resources