I have multiple projects that need to share resource files (.resx) Suggestions have been made to move resource files to a separate assembly and have web projects reference it. Is there an example of how to do this?
Do I create a new Class Library project and move App_GlobalResource folder inside of that? I don't think that will work because code classes that are generated for resource files are marked as 'internal' which means that they can not be accessed outside of this assembly.
In the properties window of Visual Studio, you should be able to set the access modifier of the resource file to public. You won't, however, be able to access the resources in aspx files using the normal <%$ Resources:... %> syntax, since it does not support resources in referenced assemblies. I had the same problem and solved it by implementing a custom ExpressionBuilder, but I don't have access to my source code at the moment. If it's still needed then, I can look up the code tonight.
EDIT: OK, here's how I solved that problem:
Step 1: Move the resx files into the class library. They do not need to be in a specific folder. In the visual designer of the resx file, set the "Access Modifier" (upper right-hand corner) to "Public"
You should now be able to
reference the resources in C#/VB code (in the library as well as in the web project), e.g., Dim myMessage As String = [Namespace.]Resources.NameOfResx.NameOfResource
reference the resource as inline code in aspx pages, e.g., <h1><%= [Namespace.]Resources.NameOfResx.MyTitle %></h1>.
What won't work at this point is to use Resources expression, e.g., <asp:Button runat="server" Text="<%$ Resources:NameOfResx,MyButtonText %>" />. Unfortunately, you cannot simply replace this with inline code, since it's inside the property of a server side control.
Step 2: Let's make a custom ExpressionBuilder in our library, which interprets arbitrary code expressions. Fortunately, we can let the powerful classes of the .net Framework do all the work for us:
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
Then we need to register this ExpressionBuilder in the web.config:
<system.web>
...
<compilation ...>
<expressionBuilders>
<add expressionPrefix="Code" type="NamespaceOfYourLibrary.CodeExpressionBuilder" />
</expressionBuilders>
</compilation>
</system.web>
Now you should be able to do the following:
<asp:Button runat="server" Text="<%$ Code:[Namespace.]Resources.NameOfResx.MyButtonText %>" />
Credit: I got the idea for the CodeExpressionBuilder from the Infinites Loop blog. If you're more into C# than VB, you can have a look at the code examples there.
We had a already developed application where we had to have 2 copies of all the resource files, one for services and one for the asp.net project, also the project relied on the <%$ Resources:NameOfResx,MyButtonText %> syntax, so changing syntax was no option.
After some time i found the ExpressionBuilder and came up with the following solution:
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);
}
}
Replace OneTypeInResourceAssembly with a type in the assembly containing the resources.
After that you can just add the following to web.config and it should just work..
<system.web>
<compilation>
<expressionBuilders>
<remove expressionPrefix="Resources" />
<add expressionPrefix="Resources" type="Assembly.ResourceExpressionBuilder" />
</expressionBuilders>
</compilation>
</system.web>
Related
i am using Swagger + xml comment file for my Asp.net webapi documentation.
The value in the summary tag is displayed, but the param tag gets ignored.
I have an OdataController v4
// GET: api/L_controller('L')
/// <summary>
/// This is my summary
/// </summary>
/// <param name="key">This is my Description</param>
[EnableQuery]
public IEnumerable<L_model> GetL_controller([FromODataUri] string key)
{
return someResult;
}
What am i doing wrong?
It seems there's nothing wrong with your code but it's a bug in Swashbuckle.Odata: https://github.com/rbeauchamp/Swashbuckle.OData/issues/73
"Key param handler overwrites xml-doc commented documentation"
I've observed the same problem. Whenever I use a key (the entity field annotated with [key]) the description is just
key:Code
(Code is the name of the key field in my entity)
The documantation of other, non-key parameters works fine.
One workaround could be to add a remarks tag to your documentation which you use to add a note about the parameter, e.g:
/// <summary>
/// retrive user by key
/// {URL}/User(key)
/// </summary>
/// <remarks>this documentaion will be displayed</remarks>
/// <param name="key">this documentation will be ignored</param>
In Bundling and Minification, I've known that the bundler will move around certain known file types -- so that things like jQuery will be moved to the front.
By default, when files are bundled by ASP.NET they are sorted
alphabetically first, just like they are shown in Solution Explorer.
Then they are automatically shifted around so that known libraries and
their custom extensions such as jQuery, MooTools and Dojo are loaded
before anything else.
-source
But after reading this recent question: ASP.NET MVC - Bundle Config order, which shows how a file is getting moved by the bundler even when the user has specified the load order, I realized I didn't know WHAT these known file types are, or the ORDER they will be listed in.
I've never seen a list explaining this, and in searching, I came up with nothing.
Is there a list the shows what the known file types are and the order they will be rendered in? I would think this is something the ASP.NET team should provide developers as a resource.
Its in the doc comments for BundleCollection.AddDefaultFileOrderings:
/// <summary>
/// Add default file ordering for common popuular script and style libraries.
/// </summary>
/// <param name="list">A collection of <see cref="BundleFileSetOrdering"/> objects to populate with default values.</param>
/// <remarks>
/// The purpose for applying these default file ordering values is to ensure that common libraries such as jquery are always located
/// at or close to the top within a bundle. These values can be all removed with <see cref="ResetAll"/>.
///
/// The default ordering values are as follows:
/// <list type="bullet">
/// <item><description>reset.css</description></item>
/// <item><description>normalize.css</description></item>
/// <item><description>jquery.js</description></item>
/// <item><description>jquery-min.js</description></item>
/// <item><description>jquery-*</description></item>
/// <item><description>jquery-ui*</description></item>
/// <item><description>jquery.ui*</description></item>
/// <item><description>jquery.unobtrusive*</description></item>
/// <item><description>jquery.validate*</description></item>
/// <item><description>modernizr-*</description></item>
/// <item><description>dojo.*</description></item>
/// <item><description>mootools-core*</description></item>
/// <item><description>mootools-*</description></item>
/// <item><description>prototype.js</description></item>
/// <item><description>prototype-*</description></item>
/// <item><description>scriptaculous-*</description></item>
/// <item><description>ext.js</description></item>
/// <item><description>ext-*</description></item>
/// </list>
/// </remarks>
public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list) {
if (list == null) {
throw new ArgumentNullException("list");
}
BundleFileSetOrdering css = new BundleFileSetOrdering("css");
css.Files.Add("reset.css");
css.Files.Add("normalize.css");
list.Add(css);
BundleFileSetOrdering jquery = new BundleFileSetOrdering("jquery");
jquery.Files.Add("jquery.js");
jquery.Files.Add("jquery-min.js");
jquery.Files.Add("jquery-*");
jquery.Files.Add("jquery-ui*");
jquery.Files.Add("jquery.ui*");
jquery.Files.Add("jquery.unobtrusive*");
jquery.Files.Add("jquery.validate*");
list.Add(jquery);
BundleFileSetOrdering mod = new BundleFileSetOrdering("modernizr");
mod.Files.Add("modernizr-*");
list.Add(mod);
BundleFileSetOrdering dojo = new BundleFileSetOrdering("dojo");
dojo.Files.Add("dojo.*");
list.Add(dojo);
BundleFileSetOrdering moo = new BundleFileSetOrdering("moo");
moo.Files.Add("mootools-core*");
moo.Files.Add("mootools-*");
list.Add(moo);
BundleFileSetOrdering proto = new BundleFileSetOrdering("prototype");
proto.Files.Add("prototype.js");
proto.Files.Add("prototype-*");
proto.Files.Add("scriptaculous-*");
list.Add(proto);
BundleFileSetOrdering ext = new BundleFileSetOrdering("ext");
ext.Files.Add("ext.js");
ext.Files.Add("ext-*");
list.Add(ext);
}
I created one web user control with property named "ReadonlyField" with boolean datatype. I am able to use in my web pages and now I wanted to add a description to that property so that I don't need to explain each time to my team member what is that property's intention.
I got following snippet in c# but didnt find any equivalent in vb.net and also not sure whether it will work or not.
[Description("My Description")]
public int MyIntProperty
{
get {..}
set {..}
}
A literal translation in VB 10
<Description("My Description")> Public Property MyIntProperty As Integer
If this is for other programmers you may want to offer Intellisense support via XML comments. This is the standard way of doing it in both VB and C#.
VB
''' <summary>
''' Description goes here
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property MyIntProperty As Integer
Actually, I put mine into the summary block, and then it shows in Intellisense...
''' <summary>
''' Returns "INSTALLATION ACTION INITIATED"
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property IAS
Get
Return _dict("IAS")
End Get
End Property
I need some EXAMPLES or IDEAS on how to created dynamic breadcrumb control which will dynamically generated breadcrumbs for Dynamic Date framework powered by LINQTOSQL
You'll probably need three things:
A hierarchy structure in your database*
A custom SiteMap provider based on the StaticSiteMapProvider to read the hierarchy
A SiteMapPath control to display the Breadcrumb.
* I'd done some hunting around when I wanted something similar for a client site, and decided that storing the path structure in the database would be simplest - I've given the answer previously here for an arbitrary depth site map - note that if you're using SQL2008 you can use the new HierarchyId data type to make this a bit easier.
That being said, if you've got things like categories and products, you can probably get away with a simpler system in your database.
The key functions I needed to create to resolve this were things like:
/// <summary>
/// Gets this SiteMaps children.
/// </summary>
/// <value>The children.</value>
public List<SiteMap> Children {
get {
if (null == m_Children && !m_AttemptedToLoadChildren) {
m_AttemptedToLoadChildren = true;
m_Children = ctx.GetSiteMapChildrenByPath(_Path, 1).ToList();
// Sorts ascending.
m_Children.Sort(( sm1, sm2 ) => sm1.SortOrder.CompareTo(sm2.SortOrder));
// CMS Sorts Descending, so reverse the list.
m_Children.Reverse();
}
return m_Children;
}
}
/// <summary>
/// Gets a value indicating whether this instance has any children.
/// </summary>
/// <value>
/// <c>true</c> if this instance has children; otherwise, <c>false</c>.
/// </value>
public bool HasChildren {
get {
if (null != Children && Children.Any()) {
m_HasChildren = true;
}
return m_HasChildren;
}
}
/// <summary>
/// Gets this SiteMaps parent.
/// </summary>
/// <value>The parent.</value>
public SiteMap Parent {
get {
if (null == m_Parent && null != _ParentId) {
m_Parent = ctx.GetSiteMap(_ParentId);
}
return m_Parent;
}
}
GetSiteMap and GetSiteMapChildrenByPath call into stored procs to build the hierarchy as pulling it out with LINQ was going to be quite complex.
Hi have you had a look at my custom SitMapProvider here
This allows you to get the structure from the metamodel with annotation and a seperate sitemap file for non DD pages.
I have an ASP .NET Website where i have an index.aspx page and 3 Folders along with it.ie;My Root has index.aspx ,FolderA,FolderB and then FolderCommon(these 3 are folders).
I have got few asp pages in FolderA and FolderB.FolderCommon stores js files ,CSS files and common code etcc....
I have a user control called pageFooter , inside which i am keeping all footer links of my page.Now my problem is when i use the same footer user control in my index page which is available in the root folder,it will not work for other pages,because the path is different.So how can i redesign the footer user control so that links will be consistent across all pages irrespective of folder structure or the place where they are being present.
Note : I dont want to give a full link to the href property (Ex: http://sitename/folderA/fielname.aspx)
Any thoughts ???
If you are doing asp:Hyperlink, always set the links this way:
NavigateUrl="~/index.aspx"
NavigateURL="~/Folder/Default.aspx"
The ~ basically means "root"
If you are doing regularl <a href=""> then you need to provide the relative path to the link based off wherever the file is.
So if you are in folderA, and you want to reference the root.
We stack with the same problem. We have used absolute URL with following utility to convert already existing '~' to correct path
public static class UrlUtils
{
/// <summary>
///This method returns the correct relative path when installing
/// the portal on a root web site instead of virtual directory
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static string GetApplicationPath(HttpRequest request)
{
string path = string.Empty;
if (request.ApplicationPath != "/")
path = request.ApplicationPath;
return path;
}
/// <summary>
/// Changes leading '~' to absolute URL including lead address e.g. http[s]://.... using
/// <see cref="HttpContext.Current" />.
/// </summary>
/// <param name="url">Relative or absolute URL.</param>
/// <returns>Absolute URL.</returns>
public static string ResolveAbsoluteUrl(string url)
{
if (url.StartsWith("~"))
{
HttpRequest request = HttpContext.Current.Request;
string _BaseUrl = new Uri(request.Url.ToString()).GetLeftPart(UriPartial.Authority);
string baseUrl;
baseUrl = _BaseUrl + GetApplicationPath(request);
return baseUrl + url.Substring(1);
}
return url;
}
This is (probably) what you have now...
Link
You can try:
Link
And you should find that the slash makes all the difference!
I'm not sure of the exact nature of your problem, but have you tried using root-relative paths? Something like:
"~/Folder/{control or page}"
An example of your code would be helpful.
Could you check the URL of the page the control is on?
Dim currentURL as string = HttpContext.Current.Request.Url.ToString
Once you know the URL you should know which links to show.