从javascript文件中使用ASP.NET资源字符串

29

如何将resx资源字符串导入到存储在.js文件中的javascript代码中?

如果你的javascript代码是在标记中的脚本块中,你可以使用以下语法:

<%$Resources:Resource, FieldName %>

在渲染页面时,它会将资源值解析为文本并呈现...不幸的是,只有当JavaScript出现在页面正文中时,它才会被解析。在 <script> 标签引用的外部 .js 文件中,这些服务器标记显然永远不会被解析。

我不想编写 ScriptService 来返回这些资源或其他任何内容,因为在页面呈现后它们不会改变,所以使用活动状态的东西是浪费资源。

一个可能的解决方法是编写一个 ashx 处理程序,并将 <script> 标签指向它,但我仍然不确定如何在流式传输文本到客户端之前读取 .js 文件和解析其中的任何服务器标记。是否有一行代码可以运行来执行类似于 ASP.NET 解析器的任务?

还有其他建议吗?

9个回答

34

这是我目前的解决方案。我相信未来我还需要让它更加通用...但到目前为止,它已经很不错了。

using System.Collections;
using System.Linq;
using System.Resources;
using System.Web.Mvc;
using System.Web.Script.Serialization;

public class ResourcesController : Controller
{
    private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();

    public ActionResult GetResourcesJavaScript(string resxFileName)
    {
        var resourceDictionary = new ResXResourceReader(Server.MapPath("~/App_GlobalResources/" + resxFileName + ".resx"))
                            .Cast<DictionaryEntry>()
                            .ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
        var json = Serializer.Serialize(resourceDictionary);
        var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.{0} = {1};", resxFileName, json);

        return JavaScript(javaScript);
    }

}

// In the RegisterRoutes method in Global.asax:
routes.MapRoute("Resources", "resources/{resxFileName}.js", new { controller = "Resources", action = "GetResourcesJavaScript" });

所以我可以这样做

<script src="/resources/Foo.js"></script>

然后我的脚本可以引用例如 window.Resources.Foo.Bar 并获取一个字符串。


我使用Framework 4,我的应用程序是Web应用程序,我必须添加对System.Windows.Forms.dll的引用以解决“ResXResourceReader”方法。我无法进入“ResourcesController”,因为ResourcesController类位于App_GlobalResources文件夹中。我将resx文件设置为Build Action: Resource。我设置了断点,但没有任何反应。 - Hernaldo Gonzalez
序列化为 JSON 的类名叫做 JavaScriptSerializer,而不是 Serializer,并且它不是静态的。 - Martin Braun
我正在尝试使用它,但我从未到达控制器。我在操作中设置了断点,但它从未到达那里。此外,_<script src="/resources/Foo.js"></script>_ 这个会被添加到 _layout.chtml 文件中吗? - mohsinali1317
除了上面的答案之外,我还必须在web.config中添加一个处理程序,以便IIS不会在该地址查找静态文件: - dalcam

21

这方面没有本机支持。

我一段时间前创建了一个JavaScriptResourceHandler,可以通过对象将服务器端资源提供到客户端页面,其中每个属性代表本地化资源ID及其值。你可以查看并从这篇博客文章中下载:

http://www.west-wind.com/Weblog/posts/698097.aspx

我在许多应用程序中广泛使用它,效果很好。主要优势在于可以在一个地方本地化资源(Resx或我的情况下使用数据库的自定义ResourceProvider),而不必拥有多个本地化方案。


嗯,一个有趣的方法。可能适合我。缺点是我必须有一个单独的资源文件,只包含我想要推出的内容,否则会发送一些无用的额外内容...而且我在SharePoint内部,因此将resx作为文件读入并解析可能会成为问题,我们会看到的。感谢您的帖子! - Grank

6

"Common"是资源文件的名称,而Msg1是字段名。这也适用于文化变化。

            Partial Javascript...:
            messages: 
            {
                <%=txtRequiredField.UniqueID %>:{                       
                    required: "<%=Resources.Common.Msg1 %>",
                    maxlength: "Only 50 character allowed in required field."
                }
            }

谢谢!完美运行。code alert("<%=Resources.LocalizedText.ErrorMessage %>"); - equiman

2
如果您的资源在单独的程序集中,您可以使用ResourceSet而不是文件名。在@Domenics的优秀答案的基础上进行改进:
public class ResourcesController : Controller
{
    private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();

    public ActionResult GetResourcesJavaScript()
    {
        // This avoids the file path dependency.
        ResourceSet resourceSet = MyResource.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);

        // Create dictionary.
        var resourceDictionary = resourceSet
                        .Cast<DictionaryEntry>()
                        .ToDictionary(entry => entry.Key.ToString(), entry => entry.Value.ToString());
        var json = Serializer.Serialize(resourceDictionary);
        var javaScript = string.Format("window.Resources = window.Resources || {{}}; window.Resources.resources = {1};", json);

        return JavaScript(javaScript);
    }
}

缺点是这样做不能为每个操作启用多个资源文件。在这种情况下,@Domenic的答案更通用和可重用。

您还可以考虑使用OutputCache,因为资源在请求之间不会经常更改。

[OutputCache(Duration = 3600, Location = OutputCacheLocation.ServerAndClient)]
public ActionResult GetResourcesJavaScript()
{ 
    // Logic here...
}

http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/improving-performance-with-output-caching-cs


除了上面的答案之外,我还需要在web.config中添加一个处理程序,以便IIS不会在该地址查找静态文件: - dalcam
@user1191559 不应该需要,因为我发布的答案没有使用 .js 后缀。它只是像其他任何端点一样。 - smoksnes
嗨@smoksnes,看到你的回答没有包括脚本实现部分,大多数用户会使用Domenics实现(包括.js),所以这种情况下应该有帮助! - dalcam

2
简而言之,让ASP.NET为特定页面提供javascript而不是HTML。最好使用自定义的IHttpHandler来实现,但如果时间紧迫,也可以使用一个页面,只需记住以下几点:
1)清除所有ASP.NET内容,使其看起来像JS文件。
2)在codebehind中将内容类型设置为"text/javascript"。
一旦您设置了这样的脚本,就可以创建客户端资源的副本,其他客户端脚本可以从您的应用程序引用。

0
在BasePage类中添加该函数:
    protected string GetLanguageText(string _key)
    {
        System.Resources.ResourceManager _resourceTemp = new System.Resources.ResourceManager("Resources.Language", System.Reflection.Assembly.Load("App_GlobalResources"));
        return _resourceTemp.GetString(_key);
    }

Javascript:

    var _resurceValue = "<%=GetLanguageText("UserName")%>";

或直接使用:

    var _resurceValue = "<%= Resources.Language.UserName %>";

注意: 这里的Language是我的资源名称。例如:Language.resx和Language.en-US.resx。

0
使用隐藏字段来保存资源字符串的值,然后在JavaScript中访问该字段的值。例如:
``` var todayString = $("input[name=TodayString][type=hidden]").val(); ```

0
在我正在处理的这个棕色应用程序中,我们有一个XSLT,它将resx文件转换成JavaScript文件,并作为构建过程的一部分。由于这是一个Web应用程序,所以这个功能非常有效。但我不确定原来的问题是否涉及到Web应用程序。

0
通常我会将资源字符串作为参数传递给我调用的任何JavaScript函数,这样我就可以继续在HTML中使用表达式语法。

这通常也是我的倾向,但在这种情况下,它是一个RadMenu的客户端项目点击处理程序,因此它会导致一个带有7个case的switch语句,所有这些都显示不同的“确定吗?”字符串:( - Grank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接