C# .NET Core Filters

.NET Core Filters

Filters are used to implement reusable MVC pipeline logic that can be applied across the system, without writing that logic in all of your actions. Examples might be Exception handling, authorization, response caching etc. Filters intercept the stages of the MVC pipeline and allows us to run code before/after their executions.

There are different types of filters, and each happens in a different stage of the pipeline.

  • Authorization Filters run first to determine if the request is authorized and can short-circuit the pipeline if it is unauthorized.
  • Resource Filters are first after authorization. They can run code against the request on the way in and on the way out. Often used for caching or influencing the model binding. Can short-circuit the pipeline.
  • Action Filters are used to run code immediately before and/or immediately after the controller action. Can manipulate the arguments or results of the action.
  • Exception Filters are used go apply global policies to unhandled exceptions before anything is written to the response.
  • Result Filters are used to run code immediately before and/or after successful execution of action results. Useful for view formatting.

Filter Scopes

You can add a filter to request pipelines in 3 scope levels:

  • Globally using MvcOptions.Filters in ConfigureServices of your Startup
  • Controller level via Attributes
  • Specific action via Attributes
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(typeof(ExceptionFilter));
    });
}

As an attribute

public class ExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        ILogger logger = LogManager.GetLogger(context.ActionDescriptor?.DisplayName);

        logger.Error(context.Exception);
    }
}

On the Controller


[ExceptionFilter]
public class TestController : Controller
{
    // GET: api/test
    [HttpGet]
    public IEnumerable Get()
    {
        return View(new HomeViewModel());
    }
}

On the Action


public class TestController : Controller
{
    // GET: api/test
    [HttpGet]
    [ExceptionFilter]
    public IEnumerable Get()
    {
        return View(new HomeViewModel());
    }
}

You can set order on Filters with an Order property.
[ExceptionFilter, Order = 5]

Filters with the same Order run outside-in, meaning first global, then controller and then action-level filters are run.

Async / Sync Filters

Filter supports synchronous and asynchronous filters; The implementations use different interfaces.

Synchronous filters specify directly what happens in order using OnActionExecuting and OnActionExecuted. OnActionExecuting method is called before the action method and OnActionExecuted method is called after the action method.


public class CustomActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //To do : before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            //To do : after the action executes
        }
    }

Asynchronous filters are implemented with a single method, OnStageExecutionAsync


public class CustomAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            //To do : before the action executes
            await next();
            //To do : after the action executes
        }
    }

.NET checks first for async filters, if found is called. If it is not found it calls the synchronous interface’s method(s). If both are implemented, the sync version will not be called.

HTML – Using ARIA to make our web pages accessible

HTML – Using ARIA to make our web pages accessible

ARIA stands for ‘Accessible Rich Internet Applications’ and can help make your website more accessible to people with disabilities such as hearing or visual impairment.

We have a lot of help from modern HTML that will help set up the semantic meaning of our websites.

Use semantic HTML elements where possible.
The browser has gotten pretty good at applying semantics to pieces of a page when we use the correct elements to lay out our page. Some examples are nav, button, article. They have default aria statements of role="navigation" etc. It used to be pretty common to have elements like <div class="main-navigation" role="navigation">. But, today we can replace the div with a nav and no longer need to specify the role.

There are times that we need to provide more context to what is going on on our page, so we can describe many more things with additional ARIA attributes.


role

Roles describe widgets and structure. They are added as attributes on elements.
Roles are used as navigation aids for assistive software like screen readers.

<div id="header" role="banner">
<div id="nav"  role="navigation">

aria-label and aria-labelledby

The aria-label attribute is used to label a form element that is not visible on the page, maybe this is dictated by design etc, but we still need to provide the screen reader with something to describe the widget.

A button may be styled to look like a close button, with an X in the middle. Since there is nothing indicating that the purpose of the button is to close the dialog, the aria-label attribute is used to provide the label to assistive technologies.


<button aria-label="Close" onclick="myDialog.close()">X</button>

When the text is visible, we should use aria-labelledby instead.

<div id="billing">Billing</div>
  <div>
    <div id="name">Name</div>
    <input type="text" aria-labelledby="billing name"/>
  </div>
  <div>
    <div id="address">Address</div>
    <input type="text" aria-labelledby="billing address"/>
  </div>

aria-disabled

Some aria attributes are used to describe the state of the widget. It is common for aria states to change on a page, whereas properties generally stay static.
aria-disabled="true" helps describe to assistive technology that a widget is present, but it is not currently functional – disabled. Some readers will skip right over disabled content, some will announce that it’s unavailable.


aria-haspopup

The aria-haspopup="true" can be used to describe that there is a menu or sub-menu. You attach it to the element that will trigger the menu.


aria-hidden

The aria-hidden attribute is used to tell the screen readers to ignore the element. This will cover children elements as well. The elements are described as not perceivable to any user.


aria-expanded

The aria-expanded is another aria state that can take true or false saying that an element is currently expanded and visible. False means the expandable section or items are currently collapsed or invisible.


aria-busy

The aria-busy="true" state is used as part of a live region. Setting this to true when a relevant portion of the page is currently getting updated and the users are waiting to get the updated content. Readers will wait until the attribute is removed before it continues providing that information to the user. Sometimes they will hear “busy” audibly while waiting.


aria-*

aria-* is used to describe global aria attributes that can be used on any html element in any role. Some aria attributes are limited to be used in only certain roles.

ARIA roles, states and properties permitted for use in HTML

HTML Forms – Identifying inputs

HTML Forms – Identifying inputs

Label

The <label> element is the most formal way to tie an input to it’s label. This is the most important element when building accessible forms. When you implement it correctly, screen readers and other software will speak aloud the element’s label along with any other related instructions.

This is how we use it:

<label for="name">Name:</label> <input type="text" id="name" name="user_name">

You associate the label to the input via the for and id attributes.

This will get the screen reader to read something like “Name. Edit text”

Another bonus of setting a label to tie to it’s input, is when you use a checkbox or radio, it will actually make the label click-able and correctly check or uncheck the box.

<div>
  <input type="checkbox" id="coding" name="interest" value="coding" checked>
  <label for="coding" style="display: inline-block">Coding</label>
  </div>
  <div>
    <input type="checkbox" id="music" name="interest" value="music">
    <label for="music" style="display: inline-block">Music</label>
</div>

Fieldsets and legends

The <fieldset> element can be used to group inputs together, semantically and/or with styles. You can add a label to a fieldset by using the <legend> tag. The legend is used to formally describe the fieldset that it is inside.

Assistive software like screen readers will read the legend of a fieldset with each input.

<form>
  <fieldset>
    <legend>Fruit juice size</legend>
    <p>
      <input type="radio" name="size" id="size_1" value="small">
      <label for="size_1">Small</label>
    </p>
    <p>
      <input type="radio" name="size" id="size_2" value="medium">
      <label for="size_2">Medium</label>
    </p>
    <p>
      <input type="radio" name="size" id="size_3" value="large">
      <label for="size_3">Large</label>
    </p>
  </fieldset>
</form>
Fruit juice size

The screen reader, for the above code, would speak something like “Fruit juice size small” for the first input, and “Fruit juice size medium” for the second and so on.

This use case is one of the most important when considering accessibility. You should nest each radio group inside of a fieldset.

It can also be used to break up forms into sections. But make sure that it makes sense. It sometimes is better to break up the form across multiple pages rather than sectioning off a single page.

Listen to it on screen reader software and make sure that it makes sense and isn’t too complicated to understand.

HTML Inputs

HTML Inputs

In your HTML you often will want to collect information from the user. We generally do this through the use of different types of inputs. These might be different kinds of text inputs or some kind of choice inputs. Most of these will be implemented using the <input> tag with a type attribute.


Input Type Text

<input type="text"> Is used for a one-line text input.

<form>
    Favorite Food:<br>
    <input type="text" name="favoritefood"><br>
    Favorite Drink:
    <input type="text" name="favoritedrink"><br>
  </form>

How this will look on the page:

Favorite Food:

Favorite Drink:


Input Type Password

<input type="password"> Is used for an obfuscated password input.

<form>
    User name:<br>
    <input type="text" name="username"><br>
    Password:
    <input type="password" name="password"><br>
  </form>

How this will look on the page:

User name:

Password:


Input Type Email

<input type="email"> Is used as an email input field.
Some browsers will automatically validate email format on submit.
Some mobile browsers will use a special keyboard for email inputs, that includes a “.com” button etc.

<form>
    E-Mail:<br>
    <input type="email" name="email"><br>
  </form>

How this will look on the page (try it on mobile):

E-Mail:


Input Type File

<input type="file"> Is used for a file-select input, with a “Browse” or “Choose file” button for file uploads.

<form>
    Select File:<br>
    <input type="file" name="file"><br>
  </form>

How this will look on the page:

Select File:


Input Type Range

<input type="range"> Is used as a selector for a number within a certain range. The default range is 0 to 100, but you can define those restrictions

<form>
    Order Quantity:<br>
    <input type="range" name="qty" min="0" max="10"><br>
  </form>

How this will look on the page:

Order Quantity:


Input Type Hidden

<input type="hidden"> Is used to include data in your form to be submitted, that you don’t want to actually display on the page.

Warning: It will still be in the markup, so don’t store sensitive data here.

<form>
  Favorite Food:<br>
  <input type="text" name="favoritefood"><br>
  Favorite Drink:
  <input type="text" name="favoritedrink"><br>

  <input type="hidden" id="sessionid" name="sessionid" value="x8ysia7">
  <button type="submit">Submit</button>
</form>

How this will look on the page:

Favorite Food:

Favorite Drink:




Input Placeholder attribute

<input type="text" placeholder="pattern"> Is used as a hint that describes the expected value for the input.
It is allowed on input types: text, search, url, tel, email, and password.

Warning: Do not use the placeholder attribute in place of a <label> element. The label describes the role of the input. The placeholder is just a hint. There are cases that the placeholder will not be shown or not understood correctly for accessibility, so the form must be understandable without it.

<form>
    Phone Number:<br>
    <input type="tel" name="tel" placeholder="(###) ###-####"><br>
  </form>

How this will look on the page:

Phone Number:


Input Type Radio

<input type="radio"> Is used as a choice input where only one option may be chosen.

The name attribute is what will group these together as semantically belonging together as a group.

<form>
  Gender:<br>
  <input type="radio" name="gender" value="male"> Male<br>
  <input type="radio" name="gender" value="female"> Female<br>
  <input type="radio" name="gender" value="other"> Other

How this will look on the page:

Gender:
Male
Female
Other

Input Type Checkbox

<input type="radio"> Is used as a choice input where multiple options may be chosen, or there is just an on/off or yes/no state.

The name attribute is what will be the data key if you are using a form submit action. The value for that key will be in the value attribute, if no value is provided, it will default to on. An unchecked checkbox will not send a value on a submit.

You can use the checked attribute to default a checkbox to checked.

<fieldset>
  <legend>Choose your interests</legend>
  <div>
    <input type="checkbox" id="coding" name="interest" value="coding" checked>
    <label for="coding">Coding</label>
  </div>
  <div>
    <input type="checkbox" id="music" name="interest" value="music">
    <label for="music">Music</label>
  </div>
</fieldset>

How this will look on the page:

Choose your interests

Select dropdown input

<select> Is it’s own input type that can have multiple options to choose from a dropdown.

You can provide a selected attribute to set a default. You can also provide a value attribute to specify the value saved when selected.

You can use the multiple attribute to allow for the user to ctrl-click multiple selections. But this can be a difficult interaction for users if they aren’t familiar with that functionality, and even more difficult when considering accessibility and people using only keyboards.

<select name="optionid">
  <option value="option1">Option 1</option>
  <option value="option2">Option 2</option>
  <option value="option3" selected>Option 3</option>
</select>

How this will look on the page:

You can use the <optgroup> element to break options into sections.

<select>
  <optgroup label="Group 1">
    <option>Option 1.1</option>
  </optgroup>
  <optgroup label="Group 2">
    <option>Option 2.1</option>
    <option>Option 2.2</option>
  </optgroup>
  <optgroup label="Group 3" disabled>
    <option>Option 3.1</option>
    <option>Option 3.2</option>
    <option>Option 3.3</option>
  </optgroup>
</select>

How this will look on the page:


Input Type Submit

You use the submit input type for the control, usually a button, that will submit the form data, generally to your back-end.

An input with type submit will be styled as a button, and the value attribute describes what the text on the button will say. If value is omitted, the browser will use it’s default.

<input type="submit" value="Send">

You can use your own custom element or button, but be aware that if there is only one <button> element inside a form, it will be treated as the submit action. So, you should get in the habit of always applying the type="submit" attribute.


Destructure Nested Array And Object

When doing deep and nested destructuring, you can destructure array items by index

function nestedArrayAndObject() {
  const info = {
    title: 'Once Upon a Time',
    protagonist: {
      name: 'Emma Swan',
      enemies: [
        {name: 'Regina Mills', title: 'Evil Queen'},
        {name: 'Cora Mills', title: 'Queen of Hearts'},
        {name: 'Peter Pan', title: `The boy who wouldn't grow up`},
        {name: 'Zelena', title: 'The Wicked Witch'},
      ],
    },
  }

  // const title = info.title
  // const protagonistName = info.protagonist.name
  // const enemy = info.protagonist.enemies[3] <----
  // const enemyTitle = enemy.title
  // const enemyName = enemy.name

  const {
    title,
    protagonist: {
      name: protagonistName,
      enemies: {
        3: { // destructure nested array by index
          title: enemyTitle,
          name: enemyName,
        },
      },
    },
  } = info;

  return `${enemyName} (${enemyTitle}) is an enemy to ${protagonistName} in "${title}"`
}

console.log(nestedArrayAndObject());
// Zelena (The Wicked Witch) is an enemy to Emma Swan in "Once Upon a Time"

Thanks to @KentDodds for the example on his ES6 and Beyond YouTube series.

Never console.log(objOrArray) and have to dig down into the items or properties again!

console.table(data) logs your data as a table in the console

console.table(data) can be used to log any array or enumerable properties of an object into a table format in the console.

This function is available in all modern browsers, except IE.

The function takes one mandatory argument, the data that you want to log. It must be an object or array. It has a second optional parameter which can define which columns that you want to display.

The first column in the table will be labeled (index). If data is an array, then its values will be the array indices. If data is an object, then its values will be the property names.

// logs a sortable table right in the console!
console.table(["one", "two", "three"]);
(index) Values
0 “one”
1 “two”
2 “three”

Object with string properties


  const person = {
    firstName: "RJ",
    lastName: "Schmertz"
  }

  console.table(person);
(index) Values
firstName “RJ”
lastName “Schmertz”

Array of objects


  const person1 = {
    firstName: "RJ",
    lastName: "Schmertz"
  }
  const person2 = {
    firstName: "Ryan",
    lastName: "Smith"
  }
  const person3 = {
    firstName: "Cassie",
    lastName: "Jones"
  }

  console.table([person1, person2, person3]);
(index) firstName lastName
0 “RJ” “Schmertz”
1 “Ryan” “Smith”
2 “Cassie” “Jones”

Object whose properties are objects


  const person1 = {
    firstName: "RJ",
    lastName: "Schmertz"
  }
  const person2 = {
    firstName: "Ryan",
    lastName: "Smith"
  }
  const person3 = {
    firstName: "Cassie",
    lastName: "Jones"
  }

  const family = {};

  family.father = person1;
  family.brother = person2;
  family.sister = person3;


  console.table(family);
(index) firstName lastName
father “RJ” “Schmertz”
brother “Ryan” “Smith”
sister “Cassie” “Jones”

Restricting which columns are displayed


  const person1 = {
    firstName: "RJ",
    lastName: "Schmertz"
  }
  const person2 = {
    firstName: "Ryan",
    lastName: "Smith"
  }
  const person3 = {
    firstName: "Cassie",
    lastName: "Jones"
  }

  const family = {};

  family.father = person1;
  family.brother = person2;
  family.sister = person3;


  console.table([person1, person2, person3], ["firstName"]);
(index) firstName
0 “RJ”
1 “Ryan”
2 “Cassie”

CSS Variables

CSS Variables

We all know that we’ve had variables in SASS/LESS etc for a long time. But did you know, that we have native CSS variables right in the browser now!? With zero compiling, transforms or transpiling.

CSS variables, like variables in any programming language, allow us to define styles and reference them anywhere else and even modify them with javascript.

CSS Variables are supported by all modern browsers, except IE
MDN is calling them Custom properties (–*)


How to use them

We can define any CSS property in a CSS variable, ie: color, border, size, position. We prefix their name with --. We declare them by adding them to any element, which will scope just like any other CSS property would.


:root {
  --base-color: #ffc600;
  --spacing: 10px;
  --blur: 10px;
} 

Remember, we can place these on any element, to create scoping. If we created these properties inside the class .main-content and tried to use them outside the scope of elements inside of that class, it would not be applied.


We use them by putting them inside of a var().


img {
  padding: var(--spacing);
  background: var(--base-color);
  filter: blur(var(--blur));
}

We can also provide an optional default value to the var() call.


padding: var(--spacing, 5px);

/* or even multiple fallbacks */
color: var(--color-one, --color-two, red);

You can access and modify your CSS variables in Javascript

One of the most powerful gains we get by using native CSS variables, is we can modify them right inside our page with javascript. Your transpiled languages like SASS are only for build time, and once they are set, they are set.


document.documentElement.style.setProperty('--base-color', 'blue');

No more adding-removing classes just to change between different style sets.


No more defining multiple variables for different media queries

…Or any other scoped changes.

So, you want different link styles on your mobile site than you do on your desktop site? And you still want to provide consistency with variables? Easy. We will use native CSS scoping to redefine the value of our variables only for that scope.


body {
  --primary: #7F583F;
  --secondary: #F7EFD2;
}

a {
  color: var(--primary);
  text-decoration-color: var(--secondary);
}

@media screen and (min-width: 768px) {
  body {
    --primary:  #F7EFD2;
    --secondary: #7F583F;
  }
}

Working example

@Wesbos has a great example of this in his FREE #Javascript30 series. I’ve posted it in a codepen here for you to play with

Working Example


Reminder, Pluralsight has many courses on all of this in many different languages and implementations, and they have a FREE Trial!

Start a 10-day free trial at Pluralsight

CSS Selectors

CSS Selectors

In CSS, selectors are patterns used to select the elements that you want to apply the style to.

Class

Usage: .classname will select any element that has class=”classname”


ID

Usage: #myId will select any element that has id=”myId”. There should always only be one element in a document with a given ID.


Attribute

Selects elements based on the value of the given attribute
Usage: [attr] [attr=value]
More Examples:

/* <a> elements with a title attribute */
a[title] {
  color: purple;
}

/* <a> elements with an href matching "https://example.org" */
a[href="https://example.org"] {
  color: green;
}

/* <a> elements with an href containing "example" */
a[href*="example"] {
  font-size: 2em;
}

/* <a> elements with an href ending ".org" */
a[href$=".org"] {
  font-style: italic;
}

[attr]
Represents an element with an attribute name of attr.

[attr=value]
Represents an element with an attribute name of attr whose value is exactly value.

[attr~=value]
Represents an element with an attribute name of attr whose value is a whitespace-separated list of words, one of which is exactly value.

[attr|=value]
Represents an element with an attribute name of attr whose value can be exactly value or can begin with value immediately followed by a hyphen, – (U+002D). It is often used for language subcode matches.

[attr^=value]
Represents an element with an attribute name of attr whose value is prefixed by value.

[attr$=value]
Represents an element with an attribute name of attr whose value is suffixed by value.

[attr*=value]
Represents an element with an attribute name of attr whose value contains at least one occurrence of value within the string.

[attr operator value i]
Adding an i (or I) before the closing bracket causes the value to be compared case-insensitively


Pseudo-classes

Allows the selection of elements based on state information that is not contained in the document tree.

Examples: :active :disabled :focus :visited


Sibling

Adjacent sibling: The + combinator selects adjacent siblings. This means that the second element directly follows the first, and both share the same parent.
Example: h2 + p will match all <p> elements that directly follow an <h2>.

General siblings: The ~ combinator selects siblings. This means that the second element follows the first (though not necessarily immediately), and both share the same parent.
Example: p ~ span will match all <span> elements that follow a <p>.

Child combinator: The > combinator selects nodes that are direct children of the first element.
Example: ul > li will match all <li> elements that are nested directly inside a <ul> element.

Descendant combinator: The     (space) combinator selects nodes that are descendants of the first element.
Example: div span will match all <span> elements that are inside a <div> element.

HTML base elements

HTML DOCTYPE

The first line of an HTML document is the Doctype declaration. This is used to tell the browser what version of HTML you are using. DOCTYPEs are required for legacy reasons. HTML is responsible for informing the browser how text and objects will appear in the web page. DOCTYPE declaration is not an HTML tag. It is only a declaration and always appears at the first line of your HTML documents. There are a number of different doctype declarations that correspond to various versions of HTML.

HTML5 – does not have a formal DTD (Document Type Definition) in the form of a URL or other Formal Public Identifier

<!DOCTYPE html>

HTML 4.01 Strict – Does not allow Framesets, presentational or deprecated elements

<DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

etc …


HTML lang attribute

You can provide HTML Language Code Reference.

ISO Language Codes – The HTML lang attribute is used to declare the language of the web page, used by search engines and the browser. It is best practice to provide the primary language on the lang attribute on the root HTML tag.

In HTML5, the lang attribute can be used on any HTML element (it will validate on any HTML element. However, it is not necessarily useful).

In HTML 4.01, the lang attribute cannot be used with: <base>, <br>, <frame>, <frameset>, <hr>, <iframe>, <param>, and <script>.

<html lang="en">
  ...
</html>

In XHTML, the language is declared inside the html tag as well


<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
...
</html>

You can find a list of the language codes here


HTML HEAD element

The <head> element is a container for all the head elements.

The <head> element can include a title for the document, scripts, styles, meta information, and more.

The following elements can go inside the <head> element:

<title> (this element is required in an HTML document)
Defines the Title in the browser tab
Used as the title when added to favorites
Displayed as the title in search engine results

<style>
Used to define style information for the HTML page. CSS

<base>
specifies the base URL and base target for all relative URLs in a page

<link>
Used to link external resources and stylesheets

<meta>
used to specify which character set is used, page description, keywords, author, and other metadata.

<script>
used to define client-side JavaScripts.

<noscript>
defines an alternate content for users that have disabled scripts in their browser or have a browser that doesn’t support script.

In HTML 4.01, the head element is required,
In HTML5 it may be omitted.

Strategy Pattern

What is the Strategy Pattern?

Wikipedia describes it as:

In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. The strategy pattern:

  • – defines a family of algorithms
  • – encapsulates each algorithm
  • – makes the algorithms interchangeable within that family

The Strategy Pattern allows you to implement algorithms and usages of those algorithms completely separate. This allows you to have very flexible and reusable code, without the client that is using the code to know anything about how it works. The client can choose which version of the algorithm based on the information that it has; maybe the type of data, where the data came from, maybe user interaction. This can be done in a multitude of ways, including delegates, methods, class instances and interfaces – often using reflection to determine usage.


Let’s look at .NET/Linq’s IList.Sort as an example.

 public class Person {
  public string Name { get; set; }
  public int Age { get; set; }

  public override string ToString() {
    return $"{Name}: {Age}";
  }
}

public class Strategy {
  public static readonly ReadOnlyCollection<Person> People = new List<Person>
  {
    new Person { Name = "RJ", Age = 32 },
    new Person { Name = "Ryan", Age = 30 },
    new Person { Name = "Cassie", Age = 28 },
    new Person { Name = "Robert", Age = 57 }
  }.AsReadOnly();

  public void main() {
    var list = People.ToList();
    // Use a built delegate
    list.Sort(CompareByAge);

    // Use explicit lamda expression
    list.Sort((x, y) => x.Age.CompareTo(y.Age));

    // Implemented Single Method Interface
    list.Sort(new AgeComparer());

    foreach (var person in list) {
      Console.WriteLine(person);
    }
  }

  static int CompareByAge(Person left, Person right) {
    return left.Age.CompareTo(right.Age);
  }

  public class AgeComparer : IComparer<Person> {
    public int Compare(Person left, Person right) {
      return left.Age.CompareTo(right.Age);
    }
  }
}

None of the Comparison methods, know about sorting.

The sort method doesn’t know how to compare.

Clean separation of concerns

Adheres to the SOLID principle, enforcing Single Responsibility for more flexible code.

Using the strategy and implementing the strategy are completely separate.

Linq has endless uses of the Strategy pattern.


My company also takes advantage of this pattern for MVC Controller input model validation. This is just a snippet of it, but we plug in FluentValidation which has an AbstractValidator<T> that registers this Strategy to controllers that have an input model of T. This makes it so the controller does not even need to know about any validation at all. You just register how your Strategy should be applied with a marker interface of IValidated, and it does it. Very easy to add rules and sub-rules, and change it whenever you want, without changing your controller code.


public class AttributesInputModel : FormAttributes, IValidated
{
}

public class AttributesInputModelValidator : AbstractValidator<AttributesInputModel>
{
  public AttributesInputModelValidator(IFormAttributesCache cache)
  {
    CascadeMode = CascadeMode.StopOnFirstFailure;

    RuleFor(x => x.EffectiveDateString)
      .NotNull()
      .WithMessage("The effective date must be provided.");

    RuleFor(x => x.EffectiveDateString)
      .SetValidator(new DateValidator("Must provide a valid effective date."));

    RuleFor(x => x.EffectiveDate)
      .Must(x => x.Day == 1)
      .When(x =>
        !string.IsNullOrEmpty(x.EffectiveDateString)
        && DateValidator.IsValid(x.EffectiveDateString))
      .WithMessage("The effective date must be the first of the month.");

    RuleFor(x => x.ExpirationDateString)
      .SetValidator(new DateValidator("Must provide a valid expiration date, when provided."))
      .When(x => !string.IsNullOrEmpty(x.ExpirationDateString));

    RuleFor(x => x.ExpirationDate)
      .Must((model, x) => !x.HasValue || model.EffectiveDate <= x.Value)
      .When(x =>
        !string.IsNullOrEmpty(x.ExpirationDateString)
        && DateValidator.IsValid(x.ExpirationDateString))
      .WithMessage("Effective date must come before the expiration date.");

    RuleFor(x => x.ExpirationDate)
      .Must((model, x) =>
        !x.HasValue
        || x.Value.Day == DateTime.DaysInMonth(x.Value.Year, x.Value.Month))
      .When(x =>
        !string.IsNullOrEmpty(x.ExpirationDateString)
        && DateValidator.IsValid(x.ExpirationDateString))
      .WithMessage("Expiration date must be the last day of the month.");
  }
}

public class DateValidator : PropertyValidator
{
  public DateValidator(string errorMessage)
    : base(errorMessage) {}

  protected override bool IsValid(PropertyValidatorContext context)
  {
    var dateString = (string)context.PropertyValue;
    return IsValid(dateString);
  }

  public static bool IsValid(string dateString)
  {
    DateTime date;
    var result = DateTime.TryParse(dateString, out date);
    return result;
  }
}

Reminder, Pluralsight has many courses on different design patterns in many different languages and implementations, and they have a FREE trial!

Start a 10-day free trial at Pluralsight