Mittwoch, 13. Dezember 2017

PantherDI - Part 4: The first release

Okay, so here it is. The blogpost with which the first released version of PantherDI will be published.
But still this does not mean that PantherDI is finished. The roadmap can be viewed in the GitHub-Issues by filtering by the "New Feature"-Tag.

Switching to DotNetStandard

The easiest part in this blogpost will be the switch to DotNetStandard. A colleague actually triggered me trying it after having had issues with KittyDI and the test project. Well, what can I say? I simply created a new Project in the solution, targeted DotNetStandard 1.0, copied all files to it and changed the reference in the test project. Basically the only changes I needed to to was switching between TypeInfo and Type in several places and replacing a.IsInstanceOfType(b) by b.IsAssignableFrom(a). 
After that all the projects compiled again and the tests ran green.


This one actually got lost while adding the reflection stuff.
The DirectoryCatalog simply scans a directory for assemblies, tries to load them and if it succeeds will create an AssemblyCatalog for each found assembly. The DirectoryCatalog itself will return the merged result of these AssemblyCatalogs. Since loading an assembly from a file is not supported in DotNetStandard (yet?), the DirectoryCatalog will be part of an extension that targets the regular .NET-Framework.

Fluent Syntax for ContainerBuilder

This is mainly convenience for the developer using the library. The goal is to give the developer an opportunity to do all registrations that PantherDI offers by calling methods on the ContainerBuilder.
Also the code that converts registrations to the knowledge base is moved out of the ContainerBuilder itself.

The ContainerBuilder now knows three ways to add something to the configuration which will then produce the DI-container:

  • Using a version of the Add-Method
    This enables the use of the collection initializer syntax too.
  • Using one of the With*-Methods
    These return the ContainerBuilder itself, so they can be chained.
  • Using one of the Register*-Methods
    These return a different object, which enables to change the registration using a fluent interface.

Since the collection initializer syntax is only available, when an object implements ICollection, the ContainerBuilder will enumerate over all catalogs, registrations and resolvers that it contains when enumerating its contents.

In addition a helper class for RegisterType has been introduced that enables configuring how the type should behave. By default it will neither use reflection to determine which contracts the type providdes nor use the constructors of the type as factories. This behavior can be changed however.

Also the With*-Methods contain convenience-methods, so the setup can be more concise when using the encouraged configuration. For example the method WithGenericResolvers will add all resolvers for generics that ship with PantherDI. If all but one should be used, the method WithoutResolver<T> can be used to remove the resolver again.

Adding CI/CD

Now it's getting real: I'm going to add the repository to Appveyor which will add Continous Integration to the project. Also I want to configure it that upon pushing a tag it will build a release, package it with NuGet and publish that in the Appveyour-NuGet-Stream that you get with registering a project. This means PantherDI is technically ready to be used.

During implementation of the CI/CD using AppVeyor, I decided to change how or specifically when a new release will be created: AppVeyor is set up to build each PullRequest in GitHub and upon merging them, push the resulting packages to NuGet. This means that for each PullRequest the version number in the AppVeyor-configuration needs to be updated.
Since AppVeyor is unable to change the version of a dependency, the required version of PantherDI needs to be updated in the PantherDI.DNF-Package whenever the major version of PantherDI is changed. Version numbering should be according to "Semantic Versioning" (


This does neither conclude the development of PantherDI, nor this series of blogposts. Instead all features I want to see in PantherDI are reflected in the issues on GitHub.


The code after implementing this blogpost can be found on GitHub under the Tag v1.0.0: Link


This chapter contains a cumulative list of terms that are used within this project.

The central element of PantherDI. 
It offers a way to retrieve instances of objects with all their transitive dependencies resolved.

Information about a single type, enabling a container to create it, resolve its dependencies and use it as dependency.

Any object that serves as the promise that a registration can be used as dependency. A registration can be retrieved only by contract, so the consumer does not need to know its actual type.

Basically the object representation of a function which will create an instance of a registered type.

Dependency (of a Factory or Provider, see below)
A single dependency of a factory is the object representation of one a function parameter. It includes meta-information, for example the contracts the instance passed needs to fulfil.

Created from a factory by resolving all the dependencies that can be resolved using the given registrations.

Knowledge Base (KB)
The knowledge base contains all providers that can be used by the container.

An algorithm that utilizes the knowledge base to return all providers for a given dependency.
It may create new providers from the ones given in the knowledge base, depending on its purpose.

Keine Kommentare:

Kommentar posten