Overriding default ResourceProvider

醉酒当歌 提交于 2019-12-13 03:13:22

问题


I need to retrieve local resources using an application context defined in appSettings:

<add key="ApplicationContext" value="CTX1"/>

which could also be deployed with another value:

<add key="ApplicationContext" value="CTX2"/>

and define local resources like this:

<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>

then use implicit resource name in aspx page:

<h2><asp:Literal runat="server" meta:ressourcekey="BodyTitle1"></asp:Literal></h2>

I tried to implement a custom ResourceProvider as told on msdn but did not manage to do something effective nor simple.

Any idea how to privide this without reimplementing the whole ResourceProviderFactory?

EDIT:

I want to implicitly retrieve local resources from Page1.en.resx, Page1.fr.resx according to ApplicationContext, then use an unique identifier in Page1.aspx to link to defined resources.


回答1:


According to @BartoszKP advice, I wrote a custom ExpressionBuilder that takes into acount ApplicationContext and localization (base on a Bilal Haidar article):

Web.config has to declare it :

<system.web>
    <expressionBuilders>
        <add expressionPrefix="Contextual" type="SinsedrixLibrary.ContextualExpressionBuilder"/>
    </expressionBuilders>
</system.web>

And aspx page just have to request ressource with a prefix:

<h1><asp:Literal runat="server" Text='<%$ Contextual: LitWelcome %>'></asp:Literal></h1>

Here is the 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);
    }
}
}



回答2:


In an application my team developed we handle this by first creating a OverridenResourceManager that inherits the ResourceManager (System.Resources) sample code provided below:

    /// <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);
    }
}

When the application launches, we then set the

TextOverridesDictionary = () => Session.Site.TextResourceOverrides;

Which in short calls a method that grabs the dictionary key/value pair of the resources provided. You would need to implement a method that grabbed the correct key/value from your .config file which is pretty sample. I could provide sample code if needed.

With this OverridenResourceManager any resources within the same namespace, for us "AssemblyName.Localization", will be checked for against our dictionary first then the existing resources.




回答3:


As far as my concern there is simple way to do this but let me share which i think can help you

Create a class where you can access the webconfing or appconfig file something like below

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"); }
    }
}

Then use it in aspx page like this

<h2><%=appdata.ApplicationContext%></h2>


来源:https://stackoverflow.com/questions/19385285/overriding-default-resourceprovider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!