16

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

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.

ответ

8

имеет интерфейс аннотацию HttpContext.Current. Expose только те методы, которые вам необходимы. GetUserName() назвал бы HttpContext.Current.User.Identity.Name в Например, сделайте это настолько тонким, насколько это возможно.

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

+0

Что значит «Добавить общий тип params to bags»? Звучит интригующе. –

+4

предоставить сильные типизированные обертки за сеанс –

+3

у вас есть какой-либо пример кода/ссылки, это кажется интересным _ am kinda new to DI, поэтому я не понимаю этого правильно, любая помощь/совет будут оценены ... – Haroon

2

Возможно, я что-то упустил, но вышеприведенный ответ не работает для меня (с тех пор он был удален - это был еще полезный ответ, хотя - он показал, как сообщить 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 дает подсказку о том, с чего начать, но он удалил его: *().

+0

В условиях, когда конструктор имеет зависимость от HttpContext, IoC будет проходить в экземпляре HttpContext.Current. И когда конструктор имеет зависимость от IUserProvider, IoC создаст экземпляр нового экземпляра HttpContextUserProvider и передаст его в конструктор. –

+0

Интерфейс StructureMap хорошо читается. Мое замешательство я думаю в двух частях: 1) Я только когда-либо использовал ForRequestedType - как узнать, когда выходить из строя BuildInstancesOf вместо этого (возможно, я могу просто просто сделать этот вопрос - просто вопрос) 2) Могу ли я просто принять как должное что StructureMap знает, как получить HttpContext.Current? Я предполагаю, что HttpContext немного смущает меня в том, что он, кажется, волнует все вокруг. Я не могу придумать ни одного источника, к которому я могу пойти, чтобы получить его, где все остальное имеет более ясный источник. – anonymous

+0

действительно мое решение не сработало - и с хардкорной ошибкой даже внутреннее исключение сказало что-то о ограничении JIT ... wow – sirrocco

3

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

+0

Yah ... Я не думаю, что я * получаю * HttpContext. Наверное, я привык к тому, что что-то прошло через конструктор, где, как HttpContext, кажется, есть глобально там? – anonymous

+0

Хорошо, сделал возврат HttpContext.Current.User.Identity.Name; и это работает. Я предполагаю, что я немного замедлен на этом, но текущее статическое свойство в HttpContext, которое несет ответственность за знание того, как найти текущий HttpContext. Единственный недостаток - вы не можете (я не думаю, по крайней мере) быть явным в зависимости от HttpContext через инъекцию конструктора, потому что вы не можете передать статическое свойство или тип? Вы можете сделать некоторую оболочку, такую ​​как IHttpContextProvider, которая просто возвращает HttpContext.Current, а затем вы знаете, что что-то зависит от HttpContext? Или это глупо. – anonymous

+0

Как бы вы ввели HttpContext в слове службы, который не ссылается на Интернет, возможно, мы могли бы сказать, что это сценарий использования для этого, где записи/набор данных зависят от текущего пользователя? (asp.net mvc2) ... – Haroon

9

Похоже, что вы должны использовать 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)); 
Смежные вопросы