I was looking into "Dependency Injection" on xamarin forms and found some concepts that use something like ContainerBuilder. The solutions found online such as this, talk about how you can have DI setup and inject them into your view models. However, personally, I didn't find this or the whole concept of view models and binding very tidy for several reasons. I would rather create services that can be reused by the business logic, which seems to make the code a lot cleaner. I felt that implementing an IServiceProvider would result in a much cleaner implementation. I was planning on implementing a service provider something like this:
IServiceProvider Provider = new ServiceCollection()
.AddSingleton<OtherClass>()
.AddSingleton<MyClass>()
.BuildServiceProvider();
Firstly, I am not sure why there are no xamarin examples of these. So, I am not sure if there is anything wrong with going towards this direction. I have looked into ServiceCollection class. The package it is from, Microsoft.Extensions.DependencyInjection, doesn't have "aspnetcore" in its name. It, however, has its owner as "aspnet". I am not entirely sure if ServiceCollection is only meant for web applications or it would make sense to use it for mobile apps.
Is it safe to use IServiceProvider with ServiceCollection as long as I use all singletons? is there any concern (in terms of performance or ram) I am missing?
Update
After the comments from Nkosi, I have taken another look at the link and noticed a couple of things:
The documentation link is dated around the same time Microsoft.Extensions.DependencyInjection was still in beta
All points in the list under "several advantages to using a dependency injection container" in the documentation also apply to DependencyInjection as far as I can see.
Autofac process seems to revolve around ViewModels which I am trying to avoid using.
Update 2
I managed to get DI directly into the behind code of pages with the help of a navigation function something like this:
public static async Task<TPage> NavigateAsync<TPage>()
where TPage : Page
{
var scope = Provider.CreateScope();
var scopeProvider = scope.ServiceProvider;
var page = scopeProvider.GetService<TPage>();
if (navigation != null) await navigation.PushAsync(page);
return page;
}
This implementation uses Splat and some helper/wrapper classes to conveniently access the container.
The way how the services are registered is a bit verbose but it could cover all uses cases I have encountered so far; and the life cycle can be changed quite easily as well, e.g. switching to a lazy creation of a service.
Simply use the ServiceProvider class to retrieve any instances from the IoC container anywhere in your code.
Registering of your Services
public partial class App : Application
{
public App()
{
InitializeComponent();
SetupBootstrapper(Locator.CurrentMutable);
MainPage = new MainPage();
}
private void SetupBootstrapper(IMutableDependencyResolver resolver)
{
resolver.RegisterConstant(new Service(), typeof(IService));
resolver.RegisterLazySingleton(() => new LazyService(), typeof(ILazyService));
resolver.RegisterLazySingleton(() => new LazyServiceWithDI(
ServiceProvider.Get<IService>()), typeof(ILazyServiceWithDI));
// and so on ....
}
Usage of ServiceProvider
// get a new service instance with every call
var brandNewService = ServiceProvider.Get<IService>();
// get a deferred created singleton
var sameOldService = ServiceProvider.Get<ILazyService>();
// get a service which uses DI in its contructor
var another service = ServiceProvider.Get<ILazyServiceWithDI>();
Implementation of ServiceProvider
public static class ServiceProvider
{
public static T Get<T>(string contract = null)
{
T service = Locator.Current.GetService<T>(contract);
if (service == null) throw new Exception($"IoC returned null for type '{typeof(T).Name}'.");
return service;
}
public static IEnumerable<T> GetAll<T>(string contract = null)
{
bool IsEmpty(IEnumerable<T> collection)
{
return collection is null || !collection.Any();
}
IEnumerable<T> services = Locator.Current.GetServices<T>(contract).ToList();
if (IsEmpty(services)) throw new Exception($"IoC returned null or empty collection for type '{typeof(T).Name}'.");
return services;
}
}
Here is my csproj file. Nothing special, the only nuget package I added was Spat
Shared Project csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Splat" Version="9.3.11" />
<PackageReference Include="Xamarin.Forms" Version="4.3.0.908675" />
<PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
</ItemGroup>
</Project>
I know the question has been asked 2 years ago, but I might have a solution that could match what you are asking for.
In the past few months I've been working on apps using Xamarin and WPF and I used the Microsoft.Extensions.DependencyInjection package to add constructor dependency injection to my view models, just like an ASP.NET Controller. Which means that I could have something like:
public class MainViewModel : ViewModelBase
{
private readonly INavigationService _navigationService;
private readonly ILocalDatabase _database;
public MainViewModel(INavigationService navigationService, ILocalDatabase database)
{
_navigationService = navigationService;
_database = database;
}
}
To implement this kind of process I use the IServiceCollection to add the services and the IServiceProvider to retrieve the registered services.
What is important to remember, is that the IServiceCollection is the container where you will register your dependencies. Then when building this container, you will obtain a IServiceProvider that will allow you to retrieve a service.
To do so, I usually create a Bootstrapper class that will configure the services and initialize the main page of the application.
The basic implementation
This example show how to inject dependencies into a Xamarin page. The process remains the same for any other class. (ViewModels or other classes)
Create a simple class named Bootstrapper in your project and intitialize a IServiceCollection and IServiceProvider private fields.
public class Bootstrapper
{
private readonly Application _app;
private IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app)
{
_app = app;
}
public void Start()
{
ConfigureServices();
}
private void ConfigureServices()
{
_services = new ServiceCollection();
// TODO: add services here
_serviceProvider = _services.BuildServiceProvider();
}
}
Here in the ConfigureServices() method we just create a new ServiceCollection where we are going to add our services. (See https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=dotnet-plat-ext-3.1)
Once our services have been added, we build the service provider that will allow us to retrieve the previously registered services.
Then in your App class constructor, create a new Bootstrapper instance and call the start method to initialize the application.
public partial class App : Application
{
public App()
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this);
bootstrapper.Start();
}
...
}
With this piece of code, you have setup your service container, but we still need to initialize the MainPage of the application. Go back to the bootstrapper's Start() method and create a new instance of the wanted main page.
public class Bootstrapper
{
...
public void Start()
{
ConfigureServices();
// Real magic happens here
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
}
Here we use the ActivatorUtilities.CreateInstance<TInstance>() method to create a new MainPage instance. We give the _serviceProvider as parameter, because the ActivatorUtilities.CreateInstance() method will take care of creating your instance and inject the required services into your object.
Note that this is what ASP.NET Core using to instanciate the controllers with contructor dependency injection.
To test this, create a simple service and try to inject it into your MainPage contructor:
public interface IMySimpleService
{
void WriteMessage(string message);
}
public class MySimpleService : IMySimpleService
{
public void WriteMessage(string message)
{
Debug.WriteLine(message);
}
}
Then register it inside the ConfigureServices() method of the Bootstrapper class:
private void ConfigureServices()
{
_services = new ServiceCollection();
_services.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
And finally, go to your MainPage.xaml.cs, inject the IMySimpleService and call the WriteMessage() method.
public partial class MainPage : ContentPage
{
public MainPage(IMySimpleService mySimpleService)
{
mySimpleService.WriteMessage("Hello world!");
}
}
There you go, you have successfully registered a service and injected it into your page.
The real magic with constructor injection really occurs using the ActivatorUtilities.CreateInstance<T>() method by passing a service provider. The method will actually check the parameters of your constructor and try to resolve the dependencies by trying to get them from the IServiceProvider you gave him.
Bonus : Register platform specific services
Well this is great right? You are able to inject services into any classes thanks to the ActivatorUtilities.CreateInstance<T>() method, but sometimes you will also need to register some platform specific services (Android or iOS).
With the previous method is not possible to register platform-specific services, because the IServiceCollection is initialized in the Bootstrapper class. No worries, the workaround is really simple.
You just need to extract the IServiceCollection initialization to the platform-specific code. Simply initialize the service collection on the MainActivity.cs of your Android project and in the AppDelegate of your iOS project and pass it to your App class that will forward it to the Bootstrapper:
MainActivity.cs (Android)
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
...
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
}
...
}
AppDelegate.cs (iOS)
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
return base.FinishedLaunching(app, options);
}
}
App.xaml.cs (Common)
public partial class App : Application
{
public App(IServiceCollection services)
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this, services);
bootstrapper.Start();
}
...
}
Bootstrapper.cs (Common)
public class Bootstrapper
{
private readonly Application _app;
private readonly IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app, IServiceCollection services)
{
_app = app;
_services = services;
}
public void Start()
{
ConfigureServices();
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
private void ConfigureServices()
{
// TODO: add services here.
_serviceCollection.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
}
And that's all, you are now able to register platform-specific services and inject the interface into your pages / view models / classes easily.
Related
Here is what I have so far. I am trying to create a new ThemeManagementViewModel and inject into that a resource service using:
Microsoft.Extensions.DependencyInjection version 5.0.1 nuget package
public static class Startup
{
public static IServiceProvider ServiceProvider { get; set; }
public static IServiceProvider Init()
{
var serviceProvider = new ServiceCollection().ConfigureServices()
.BuildServiceProvider();
ServiceProvider = serviceProvider;
return serviceProvider;
}
}
public static class DependencyInjectionContainer
{
public static IServiceCollection ConfigureServices(this IServiceCollection services)
{
services.AddSingleton<IDatabaseService, DatabaseService>();
services.AddSingleton<IResourceService, ResourceService>();
services.AddTransient<ThemeManagementViewModel>();
return services;
}
}
public partial class ThemeManagementViewModel : BaseViewModel
{
private readonly IResourceService _resourceService;
public ThemeManagementViewModel(IResourceService resourceService)
{
_resourceService = resourceService;
}
}
public partial class ResourceService : IResourceService
{
private IDatabaseService _databaseService;
public ResourceService(IDatabaseService databaseService)
{
_databaseService = databaseService;
}
}
public interface IResourceService
{
void SetResourceColors();
}
public class ThemeManagementPage : HeadingView
{
private readonly ThemeManagementViewModel _vm;
public ThemeManagementPage()
{
BindingContext = _vm = new ThemeManagementViewModel();
}
}
When I build my application it gives me a message for this line:
BindingContext = _vm = new ThemeManagementViewModel();
and this is the message that I am getting.
There is no argument given that corresponds to the required
formal parameter 'resourceService' of
'ThemeManagementViewModel.ThemeManagementViewModel(IResourceService)'
I thought that the DI was supposed to insert the service into the constructor of ThemeManagementViewModel but it seems not to be working.
Dependency injection will not simply take place anywhere where you construct an object. You need to go explicitly through your DI framework.
In this case, you need to call GetRequiredService() of your IServiceProvider object.
var _vm = Startup.ServiceProvider.GetRequiredService<ThemeManagementViewModel>();
Also, from your code, we don't see that you use your DependencyInjectionContainer class at all. You must make sure that your ConfigureServices method is called explicitly.
DI cannot do magic. The compiler doesn't know anything about it. You have to use it explicitly. It looks like it could do magic in the context of ASP.net website projects. But that is only because there it is the ASP.net framework that handles the things that you need to do explicitly in other types of projects.
Tutorial on how to use DI in .net applications
How can I inject one class into another inside a .NET Core library project?
Where should I configure DI as it is done in StartUp Class ConfigureServices in API project?
After googling a lot I could not find a comprehensive answer with an example to this question. Here is what should be done to use DI in Class library.
In your library:
public class TestService : ITestService
{
private readonly ITestManager _testManager;
public TestService(ITestManager testManager)
{
_testManager = testManager;
}
}
public class TestManager : ITestManager
{
private readonly ITestManager _testManager;
public TestManager()
{
}
}
Then extend IServiceCollection in the library:
public static class ServiceCollectionExtensions
{
public static void AddTest(this IServiceCollection services)
{
services.AddScoped<ITestManager, TestManager>();
services.AddScoped<ITestService, TestService>();
}
}
Lastly in the main app StartUp (API, Console, etc):
public void ConfigureServices(IServiceCollection services)
{
services.AddTest();
}
There are many thought processes for how you manage this, as eventually, the caller will need to register your DI processes for you.
If you look at the methods used by Microsoft and others, you will typically have an extension method defined with a method such as "AddMyCustomLibrary" as an extension method off of the IServiceCollection. There is some discussion on this here.
Dependency Injection is configured at the Composition Root, basically the application entry point. If you do not have control over the application entry point you can not force anyone to use dependency injection with your class library. However you can use interface based programming and create helper classes to register every type in your library for a variety of Composition Root scenarios which will allow people to use IOC to instantiate your services regardless of whatever type of program they are creating.
What you can do is make services in your class library depend on interfaces of other services in your library so that the natural way to use them would be to register your services with the container that is in use and also allow for more efficient unit testing.
I'm not sure I fully understood your intent... But maybe you can make your implementation spin its own private ServiceProvider, something like this:
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class MyBlackBox {
private readonly IServiceProvider _services = BuildServices();
protected MyBlackBox() {}
public static MyBlackBox Create() {
return _services.GetRequiredService<MyBlackBox>();
}
private static void ConfigureServices(IServiceCollection services) {
services.AddTransient<MyBlackBox>();
// insert your dependencies here
}
private static IServiceProvider BuildServices() {
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddOptions();
serviceCollection.AddSingleton(config);
serviceCollection.AddSingleton<IConfiguration>(config);
ConfigureServices(serviceCollection);
return serviceCollection.BuildServiceProvider();
}
private static IConfigurationRoot BuildConfig() {
var path = Directory.GetCurrentDirectory();
var builder = new ConfigurationBuilder().SetBasePath(path).AddJsonFile("appsettings.json");
return builder.Build();
}
}
You can then register your implementation on the "Parent" ServiceProvider, and your dependencies would not be registered on it.
The downside is that you'll have to reconfigure everything, mainly logging and configuration.
If you need access to some services from the parent ServiceProvider, you can create something to bind them together:
public static void BindParentProvider(IServiceProvider parent) {
_services.AddSingleton<SomeService>(() => parent.GetRequiredService<SomeService>());
}
I'm pretty sure there's better ways to create nested ServiceProviders, though.
You can use Hosting Startup assemblies class library as an alternative to explicitly register them from the calling assembly.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/platform-specific-configuration?view=aspnetcore-3.1#class-library
[assembly: HostingStartup(typeof(HostingStartupLibrary.ServiceKeyInjection))]
namespace HostingStartupLibrary
{
public class Startup : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices((context, services) => {
services.AddSingleton<ServiceA>();
});
}
}
}
You can look at ServiceCollection Extension Pattern.
https://dotnetcoretutorials.com/2017/01/24/servicecollection-extension-pattern/
If you write this extension in class library, you can inject classes/services in this.
But I don't know is it a good pattern ?
so I can call the library with its services already attached, just use them.
this works for me:
public class LibraryBase
{
ctor... (mĂșltiple services)
public static IHostBuilder CreateHostBuilder(IHostBuilder host)
{
return host.ConfigureServices(... services)
}
}
Main:
public class Program
{
Main{... ConfigureServicesAsync()}
private static async Task ConfigureServicesAsync(string[] args)
{
IHostBuilder? host = new HostBuilder();
host = Host.CreateDefaultBuilder(args);
LibraryBase.CreateHostBuilder(host);
host.ConfigureHostConfiguration()
// ... start app
await host.StartAsync();
}
}
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...
TLDR: Is it possible to modify the IServiceProvider after the Startup has ran?
I am running dll's (which implement a interface of me) during run-time. Therefore there's a file listener background job, which waits till the plugin-dll is dropped. Now I want to register classes of this dll to the dependency-injection system. Therefore I added IServiceCollection as a Singleton to the DI inside ConfigureServices to use inside another method.
In therefore I created a test-project and just tried to modify the ServiceCollection in the controller, because it was easier than stripping the background job down.
services.AddSingleton<IServiceCollection>(services);
So I added IServiceCollection to my controller to check if I can add a class to the DI after the Startup class has ran.
[Route("api/v1/test")]
public class TestController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly IServiceCollection _services;
public TestController(IServiceCollection services)
{
_services = services;
var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
if (myInterface == null)
{
//check if dll exist and load it
//....
var implementation = new ForeignClassFromExternalDll();
_services.AddSingleton<IMyInterface>(implementation);
}
}
[HttpGet]
public IActionResult Test()
{
var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
return Json(myInterface.DoSomething());
}
}
public interface IMyInterface { /* ... */ }
public class ForeignClassFromExternalDll : IMyInterface { /* ... */ }
The Service was successfully added to the IServiceCollection, but the change is not persisted yet to HttpContext.RequestServices even after multiple calls the service count increases each time but I don't get the reference by the IServiceProvider.
Now my question is: Is that possible to achieve and yes how. Or should I rather not do that?
Is it possible to modify the IServiceProvider after the Startup has ran?
Short answer: No.
Once IServiceCollection.BuildServiceProvider() has been invoked, any changes to the collection has no effect on the built provider.
Use a factory delegate to defer the loading of the external implementation but this has to be done at start up like the rest of registration.
services.AddSingleton<IMyInterface>(_ => {
//check if dll exist and load it
//....
var implementation = new ForeignClassFromExternalDll();
return implementation;
});
You can now explicitly inject your interface into the controller constructor
private readonly IMyInterface myInterface;
public MyController(IMyInterface myInterface) {
this.myInterface = myInterface;
}
[HttpGet]
public IActionResult MyAction() {
return Json(myInterface.DoSomething());
}
and the load dll logic will be invoked when that interface is being resolved as the controller is resolved.
In trying to configure ServiceStack.net to use Ninject as its IOC, I am getting errors referring to various bindings not being defined. Primarily for ICache Client.
What specific bindings need to be created to use Ninject properly?
Currently have specified:
Bind<ISessionFactory>().To<SessionFactory>();//Is this correct/needed?
Note
I have created an IContainerAdapter as per the ServiceStack documention to implement the use of Ninject.
(Found here:ServiceStack IOC Docs)
Note 2
My apphost configure method looks like this:
public override void Configure(Funq.Container container)
{
IKernel kernel = new StandardKernel(new BindingModule());
container.Adapter = new NinjectContainerAdapter(kernel);
}
Note 3
I have registered the ICacheClient as follows:
Bind().To();
And I am now getting an error pointing to IRequest
Error activating IRequestLogger\nNo matching bindings are available, and the type is not self-bindable
Container Adapter
public class NinjectContainerAdapter : IContainerAdapter
{
private readonly IKernel _kernel;
public NinjectContainerAdapter(IKernel kernel)
{
this._kernel = kernel;
}
public T TryResolve<T>()
{
return this._kernel.Get<T>();
}
public T Resolve<T>()
{
return this._kernel.Get<T>();
}
}
Have you injected your Container adapter with:
container.Adapter = new NinjectIocAdapter(kernel);
If so, try also make your AppHost class internal if you haven't done so. There should only be 1 instance of AppHost and some IOC's like to create their own instance, wiping out all the configuration from the first one.
The behavior you're getting sounds like Ninject is complaining about unresolved dependencies. Make sure you get Ninject to return null with Unresolved dependencies by using kernal.TryGet<T> in your Container Adapter, e.g:
public T TryResolve<T>()
{
return this._kernel.TryGet<T>();
}
You need to write your own IContainerAdapter and then set Container.Adapter in your AppHost