Search code examples
c#dependency-injectionconstructor-injection

DI using dynamic constructor injection


I have a problem using DI with constructor properties. I am building a PDFBuilder based on my IPDFBuilder.

public interface IPDFBuilder
{
    string templatefilepath { get; }
    string templatefilename { get; }
    Dictionary<string, string> dict { get; }    
    void CreatePDF();
}

public class PDFBuilder : IPDFBuilder
{
    public string templatefilename { get; private set; }
    public string templatefilepath { get; private set; }
    public Dictionary<string, string> dict { get; private set; }

    public PDFBuilder(string templatefilename, string templatefilepath, Dictionary<string, string> dict)
    {
        this.templatefilename = templatefilename;
        this.templatefilepath = templatefilepath;
        this.dict = dict;
    }

    public void CreatePDF() {
        //Do something
    }
}

This PDFBuilder can and will be used in multiple controllers, for example:

public class KeuringController : Controller
{
    private IPDFBuilder _PDFBuilder;
    public KeuringController(IPDFBuilder pdfBuilder)
    {
        _PDFBuilder = pdfBuilder;
    }
    //Action methods that use `PDFBuilder` below...
}

However, I can't set the properties of PDFBuilder in the startup class (where DI registration is beeing done) because different controllers will use different values for the properties of the PDFBuilder class. 1 simple solution would be to just make the setters of the properties public so in an action method I can set the values and then call CreatePDF(). However this doesn't feel right. Another simple solution would be to remove the class properties and just pass the 3 properties of PDFBuilder as method properties to the CreatePDF method like this:

public void CreatePDF(string templatefilename, string templatefilepath, Dictionary<string, string> dict) {
        //Do something
    }

But now let's say that my PDFBuilder whould have 10 methods which all need these 3 properties. Then this is not the correct solution right?

What would be the correct solution then? I have encountered this problem multiple times with different classes/interfaces implementations and would like to have some help with designing in these situations.


Solution

  • You are injecting runtime data into your component's constructor, which is a bad thing. The solution is to move those runtime values out of the constructor into the CreatePDF method:

    public interface IPDFBuilder
    {
        void CreatePDF(string templatefilepath, string templatefilename,
            Dictionary<string, string> dict);
    }