Resx缓存问题在视图上

时间:2018-01-09 11:54:31

标签: c# asp.net asp.net-mvc razor resx

这是一个.NET 4.5项目,它在我的时间之前已经设置了很长时间,因此没有很多细节说明为什么这样做。

我们有一个Web应用程序,其中每种语言都有自己的resx文件。 在每个页面加载时,通常的方式是从resx文件加载值。

string strLangResourceValue = (string)HttpContext.GetGlobalResourceObject(lang, strLangResourceKey);

这很好用。可能值得一提的是,这行代码位于一个单独的项目中,因此可以与解决方案下的其他多个项目共享。

在视图(Razor)中,我们@Application.GetLangResource("Some_Key");检索我们需要的值。该语言取自存储在HttpContext中的会话模型。

当我们更改语言时,问题就会出现,相应地翻译该页面上的每个部分视图,除了我们更改语言的“用户设置”页面。令人奇怪的是,我们有两个视图,一个只读页面只显示数据,另一个包含实际形式来修改值,其中没有一个被翻译。

已知问题是:

  • 我现在无法在Web应用程序中设置CultureInfo,我需要使用会话模型来获取此信息并使用上面的代码行来获取数据。
  • 强制刷新浏览器,清除Cookie和缓存无法解决问题。
  • 仅重新启动IIS服务器可修复问题(重新编译resx文件)

我知道resx文件是在运行时编译的并且是静态的。它们在应用程序运行期间不会在代码中更改,它只是更改的用户会话。上面的列表已经尝试解决问题的根源,但每次有人更改语言时重新启动应用程序都不是一种选择(正如您可能猜到的那样)。

有一个明显的解决方案,我错过了吗? 没有resx错误 ,它只是两个特定页面上的IIS缓存(或者至少看起来像是这样)。它们的构建方式与其他所有构建方式相同,只是不切换语言。这适用于所有用户更改语言时。

我尝试使用下面的代码行手动清除缓存,这些代码仍未保留。

Resources.AppSettings.ResourceManager.ReleaseAllResources();
Resources.English.ResourceManager.ReleaseAllResources();
Resources.Dutch.ResourceManager.ReleaseAllResources();
HttpResponse.RemoveOutputCacheItem("/Views/User/userViewDetails.cshtml");

foreach(System.Collections.DictionaryEntry entry in HttpContext.Cache) {
    HttpContext.Cache.Remove((string) entry.Key);
}

1 个答案:

答案 0 :(得分:0)

我终于解决了自己的问题,但我仍然不明白这是怎么回事。所以,问题是在第一个视图渲染时,它会从resx中获取相应语言的值,但不会在任何后续渲染中获取(就像它会缓存这些值以减少对resx的访问时间一样,这很棒)。 p>

我最终实现了自己的/* How to extract and insert information held in the st_info field. */ #define ELF32_ST_BIND(val) ... #define ELF32_ST_TYPE(val) ... ... etc. ,并且完成了这项工作。

因此,对于任何对我的解决方案感兴趣的人来说,它看起来像是:

DataAnnotationsModelMetadataProvider

public class LocalizedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { var meta = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); // Get metadata of the property string resXKey = string.Empty; object attribute = attributes.OfType<DisplayLabel>().FirstOrDefault(); // Try to get the DisplayLabel annotation // If DisplayLabel is found then... if (attribute != null) { resXKey = ((DisplayLabel)attribute).Key; // Grab the resx key added to the annotation meta.DisplayName = Application.GetLangResource(resXKey) + meta.DisplayName; // Retrieve the language resource for the key and add back any trailing items returned by the annotation } // DisplayLabel is not found... if (attribute == null) { attribute = attributes.OfType<DisplayNameLocalizedAttribute>().FirstOrDefault(); // Try to get the DisplayNameLocalizedAttribute annotation // If annotation exists then... if (attribute != null) { resXKey = ((DisplayNameLocalizedAttribute)attribute).Key; // Grab the resx key added to the annotation string resXValue = Application.GetLangResource(resXKey); // Retrieve the language resource for the key string finalValue = resXValue; // Create a new string if (((DisplayNameLocalizedAttribute)attribute).IsLabel) // Check if property annotation is set to label { finalValue = resXValue + meta.DisplayName; // Add back any trailing items returned by the annotation } meta.DisplayName = finalValue; // Set the DisplayName of the property back onto the meta } } return meta; } } DisplayLabel是自定义属性注释,它存储resx键和任何其他数据,例如(如果它是标签,通常我们可以添加“:”),如果它是输入。

DisplayNameLocalizedAttribute是一个函数,它根据给定的语言从resx文件中获取值,如果找不到值,它将返回一个合适的消息。

要使服务器使用创建的Application.GetLangResource,您需要将其设置为DataAnnotationModelMetadataProviderCurrent事件中的Application_Start个。

要做到这一点,你会这样做:

Global.asax

重要的是(如果你在global.asax中遇到错误)你正在使用LocalizedDataAnnotationsModelMetadataProvider loca = new LocalizedDataAnnotationsModelMetadataProvider(); ModelMetadataProviders.Current = loca; ,而不是System.Mvc那里出现的其他导入,因为它不会让你分配新的提供商。