-
Notifications
You must be signed in to change notification settings - Fork 0
The IoC container
ServiceStack uses a slightly modified version of Funq - which was adopted because of its excellent performance and memory characteristics. ServiceStack's version of Funq has been enhanced with Expression-based Auto-wiring and lifetime Request Scope.
If you so wish, you can still elect to use your favourite IOC by creating an IContainerAdapter
for them. See below for examples of adapters for popular IOC's. All ServiceStack's customizable hooks support Auto-wiring out-of-the-box, namely:
- Services
- Request and Response Filter attributes (are executed before a service gets called)
- Validators (validates a request DTO before the service gets called)
For each of these features, dependencies are resolved for all parameters in the constructor that has the most arguments as well as all public properties.
You can register dependencies so that all the dependencies are automatically auto-wired. Just like the hooks above, once resolved Funq will create a new instance resolving dependencies for the constructor that has the most arguments as well as all public properties.
public override void Configure(Container container)
{
container.RegisterAutoWired<MyType>();
container.RegisterAutoWiredAs<MyType,IMyType>();
}
There's also support for registration of run-time types with these APIs below:
container.RegisterAutoWiredType(typeof(MyType));
container.RegisterAutoWiredType(typeof(MyType),typeof(IMyType));
container.RegisterAutoWiredTypes(typeof(MyType),typeof(MyType2),typeof(MyType3));
Funq also supports custom creation of instances. When used no auto-wiring is performed and it's left up to you to explicitly resolve all your dependencies.
In addition to Auto-wiring Funq allows you to customize the creation of your instance with custom delegates. This is useful when your dependencies require custom configuration. E.g:
container.Register(c => new MyType(c.Resolve<IDependency>(), connectionString));
container.Register<IMyType>(c => new MyType(c.Resolve<IDependency>(), connectionString));
container.Register(c => CreateAndInitialzeMyType(c.Resolve<IDependency1>(), c.Resolve<IDependency2>));
Other than factories, you can also register custom instances where instead of returning a lambda above you can return an instance:
container.Register(new MyType(c.Resolve<IDependency>(), connectionString));
Note: When using the methods above, the properties and the constructor of the registered type aren't auto-wired (ie the properties and the constructor are not injected). You would need to do that manually like that:
container.Register<T>(c => new Foo(c.Resolve<Some>(), c.Resolve<Other>(), c.Resolve<Dependencies>());
By default all dependencies registered in Funq have singleton scope, where the same instance is injected into all dependencies. This behaviour can be changed by defining the scope explicitly, which is supported with the following APIs:
container.Register(c => new MyType()).ReusedWithin(ReuseScope.None);
container.RegisterAutoWired<MyType>().ReusedWithin(ReuseScope.None);
container.RegisterAutoWiredAs<MyType,IMyType>().ReusedWithin(ReuseScope.None);
container.RegisterAutoWiredType(typeof(MyType), ReuseScope.None);
container.RegisterAutoWiredType(typeof(MyType), typeof(IMyType), ReuseScope.None);
-
ReuseScope.Container
: Singleton scope (a instance is used per application lifetime) -
ReuseScope.Request
: Request scope (a instance is used per request lifetime) -
ReuseScope.None
: Transient scope (a new instance is created every time)
Info: Funq also supports child containers when
ReuseScope.Hierarchy
is specified, the dependency will also be available in child containers. However, most users will not require this advanced feature.
public interface IContainerAdapter {
T Resolve<T>();
T TryResolve<T>();
}
IKernel kernel = new StandardKernel();
container.Adapter = new NinjectIocAdapter(kernel);
Adding a custom ContainerAdapter allows your services to resolve its dependencies from an alternative IOC, in this way they act like a dependency repository where the services are still registered in Funq but all their dependencies are resolved by the ContainerAdapter specified. Dependencies in constructors are resolved by calling IContainerAdapter.Resolve<T>()
whilst public property dependencies are resolved with IContainerAdapter.TryResolve<T>()
, the idea is you can have missing constructor dependencies throw an exception whilst you can be more lax about property dependencies, where your service can continue to execute without them (should you wish).
Here are some example how to use some popular IoC containers side-by-side with Funq. Of course you're not only limited to the these IoC containers here:
public class NinjectIocAdapter : IContainerAdapter
{
private readonly IKernel kernel;
public NinjectIocAdapter(IKernel kernel)
{
this.kernel = kernel;
}
public T Resolve<T>()
{
return this.kernel.Get<T>();
}
public T TryResolve<T>()
{
return this.kernel.TryGet<T>();
}
}
Then in the AppHost
Configure(Container container)
method you need to enable this adapter:
//Create Ninject IoC container
IKernel kernel = new StandardKernel();
//Now register all depedencies to your custom IoC container
//...
//Register Ninject IoC container, so ServiceStack can use it
container.Adapter = new NinjectIocAdapter(kernel);
public class StructureMapContainerAdapter : IContainerAdapter
{
public T TryResolve<T>()
{
return ObjectFactory.TryGetInstance<T>();
}
public T Resolve<T>()
{
return ObjectFactory.TryGetInstance<T>();
}
}
In AppHost
Configure
:
//Configure User Defined REST Paths
container.Adapter = new StructureMapContainerAdapter();
//Register your dependencies
ObjectFactory.Inject(typeof(IFoo), new Foo());
Note: Due to a behavior of StructureMap, you need your
AppHost
declare asinternal
, eg:internal class AppHost : AppHostBase
// The "ApplicationAssemblyFilter" is a custom class that just helps to
// automate registration to assemblies which match a particular pattern
// in the app path
public class ApplicationAssemblyFilter : AssemblyFilter
{
public ApplicationAssemblyFilter()
: base(AppDomain.CurrentDomain.BaseDirectory, Assembly.GetExecutingAssembly().GetName().Name + ".*.dll"){}
}
public class WindsorContainerAdapter : IContainerAdapter, IDisposable
{
private readonly IWindsorContainer _container;
public WindsorContainerAdapter()
{
_container = new WindsorContainer().Install(FromAssembly.InThisApplication(),
FromAssembly.InDirectory(new ApplicationAssemblyFilter()));
}
public T TryResolve<T>()
{
if (_container.Kernel.HasComponent(typeof(T)))
{
return (T)_container.Resolve(typeof(T));
}
return default(T);
}
public T Resolve<T>()
{
return _container.Resolve<T>();
}
public void Dispose()
{
_container.Dispose();
}
}
public class AutofacIocAdapter : IContainerAdapter
{
private readonly IContainer _container;
public AutofacIocAdapter(IContainer container)
{
_container = container;
}
public T Resolve<T>()
{
return _container.Resolve<T>();
}
public T TryResolve<T>()
{
T result;
if (_container.TryResolve<T>(out result))
{
return result;
}
return default(T);
}
}
Then in the AppHost
Configure(Container container)
method you need to enable this adapter:
//Create Autofac builder
var builder = new ContainerBuilder();
//Now register all depedencies to your custom IoC container
//...
//Register Autofac IoC container adapter, so ServiceStack can use it
IContainerAdapter adapter = new AutofacIocAdapter(builder.Build());
container.Adapter = adapter;
The AppHost.Release(instance)
method gets called for every resolved service right after it's used.
This is the default implementation (which can be overridden):
var iocAdapterReleases = Container.Adapter as IRelease;
if (iocAdapterReleases != null)
{
iocAdapterReleases.Release(instance);
}
else
{
var disposable = instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
Which will first try to call your ContainerAdapter if it implements IRelease
otherwise if the service is IDisposable
it will just dispose of it itself.
So to have resolved services released back into your IOC, implement the IRelease
interface on your IContainerAdapter, e.g:
public class WindsorContainerAdapter : IContainerAdapter, IRelease
{
private readonly IWindsorContainer _container;
public void Release(object instance)
{
_container.Release(instance);
}
}
Otherwise you can override default implementation in your AppHost.Release(instance)
if you want to do something other than the default implementation.
Next wikipage: Metadata page
- Why ServiceStack?
- What is a message based web service?
- Advantages of message based web services
- Why remote services should use separate DTOs
- Getting Started
- Reference
- Clients
- Formats
- View Engines 4. Razor & Markdown Razor
- Hosts
- Advanced
- Configuration options
- Access HTTP specific features in services
- Logging
- Serialization/deserialization
- Request/response filters
- Filter attributes
- Concurrency Model
- Built-in caching options
- Built-in profiling
- Messaging and Redis
- Form Hijacking Prevention
- Auto-Mapping
- HTTP Utils
- Virtual File System
- Config API
- Physical Project Structure
- Modularizing Services
- Plugins
- Tests
- Other Languages
- Use Cases
- Performance
- How To
- Future