voxtm
voxtm

Reputation: 490

How to assign new value to object created by Autofac and pass to the constructor of another injected object?

I'm implementing dependency injection with Autofac. I have trouble using the correct instance of an object that I pass into the component constructor.

My intention here is for the Autofac to create both ReportFileGenerator and ReportDefinition and then change the values of ReportDefinition by the post action in the controller before creating the ReportFileGenerator so the updated value can be passed as its parameter.

I have a ReportController:

public class ReportController
{        
    private readonly IReportFileGenerator _reportFileGenerator;

    private IReportDefinition _reportDefinition;

    public ReportController(            
        IReportFileGenerator reportFileGenerator,
        IReportDefinition reportDefinition
    {
        _reportFileGenerator = reportFileGenerator;
        _reportDefinition = reportDefinition;
    }

(...)

    [HttpPost]
    public ActionResult Report(ReportViewModel viewModel)
    {            
        _reportDefinition = viewModel.ReportDefinition

        return _reportFileGenerator.GenerateReportFile();
    }
}

ReportFileGenerator

public class ReportFileGenerator : IReportFileGenerator
{
    private readonly IReportDefinition _reportDefinition;

    public ReportFileGenerator(
        IReportDefinition reportDefinition)
    {            
        _reportDefinition = reportDefinition
    }

    public FileContentResult GenerateReportFile()
    {
        [some logic to generate file result using reportDefinition] 
    }
}

and finally my registrations:

builder.RegisterType<ReportFileGenerator>()
   .As<IReportFileGenerator>()
   .InstancePerRequest();

builder.RegisterType<ReportDefinition>()
   .As<IReportDefinition>()
   .InstancePerRequest();

The problem is the ReportDefinition that is being passed into the ReportFileGenerator does not have values assigned in the controller action (it is just a brand new instance with default values).

Upvotes: 1

Views: 418

Answers (1)

Nkosi
Nkosi

Reputation: 247008

Review the current design. It appears that ReportDefinition should be used as an explicit dependency for IReportFileGenerator.GenerateReportFile()

public interface IReportFileGenerator {
    FileContentResult GenerateReportFile(ReportDefinition reportDefinition);
}

You appear to be using ReportDefinition more like a model, than a service. I see no need to be injecting it via constructor.

public class ReportFileGenerator : IReportFileGenerator {

    public FileContentResult GenerateReportFile(ReportDefinition reportDefinition) {
        //[some logic to generate file result using reportDefinition] 
    }
}

Which would allow the controller to invoke the IReportFileGenerator as intended

public class ReportController { 
    private readonly IReportFileGenerator reportFileGenerator;

    public ReportController( IReportFileGenerator reportFileGenerator) {
        this.reportFileGenerator = reportFileGenerator;
    }

    //(...)

    [HttpPost]
    public ActionResult Report(ReportViewModel viewModel) { 
        ReportDefinition reportDefinition = viewModel.ReportDefinition;    
        return reportFileGenerator.GenerateReportFile(reportDefinition);
    }
}

In your original design, you appear to misunderstand how to use DI in that situation.

Upvotes: 2

Related Questions