Introduction
A project that I am working on makes heavy use of the DisplayAttribute
from the System.ComponentModel.DataAnnotations
namespace. Because the application is localized in various languages, I make use of resource files.
The problem is that in case one makes a type in the name of one of these resource string
s, the application will only throw an error during runtime. I wrote some code to verify all the DisplayAttributes
I used in my project in a unit test, allowing me to check the validity without any manual labour.
Background
The DisplayAttribute
is used as follows in a localized application:
[Display(Name = "PropertyName", ResourceType = typeof(YourProject.Resources.Strings))]
public string Name { get; set; }
In the example case, a resource string
named "PropertyName
" should exist in the YourProject.Resources.Strings
resource file. If it does not and your code attempts to make use of the DisplayAttribute
, you'll see the following exception:
InvalidOperationException
Cannot retrieve property 'Name' because localization failed.
Type 'YourProject.Resources.ContractStrings' is not public or does not contain
a public static string property with the name 'PropertyName'.
The most elegant way would be to come up with some statically typed solution, which can check the presence of the resources at run time. This would eliminate the problem all together. I have however not yet seen such a solution.
In order to catch any misspelled or missing resource names before deployment and without manual testing, I created a unit test, which uses all the DisplayAttributes
I used in my code.
Using the Code
Wrap the code below in a unit test. Make sure to update the assembly selection query in the first line.
Note that you need to make sure that the relevant assemblies are loaded in the application domain when running this test.
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where
(a => a.FullName.ToLower().Contains("yourKeyword"));
foreach (var assembly in assemblies)
{
var members = assembly.GetTypes()
.SelectMany(type => type.GetMembers().Where
(m => Attribute.IsDefined(m, typeof(DisplayAttribute))));
foreach (var member in members)
{
foreach (var attribute in member.GetCustomAttributes
(typeof(DisplayAttribute), true).Cast<DisplayAttribute>())
{
attribute.GetName();
attribute.GetDescription();
attribute.GetShortName();
}
}
}