Constructor injection on deserialization with the csharp driver

Hello,

We need to use the following pattern in our application for our entities since our polymorphic objects have different behaviors needing different external dependencies depending on their type:

public abstract class TypeA
    {
        // Your polymorphic method
        public abstract void AbtractMethod();
        // Only exposing this for the purpose of demonstration
        public abstract IDependency Dependency { get; }
    }
    public class TypeB : TypeA
    {
        private readonly ISpecializedDependencyForB _dependency;
        public TypeB(ISpecializedDependencyForB dependency)
        {
            _dependency = dependency;
        }
        public override void AbtractMethod()
        {
           // Do stuff with ISpecializedDependencyForB without leaking the dependency to the caller
        }
        // You hopefully won't need this prop
        public override IDependency Dependency
        {
            get { return _dependency; }
        }
    }

    public class TypeC : TypeA
    {
        private readonly ISpecializedDependencyForC _dependency;
        public TypeC(ISpecializedDependencyForC dependency)
        {
            _dependency = dependency;
        }
        public override void AbtractMethod()
        {
           // Do stuff with ISpecializedDependencyForC without leaking the dependency to the caller
        }
        public override IDependency Dependency
        {
            get { return _dependency; }
        }
    }

Json.NET allows injecting constructor dependencies during deserialization through their through their ContractResolver abstraction. However I cannot find an equivalent feature with the MongoDB csharp driver, which I find surprising considering the vast efforts that went into providing best-in-class support for polymorphism in MongoDB.

2 Likes

I have the same problem. Did you find the answer? Thanks to AI, search engines are incapable of finding tech resources.

Unfortunately no, I haven’t found any solution for this and we have since moved to another database for a variety of reasons.

@R_B and @Nima_Niazmand

This defeats the design of the C# driver, the purpose of the driver is to map to BSON data.

MongoDB’s C# driver uses class mapping to map BSON documents from the database to C# objects. But the issue is that the Driver doesn’t do constructor injection during deserialization.

You deserialize your MongoDB documents into instances of TypeB and TypeC , the DI container will automatically provide the required dependencies. But it doesn’t support the injection, you’d need something else to do that.

This can be done with the C# Injection using .NET’s built-in DI framework (or any other DI framework you prefer) to provide instances of ISpecializedDependencyForB and ISpecializedDependencyForC when needed.

Does this make sense?

I had the same issue when I was building a blockchain based .Net server recently and had to dig in the Drivers source on GitHub.

It doesn’t support direct injection and that causes your problem. I used the normal .NET DI Framework to do all this instead.

No, It’s obviously not possible with built-in DI or any other DI. The purpose of Newtonsoft.Json is to map to JSON. But it provides extendibility. Lack of extendibility is a bad design.

1 Like

It’s up to you, but I’d try .Net’s built in DI Framework.

You should try to learn its not possible.

It seems like you may not be understanding the use case we are trying to address. Injecting dependencies in our application generally speaking IS NOT what we are trying to do, injecting dependencies in our entities as they are being deserialized IS what we are trying to do.

When a library is properly designed and is extensible like for example JSON.NET, you can do this kind of thing, and you’d typically configure the library to use the built-in DI of .NET to resolve dependencies during deserialization. But the library needs to expose proper extensibility points to make it possible. As you can see, the problem is not about using built-in DI or not, this is besides the point. There are a number of reasons for wanting to inject dependencies at deserialization, the polymorphic dependencies example I posted is one of them, but there are others.

1 Like

@Nima_Niazmand Actually I remember what we did, we used a static ServiceLocator inside our entities instead of doing constructor injection, something looking like:

public class MyEntity
{
    IDependency _dependency => StaticDomainServiceProvider<IDependency>.GetInstance();
}

And then somewhere in the entry point of your application (startup.cs or program.cs for example)

StaticDomainServiceProvider<IDependency>.GetInstance = serviceProvider.Resolve<IDependency>()

This is the overally idea. If you use ASP.NET Core, make sure to use an HttpContextAccessor to get the scoped serviceProvider for the HttpContext of the current request instead of hooking into the root scope as I’ve done in the example above, otherwise you may have lifetime issues with your injected dependencies (for example the “scoped” lifetime may not be what you expect it to be since it will not be tied to the lifetime of the request as you’d probably expect).

This approach works well and is a good enough compromise, but we were hoping to leave it behind once for all because constructor injection has a number of benefits (no need to add configurations in the entry point of the application, dependencies are more explicit while remaining encapsulated enough - if the deserialization library is able to inject them - etc…)

Thank you @R_B
I wanted to avoid static properties, but it seems it’s the only solution that works. I appreciate your help.

@R_B

If you don’t mind me asking, what is the benefit of this approach in your use case?

Any pros/cons? And I apologize for the misunderstanding of your use case.

I honestly haven’t seen this need before, and honestly I’m a little puzzled at the concept for use case reasons.

I would greatly appreciate more feedback on this, as I love learning things that are new.

You may want to look into Domain Driven Design. The need for the approach above typically arise when you need to deserialize rich domain models rather than basic POCOs because a rich entity may need external services (domain services) to do its job. This is one of the use cases of this approach.

I’m familiar with DDD, but most often just DI the data as stated above.

Is there by chance a sample project I can get a hold of that demonstrates this design that isn’t working so far for you?

No unfortunately I do not have time for that, however the sample included in the original post should already provide you what you are asking for.

My feeling is that at this point, what may actually be lacking is a similar code sample describing the solution you are alluding to. But I’m pretty sure you are not adressing the same problem.