0
votes

I am running an MVC app that contains a number of services (that call other services/helpers/etc). I am trying to inject parameter values that are only known at runtime using the strategy outlined

https://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container

As mentioned in the article it is preferable to not simply use Unity as a ServiceLocator - as well, I would much prefer not to new-up an instance of the UnityContainer (and write a fairly ugly Resolve statement) every time I want to do anything out of the ordinary (like inject runtime parameters).

The article is now a couple of years old and Unity now supports TypeFactory and DelegateFactory types, so it could easily be improved but the idea of injecting a delegate into the constructor to go and get your parameter values nicely decouples the process (note I'm happy to discuss equally decoupled strategies such as abstracting to a factory)

I'm almost there with the delegate approach described in the article however although I can inject the delegate and get the delegate to call out to get the values in an abstracted class, the instance of that class is different to the one where I place the values, hence the values the delegate call sees are null

I've tried using named registrations, and tried different lifetime options to no avail - typically it makes little difference or Unity doesn't pickup the resolution and I get the ...make sure there is parameterless constructor... exception message. Also note that if I am off the mark with how the parameters are assigned and retrieved, feel free to comment

The essence of my code is as follows

Bootstrap:

container.RegisterType<IExportDetail, ExportDetail>();
container.RegisterType<IExportHelper, ExportHelper>();

container.RegisterType<Func<IExportDetail>>(
    new InjectionFactory(c =>
    //new Func<string, IExportDetail>(name => c.Resolve<IExportDetail>(name))));
    new Func<IExportDetail>(() => container.Resolve<IExportDetail>())));

Abstracted parameter declarations:

public interface IExportDetail
{
    string Parm1{ get; set; }
    string Parm2{ get; set; }
}
public class ExportDetail : IExportDetail
{
    public string Parm1{ get; set; }
    public string Parm2{ get; set; }
}

Helper/Service being called:

public class ExportHelper : IExportHelper
{
    private IExportDetail _service;
    public ExportHelper(
            Func<IExportDetail> serviceFactory
        )
    {
        _service = serviceFactory();
        _parm1 = _service.Parm1; // <--!!this is null!!
        _parm2 = _service.Parm2; // <--!!this is null!!
    }
}

Caller :

IExportHelper _exportHelper; //<--DI'd
IExportDetail _exportDetail; //<--DI'd

_exportDetail.Parm1 = parm1ValueSetAtRuntime;
_exportDetail.Parm2 = parm2ValueSetAtRuntime;
return _exportHelper;
1
I think your main issue is that what you are trying to inject is not a service, it is a data container. Services generally don't contain any state - they contain business logic to be executed (and may be passed a model such as your ExportDetail, which would not need an interface). See this article to understand the difference between newables (which you should just use the new keyword for) and injectables. - NightOwl888
Thanks NightOwl - I read the article in your post - I can see that my DTO (ExportDetail) doesn't need to be instantiated via Unty as it is simply a DTO. However for my requirement, the only reason it was created was to inject - if there is a better approach it can easily be dismissed - if for example it can be replaced by a factory for ExportHelper then as a strategy I'm good to go with that - the question I'm asking is how this is done - TerrorBight
I have seen numerous examples on the Internet - they fall into three categories - (a) a service locator (b) they register/resolve via the Unity container within the service code (c) use a delegate or factory to inject and centralize all Register Unity code within the Bootstrap - my preference is (c) - but as in the article in my original post, it doesn't actually show how/where to actually assign the run-time value(s) - TerrorBight

1 Answers

0
votes

You can register some instance of type in runtime, see example below.

By the way, it's very strange that you want register instance of some data object using Unity and put it into helpers\services, see comment of NightOwl888. (I don't know how reply to comment from answer)

Bootstrap:

container.RegisterType<Func<string, IExportDetail>>(
    new InjectionFactory(c =>
    new Func<string, IExportDetail>(name => c.Resolve<IExportDetail>(name))));

Register object in runtime:

container.RegisterInstance<IExportDetail>("someName", new ExportDetail
{
    Param1 = parm1ValueSetAtRuntime,
    Param2 = parm2ValueSetAtRuntime
});

Helper:

public ExportHelper(Func<string, IExportDetail> serviceFactory)
{
    IExportDetail exportDetail = serviceFactory("someName");
    // Use here exportDetail
}