我有多个需要共享资源文件的项目(.resx)已经建议将资源文件移动到单独的程序集并让Web项目引用它。有一个如何做到这一点的例子?
我是否创建了一个新的类库项目并在其中移动App_GlobalResource文件夹?我认为这不会起作用,因为为资源文件生成的代码类被标记为“内部”,这意味着它们无法在此程序集之外访问。
答案 0 :(得分:20)
在Visual Studio的属性窗口中,您应该能够将资源文件的访问修饰符设置为public。但是,您不能使用普通的<%$ Resources:... %>
语法访问aspx文件中的资源,因为它不支持引用程序集中的资源。我有同样的问题并通过实现自定义ExpressionBuilder解决了它,但我目前无法访问我的源代码。如果它仍然需要,我今晚可以查找代码。
编辑:好的,这就是我解决这个问题的方法:
步骤1 :将resx文件移动到类库中。它们不需要位于特定文件夹中。在resx文件的可视化设计器中,将“访问修饰符”(右上角)设置为“公共”
你现在应该可以
了引用 C#/ VB代码中的资源(在库中以及在Web项目中),例如Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource
将资源引用为aspx页面中的内联代码,例如<h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>
。
此时不会工作的是使用Resources表达式,例如<asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />
。不幸的是,你不能简单地用内联代码替换它,因为它在服务器端控件的属性中。
第2步:让我们在我们的库中创建一个自定义的ExpressionBuilder,它解释任意代码表达式。幸运的是,我们可以让强大的.net框架类为我们完成所有工作:
Imports System.Web.Compilation
Imports System.Resources
Imports System.CodeDom
<ExpressionPrefix("Code")> _
Public Class CodeExpressionBuilder
Inherits ExpressionBuilder
Public Overrides Function GetCodeExpression(ByVal entry As System.Web.UI.BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As System.CodeDom.CodeExpression
Return New CodeSnippetExpression(entry.Expression)
End Function
End Class
然后我们需要在web.config中注册这个ExpressionBuilder:
<system.web>
...
<compilation ...>
<expressionBuilders>
<add expressionPrefix="Code" type="NamespaceOfYourLibrary.CodeExpressionBuilder" />
</expressionBuilders>
</compilation>
</system.web>
现在您应该可以执行以下操作:
<asp:Button runat="server" Text="<%$ Code:[Namespace.]Resources.NameOfResx.MyButtonText %>" />
信用:我从Infinites Loop blog得到了CodeExpressionBuilder的想法。如果您更喜欢C#而不是VB,那么您可以查看那里的代码示例。
答案 1 :(得分:7)
我们有一个已经开发的应用程序,我们必须拥有所有资源文件的2个副本,一个用于服务,一个用于asp.net项目,项目依赖于<%$ Resources:NameOfResx,MyButtonText %>
语法,因此更改语法别无选择。
一段时间后,我找到了ExpressionBuilder并提出了以下解决方案:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Web.Compilation;
using System.Resources;
using System.CodeDom;
using System.Reflection;
/// <summary>
/// This class allows asp.net Resource lookups to different assembly
/// </summary>
[ExpressionPrefix("Resources")]
public class ResourceExpressionBuilder : ExpressionBuilder
{
static readonly Dictionary<string, ResourceManager> mResourceManagers = new Dictionary<string, ResourceManager>(StringComparer.OrdinalIgnoreCase);
static ResourceExpressionBuilder()
{
Assembly resourceAssembly = Assembly.GetAssembly(typeof(OneTypeInResourceAssembly));
const string suffix = ".resources";
string assemblyName = resourceAssembly.GetName().Name;
foreach (string resource in resourceAssembly.GetManifestResourceNames()) {
if ((resource.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))) {
string resourceName = resource.Substring(0, resource.Length - suffix.Length);
string resourceFriendlyName = resourceName.Substring(assemblyName.Length + 1, resourceName.Length - (assemblyName.Length + 1));
mResourceManagers.Add(resourceFriendlyName, new ResourceManager(resourceName, resourceAssembly));
}
}
}
/// <summary>
/// When overridden in a derived class, returns a value indicating whether the current <see cref="T:System.Web.Compilation.ExpressionBuilder" /> object supports no-compile pages.
/// </summary>
/// <returns>true if the <see cref="T:System.Web.Compilation.ExpressionBuilder" /> supports expression evaluation; otherwise, false.</returns>
public override bool SupportsEvaluate {
get { return true; }
}
/// <summary>
/// When overridden in a derived class, returns an object that represents an evaluated expression.
/// </summary>
/// <param name="target">The object containing the expression.</param>
/// <param name="entry">The object that represents information about the property bound to by the expression.</param>
/// <param name="parsedData">The object containing parsed data as returned by <see cref="M:System.Web.Compilation.ExpressionBuilder.ParseExpression(System.String,System.Type,System.Web.Compilation.ExpressionBuilderContext)" />.</param>
/// <param name="context">Contextual information for the evaluation of the expression.</param>
/// <returns>
/// An object that represents the evaluated expression; otherwise, null if the inheritor does not implement <see cref="M:System.Web.Compilation.ExpressionBuilder.EvaluateExpression(System.Object,System.Web.UI.BoundPropertyEntry,System.Object,System.Web.Compilation.ExpressionBuilderContext)" />.
/// </returns>
public override object EvaluateExpression(object target, System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
{
if ((parsedData != null && object.ReferenceEquals(parsedData.GetType(), typeof(string)))) {
return GetRequestedValue(Convert.ToString(parsedData));
}
return base.EvaluateExpression(target, entry, parsedData, context);
}
/// <summary>
/// When overridden in a derived class, returns code that is used during page execution to obtain the evaluated expression.
/// </summary>
/// <param name="entry">The object that represents information about the property bound to by the expression.</param>
/// <param name="parsedData">The object containing parsed data as returned by <see cref="M:System.Web.Compilation.ExpressionBuilder.ParseExpression(System.String,System.Type,System.Web.Compilation.ExpressionBuilderContext)" />.</param>
/// <param name="context">Contextual information for the evaluation of the expression.</param>
/// <returns>
/// A <see cref="T:System.CodeDom.CodeExpression" /> that is used for property assignment.
/// </returns>
public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
{
CodeExpression[] inputParams = new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()) };
return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(this.GetType()), "GetRequestedValue", inputParams);
}
/// <summary>
/// Gets the requested value.
/// </summary>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static object GetRequestedValue(string expression)
{
string[] parts = expression.Split(new char[] { ',' }, 2, StringSplitOptions.None);
if ((parts.Length != 2)) {
throw new ArgumentException("Expression must contain ,");
}
string resourceFile = parts[0].Trim();
string resourceName = parts[1].Trim();
return mResourceManagers[resourceFile].GetString(resourceName);
}
}
将OneTypeInResourceAssembly
替换为包含资源的程序集中的类型。
之后你可以将以下内容添加到web.config中,它应该可以工作..
<system.web>
<compilation>
<expressionBuilders>
<remove expressionPrefix="Resources" />
<add expressionPrefix="Resources" type="Assembly.ResourceExpressionBuilder" />
</expressionBuilders>
</compilation>
</system.web>