Skip to content

Commit

Permalink
adding missing Old md docs so that navigation is working and in order…
Browse files Browse the repository at this point in the history
… to convert to .cs
  • Loading branch information
dadhi authored and Leszek-Kowalski committed Oct 11, 2019
1 parent 668123c commit 00c5b11
Show file tree
Hide file tree
Showing 6 changed files with 1,397 additions and 0 deletions.
31 changes: 31 additions & 0 deletions docs/DryIoc.Docs/InstallationOptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Installation Options

[TOC]

## Source and Binary NuGet packages

DryIoc and its extensions distributed via [NuGet](https://www.nuget.org/packages?q=dryioc) either as a __Source__ or a Binary package.

__Note:__ Source code is the default way of distribution (e.g. __DryIoc__ package) for a historical reasons. If you want a "normal" assembly reference, please use the packages with `.dll` suffix (e.g. __DryIoc.dll__ package).

### Source package

__DryIoc package__ contains source files: _Container.cs_ and maybe couple of others depending on target framework. All the files will be located in the target project in _DryIoc_ folder.

`PM> Install-Package DryIoc`

### Binary package

__DryIoc.dll package__ has a `.dll` suffix and contains assembly that normally referenced by target project.

`PM> Install-Package DryIoc.dll`


## Assembly Signing

By default DryIoc binaries provided without strong-signing. For those who requires strong-signing DryIoc package includes two files:

- _tools\SignPackageAssemblies.ps1_
- _tools\DryIoc.snk_

Run _SignPackageAssemblies.ps1_ from __NuGet Package Manager -> Package Manager Console__ to sign the installed DryIoc assemblies with _DryIoc.snk_ key.
245 changes: 245 additions & 0 deletions docs/DryIoc.Docs/SelectConstructorOrFactoryMethod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
# Select Constructor or Factory Method

[TOC]

## Multiple constructors

By default DryIoc expects implementation to have only single constructor.
This constructor will be used for Constructor Injection of parameter dependencies.

Default constructor means no dependencies.

If class has multiple constructors the default behavior is to throw corresponding `ContainerException`.
To avoid the exception you may specify what constructor to use while registering.

Given class with two constructors:
```
#!c#
public class Foo
{
public Foo() {}
public Foo(IDependency dep) { Dep = dep; }
}
```

There are multiple ways to select constructor:

- The preferable way is strongly typed specification with [Expression Tree](https://msdn.microsoft.com/en-us/library/bb397951.aspx) expression:

```
#!c#
c.Register<Foo>(made: Made.Of(() => new Foo(Arg.Of<IDependency>())));
```

__Note:__ Code `() => new Foo(Arg.Of<IDependency>()` is just specification expression and won't be executed.

`Arg` class provides static methods to specify injected dependency details as explained here: [Specify Dependency or Primitive Value Injection](https://bitbucket.org/dadhi/dryioc/wiki/SpecifyDependencyOrPrimitiveValueInjection).

- Another way is using Reflection:
```
#!c#
c.Register<Foo>(made: Made.Of(typeof(Foo).GetConstructor(new[] { typeof(IDependency) })));
```

__Note:__ When registering open-generic the reflection is the only way:
```
#!c#
c.Register(typeof<Foo<>>,
made: Made.Of(typeof(Foo<>).GetConstructor(new[] { typeof(IDependency<>) })));
```


## Selecting constructor with resolvable parameters

DryIoc supports selecting of constructor with all resolvable parameters. The process is peeking constructor with
maximum number of parameters first and trying to resolve them. If some parameter is not resolved, then container will proceed to next constructor with less
parameters. If no constructors resolved successfully and there is no default constructor container will throw meaningful exception.
Succeeded it will use the constructor for service resolution.

The rule may be used:

- Per service registration (preferable to pin-point problematic service but stay deterministic for rest of registrations):
```
#!c#
c.Register<Foo>(made: FactoryMethod.ConstructorWithResolvableArguments);
```

- Per whole Container:
```
#!c#
var c = new Container(rules => rules.With(FactoryMethod.ConstructorWithResolvableArguments));
c.Register<Foo>(); // no need to specify how to select constructor
```

Registration level rule will override container rule if both are present.


## Factory Method instead of Constructor

Some designs may require to use static or instance method for creating service, e.g. `OpenSession`.
This way API provider may additionally configure or initialize service before returning it to client.

DryIoc directly supports static or instance factory methods. Container will inject dependencies into method parameters the
same way as for constructors.

__Note:__ Please prefer to use factory method over `RegisterDelegate` to minimize state capturing problems leading to memory leaks and to keep code as container-agnostic as possible.

Using static factory method:
```
#!c#
public static class FooFactory
{
public static IFoo CreateFoo(IRepo repo)
{
var foo = new Foo();
repo.Add(foo);
return foo;
}
}
// elsewhere
c.Register<IRepo, Repo>();
c.Register<IFoo>(made: Made.Of(() => FooFactory.CreateFoo(Arg.Of<IRepo>())));
```

Using instance factory method:
```
#!c#
public class FooFactory : IFooFactory
{
public FooFactory(FactoryDependency dep) { /*...*/ }
public IFoo CreateFoo(IRepo repo)
{
var foo = new Foo();
repo.Add(foo);
return foo;
}
}
// elsewhere
c.Register<FactoryDependency>();
c.Register<IFooFactory, FooFactory>(Reuse.Singleton);
c.Register<IRepo, Repo>();
c.Register<IFoo>(made: Made.Of(r => ServiceInfo.Of<IFooFactory>(), f => f.CreateFoo(Arg.Of<IRepo>())));
```

With instance factory methods you can use chain of factories if necessary.


## Property/Field as Factory Method

If DryIoc supports factory methods then why not support Properties and Fields?

Here we are:
```
#!c#
public class FooFactory : IFooFactory
{
public IFoo Foo { get; private set; }
public FooFactory(IRepo repo) { Foo = new Foo(repo); /*...*/ }
}
// elsewhere
c.Register<IRepo, Repo>();
c.Register<IFooFactory, FooFactory>(Reuse.Singleton);
c.Register<IFoo>(made: Made.Of(r => ServiceInfo.Of<IFooFactory>(), f => f.Foo));
```


## Open-generic Factory Method

DryIoc supports open-generic methods (and properties/fields) defined in open-generic classes. The level of support is the same as for [OpenGenerics](OpenGenerics). That means the Container is capable to match repeated, recurring, position-swapped, etc. generic type parameters with service type arguments. Generic parameter constraints are supported too.

Example:
```
#!c#
[Export, AsFactory]
public class Factory<A>
{
[Export]
IService<A, B> Create<B>(A a)
{
var service = new ServiceImpl<A, B>();
service.Initialize(a);
return service;
}
}
// With DryIoc MefAttributedModel (Export attributes) the registration is simple
var container = new Contaner().WithMefAttributedModel();
container.RegisterExports(typeof(Factory<>));
// Manual registration is more tedious
container.Register(typeof(Factory<>));
container.Register(typeof(IService<,>),
made: Made.Of(typeof(Factory<>).GetSingleMethodOrNull("Create"), ServiceInfo.Of(typeof(Factory<>))));
container.Register<Foo>(); // register required dependency A for Create
// Then resolve:
container.Resolve<IService<Foo, string>>();
```


## Using Factory Method as Initializer

It may be more advanced topic, but it is actually quite easy to do DryIoc.
Initializer is method that expects service as input and returns initialized (or may be completely new) service as output. This looks quite similar to [Decorator](http://en.wikipedia.org/wiki/Decorator_pattern) and indeed may be implemented as Decorator:
```
#!c#
public class Service : IService { /* ... */ }
public class Initializer
{
public IService Init(IService service, IOtherDependency dep, IAnotherOneDep anotherDep) {
service.Configure(dep, anotherDep, "greetings");
return service;
}
}
// elsewhere
c.Register<IService, Service>();
c.Register<Initializer>();
// register the rest of dependencies ...
c.Register<IService>(made: Made.Of(r => ServiceInfo.Of<Initializer>(),
i => i.Init(Arg.Of<IService>(), Arg.Of<IOtherDependency>(), Arg.Of<IAnotherOneDep>())),
setup: Setup.Decorator); // Important!
// resolve as usual:
c.Resolve<IService>(); // after creating Service will call Initializer.Init injecting dependencies.
```


## Easy Factory Method with DryIoc.MefAttributedModel

I wanted to show how easy to specify Factory Method and Initializers without notion of container (fully container-agnostic) using _DryIoc.MefAttributedModel_ extension:
```
#!c#
[Export, AsFactory]
public class FooFactory
{
public FooFactory(FactoryDependency dep) { /*...*/ }
[Export]
public IFoo CreateFoo(IRepo repo)
{
var foo = new Foo();
repo.Add(foo);
return foo;
}
[Export]
public IBlah Blah { get; private set; }
[Export, AsDecorator]
public IBlah ConfigureBlah(IBlah original) { /* initilialize blah */ }
}
// elsewhere
var container = new Container(rules => rules.WithMefAttributedModel());
container.RegisterExports(new[] { appAssembly });
```
62 changes: 62 additions & 0 deletions docs/DryIoc.Docs/ThreadSafety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Thread Safety

[TOC]

## DryIoc is Thread-Safe

DryIoc ensures that:

- Registrations and resolutions could be invoked concurrently on the same container (possibly from a different threads) without corrupting container state.
- Registrations do not stop-the-world for resolutions. __There is no locking associated with registrations__.
- Resolutions do not block registrations either. __No locking except for reused instances as explained below__.
- Registration won't be visible for resolutions until it is completed. If it is incompleted (due exception) all its changes will be ignored.

The above guaranties are possible because of Container structure design. In pseudo code and simplifying things the DryIoc Container may be represented as following:

class Ref<T> { T Value; } // represents CAS (compare-and-swap) box for the referenced value

class Container
{
Ref<Registry> registry;
}

class Registry
{
ImmutableMap registrations;
Ref<ResolutionCache> resolutionCache;
}

class ResolutionCache
{
ImmutableMap cache;
}

Given the structure Registration of new service will produce new `registry`, then will swap old `registry` with new one inside the container. If some concurrent registration will intervene then the Registration will be retried with new `registry`.

Resolution on the other hand will produce new `resolutionCache` and will swap new cache inside the same registry object. This ensures that resolution cache is bound to the specific registry, and does no affected by new registrations (which produce new registries).

__Note:__ In addition to providing thread-safety the described Container structure allows to produce new Container very fast, at O(1) cost. This makes creation of ["Child" containers and Open Scope](KindsOfChildContainer) a cheap operation.


## Locking is only used for reused service creation

Lock is required to ensure that creation of reused service happens only once. For instance for singleton service A:

public class A
{
public static int InstanceCount;

public A() { ++InstanceCount; }
}

container.Register<A>(Reuse.Singleton);

//thread1:
container.Resolve<A>();

//thread2:
container.Resolve<A>();

// A.InstanceCount == 1

The lock boundaries are minimized to cover service creation only - the rest of resolution bits are handled outside of lock.

0 comments on commit 00c5b11

Please sign in to comment.