Attributes are a great way to add metadata or information in a declaritive way to your code. In .NET MVC projects with C#, you can find attributes used to add validation to models.
1 [Required]
2 [StringLength(50, MinimumLength = 10)]
3 public string Title { get; set; }
4
5 [Required]
6 [Display(Name = "Article Date")]
7 [DataType(DataType.Date)]
8 public DateTime ArticleDate { get; set; }
Attributes help define routes, HTTP verbs, and permissions.
1[Route("Articles")]
2[Authorize(Policy = "Editor")]
3public class NewsArticleController : Controller
4{
5 [Route("")]
6 [Route("List")]
7 public IActionResult Index() { ... }
8
9 [HttpPost("article/{id}")]
10 public IActionResult Edit(int id) { ... }
11}
In Visual Studio the quickest and easiest way to get started with Attributes is with the Attribute Snippet. You can type Attribute
and press Tab
to have Visual Studio generate a sample Attribute snippet. That Attribute snippet generates the following:
1[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
2sealed class MyAttribute : Attribute
3{
4 // See the attribute guidelines at
5 // http://go.microsoft.com/fwlink/?LinkId=85236
6 readonly string positionalString;
7
8 // This is a positional argument
9 public MyAttribute(string positionalString)
10 {
11 this.positionalString = positionalString;
12
13 // TODO: Implement code here
14
15 throw new NotImplementedException();
16 }
17
18 public string PositionalString
19 {
20 get { return positionalString; }
21 }
22
23 // This is a named argument
24 public int NamedInt { get; set; }
25}
This generates a new class that inherits from the Attribute class. It is not required that the class ends with "Attribute" but it is a convention to help others understand your code.
An important thing to note is that the class has an attribute itself that asks three questions.
An Attribute class can accept required constructor parameters, optional constructor parameters, and multiple constructor overloads, just like most any other class in C#.
Using a similar example to the one in Jason Roberts' C# Attributes: Power and Flexibility for Your Code Pluralsight course, we can create an attribute that changes the color of a property when displayed in a console app.
We will modify the original snippet generated by Visual Studio to create a Color Attribute class.
1[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
2sealed class ColorAttribute : Attribute
3{
4 public ColorAttribute(ConsoleColor color = ConsoleColor.Cyan)
5 {
6 Color = color;
7 }
8
9 public ConsoleColor Color { get; }
10}
This allows someone to use [Color]
or [Color(ConsoleColor.Red)]
on a property. It sets the default color to be Cyan if no color is added to the attribute when used.
A common thing that trips people up with custom attributes is that they are a two step process. The above code only allows us to set the attribute on a property. We now need to add logic elsewhere in our application to use our new attribute.
1// First apply our new attributes to properties in a class
2public class Dog
3{
4 [Color(ConsoleColor.Red)]
5 public string Name { get; set; }
6 [Color]
7 public string Breed { get; set; }
8 public int Age { get; set; }
9}
10
11// Next create a class to use those properties
12public static class DogConsoleWriter
13{
14 public static void Line(Dog dog)
15 {
16 var defaultColor = Console.ForegroundColor;
17 Console.Write("Name: ");
18 // Here the console foreground is set to either the attribute color or a default color
19 Console.ForegroundColor = GetPropertyColor(nameof(Dog.Name)) ?? defaultColor; ;
20 Console.Write(dog.Name);
21 Console.ForegroundColor = defaultColor;
22 Console.WriteLine();
23
24 Console.Write("Breed: ");
25 Console.ForegroundColor = GetPropertyColor(nameof(Dog.Breed)) ?? defaultColor;
26 Console.Write(dog.Breed);
27 Console.ForegroundColor = defaultColor;
28 Console.WriteLine();
29
30 Console.Write("Age: ");
31 Console.ForegroundColor = GetPropertyColor(nameof(Dog.Age)) ?? defaultColor;
32 Console.Write(dog.Age);
33 Console.ForegroundColor = defaultColor;
34 Console.WriteLine();
35 }
36
37 // Here is the most important part
38 private static ConsoleColor? GetPropertyColor(string propertyName)
39 {
40 // This uses C#'s reflection to get the attribute if one exists
41 PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
42 ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
43
44 // If colorAttribute is not null, than a color attribute exists
45 if(colorAttribute != null)
46 {
47 return colorAttribute.Color;
48 }
49 return null;
50 }
51}
Now a Console application could use this class in a similar fashion:
1DogConsoleWriter.Line(new Dog
2{
3 Name= "Astro",
4 Breed= "Newfoundland"
5});
Let's take a closer look at the GetPropertyColor
method where the most important steps are done.
1private static ConsoleColor? GetPropertyColor(string propertyName)
2{
3 PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
4 ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
5
6 if(colorAttribute != null)
7 {
8 return colorAttribute.Color;
9 }
10 return null;
11}
This method accepts a string of the property name GetPropertyColor(string propertyName)
. The string is passed by using the nameof operator, nameof(Dog.Age)
, to provide type safety.
The property name is then used in the first line of the method to get the Property Info for the type specified. The type in our case is the Dog type. PropertyInfo propertyInfo = typeof(Dog).GetProperty(propertyName);
Once the PropertyInfo is obtained we can check to see if it has any attributes applied. Since we only care about the ColorAttribute, we specify that type. ColorAttribute colorAttribute = (ColorAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColorAttribute));
GetCustomAttribute will return null if it cannot find an attribute.
You can add an attribute to any of the following in C#:
Adding attributes helps others to understand what your code aims to accomplish at a quick glance, without having to understand the logical steps that make it happen.
To learn even more about C# Attributes, check out the full course C# Attributes: Power and Flexibility for Your Code by Jason Roberts. Jason describes multiple attribute use case examples and even more advanced methods of creating and using attributes.