С LightInject, как я могу передать аргументы дочерним зависимостям без регистрации группы фабрик?

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

Как я:

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

б) не нужно регистрировать фабрику для моих 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 ответ

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

а) используйте 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 { }
Другие вопросы по тегам