Search code examples
c#asp.netdependency-injectionstructuremap

Why StructureMap container doesn't return the control then calling GetInstance?


I have following registration of the service:

For<Internal.FullPdfExporter>().Use<Internal.FullPdfExporter>();

I have a exporter factory to create different exporters. First of all injected StructureMap container to this factory:

private readonly IContainer _container;
public ExporterFactory(IContainer container)
{
   _container = container;
}

Then i use following code to get a instance of FullPdfExporter:

private IExporterBase CreateInstance(Type exporterType)
{
    return _container.GetInstance(exporterType) as IExporterBase ;
}

But this code doesn't return control at all. What's the problem is here?

I tried to check all registered instances in debug, and notices that container has registration for "Internal.FullPdfExporter".

Note: Internal is a alias for namespace;

How i get exporter from factory (code of business service which is called from Http Controller):

var task = Task.Run(async () =>
{               
    foreach (var item in exportData.OrderBy(x => x.ExportUid))
    {
        var exporter = _exporterFactory.GetBookExporter(param1, param2);
        await exporter.StartExport(item.ExportUid);
        if (!exporter.IsCompletedSuccessfully)
        {
            break;
        }
    }
});
return response;

Note: If to place _exporterFactory.GetBookExporter call before the task.Run, everything works good. Container is able to resolve the dependency.

Code of the GetBookExporter method:

public IExporterBase GetBookExporter(BookSchema bookSchema, PublishProfileType publishProfileType)
{
   return CreateInstance(typeof(Internal.FullPdfExporter)); 
}

Solution

  • Your general logic is flawed. You expect things to run, even after your http call is already over.

    Once you return a response, things happen in the ASP.NET framework.

    Dependency injection containers finish their scope, objects get disposed.

    Keeping those references that are probably scoped or transient in nature until after the call has completed is not going to work. Granted, sometimes it might work, when you have classes that do not implement IDisposable or you just get lucky with a microsocond timing, but generally speaking, this is not anticipated and not meant to work.

    If you want to do work after sending out the reply, you have to hand this work over to another party. Maybe you save it into a database and another service picks it up and works on it. Or maybe you have another program or thread running and you try some IPC. But you should not expect threads or tasks referencing things from the scope of your http call to work after it's done.