ILocalizedStringManager是否在请求中意外重用?

时间:2019-07-12 09:50:16

标签: c# asp.net-mvc autofac orchardcms

我认为这真的是意外的,因为ILocalizedStringManagerIDependency,这意味着应该始终为每个请求创建它。

我在实现类中放置了一些日志,如下所示:

public class LocalizedStringManager : ILocalizedStringManager
{
    private readonly ITranslator _translator;
    public LocalizedStringManager(ITranslator translator)
    {
        _translator = translator;
        //we defined an OID on ITranslator to help debug this
        Debug.Print($">>>>>>>>> Init LocalizedStringManager ... ({_translator.OID})");
    }
    public string GetLocalizedString(string scope, string text, string cultureName)
    {
        return _translator.Translate(text).Text;
    }
}

public interface ITranslator : IDependency, IDisposable {
    string Translate(string text);
    Guid OID {get;}
}

public class Translator : ITranslator {
   public Guid OID {get;}
   public Translator(){
       OID = Guid.NewGuid();
   }
   public string Translate(string text){
       //...
   }
   public void Dispose(){
       Debug.Print($">>>>>>>>> Disposing ... {OID}");
   }
}

对于第一个请求,我可以看到它已打印出来

>>>>>>>>> Init LocalizedStringManager ... 086a1487-bad9-481d-92f0-4615b9c6c5fd

然后最后处理引用的ITranslator,并打印以下内容:

>>>>>>>>> Disposing ... 086a1487-bad9-481d-92f0-4615b9c6c5fd

所以这里一切都很好,但是以某种方式(来自浏览器)的下一个请求通过LocalizedStringManager触发了NullLocalizer,奇怪的是我没有看到像>>>>>>>>> Init LocalizedStringManager ...这样的行被打印,但是在引发异常之前,我有一条日志行打印出ITranslator OID,它与值086a1487-bad9-481d-92f0-4615b9c6c5fd相匹配,真令人困惑。

这是第二个连续请求运行的代码:

public interface ISomeService : IDependency {
     SomeModel LoadData();
}
public class SomeService : ISomeService {
    public Localizer T {get;set;}      
    public SomeService(){
        T = NullLocalizer.Instance;
    }  
    public SomeModel LoadData(){
        //use the Localizer T here, such as to translate some text
        var model = new SomeModel();
        model.SomeText = T("SOME_KEY");
        //...
        return model;
    }
}

因此T(...)将触发一些LocalizedStringManager,实际上我希望它创建一个新的(内部引用了新的ITranslator),但是以某种方式 重用 (之前已在请求中创建的那一行)(因为这次我没有看到任何类似>>>>>>>>> Init LocalizedStringManager ...的行被打印出来。 最后,它还将调用重用的ITranslator(其Translate方法),但此方法已在处理之前(在请求之前)处理,现在它抛出了一个异常,内容如下:

  

抛出异常:Autofac.dll中的'System.ObjectDisposedException'

     

Autofac.dll中发生了'System.ObjectDisposedException'类型的异常,但未在用户代码中处理   无法解决实例,并且无法从此LifetimeScope创建嵌套生命周期,因为该LifetimeScope已被处置。

一切似乎都无法控制。全部由Orchard框架设置。我真的不明白如何LocalizedStringManager可以这么容易地重用?永远不要那样重复使用它。现在(在尝试通过多语言支持使我们的网站全球化之后),我们相当频繁地遇到这种异常。

尤其是这种情况并非总是可重复的(我是说它间歇性地发生)。我希望有人对Orchard有足够的经验,至少可以给我一些好的建议,以解决此问题。谢谢!

更新: 我无法提供确切的实际代码(逐个单词),但是主要逻辑可能如下所示(此处最不同的是IDisposable未实现,IRepositoryITranslator中使用)实施):

public interface ITranslator : IDependency {
    string Translate(string text);
    LanguageInfo GetCurrentUserLanguage();
}

public class LanguageInfo {
    public string Name {get;set;}
    public string DisplayName {get;set;}
}

public class Translator : ITranslator {       
   readonly IRepository<LanguageRecord> _languageRepo;
   readonly IOrchardServices _orchardServices;
   public Translator(IRepository<LanguageRecord> languageRepo, 
                     IOrchardServices orchardServices){
      _languageRepo = languageRepo;
      _orchardServices = orchardServices;
   }
   public LanguageInfo GetCurrentUserLanguage() {
       if(_orchardServices.WorkContext.CurrentUser == null){
          //obtain the language for not-logged-in user from his browser's cookie
          var langCode = _orchardServices.WorkContext.HttpContext.Request.Cookies["LangCode"] ?? "en";
          //get full language info
          //this is where the exception thrown (because of using the disposed repository)
          var fullInfo = _languageRepo.Table.FirstOrDefault(e => e.Code == langCode);
          return new LanguageInfo { Name = fullInfo.Name, DisplayName = fullInfo.DisplayName };

       } else {
          //obtain from DB the settings for the current user
          //however my test is for the case user not logging in 
          //So this branch is not important in this specific question.
          //...
       }
   }
   public string Translate(string text){
       //get current user language
       var lang = GetCurrentUserLanguage();
       //do the translation … (not important in this specific question)
       //...
   }   
}

同样,我必须说这种情况 间歇地 发生,没有办法确保它可以很容易地重现(这是最难找出原因的原因),尤其是在您可以重现一次。就我而言,在开始首页后,GetCurrentUserLanguage被调用了几次(对于每个翻译),一切都很好。但是所有呼叫均来自T(…) 剃刀内部视图

但是,在单击一个链接(调用api ISomeService)后会引发异常,其他链接确实使用了翻译,但是它们将T用作Orchard的WebPage库的一部分(在razor视图中呈现) ,这些至少在我第一次尝试浏览网站时不会造成异常。现在很奇怪,因为重新访问该链接(正如我通过间歇性地使用 所描述的那样),不会引发异常。从那时起,实际上我几乎无法复制它,但是对于生产网站,我们仍然可以看到相当多的日志行显示间歇性事件(而且我敢肯定,其中许多是在剃刀视图中使用T(…) ,而不仅仅是从ISomeService中获得,就像我第一次可以轻松重现异常时一样。

请注意,上面的代码不好,不是我最初写的(我们有几个成员组成的团队)。而且我知道应该对其进行重构,但这不是正确的时机,即使我已经解决了这个问题,也只是一个快速的解决方案。)

0 个答案:

没有答案