С LightInject, как я могу передать аргументы дочерним зависимостям без регистрации группы фабрик? - PullRequest
0 голосов
/ 06 декабря 2018

В приведенном ниже коде я пытаюсь внедрить ViewModel в View, в то время как ViewModel требует обернуть Model и другую службу, которая находится в контейнере.Модель не зарегистрирована, поскольку она на самом деле не является «службой».

Как мне:

a) не нужно предоставлять экземпляр IService в качестве аргумента (пусть контейнер разрешит его),

b) не нужно регистрировать фабрику для моих моделей ViewModels (будет много )

Так что я действительно прошу контейнер сделать так, чтобы он обработал моюМодель (которую я передаю в качестве аргумента), как если бы она была зарегистрированной «службой» на время этого вызова GetInstance.

Если это невозможно с LightInject, существуют ли какие-либо контейнеры, которые имеют что-токак это?

public static class Program
{
    public static void Main()
    {
        var container = new LightInject.ServiceContainer();
        var service = new Service1();
        container.RegisterInstance<IService>(service);

        // Have to register the factory
        container.Register<IService, PersonModel, PersonViewModel>(
                (f, s, p) => new PersonViewModel(s, p));

        container.Register<View>();

        var person = new PersonModel(); // this is contextual -- not a service.
        object view = CreateView(container, typeof(View), service, person);

        // ultimate desired code:
        //var view = container.GetInstance(typeof(View), new object[] { person });

    }

    private static object CreateView(ServiceContainer container, Type viewType, IService service, object model)
    {
        var ctor = viewType.GetConstructors()[0];
        var parameters = new List<object>();
        foreach (var param in ctor.GetParameters())
        {
            var attr = param.GetCustomAttributes(typeof(ModelAttribute), false).FirstOrDefault();
            if (model != null && attr != null)
            {
                parameters.Add(model);
            }
            else
            {
                parameters.Add(container.GetInstance(param.ParameterType, new object[] { service, model }));
            }
        }
        return Activator.CreateInstance(viewType, parameters.ToArray());
    }
}

public interface IService
{
}

public class Service1 : IService
{
}

public class PersonModel
{
}

public class PersonViewModel
{
    public PersonModel PersonModel { get; set; }
    public PersonViewModel(IService service, [Model] PersonModel person)
    {
        PersonModel = person;
    }
}

public class View
{
    public PersonViewModel PersonViewModel { get; set; }
    public View(PersonViewModel vm)
    {
        PersonViewModel = vm;
    }
}

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public class ModelAttribute : Attribute
{

}

1 Ответ

0 голосов
/ 11 декабря 2018

Я решил проблемы с помощью комбинации методов ...

a) использовать Scope и зарегистрировать ViewModel и View с PerScopeLifetime.

b) использовать зарегистрированный "ModelTracker"с фабрикой, позволяющей вводить экземпляр, не созданный контейнером (поскольку модели будут создаваться с помощью клиентского кода или DbContext).

Эта комбинация также позволяет мне не регистрировать фабрику для каждого типа ViewModel -- но вместо этого используйте встроенные функции массовой регистрации (например, RegisterAssembly).

public static class Program
{
    public static void Main()
    {
        var container = new LightInject.ServiceContainer();

        container.RegisterInstance<IService>(new Service1());

        container.Register<View>(new PerScopeLifetime());
        container.Register<PersonViewModel>(new PerScopeLifetime());
        container.Register<ModelTracker>(new PerScopeLifetime());
        container.Register<PersonModel>((f) => (PersonModel)f.GetInstance<ModelTracker>().Instance);

        using (var scope = container.BeginScope())
        {
            var tracker = scope.GetInstance<ModelTracker>();
            tracker.Instance = new PersonModel() { Name = "person1" };

            var view = scope.GetInstance<View>();
        }

    }

}

public class ModelTracker
{
    public object Instance { get; set; }
}

public class PersonModel
{
    public string Name { get; set; }

}

public class PersonViewModel
{
    private readonly IService service;
    private readonly PersonModel person;

    public PersonViewModel(IService service, PersonModel person)
    {
        this.service = service;
        this.person = person;
    }
}

public class View
{
    public PersonViewModel PersonViewModel { get; set; }
    public View(PersonViewModel vm)
    {
        PersonViewModel = vm;
    }
}

public interface IService { }
public class Service1 : IService { }
...