Resource Files and ASP.NET MVC Projects

If you try some of the traditional ASP.NET approaches to localization and internationalization in an MVC application you’re likely to run into a couple interesting* obstacles.

Resx Files In App_GlobalResources

Using resource files in App_GlobalResources from your controller code will break your unit tests.

When you drop a .resx file in the special App_GlobalResources folder, the IDE uses the GlobalResourceProxyGenerator to generate a strongly typed internal class to wrap the resources inside. The internal class gives any code in the MVC project access to the resources:

var greeting = Resources.Strings.Greeting;

You can also use the resources from a view:

<%= Html.Encode(Resources.Strings.Greeting) %>

The problem is that global resources are not actually embedded into the project’s .dll. Instead it is the ASP.NET runtime that creates an App_GlobalResources assembly with the resources inside. This assembly is referenced by all the view assemblies ASP.NET creates, and is explicitly loaded by the strongly typed wrapper generated by the GlobalResourceProxyGenerator. Since the App_GlobalResources assembly doesn’t exist without an ASP.NET compilation phase, it’s not available when unit tests are running. Controller code under test that tries to access the resources will bomb with an exception.

Note that you’ll also have some Intellisense problems when using the view syntax shown above. I'm guessing this is because the IDE is confused by seeing the resource wrapper in two places (the project assembly, and a wrapper also goes into the App_GlobalResource created by ASP.NET in the Temporary ASP.NET Files folder. ).

There is a way to make resx files in App_GlobalResources work, but the folder isn’t truly necessary in an MVC project (or a web application project, for that matter). I think it’s just as easy to add resx files in a different location, even a separate class library, to avoid any confusion on how App_GlobalResources will behave.

In short: avoid App_GlobalResources and App_LocalResources (which has its own set of problems) in MVC.

Resx Files Outside Of Special Resource Directoriesresx properties in MVC

If you add a resx file to any other folder in an MVC project or class library, the resx is automatically set to be embedded into the project’s output assembly - this is good. The IDE also assigns the resx a custom tool of ResxCodeFileGenerator to generate a strongly typed wrapper - this is good. The generated class is internal by default – this is bad. The assembly created for a view (by ASP.NET) won’t be able to use the internal class because it is in a different assembly – the project assembly compiled in Visual Studio.

Solution

The easy fix is to make sure the custom tool is set to  PublicResXFileCodeGenerator instead of ResXCodeFileGenerator. You can do this in the property window for the file, or in the resource editor that gives you a drop down for “Access Modifer” (the options are Internal, Public, and No Code Generation – choose Public).

You can also set the “Custom Tool Namespace” for the generated wrapper in the properties window. My suggestion is to use a convention like “Resources” for global resources, and “Resources.Controller.View” for resources dedicated to a specific view.

This approach means you can use the resources in unit-testable controller code, and in views, too. The syntax remains the same as above. The ResouceManager used in the wrapper classes can automatically resolve the proper resource to use depending on the current UI culture setting of the thread.

Setting The UI Culture

The easiest approach to having the correct UI culture in effect during web request processing is to use the globalization section of web.config.

<globalization uiCulture="auto" culture="auto"/>

The above will set both the current UI culture and current culture settings for the request. See Dennis Dietrich’s post for a good explanation of the two settings: YACVCP (Yet another CurrentCulture vs. CurrentUICulture post).

If you need to set the culture up according to a user’s preference, or a URL parameter, then the best bet is to write a custom HTTP module or action filter.

* Interesting only if you consider localization and resource files interesting, in which case you might need to take some medication.

Print | posted @ Thursday, July 16, 2009 3:30 AM

Comments on this entry:

Gravatar # re: Resource Files and ASP.NET MVC Projects
by Stan at 7/16/2009 12:46 PM

Thank you for saving hours of my time!
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Kevin Radcliffe at 7/16/2009 3:28 PM

Thanks! Very useful info.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by jin at 7/17/2009 9:12 AM

hi,scott
i have read your article "ASP.NET and Windows Workflows Foundation",and i got some
question about your sample code.There is a code snippet:
public class OrderService : IOrderService
{
public bool CreateOrder(Order order)
{
Check.ArgumentIsNotNull(order, "order");

// create order must first create the workflow, then raise event, then run again
WorkflowResults workflowResults = WorkflowMediator.Instance.RunWorkflow(typeof(OrderStateMachine));
Check.IsNotNull(workflowResults, "Could not harvest workflow results");
VerifyResults(workflowResults, WorkflowStatus.Running);
order.WorkflowId = workflowResults.InstanceId;

bool eventResult = RaiseEvent(OrderCreated, order, order.WorkflowId);
if (eventResult == true)
{
workflowResults = WorkflowMediator.Instance.RunWorkflow(order.WorkflowId);
Check.IsNotNull(workflowResults, "Could not harvest workflow results");
VerifyResults(workflowResults, WorkflowStatus.Running);

}
return eventResult;
}
}

First you create the workflow and then raise evnet, but the workflowItem dosen't be invoked by the event,and then you run workflow again.This time the handleExternalEventActivity1 in Intial
state is invoked by the event,so i want to know why the event invoke the
handleExternalEventActivity1 in Intial state again.And i think that the event is invoked in the first time and never be invoked again except for call explicity,but it dosent' true.
Please help me and forgive my poor english
jin
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by scott at 7/17/2009 12:45 PM

Hi Jin:

The first time we run the workflow is to just get it initialized and into the initial state. The "run workflow" step wouldn't be needed, except we are using the manual scheduler that requires us to give it the thread to run the workflow.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by jin at 7/20/2009 6:03 AM

Hi Scott:
Thank you for your explanation of the manual scheduler service.I have read your another article "Hosting Windows Workflow",so
i get an result that the first runworkflow is just do some preparation,and raise the event, the workflow queues just take the event
into queue,then runworkflow with an instance ID,the workflow queues find the handleExternalEventActivity1 in Intial
state.That's all of the content of the CreateOrder funtion.Thank you again.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Microsoft .NET Training at 7/21/2009 6:50 PM

Pluralsight offers comprehensive .NET training
  
Gravatar # LocalResources - has its own set of problems
by Mathias Fritsch at 7/24/2009 9:57 PM

What problem you see in local resources?

I use them in views and it looks ok (using blog.eworldui.net/...)
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by scott at 7/27/2009 6:30 PM

@mathias:

Great article, Mathias. I believe I'd still have a problem using the local resources in a controller that is unit tested even using your approach, right?
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Mathias Fritsch at 8/3/2009 7:39 PM

I believe I'd still have a problem ...
Yes.
The article in the link is only about views. I thought you argued against using local resources at all and was afraid I would see the limits to late in my project. Its clear to me now, that you talk about controller/model.

thnx
Mathias
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Jeff at 10/14/2009 6:21 PM

It appears that moving the resources out of the App_GlobalResources disables the Explicit Localization expressions in ASP.NET Web Application Project such as
<asp:Button ID="Button1" runat="server"
Text="<%$ Resources:WebResources, Button1Caption %>" />

  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Nady Fayek at 11/24/2009 6:44 PM

HI,
I am using local resources in asp.net website.
i use two language English as a default and Danish. the problem that sometimes when adding a key in Danish ,it can not bee seen when running website, it just get the value from english local resource file although that the current culture is Danish.
Thx
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by scott at 11/24/2009 10:23 PM

@Nady: I'm afraid I don't know the answer. It sounds like something that should just work.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by David at 1/14/2010 10:16 AM

Hi,

I have a class where i want to use a resources file in.
How can i retrieve a value from a specific resource file?

Thanks
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Anders at 2/8/2010 5:02 AM

Why would you ever use resources from within controllers? Resources exist on the view-level, and your unit tests should not ever rely on resources being available.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Scott Allen at 2/8/2010 8:59 AM

@Anders: I'm not sure what you mean by "resources exist on the view-level". You can use resource to localize exception messages and the text of validation messages, for example, and neither of those activities are tied to a view. I can put resource files into any assembly.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Shanu at 2/9/2010 5:59 AM

Hi,
I have a small doubt..
Is resource file have any specific size limit for the string or images..

ie, If i need to insert bulk content, then How it performs...? Can anyone help me...??
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by sikat ang pinoy at 2/9/2010 7:42 PM

asp.net comments using server side comments that can disabled code controls in the page. Because AJAX enabled the comment form.
  
Gravatar # re: Resource Files and ASP.NET MVC Projects
by Andy at 2/20/2010 3:43 PM

Do you recommend having a specific resource file for each view and also having a global resource file or having one resource for the entire application?

I noticed that for each resource file I create, VS creates a new file under /obj/ directory.
  

Your comment:

Title:
Name:
Email:
Website:
 
Italic Underline Blockquote Hyperlink
 
 
Please add 3 and 2 and type the answer here: