Подтвердить что ты не робот

ASP.NET MVC: HTTPContext и зависимая инъекция

В настоящее время у меня есть ActionFilter, который получает имя текущего пользователя из HttpContext и передает его в действие, которое использует его для метода службы. например:

Service.DoSomething(userName);

У меня теперь есть причина сделать это не на уровне действия, а на уровне конструктора контроллера. В настоящее время я использую структуру структуры для создания контроллеров и ввода услуги. Я смотрю на что-то вроде:

public interface IUserProvider
{
    string UserName { get; }
}

public class HttpContextUserProvider : IUserProvider
{
    private HttpContext context;

    public HttpContextUserProvider(HttpContext context)
    {
        this.context = context;
    }

    public string UserName
    {
        get
        {
            return context.User.Identity.Name;
        }
    }
}

Тем не менее, мой IoC foo действительно слаб, так как это первый проект, в котором я его использовал.

Итак, мой вопрос... как я могу передать структуру структуры для передачи в HttpContext в конструкторе для HttpContextUserProvider? Это просто кажется странным... Я не уверен, как думать о HttpContext.

4b9b3361

Ответ 1

Имейте абстрактный интерфейс HttpContext.Current. Выставлять только те методы, которые вам нужны. GetUserName() будет вызывать HttpContext.Current.User.Identity.Name в реализации, например. Сделайте это настолько тонким насколько возможно.

Возьмите эту абстракцию и введите ее в свой другой класс провайдера. Это позволит вам протестировать поставщика, высмеивая абстракцию контекста HTTP. В качестве побочного преимущества вы можете делать другие отличные вещи с помощью абстракции HttpContext, помимо этого. Повторно используйте его, с одной стороны. Добавьте общие параметры типа в пакеты и т.д.

Ответ 2

Похоже, вы должны использовать HttpContextBase вместо HttpContextUserProvider. Это абстрактная абстракция HttpContext и позволяет вам создавать макет, писать UnitTests и вводить ваши зависимости.

public class SomethingWithDependenciesOnContext
{
    public SomethingWithDependenciesOnContext(HttpContextBase context) {
        ...
    }

    public string UserName
    {
        get {return context.User.Identity.Name;}
    }
}

ObjectFactory.Initialize(x => 
          x.For<HttpContextBase>()
          .HybridHttpOrThreadLocalScoped()
          .Use(() => new HttpContextWrapper(HttpContext.Current));

Ответ 3

Я не уверен, почему ты беспокоишься. Кажется, что просто использовать HttpContext.Current прямо в HttpContextUserProvider - это правильная вещь. Вы никогда не будете заменять другой HttpContext...

Ответ 4

Возможно, я что-то оставил, но приведенный выше ответ не работает для меня (с тех пор он был удален - это был еще полезный ответ, хотя - он показал, как сообщить SM, чтобы передать аргументы конструктора). Вместо этого:

ObjectFactory.Initialize(x =>
{
    x.BuildInstancesOf<HttpContext>()
         .TheDefault.Is.ConstructedBy(() => HttpContext.Current);
    x.ForRequestedType<IUserProvider>()
         .TheDefault.Is.OfConcreteType<HttpContextUserProvider>();
});

Я заработал. Я сделал это после обнаружения: http://codebetter.com/blogs/jeremy.miller/archive/2008/03/20/if-you-need-something-in-structuremap-but-you-can-t-build-it-with-new.aspx


изменить:

Благодаря ответу Брэда, я думаю, что я лучше разбираюсь в HttpContext. Его ответ определенно работает, я просто не уверен, что мне нравится иметь вызов HttpContext.Current внутри класса (похоже, что он скрывает зависимость, но я далек от эксперта по этому поводу).

Вышеприведенный код должен работать для инъекции HttpContext, насколько я могу судить. Мэтт Хинзе добавляет, что если все, что мне нужно из HttpContext, является User.Identity.Name, мой проект должен быть явным в этом отношении (имея интерфейс вокруг HttpContext, только разоблачающий то, что мне нужно). Я думаю, что это хорошая идея.

Дело в том, что я ждал, что мой сервис действительно зависит от строки: userName. Если это зависит от IUserProvider, возможно, не имеет большой добавленной стоимости. Поэтому я знаю, что не хочу, чтобы он зависел от HttpContext, и я знаю, что все, что мне нужно, это строка (имя_пользователя). Мне нужно узнать, могу ли я достаточно изучить StructureMap foo, чтобы установить это соединение для меня. (ответ sirrocoo дает подсказку о том, с чего начать, но он удалил его: *().