Eliminating the need of adding an empty constructor to bind navigation properties by using IL weaving and the Fody plugin EmptyConstructor.Fody.
Eliminating the need of adding an empty constructor to bind navigation properties by using IL weaving and the Fody plugin EmptyConstructor.Fody.
When designing a clean DDD solution, many times you need to pollute your domain with infrastructure code in order to get Entity Framework (EF) working. This blog series will look at some of these issues and how to resolve them.
When constructor parameters cannot be bound to properties, the Entity Framework requires an empty constructor. This happens for example when your constructor parameter is a navigation property. In this case EF will go via the emtpy constructor and bind the property directly.
If you check the EF Core documentation, it says:
EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor.
In our example we will have to define a protected empty constructor, since EF cannot bind the Specs property from the constructor:
public class Car
{
public Car(string name, Specs specs)
{
Name = name;
Specs = specs;
}
protected Car()
{
}
public CarHolder? CarHolder { get; protected set; }
public int Id { get; protected set; }
public string Name { get; protected set; }
public Specs Specs { get; protected set; }
}
However, this protected empty constructor is something we would like to get rid of, when designing a clean DDD domain entity. It doesn't belong to our domain logic.
With the help of IL Weaving
we can keep the domain model clean at design-time and weave the empty constructor into our entities at build-time. After some quick research we came across the very helpful Fody plugin EmptyConstructor.Fody, which does exactly that. The are only the following steps necessary:
<EmptyConstructor/>
to FodyWeavers.xml
family
, which is the IL equivalent of protected
In our case we configured the FodyWeavers.xml
to include only our domain entities in the Domain.Model namespace and below:
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<EmptyConstructor Visibility='family'>
<IncludeNamespaces>
OurProjectTitle.Domain.Model
OurProjectTitle.Domain.Model.*
</IncludeNamespaces>
</EmptyConstructor>
</Weavers>
Instead of polluting our domain entities with "unneccessary" (i.e. irrelevant for our business domain) protected empty constructor we end up with a clean domain entity class, not carrying any infrastructure code:
public class Car
{
public Car(string name, Specs specs)
{
Name = name;
Specs = specs;
}
public CarHolder? CarHolder { get; protected set; }
public int Id { get; protected set; }
public string Name { get; protected set; }
public Specs Specs { get; protected set; }
}
And thanks to the Fody plugin, after the build, EF Core will find an empty constructor, which allows it to set the Specs
value object.
The part 3 of our series will take a closer look at the setters in our properties, which we are not using at the moment.