3

Я занимаюсь этим вопросом в течение нескольких часов, поэтому я решил написать и попросить о помощи.Внедрение в другой проект/сборку

Есть много ответов уже на этом форуме, которые я могу определить как решение моей проблемы, но я просто не могу соединить все точки внутри моей головы; и я не делаю этого.

Я пытаюсь изменить инжектор на большое приложение MVC, от StructureMap до SimpleInjector.

Мне нужно правильно передать текущего пользователя HttpContext другому проекту в том же решении, содержащем все репозитории и DBContext, чтобы его можно было использовать/записывать, когда выполняю некоторые операции CRUD.

Я явно не понял, как была создана проводка StructureMap; Мне было сложно. Я это на проекте MVC (может предоставить больше информации, потому что десятка классов с использованием StructureMap):

public class GlobalRegistry : StructureMap.Registry 
{ 
    public GlobalRegistry() 
    { 
     For<INotificationRepository>().Use<NotificationRepository>(); 
     ... 

и на репозиториев проекта/класс:

public class NotificationRepository : BaseRepository,INotificationRepository 
{ 
    public NotificationRepository(string userContext) : base(userContext) { } 

(... по magic ...) конструктор будет использовать параметр userContext для использования позже в вызываемом методе.

После замены SimpleInjector я не понимаю, как этот параметр вводится.

Для целей тестирования, это работает:

container.Register<INotificationRepository>(() => new NotificationRepository("username"), 
    Lifestyle.Singleton); 

Я прочитал, что я не должен вводить HttpContext в конструкторе, так как это является переменной во время выполнения, и я понимаю, почему.

Дальше Я пробовал IUserContextFactory, но это тоже не сработало.

На том же проекте MVC, у меня есть свой класс:

public static class ObjectFactory 
{ 
    private static SimpleInjector.Container _container; 

    public static void SetContainer(Container container) 
    { 
     ObjectFactory._container = container; 
    } 

    public static T GetInstance<T>() where T : class 
    { 
     return _container.GetInstance<T>(); 
    } 
} 

Я использую этот класс, чтобы хранить контейнер после container.Verify();

ObjectFactory.SetContainer(container); 

На любом контроллере MVC Я использую его, как это :

IUserContext ctxUser = ObjectFactory.GetInstance<IUserContext>(); 

Я также пробовал что-то вроде следующего в репозитории на протяжении всего моего но я всегда получаю нуль UserName.

public NotificationRepository(IUserContext userContext) : base(userContext) { } 

(общий интерфейс между проектом MVC и проектом хранилища)

public interface IUserContext 
{ 
    string Username { get; set; } 
} 

более важен, чем знать решение, я хотел бы понять, как решение работает и преодолеть трудности, у меня были в течение последних нескольких часов пытался понять и решить эту проблему.

+0

Ну, также должна быть регистрация для контекста в 'StructureMap', конвертировать его в другой синтаксис. Кстати, этот «Lifestyle.Singleton» выглядит не очень хорошо. –

+0

Я не понимаю, какова ваша фактическая проблема, где вы застряли и что именно вы пытаетесь понять. – Steven

+0

@ Герт Арнольд, не нашел контекста на вставке StructureMap. Когда пользователь входит в систему, он остается прежним до тех пор, пока он не выйдет из системы, где я что-то пропущу? Несколько пользователей !? – chapas

ответ

1

Передача примитивного значения времени выполнения в качестве параметра для конструктора напрямую не доступна в Simple Inject.Вместо этого вы можете ввести компонент, который позволит вам получить это значение во время выполнения, поэтому ваш подход с IUserContext кажется хорошим способом, он должен работать. Измените свой класс, чтобы добавить этот компонент в свой конструктор вместо строки userName. Зарегистрируйте новый компонент и дайте ему контейнер вставлять его автоматически при вызове конструктора.

Пример реализации:

class HttpSessionUserContext : IUserContext 
{ 
    //Your specific implementation of getting the user name from your context 
    public string CurrentUserName => (string)HttpContext.Session["userName"]; 
} 

Регистрация:

container.Register<IUserContext, HttpSessionUserContext>(Lifestyle.Scoped); 
container.Register<INotificationRepository, NotificationRepository> (Lifestyle.Scoped); 

Here у вас есть больше информации о причине, почему проходящие параметры примитивным времени выполнения в конструкторах не реализован в простом Inject.

О сфере Образ жизни: Вы, вероятно, не должны использовать Lifestyle.Singleton в качестве своей возможности для этого компонента, так как он будет создан только один раз и повторно использован как одноэлементный. В веб-приложениях вы обычно хотите применить область Per-HttpRequest. Вы можете сделать это следующим образом: после создания контейнера определяют его объем по умолчанию, как WebRequestLifestyle или WebApiRequestLifestyle:

var container = new Container(); 
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle(); 

И тогда, когда вы регистрируете ваши компоненты используют значение Lifestyle.Scoped, который будет применяться по умолчанию области видимости Стиль:

container.Register<SomeInterface, SomeClass>(Lifestyle.Scoped); 

Edit: согласно Steven «s комментарий, в этом случае было бы лучше регистрировать HttpSessionUserContext как Singleton, потому что он является лицом без гражданства. В целом, Singleton имеет лучшую производительность, поскольку он создается только один раз и делится, но будьте осторожны с компонентами, которые не являются апатридами или имеют зависимости от других компонентов.

Кроме того, убедитесь, что вы зарегистрировали свои контроллеры MVC и присвоили экземпляр вашего контейнера MVC DependencyResolver. Это то, что действительно позволяет автоматически разрешать и вводить параметры в конструкторах в контроллерах. Я думаю, вы сделали это в своем обработчике событий Application_Start.

container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); 
container.Verify(); 
DependencyResolver.SetResolver(
     new SimpleInjectorDependencyResolver(container)); 
+0

Согласен с вашим ответом, Диана, спасибо за вашу помощь. Я вставляю IUserContext в LoginControler, а затем получаю имя пользователя после правильного входа в систему, который останется неизменным до выхода из системы, но не может ничего не видеть в этой ситуации. – chapas

+0

Поскольку класс 'HttpSessionUserContext' является апатридом, он может быть зарегистрирован как singleton, и поэтому мой совет должен фактически зарегистрировать его как singleton. Нет никакого вреда в этом.На самом деле, я считаю хорошей практикой иметь как можно больше синглтон-регистраций. – Steven

+0

@Steven Вы правы, это будет лучше, лучше, лучше. Я использую для регистрации вещи в соответствии с запросом, как консервативный подход, если производительность не является критичной, но регистрация Singleton более эффективна. Просто будьте осторожны с компонентами, которые не являются апатридами или имеют зависимости от других компонентов. – Diana