I have the following class, which is compiled into a DLL called ExternalTask.dll and is housed externally in my filing system
public class ExampleJob : IJob
{
public void Execute(IJobExecutionContext context)
{
Console.WriteLine("ExampleJob is executing. {0}", System.DateTime.Now.ToUniversalTime());
}
}
I have placed the dll in the following directory : C:\External
I am attempting to use ninject to search the directoru and setup the bindings.
The following binding works if the class work in the same assembly as my main coded, but I want the dll to be separated off.
kernel.Bind<IJobSetup>().To<JobSetup<ExampleJob>>();
Does anyone know the correct binging to setup using the ninject conventions? I am currently trying this, but know I need more - I just cannot find much decent documentation to help.
kernel.Bind(scanner => scanner
.FromAssembliesInPath(
#"C:\External\")
.SelectAllClasses()
.BindAllInterfaces());
If your project is going to get bigger use Ninject Conventions:
public class ProjectRepository : IProjectRepository
{
....
}
and set binding as a module:
using Ninject.Extensions.Conventions;
public class RepositoryModule : NinjectModule
{
public override void Load()
{
IKernel ninjectKernel = this.Kernel;
ninjectKernel.Scan(kernel =>
{
kernel.FromAssemblyContaining<ProjectRepository>();
kernel.BindWithDefaultConventions();
kernel.AutoLoadModules();
kernel.InRequestScope();
});
}
}
then load it:
IKernel kernel = new StandardKernel(new RepositoryModule());
Related
I am creating the controller dynamically for the types to be loaded from the dll. For that I created one base controller to handle dynamic controller request.
My dynamic controller has following dependencies in the construcor
public class Order
{
private readonly IDBLogger _logger;
private readonly IExceptionHandler _handler
public Order(IDBLogger logger, IExceptionHandler handler)
{
_logger=logger;
_handler=handler
}
public void GetOrderDetail()
{
_logger.log("....."); //Here I am getting null reference as I am not able resolve this _logger type.
/// rest code
}
}
Since the class is loaded from the dll how can I resolve this.
I think my assumption of your objective was way off and it actually seems to me you don't need to mess with ApplicationParts or FeatureProviders at all. To me it appears to be a DI registration issue.
I started with boilerplate .net core 3.1 MVC application (nothing fancy there)
then I added two more class library projects: Common and Orders
Common.dll
I assumed that your interfaces (I'll just use IDBLogger for brevity) must be made available to the controller assembly as well as to the main application. So both projects are set to depend on it.
namespace Common
{
public interface IDBLogger
{
void Log(string s);
}
}
Orders.dll
this assembly defines a web api controller:
using Common;
namespace Orders
{
public class Order
{
private readonly IDBLogger _logger;
public Order(IDBLogger logger)
{
_logger = logger;
}
public void GetOrderDetail()
{
_logger.Log("Inside GetOrderDetail");
}
}
}
MVC
as most of the code is stock standard I'd only list files that I changed.
Note, that now I'm relying on default Controller resolver I only need to register my types onto ServiceCollection
Startup.cs
...
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(); // add all controllers as you normally would. I think you don't need to mess with ApplicationParts. but if you do, you are already aware that https://stackoverflow.com/questions/36680933/discovering-generic-controllers-in-asp-net-core is a good example
services.AddScoped<IDBLogger, IdbLogger>();
// load assembly and register with DI
var assembly = Assembly.LoadFrom(Path.Combine("..\\path\\to", "Orders.dll"));
var orderType = assembly.ExportedTypes.First(t => t.Name == "Order");
services.AddScoped(orderType); // this is where we would make our type known to the DI container
var loadedTypesCache = new LoadedTypesCache(); // this step is optional - I chose to leverage the same DI mechanism to avoid having to load assembly in my controller for type definition. you can probably find a better approach at doing this
loadedTypesCache.LoadedTypes.Add("order", orderType);
services.AddSingleton(loadedTypesCache); // singleton seems like a good fit here
}
IdbLogger.cs
using Common;
using System;
namespace Test
{
public class IdbLogger : IDBLogger
{
public void Log(string s)
{
Console.WriteLine(s); // nothing fancy here either
}
}
}
ValuesController.cs
[Route("api/[controller]")]
[ApiController]
public class ValuesController
{
public ValuesController(IServiceProvider serviceProvider, LoadedTypesCache cache)
{
var order = serviceProvider.GetService(cache.LoadedTypes["order"]); // you could load the same assembly here to get the type again, but i opted to inject a dictionary with preloaded type instead
// following two lines are just to call the method. you probably have better way of doing it
var m = cache.LoadedTypes["order"].GetMethod("GetOrderDetail", BindingFlags.Public|BindingFlags.Instance);
m.Invoke(order, new object[] { });
}
[HttpGet]
public IEnumerable<string> Get()
{
return new [] { "value1", "value2" };
}
}
relying on built-in DI container allows us to not think about manually instantiating your dynamically loaded types (and their dependencies as long as they are known to the DI container). You might find that having to use reflection to work with these instances is a bit cumbersome so you might want to explore your options there.
hopefully this is the missing piece
You can dynamically load the dependencies and the controller using reflection.
For more info, you can visit the following link.
Assemblies
I want to take advantage of dependency injection in my Xamarin project but can't get constructor injection to work in C# classes behind XAML views. Is there any way to do it ?
I've seen guides how to setup dependency injections in View Models, to later use them as repositories but that doesn't work for me.
So far I tried Ninject and Unity.
Code:
This is the service I want to use inside of my PCL project:
public class MyService : IMyService
{
public void Add(string myNote)
{
//Add Note logic
}
}
Interface:
public interface IMyService
{
void Add(string myNote);
}
Unity setup in App.Xaml:
public App ()
{
InitializeComponent();
var unityContainer = new UnityContainer();
unityContainer.RegisterType<IMyService, MyService>();
var unityServiceLocator = new UnityServiceLocator(unityContainer);
ServiceLocator.SetLocatorProvider(() => unityServiceLocator);
MainPage = new MainMasterMenu(); //<-- feel that I'm missing something here as I shouldn't be creating class instances with DI, right ?
}
Usage that I'd like to see. This is .CS file behind a XAML starting page:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainMasterMenu : MasterDetailPage
{
private IMyService _myService;
public MainMasterMenu(IMyService myService)
{
_myService = myService
}
private void SomeFormControlClickEvent(object sender, ItemChangedEventArgs e)
{
_myService.Add("hi");
}
}
For that simple example creating the MainMasterMenu directly would be no issue, but you would have to pass the reference to your service
MainPage = new MainMasterMenu(unityContainer.Resolve<IMyService>());
But this would mean that you'll have to change that line every time the constructor of MainMasterMenu changes. You could circumvent this by registering the MainMasterMenu, too.
unityContainer.RegisterType<MainMasterMenu>();
...
MainPage = unityContainer.Resolve<MainMasterPage>();
Anyway, anytime you want to navigate to another page, which needs any dependency registered with unity, you'll have to make sure to resolve its dependencies properly, which requires (at least indirect) access to the unity container. You could pass a wrapper that encapsules the access to unity
interface IPageResolver
{
T ResolvePage<T>()
where T : Page;
}
and then implement that resolver with unity
public class UnityPageResolver
{
private IUnityContainer unityContainer;
public UnityPageResolver(IUnityContainer unityContainer)
{
this.unityContainer = unityContainer;
}
public T ResolvePage<T>()
where T : Page // do we need this restriction here?
{
return unityContainer.Resolve<T>();
}
}
This gets registered with unity
unityContainer.RegisterInstance<IUnityContainer>(this);
unityContainer.RegisterType<IPageResolver, UnityPageResolver>();
But you should have a look at the Prism library (see here) that solves many of the issues (e.g. it provides an INavigationService that lets you navigate to other pages without caring about the dependencies and it provides facilities to resolve viewmodels automatically, including dependencies).
I have an asp.net MVC 4.5 application with Castle.Windsor 3.2.2 as DI and I'm trying to add FluentValidation version 5.0.0.1 for the first time.
I created the factory inheriting from ValidatorFactoryBase
public class WindsorFluentValidatorFactory : ValidatorFactoryBase
{
private readonly IKernel _kernel;
public WindsorFluentValidatorFactory(IKernel kernel)
{
_kernel = kernel;
}
public override IValidator CreateInstance(Type validatorType)
{
return _kernel.HasComponent(validatorType)
? _kernel.Resolve<IValidator>(validatorType)
: null;
}
}
Also created the installer for Castle:
public class FluentValidatorsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes
.FromThisAssembly()
.BasedOn(typeof(IValidator<>))
.WithService
.Base());
}
}
Now, in the Global.asax, I tried (following documentation on web) to hook things like this:
var fluentValidationModelValidatorProvider = new FluentValidationModelValidatorProvider(new WindsorFluentValidatorFactory(container.Kernel));
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
However, the second line gives the following error:
"The best overloaded method match for
'System.Collections.ObjectModel.Collection.Add(System.Web.Mvc.ModelValidatorProvider)'
has some invalid arguments Argument 1: cannot convert from
'FluentValidation.Mvc.WebApi.FluentValidationModelValidatorProvider'
to 'System.Web.Mvc.ModelValidatorProvider'"
So, it seems that this way of doing it is not working on the versions I use.
I also tried to hook this using the Configure method doing this:
FluentValidationModelValidatorProvider.Configure(x => x.ValidatorFactory = new WindsorFluentValidatorFactory(container.Kernel));
However, it's not working. Debugging I checked at ModelValidatorProviders.Providers and there is no new provider being add with the Configure method.
Any ideas on what I might be doing wrong?
Thanks,
Andres
Solved
I got a solution in another forum but I'll post the answer it's useful for someone else.
I was using the wrong Provider
There are two providers - one for MVC and one for WebApi. It seems that I was using the WebAPI one.
Changed it to FluentValidation.Mvc.FluentValidationModelValidatorProvide and the problem was solved
I have a .Net MVC 3.0 application and I'm using Ninject 3.0. I didn't install any nuget. I'm referencing Ninject.dll, Ninject.Web.Common.dll and Ninject.Web.Mvc.dll (and 2 others). I want to have dependencies injected in a custom HttpModule and I can't figure out how to make it work with a NinjectHttpApplication.
I have this error:
Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Here is the code:
Global.asax
public class MvcApplication: NinjectHttpApplication
{
...
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule()
};
IKernel kernel = new StandardKernel(modules);
return kernel;
}
}
Web.Config
<httpModules>
<add name="NinjectHttpModule" type="Ninject.Web.Common.NinjectHttpModule"/>
</httpModules>
CustomHttpModule.cs
public class CustomHttpModule : IHttpModule
{
private ITesttService service;
public CustomHttpModule(ITesttService service)
{
this.service = service;
}
...
}
ServiceModule.cs
public class ServiceModule : NinjectModule
{
public override void Load()
{
...
Kernel.Bind<ITestService>().To<TestService>();
Kernel.Bind<IHttpModule>().To<CustomHttpModule>().InSingletonScope();
}
}
This binding solves my problem:
kernel.Bind<Func<IKernel>>().ToMethod(c => () => this.Kernel);
But according to this post on github, I'm not supposed to do it.
Can you someone tell me what I'm doing wrong or missing?
Currently there is no good way to use the NinjectHttpModule when deriving from NinjectHttpApplication. The bootstrapper registers the HttpApplicationInitializationHttpModule for both ways and as soon as the NinjectHttpModule is loaded this module is loaded as well.
Unfortunately there is no good point where you can unload it.
I suggest you use the WebActivator instead on deriving from NinjectHttpApplication. It's the only proper way to get it running. You don't necessarily have to use nuget to setup your application that way. You can also add the same files manually and manually reference all required assemblies.
I am using Ninject to load several modules. When two modules try to bind two different implementations for an interface, ninject raises an error that multiple binding for a
service are not allowed.
All other IoC frameworks I'm using (Unity, Windsor, Spring.net, etc)
all have the ability to 'register' multiple implementations for an
interface.
Let me give a real life example:
public class HealtMonitorEmailAlertServiceModule : StandardModule
{
public override void Load()
{
this.Bind<IAlertService>().To<EmailAlertService>();
}
}
public class HealtMonitorSmsAlertServiceModule : StandardModule
{
public override void Load()
{
this.Bind<IAlertService>().To<SmsAlertService>();
}
}
public class Program
{
static void Main()
{
var emailService = new HealtMonitorEmailAlertServiceModule();
var smsService = new HealtMonitorSmsAlertServiceModule();
IKernel kernel = new StandardKernel(emailService, smsService);
kernel.Get<IAlertService>()
}
}
The above generates an exception, i would expect it to resolve the type registered in the last module to load into the kernel. I have tried the exact same approach using Autofac and it works as I expected.
Ninject 2.0 has this capability, but Ninject 1.x does not. While 2.0 is still in beta, I'd encourage you to take a look, because 1.x will be end-of-life within a couple of months.