1

在下面的代码中,我试图将 ViewModel 注入到 View 中,而 ViewModel 需要一个模型来包装和容器中的另一个服务。该模型未注册,因为它不是真正的“服务”。

我如何能:

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
{

}
4

1 回答 1

0

我已经用多种技术解决了这些问题......

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 { }
于 2018-12-11T17:24:03.100 回答