3

I'm trying to build a package for Lamar for a framework which I maintain. To show what I mean by reference to StructureMap, the relevant method which was able to mix a runtime object with Service abstractions is (where the container is passed in to the constructor of this factory class):

public IPresenter Create(Type presenterType, Type viewType, IView viewInstance)
{
    container.Configure(x => x.For(presenterType)
        .Use(presenterType)
        .Named(presenterType.Name)
        );

    var args = new ExplicitArguments();
    args.Set("view");
    args.SetArg("view", viewInstance);

    return (IPresenter)container.GetInstance(presenterType, args);
}

I realise that Lamar does not implement ExplicitArguments (fair enough).

I played around with the Injectable feature, but was no able to get that to work:

public IPresenter Create(Type presenterType, Type viewType, IView viewInstance)
{
    var c = _container.GetNestedContainer();
    c.Inject(viewInstance);

    // return c.GetInstance(presenterType, presenterType.Name.ToString()) as IPresenter; // BOOM!!!

    return _container.GetInstance(presenterType) as IPresenter; // BOOM!!!
}

Is there an alternative way in Lamar?

This is my registration code:

IContainer container = new Container(c =>
{
    c.AddTransient<ISomeService, SomeService>();
    c.Injectable<IMainView>();
    c.AddTransient<MainPresenter>();
});    

I have created a sample project which recreates the issue which can be downloaded here. It uses .NET 5

In that project, if you put a break-point in the class MainPresenter, you will see that the IView parameter is null and the OrdersService does resolve.

I need that concrete object, which is the main form, to be passed in as well (as the IView).

Cheers

onefootswill
  • 3,707
  • 6
  • 47
  • 101
  • I seem to have got this working with the above code. The mistake that I was making was that I was registering the injectable as IView instead of the interface which inherited from IView, namely IMainView. So, `c.Injectable();` – onefootswill Dec 13 '20 at 02:00
  • I have spoken too soon. This does not work. The IView is null when the IPresenter is resolved. I've updated the answer with the registration code which I am using. – onefootswill Dec 28 '20 at 06:41
  • Please [edit] your question to include the full source code you have as a [mcve], which can be compiled and tested by others. Also see: [What Do You Mean “It Doesn't Work”?](https://meta.stackexchange.com/q/147616). What exactly do you mean by "BOOM!!!"? Do you get an exception? – Progman Dec 28 '20 at 23:43
  • @Progman I have added a link to a zip file with a sample project which recreates the issue. I was initially getting an exception and forgot to remove the references to BOOM when I posted the question. Thanks. – onefootswill Dec 29 '20 at 07:59
  • Do not add the source code on an external site, add the MCVE to the question itself. – Progman Dec 29 '20 at 10:57

1 Answers1

2

there is a problem with LamarPresenterFactory.Create method viewInstance parameter

public IPresenter Create(Type presenterType, Type viewType, IView viewInstance)
{
}

I've noticed that it should be of IMainView type like below

public IPresenter Create(Type presenterType, Type viewType, IMainView viewInstance)
{
    var nestedContainer = _container.GetNestedContainer();
    nestedContainer.Inject(viewInstance);

    return nestedContainer.GetInstance(presenterType) as IPresenter;
}

nestedContainer.Inject(viewInstance) parameter data type requires viewInstance to be the same type that was used with c.Injectable<IMainView>();

I'm getting OrdersService.GetOrders exception since there is no orders.zip file available

oleksa
  • 3,688
  • 1
  • 29
  • 54
  • `IMainView` inherits `IView`. Unfortunately, that parameter has to be IView, otherwise we'd have to write a Create method for every presenter. And the Create method is from a general interface which all supported DI containers implement (only 2 so far). I originally tried registering with `c.Injectable();` , but an exception is thrown at the call for `GetInstance`. – onefootswill Dec 30 '20 at 01:01
  • @onefootswill it looks wierd since you are declaring to `IMainView` to be injected but whant to get `IView` instance injected instead. It may cause `Create` will get `IView` parameter instance (not `IMainView`) and how do you think container will inject `IView` to the `presenterType` instead of `IMainView`? You may configure container as `c.Injectable();` and this allow to inject `IView` instance into presenterType constructor. – oleksa Dec 30 '20 at 09:11
  • It looks like Lamar does not have the capability that I am after yet. If you look at the top of my post, it was possible with StructureMap. The `ExplicitArguments` are configured right there and then in the `Create` method. I've also implemented it with `SimpleInjector` and `Autofac`, who both have different, yet effective, ways of doing it. It's no big deal. I'll support as many IOC frameworks as I can. If Lamar supports it in the future, I'll add support. If it does now and someone can show me how, likewise. Lamar looks great, so I'll definitely support it if I can. Cheers. – onefootswill Dec 30 '20 at 22:24