重写默认资源提供程序
本文关键字:程序 资源 默认 重写 | 更新日期: 2023-09-27 18:35:22
我需要使用 appSettings
中定义的应用程序上下文检索本地资源:
<add key="ApplicationContext" value="CTX1"/>
也可以使用另一个值进行部署:
<add key="ApplicationContext" value="CTX2"/>
并像这样定义本地资源:
<root>
<data name="CTX1_BodyTitle1" xml:space="preserve">
<value>Welcome to context 1</value>
</data>
<data name="CTX2_BodyTitle1" xml:space="preserve">
<value>Welcome to context 2</value>
</data>
<root>
然后在 ASPX 页中使用隐式资源名称:
<h2><asp:Literal runat="server" meta:ressourcekey="BodyTitle1"></asp:Literal></h2>
我尝试按照 msdn 上的说法实现自定义资源提供程序,但没有设法做一些有效或简单的事情。
知道如何在不重新实现整个ResourceProviderFactory
的情况下获得特权吗?
编辑:
我想根据应用程序上下文从Page1.en.resx
隐式检索本地资源,Page1.fr.resx
,然后在Page1.aspx
中使用唯一标识符链接到定义的资源。
根据@BartoszKP的建议,我编写了一个自定义ExpressionBuilder
,其中包含了 acount ApplicationContext 和本地化(基于 Bilal Haidar 文章):
Web.config 必须声明它:
<system.web>
<expressionBuilders>
<add expressionPrefix="Contextual" type="SinsedrixLibrary.ContextualExpressionBuilder"/>
</expressionBuilders>
</system.web>
aspx 页面只需要请求带有前缀的 ressource:
<h1><asp:Literal runat="server" Text='<%$ Contextual: LitWelcome %>'></asp:Literal></h1>
这是ExpressionBuilder
:
namespace SinsedrixLibrary
{
/// <summary>
/// This source file includes the source code for the
/// XmlSettingExpressionBuilder, which is used to handle
/// declarative expressions based on an XML settings file.
/// </summary>
public class ContextualExpressionBuilder : ExpressionBuilder
{
public ContextualExpressionBuilder()
{ }
/// <summary>
/// This method will be called during page execution
/// to get the expression that is going to be executed
/// to return the value of the declarative expression
/// </summary>
/// <param name="entry"></param>
/// <param name="parsedData"></param>
/// <param name="context"></param>
/// <returns></returns>
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
// Get a reference to this class since we are going to
// execute a method on this class that will evaluate
// the required expression
CodeTypeReferenceExpression thisType = new CodeTypeReferenceExpression(base.GetType());
// Create a new expression based on the KEY specified
// in the declarative expression, this will be used
// as an input to the method that will evaluate the
// required expression
CodePrimitiveExpression expression = new CodePrimitiveExpression(entry.Expression.Trim().ToString());
string l_resxPath = Path.GetDirectoryName(context.VirtualPath) + "''App_LocalResources''"+ Path.GetFileName(context.VirtualPath);
CodePrimitiveExpression resxPath = new CodePrimitiveExpression(l_resxPath);
// The static method name that will evaluate the
// expression, by accessing the XML file and retreiving
// the value that corresponds to the key specified
string evaluationMethod = "GetContextResource";
// Finally, return the expression that will invoke the method
// responsible for evaluating the expression
// The CodeMethodInvokeExpression takes as input the type on which to execute the method specified,
// the method name, and the array of CodeExpression, which represents the parameters of the method called
return new CodeMethodInvokeExpression(thisType, evaluationMethod, new CodeExpression[] { expression, resxPath });
}
/// <summary>
/// Evaluates the expression by accessing the XMLSettings file
/// and retrieve the value corresponding to the key specified in
/// the input expression.
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static string GetContextResource(string expression, string resxPath)
{
// Get the XML Setting file from the application cache if present
CultureInfo ci = CultureInfo.CurrentCulture;
string resxKey = resxPath + "." + ci.TwoLetterISOLanguageName;
XmlDocument xmlSettingDoc = (XmlDocument)HostingEnvironment.Cache[resxKey];
// check if there was an already loaded document
if (xmlSettingDoc == null)
{
// Define the document here
xmlSettingDoc = new XmlDocument();
// Get the config file path using the HostingEnvironment
// which gives information for application-specific
string resxCultureFile = resxKey + ".resx";
string resxDefaultFile = resxPath + ".resx";
string resxFile = "";
try
{
resxFile = HostingEnvironment.MapPath(resxCultureFile);
}
catch(Exception) {
resxFile = HostingEnvironment.MapPath(resxDefaultFile);
}
// Load the XML file into the XmlDocument
xmlSettingDoc.Load(resxFile);
// Create a new file dependency to be used when we add the XmlDocument
// into the Cache, so that when the XmlSettings file change, the Cache will
// be invalid.
CacheDependency settingsDepend = new CacheDependency(resxFile);
// Add the Xmldocument to the Cache
HostingEnvironment.Cache.Insert(resxKey, xmlSettingDoc, settingsDepend);
}
string ctx = ConfigurationManager.AppSettings["ApplicativeContext"];
// XPATH key used to retrieve the record needed in the form of add[@key='keyvalue']
string getXPATHKey = String.Format("//data[@name='{0}_{1}']/value", ctx, expression);
// Search for that record
XmlNode wantedRecord = xmlSettingDoc.SelectSingleNode(getXPATHKey);
// If the record exists, return the value property
if (wantedRecord != null)
return wantedRecord.InnerText;
// return a message informing users that the expression failed to
// evaluate to a real value
return string.Format("Unable to Process Expression : '{0}'", expression);
}
}
}
在我的团队开发的一个应用程序中,我们通过首先创建一个继承 ResourceManager (System.Resources) 的 OverridenResourceManager 来处理这个问题。下面提供的示例代码:
/// <summary>
/// Resource manager that uses resources found in the exceptions folder before falling back to the built-in resource file.
/// </summary>
public class OverridenResourceManager : ResourceManager
{
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="OverridenResourceManager "/>lass.
/// </summary>
/// <param name="name">
/// The name of the resource file.
/// </param>
/// <param name="culture">
/// The string culture to find resources for.
/// </param>
public OverridenResourceManager(string name, Assembly culture)
: base(name, culture)
{
this.Name = name.Replace("AssemblyName.Localization.", string.Empty);
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a function that return a dictionary of overrides for the currentsite
/// </summary>
public static Func<Dictionary<string, string>> TextOverridesDictionary { get; set;}
/// <summary>
/// Gets or sets the name of the resources class to handle.
/// </summary>
public string Name { get; set; }
#endregion
#region Public Methods and Operators
/// <summary>
/// Gets the resource named <paramref name="name"/> for the given <paramref name="culture"/>.
/// Tries to use the value in an exceptions file (through a pre-built dictionary), if any,
/// otherwise uses the built-in method.
/// </summary>
/// <param name="name">
/// The name of the resource to get.
/// </param>
/// <param name="culture">
/// The string culture to get the resource for.
/// </param>
/// <returns>
/// The <see cref="string"/> containing the value of the resource.
/// </returns>
public override string GetString(string name, CultureInfo culture)
{
if (TextOverridesDictionary != null)
{
// As we are only giving one file we need to fully qualify the name we are looking for
var resourceName = this.Name + '.' + name;
// TextOverridesDictionary contains a closure to get the dictionary
// from the session's website configuration object
var overrides = TextOverridesDictionary();
if (overrides != null && overrides.ContainsKey(resourceName))
{
return overrides[resourceName];
}
}
return base.GetString(name, culture);
}
}
当应用程序启动时,我们然后设置
TextOverridesDictionary = () => Session.Site.TextResourceOverrides;
简而言之,它调用一个获取所提供资源的字典键/值对的方法。您需要实现一个从 .config 文件中获取正确键/值的方法,这是一个非常示例的示例。如果需要,我可以提供示例代码。
使用此 OverridenResourceManager,同一命名空间中的任何资源,对于我们来说,"AssemblyName.Localization",将首先根据我们的字典进行检查,然后检查现有资源。
就我的担忧而言,有一个简单的方法可以做到这一点,但让我分享一下我认为可以帮助您的方法
创建一个类,您可以在其中访问 webconfing 或 appconfig 文件,如下所示
public static class appdata
{
static ResourceManager rm = new ResourceManager("Resources.Resource", System.Reflection.Assembly.Load("App_GlobalResources"));
static CultureInfo ci = default(CultureInfo);
private static isValidChassisTableAdapter _isvalidchassis = null;
private static SG_FORMTableAdapter _sgform = null;
private static settingTableAdapter _setting = null;
private static IsInRoleTableAdapter _Role = null;
private static tblaccountsTableAdapter _accounts = null;
private static tblloginhistoryTableAdapter _AppEvents = null;
private static configTableAdapter _AppConfig = null;
public static configTableAdapter AppConfig
{
get
{
if (_AppConfig == null)
{
_AppConfig = new configTableAdapter();
}
return _AppConfig;
}
}
public static string ApplicationContext
{
get { return ConfigurationManager.AppSettings.Get("ApplicationContext"); }
}
}
然后在aspx页面中使用它,如下所示
<h2><%=appdata.ApplicationContext%></h2>