1

Если я запустил приложение и разрешил его, он отлично работает.MVC - простой инжектор и атрибут, вызывающий исключения для исключения контекста (EF)

Однако, когда я отлаживаю приложение и закрываю вкладку браузера, прежде чем он инициализирует что-либо, а затем вызывает другое, как localhost:81/Home/Test, он выдает исключение при извлечении данных из БД (EF).

Это исключение возникает во время вызова фильтра CultureResolver, который затем вызывает LanguageService. Внутри LanguageService есть вызов БД для извлечения всех доступных языков.

Я получил много различных исключений, как:

  • контекст не может быть использована в то время как модель создается. Это исключение может быть выбрано, если контекст используется в методе OnModelCreating или если один и тот же экземпляр контекста обращается к нескольким потокам одновременно. Обратите внимание, что члены экземпляра DbContext и связанные с ними классы не гарантируют безопасность потоков.
  • Ссылка на объект не установлена ​​в экземпляр объекта.
  • Исходный провайдер не смог открыть Open.

Эти исключения происходят в одном запросе, это зависит от того, сколько времени я оставил на первой вкладке.

Так кажется, что это что-то вроде Thread-Unsafe code или этот запрос пытается получить элементы до инициализации Context.

Я следующее:

SimpleInjectorInitializer.cs

public static class SimpleInjectorInitializer 
{ 
    /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary> 
    public static void Initialize() 
    { 
     var container = new Container(); 
     container.Options.DefaultScopedLifestyle = new WebRequestLifestyle(); 

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

     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, container); 
    } 

    private static void InitializeContainer(Container container) 
    { 
     container.Options.DefaultScopedLifestyle = new WebRequestLifestyle(); 

     /* Bindings... */ 

     container.RegisterPerWebRequest<IAjaxMessagesFilter, AjaxMessagesFilter>(); 
     container.RegisterPerWebRequest<ICustomErrorHandlerFilter, CustomErrorHandlerFilter>(); 
     container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>(); 
    } 
} 

FilterConfig.cs

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container) 
    { 
     filters.Add(container.GetInstance<ICultureInitializerFilter>()); 
     filters.Add(container.GetInstance<ICustomErrorHandlerFilter>()); 
     filters.Add(container.GetInstance<IAjaxMessagesFilter>()); 
    } 
} 

CultureResolver.cs

public class CultureResolver : ICultureResolver 
{ 
    ILanguageService Service; 
    public CultureResolver(ILanguageService Service) 
    { 
     this.Service = Service; 
    } 

    public string Resolve(string CultureCode) 
    { 
     // Get the culture by name or code (pt/pt-pt) 
     ILanguageViewModel language = Service.GetByNameOrCode(CultureCode); 

     if (language == null) 
     { 
      // Get the default language 
      language = Service.GetDefault(); 
     } 

     return language.Code; 
    } 
} 

LanguageService.cs

public class LanguageService : ILanguageService 
{ 
    IMembership membership; 
    ChatContext context; 
    ILanguageConverter converter; 

    public LanguageService(
      ChatContext context, 
      IMembership membership, 
      ILanguageConverter converter 
     ) 
    { 
     this.membership = membership; 
     this.context = context; 
     this.converter = converter; 
    } 

    public virtual ILanguageViewModel GetByNameOrCode(string Text) 
    { 
     string lowerText = Text.ToLower(); 
     string lowerSmallCode = ""; 

     int lowerTextHiphen = lowerText.IndexOf('-'); 
     if (lowerTextHiphen > 0) 
      lowerSmallCode = lowerText.Substring(0, lowerTextHiphen); 

     Language item = this.context 
          .Languages 
          .FirstOrDefault(x => x.Code.ToLower() == lowerText 
               || x.SmallCode.ToLower() == lowerText 
               || x.SmallCode == lowerSmallCode); 
     return converter.Convert(item); 
    } 

    public virtual ILanguageViewModel GetDefault() 
    { 
     Language item = this.context 
          .Languages 
          .FirstOrDefault(x => x.Default); 
     return converter.Convert(item); 
    } 
} 

Это запрос, который дает мне исключения

Language item = this.context 
        .Languages 
        .FirstOrDefault(x => x.Code.ToLower() == lowerText 
             || x.SmallCode.ToLower() == lowerText 
             || x.SmallCode == lowerSmallCode); 

ответ

1

Глобальные фильтры в MVC и Web API являются одиночками. В течение всего срока службы вашего приложения есть только один экземпляр такого фильтра. Это становится очевидным, когда вы смотрите на следующий код:

filters.Add(container.GetInstance<ICultureInitializerFilter>()); 

Здесь вы решить фильтр один раз из контейнера и хранить его в течение всего срока службы контейнера.

Вы однако, зарегистрировали этот тип, как Scoped с помощью:

container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>(); 

Вы эффективно говорят, что должен быть один экземпляр на веб-запрос, скорее всего потому, что класс зависит от DbContext, который не является потокобезопасный.

Чтобы разрешить вашим фильтрам иметь зависимости, вы должны либо сделать их humble objects, либо обернуть их в скромный объект, который может их называть. Например, вы можете создать следующие действия фильтра:

public sealed class GlobalActionFilter<TActionFilter> : IActionFilter 
    where TActionFilter : class, IActionFilter 
{ 
    private readonly Container container; 
    public GlobalActionFilter(Container container) { this.container = container; } 

    public void OnActionExecuted(ActionExecutedContext filterContext) { 
     container.GetInstance<TActionFilter>().OnActionExecuted(filterContext); 
    } 

    public void OnActionExecuting(ActionExecutingContext filterContext) { 
     container.GetInstance<TActionFilter>().OnActionExecuting(filterContext); 
    } 
} 

Этот класс позволяет добавлять глобальные фильтры следующим образом:

filters.Add(new GlobalActionFilter<ICultureInitializerFilter>(container)); 
filters.Add(new GlobalActionFilter<ICustomErrorHandlerFilter>(container)); 
filters.Add(new GlobalActionFilter<IAjaxMessagesFilter>(container)); 

GlovalActionFilter<T> будет обратного вызова в контейнер для решения прилагаемое типа каждый время называется. Это предотвращает зависимость от captive, которая предотвращает возникшие у вас проблемы.

+0

Вы рок! Хорошо, но так кажется неправильным использование слова «Синглтон» столько раз, что я его избегаю. Я попробую это и обращусь к вам –

+0

Однако, я пытаюсь использовать код, который вы дали, но я не знаю, как использовать предикат вроде этого, он просто дает мне компиляционную ошибку. –

+0

@LeandroSoares: Это означает, что вы все еще используете C# 5 (вы бедная душа ;-)). Просто замените «=>» на «{» и добавьте закрытие «}» к методу. – Steven