Leveraging Acceptance Criteria When Writing Agile User Stories

As near as I can tell, everyone who's doing Agile is writing requirements in the user story format of "As <role> I need to <do something> so that I can <achieve some goal>." For example, "As a customer I need to be able to search the inventory so that I can find the products I want to buy."

It's worth remembering that this is just one format for user stories (and a very good one) -- you shouldn't be trying to force everything into that format (infrastructure or regulatory requirements often sound silly in this format: "As the VP of Finance I need to produce the list of transferred securities every month so that I don't go to jail").

There are some common extensions to this user story format. Popular ones are a "best before" date (for time constrained requirements) and acceptance criteria. The primary purpose of acceptance criteria is to participate in the "definition of done": When these tests are passed, this story is done.

That means, of course, it should always be possible to imagine a test that would prove the criteria has been achieved (preferably an automated test, but that's not essential). Personally, an acceptance criteria of "I can do my job" fails on that "testability" basis alone: How could I tell if you can do your job? Perhaps you were never capable of doing your job.

Also personally, I think you can use acceptance criteria for more than that by leveraging those criteria to create better stories.

One thing you can do with acceptance criteria is use them to provide detail for the user story. This allows you to keep the user story short (focusing on the main goal) but still record detail that matters to the user. For example, this acceptance criteria helps make it clear what the story means by "search":

User Story: As a customer I need to be able to search the inventory so that I can find the products I want to buy.

Acceptance Criteria: Customers can limit the items returned by the search using criteria that are valuable to them (price, delivery date, location).

The other thing you can use acceptance criteria for is to cross-check the user story to see if it's consistent with its criteria. An acceptance test that isn't consistent with the user story can be an indication that the story is incomplete ... or is an example of scope creep (an attempt to extend the user story beyond its mandate). Something like this list of criteria indicates there's probably a problem with the user story:

User Story: As a customer I need to be able to search the inventory so that I can find the products I want to buy.

Acceptance Criteria:
  1. Customers can limit the items returned by the search using criteria that are valuable to them (price, delivery date, location).
  2. Customers earn loyalty points when purchasing "loyalty" products.

It seems to me that criteria 2 doesn't have much to do with the user story. Either the story needs to be extended (" ... including criteria that are important to them, like loyalty points") or there's a need for another story ("As a customer, I want to accumulate loyalty points").

Posted by Peter Vogel on 11/15/2019 at 10:27 AM0 comments


Mocking an Authenticated User in Blazor/ASP.NET Core

I've done a couple of recent columns about securing Blazor Components and using claims-based policies declaratively in ASP.NET Core generally. While working with security, I'm always interested in doing end-to-end testing: Starting up the application and seeing what happens when I try to navigate to a page.

However, while that matters to me, I'm less interested in setting up users with a variety of different security configurations (so many names! so many passwords!). Inevitably while thinking I'm testing one authorization scenario, I pick a user that actually represents a different scenario.

So I created a MockAuthenticatedUser class that, once added to my application's middleware, creates an authenticated user for my application. I find it easier to configure my mock user's authorization claims in code before running a test than it is to maintain (and remember) a variety of users.

If you think you might find it useful, you can add it to your processing pipeline with code like this in your Startup class' ConfigureServices method:

services.AddAuthentication("BasicAuthentication")
                .AddScheme<AuthenticationSchemeOptions, 
                              MockAuthenticatedUser>("BasicAuthentication", null);

To use this class, you'll also need this line in your Startup class' Configure method:

app.UseAuthentication();

I should be clear that I've only used this to test Controllers so it might behave differently with Razor Pages.

Here's the code for my MockAuthenticatedUser class that configures a user with a name, an Id, a role, and some random claims:

using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace SampleBlazor.Models
{
  public class MockAuthenticatedUser : AuthenticationHandler<AuthenticationSchemeOptions>
  {
    const string userId = "phv";
    const string userName = "Jean Irvine";
    const string userRole = "ProductManager";

    public MockAuthenticatedUser(
      IOptionsMonitor<AuthenticationSchemeOptions> options,
      ILoggerFactory logger,
      UrlEncoder encoder,
      ISystemClock clock)
      : base(options, logger, encoder, clock){ }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
      var claims = new[] 
        {
          new Claim(ClaimTypes.NameIdentifier, userId),
          new Claim(ClaimTypes.Name, userName),
          new Claim(ClaimTypes.Role, userRole),
          new Claim(ClaimTypes.Email, "peter.vogel@phvis.com"),
        };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);

        return await Task.FromResult(AuthenticateResult.Success(ticket));
    }
  }
}

Posted by Peter Vogel on 11/14/2019 at 9:11 AM0 comments


Extend Your .NET Namespaces for Static Methods and Simpler Code

Let's say you've gone to the trouble of creating a CustomerRepository object with a static method called GetCustomerById. Something like this, in other words:

public class CustomerRepository
{
   public static Customer GetCustomerById(int Id)
   {

   }
}

In your file where you want to use that method you've added the appropriate using statement. Something like this, for example:

using SalesOrderMgmt.Repos;

And that's all great because now you can call your method straight from the class name, like this:

Customer cust = CustomerRepository.GetCustomerById(42);

But, because you're calling a static method, you can simplify your code a little more by extending your using statement down to the class level. Just add the keyword static to your using statement and end it with the class name. In other words, I'd rewrite my previous using statement to this:

using static SalesOrderMgmt.Repos.CustomerRepository;

Now I can use static method from my CustomerRepository class without referencing the class. My call to retrieve a customer object now looks like this:

Customer cust = GetCustomerById(42);

It also works with constants like PI in Math.PI. So go ahead and add this using statement to your code:

using static System.Math;

Now, when you calculate the area of a circle you can just write

double area = radius * PI^2;

Which I think is pretty cool. I can see how the resulting code might confuse the "next developer" who isn't familiar with this -- the next developer might reasonably expect GetCustomerById or PI to be declared in the class where I'm using it. But all that developer has to do is click on the method or constant name, press F12 and be taken straight to the actual code in the class where it's defined. If you're OK with extension methods, this isn't all that different.

Posted by Peter Vogel on 11/08/2019 at 10:46 AM0 comments


Arranging Columns in Visual Studio Windows (with Sorting!)

Admittedly, the tool window I use most in Visual Studio is the Error List (I probably use it even more than I use Solution Explorer). By and large it meets my needs but it is customizable for those occasions when it does not.

For example, the default Error List display includes a Suppression State column that I hardly ever use. If you don't use it either, you can get rid of it, making more room for the columns you do want (to be more specific: the Description column). All you have to do is right-click on any of the column headers in the Error List and pick Show Columns from the pop-up menu. That will give you a menu of available columns with the currently displayed columns checked off. Clicking on any column in the menu will add the column to the display (if the column isn't currently checked) or remove the column (if it is checked). I don't find the Code column all that useful, either, so I got rid of it also, but that might just be crazy talk as far as you're concerned.

The Grouping option on the menu is also sort of interesting: It inserts headings into the error list. I've experimented with adding a heading at the file level so that all the errors and warnings for any file appear together in the Error list, right under the file name. In the end, however, I've always decided that I wasn't willing to give up the space that the heading takes up; I'd rather have more unorganized errors than fewer organized errors, apparently.

Instead, I've counted on sorting to put all of my "related" errors together. I typically sort by Project, File, and Line number. To get that order (or any order you want), first click on the column header for the column you want as your highest sort level (in my case, that's the Project column). Then hold down the Shift key and click on the other columns you want in the sort, moving from the highest level to the lowest level (for me, that's the File column and then the Line column). If you're not happy with a column's order (ascending or descending) just click the column header again to reverse the order. Visual Studio will remember your sort order.

Posted by Peter Vogel on 10/30/2019 at 3:09 PM0 comments


Why Rejection Prevents Zombies in ASP.NET Core

If you're looking for some interesting reading, try this article by Paulo Gomes on hacking ASP.NET (actually, try googling “Hacking ASP.NET” for a bunch of interesting articles). Paulo's article specifically discusses how an innocent Web application can be used to turn your organization's server into some hacker's puppet/zombie.

One part of the article talks about how creating a zombie requires that a malicious payload be uploaded to the ASP.NET site. As Paulo points out, there is a way to avoid this: “General advice is to reject any malformed input” ... which is where the ApiController attribute comes in.

When you create a Web service in ASP.NET Core, you have the option of applying the ApiController attribute to your service controllers. With that attribute in place, when model binding finds mismatches between the data sent to your service and the parameters passed to your service methods, ASP.NET automatically returns a 400 (Bad Request) status code and doesn't invoke your method. Therefore, there's no point inside a Web Service method to check the ModelState IsValid property because if the code inside your method is executing then IsValid will be true.

You can turn that feature off by omitting the ApiController attribute. But, as Paulo points out, you don't want to: The ApiController method is doing exactly what you want by ensuring that you only accept data that is, at least, well-formed. This won't protect you against every hack, of course, but it's a very good start.

Posted by Peter Vogel on 10/22/2019 at 11:03 AM0 comments


How to Integrate Code with Code Snippets in Visual Studio

As I've noted in an earlier post, I don't use code snippets much (i.e. “at all”). One of the reasons that I don't is that I often have existing code that I want to integrate with whatever I'm getting from the code snippets library.

Some code snippets will integrate with existing code. If I first select some code before adding a code snippet, there are some snippets that will wrap that selected code in a useful way. For example, I might have code like this:

Customer cust;
        cust = CustRepo.GetCustomerById("A123");

I could then select the second line of the code and pick the if code snippet. After adding my code snippet, I'd end up with:

if (true)
        {
          cust = CustRepo.GetCustomerById(custId);
        }

That true in the if statement will already be selected, so I can just start typing to enter my test. That might mean ending up with this code:

if (custId != null)
        {
          cust = CustRepo.GetCustomerById(custId);
        }

You have to be careful with this, though -- most snippets aren't so obliging. If you do this with the switch code snippet, for example, it will wipe out your code rather than wrap it. Maybe I should go back to that previous tip on code snippets -- it discussed how to customize existing snippets (hint: you specify where the currently selected text is to go in your snippet with ${ TM_SELECTED_TEXT}).

Posted by Peter Vogel on 10/21/2019 at 12:06 PM0 comments


Calling .NET Methods With and Without Async

Let's say that you have an asynchronous method -- a method that looks something like this one that returns a Customer object wrapped inside a Task object:

public async Task<Customer> GetCustomerById(string custId) {

You can call this method with or without the await keyword. The syntax with the await keyword looks like this:

Customer cust = await GetCustomerById("A123");

Using the await keyword launches the method (and any code that follows it in the calling method) on a separate thread. When the method finishes running, the Customer object is pulled from the Task object and, in this case, stuffed into the cust variable.

The syntax without the await keyword looks like this:

Task<Customer> cust = GetCustomerById("A123");

With this syntax, you get back the Task object that manages the GetCustomerById method ... and that's it. You can now treat this cust variable as you would any other object: pass it to other methods, return it from the method with this code, store it in a global variable, and so on. When you're ready to run the Task in the cust variable, you can do asynchronously by calling the cust variable's Start method.

This code will start the GetCustomerById method running but go right on to the next line of code following the Start method:

cust.Start();

Alternatively, you can retrieve the Customer object returned by the method synchronously by reading the cust variable's Result property.

This code will cause processing to stop dead on this line of code until the GetCustomerById method managed by the Task object returns a Customer object:

Customer custResult = cust.Result;

There's more that you can with a Task object than just call the Start method and read the Result property (in fact, you'll probably use them together). But my point is that it's worth remembering that if you want the Task object associated with your async method, you can have it.

Posted by Peter Vogel on 10/17/2019 at 1:15 PM0 comments


Upgrading to ASP.NET Core Version 3.0: Top Tips

So you got excited about ASP.NET Core and started building an application in ASP.NET Core 2.0, 2.1, or 2.2. Now you're wondering how much work is involved in migrating that application to Version 3.0 which came out in late September.

If you've got a vanilla application the answer is ... it's not that painful. For example, to upgrade to Version 3.0, you just need to go into your csproj file and strip out almost everything to leave this:

<PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

And I do mean "almost everything." For example, any Package Reference elements that you have that reference Microsoft.AspNetCore packages can probably be deleted.

In ConfigureServices, you'll replace AddMvc with one or more of these method calls, depending on what technologies your application uses:

  • AddRazorPages: If you're using Razor Pages
  • AddControllers: If you're using Web services but not Views
  • AddControllersWithView: If you're using Controllers and Views. This also supports Web services so don't use it with AddControllers

In the Startup.cs file's Configure method, you'll change the IHostingEvnvironment parameter to IWebHostingEnvironment. Inside the method, you'll replace your call to UseMvc with:

  • UseAuthorization and UseAuthorization: Assuming that you're using authentication, of course
  • UseCors: If you want to support Cross-Origin Requests
  • UseEndPoints

With UseMvc gone, you'll need to move any routes you specified in that method into UseEndPoints. That will look something like this:

app.UseEndpoints(endpoints =>
    {
      endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });

Those changes are all pretty benign because they all happen in one file. The other big change you'll probably have to make (especially if you've created a Web service) is more annoying: NewtonSoft.Json is no longer part of the base package. If you've been using NewtonSoft's JSON functionality, you can (if you're lucky) just switch to the System.Text.Json namespace. If you're unlucky, you'll have some code to track down and rewrite throughout your application.

Sorry about that.

There's more, of course, and there's a full guide from Microsoft. If you've got a relatively straightforward site, though, these changes may be all you need to do.

Posted by Peter Vogel on 10/14/2019 at 2:48 PM0 comments


How to Create New Code Snippets from Existing Ones in Visual Studio

I'm not a big user of code snippets, but I know developers who are. I've noticed those developers often don't use the default value supplied for the variable part of the snippet (What! All your connection strings aren't in a variable named "conn"?). If you're one of those people or you'd just be happier with a couple more variations on the code snippets that come with Visual Studio, here's how to make that happen.

The first step is to open the Code Snippets Manager (it's on the Tools menu). The next step -- and the hardest part -- is finding the code snippet you want to change. Once you find that snippet in the manager, click on it and then look at the top of the dialog. There's a Location textbox there and in it you'll see the file path to the file that holds the code snippet. Copy that file path (sadly, Ctrl_A won't work but clicking at the start of the path and using Shift_End will).

Once you've copied the path, close the Code Snippets Manager and, from the File menu, select Open > File. Paste the file path you copied into the File Name textbox and hit the <Enter> key. You'll be looking at your code snippet in a Visual Studio editor tab.

Before you make any changes, from the File Menu select the Save ... As menu choice. It's hard to see that choice because the file name -- which is very long -- is inserted into the middle of the menu choice name. If it's any help, the Save ... As choice is the second of the two choices that begin with "Save." Once you've found it, save your file under a new name. Now, if you render the snippet inoperable, you'll still have the original to fall back on and can try again.

You will, of course, want to change the code in the snippet (otherwise why are you reading this?). But make sure that you also change two things in the XML headers at the top of the file. First, change the shortcut to (a) something you'll remember to type when you want this snippet, and (b) something that no other snippet is using. Second, change the snippet's title element to something you'll recognize in the Code Snippet Manager. If you're a decent human being, you'll also change the author tag to your name.

Posted by Peter Vogel on 10/10/2019 at 10:33 AM0 comments


How to Efficiently Validate Against Cross-Site Request Forgery Attacks in ASP.NET Core

If you're worried about CSRF (Cross-Site Request Forgery) attacks (and you probably should be), then you've already added the code to your Views that adds an anti-forgery token to the data that the browser sends back to the server. If you're using HTML Helpers, that code looks like this:

@Html.AntiForgeryToken()

If you're working in ASP.NET Core and have enabled Tag Helpers, then you don't even need to use that code -- the <form> element has a tag helper associated with it that adds the field automatically.

The issue is that, in your HttpPost methods, you need to check that you get that token back. That is easy to do in both ASP.NET MVC and ASP.NET Core: You just add the ValidateAntiForgeryToken attribute to your methods. There was always, of course, the danger that you'd miss adding it to one of your HttpPost methods, which would be ... unfortunate. It would be easier just to add the attribute to your controller class. The problem with that solution is that you'd be incurring the cost of checking for the token with every request, not just with the HttpPost methods.

If this worries you (and you're using ASP.NET Core), then you can add the AutoAntiForgeryToken to your controller classes, like this:

[AutoAntiForgeryToken]
public class TodoListController: Controller
{

This attribute checks only the dangerous methods (that is, only methods that aren't a GET or one of the other methods you never use: TRACE, OPTIONS and HEAD). You'll get all the protection you need and none that you don't.

Posted by Peter Vogel on 09/17/2019 at 8:57 AM0 comments


How to Handle Multiple HttpClients in the Same ASP.NET Core Application

It's not impossible that you're accessing several different methods from the same Web Service in your application. If so, and if you're using the HttpClientFactory (and you should be), you have an opportunity to centralize some of your code.

In your Startup class, you should be calling the AddHttpClient method, which, despite its name, actually adds an HttpClientFactory to your application's services collection. As part of that method, you can pass the AddHttpClient method a string and a lambda expression. In the lambda expression you can provide the code to configure the HttpClient objects created by the factory. When it comes time to create an HttpClient object, you can use the string you provided to get the configuration you specified.

This code, for example, passes the AddHttpClient method the name "phvis" and specifies how the BaseAddress on the HttpClient should be set when this factory is used:

services.AddHttpClient("phvis", hc =>
{
    hc.BaseAddress = new Uri("https://phvis.com/");
});

Now, when you go to create an HttpClient, you can use "phvis" to get a client that's configured for my site. As an example, this code retrieves an HttpClient configured for phvis.com (see my earlier tip on how to retrieve the factory from the services collection so that you can use it here):

var client = factory.CreateClient("phvis");

Because the client has its BaseAddress property already set, you only have to specify the back part of the service's URL when making a request. This example joins a relative URL passed to the GetAsync method with my earlier BaseAddress to send a request to https://phvis.com/Customer/A123:

var response = await Client.GetAsync("/Customer/A123");

And, if you're accessing multiple Web Services, there's nothing stopping you from setting up multiple named clients, each with their BaseAddress set for the various services you're using.

Posted by Peter Vogel on 09/16/2019 at 11:04 AM0 comments


You're Using HttpClient Wrong

There's a very good chance that, every time you need to access a Web Service, you've been creating an HttpClient object and then throwing it away. Unfortunately, that's bad for your application because you can run out of WebSockets (yes, even if you call the object's Dispose method before discarding it). Though, I have to admit, you'll only have this problem if you use the HttpClient a lot. Still, it's a bad idea to keep creating and destroying it.

In the .NET Framework, the intent was for you to create the HttpClient once in your application and use it over and over. To do that you'll have to declare your HttpClient object as a global or static variable. That creates its own problems, of course.

In ASP.NET Core, however, you have a better option: the HttpClientFactory. The HttpClientFactory provides you with HttpClient objects but takes responsibility for managing the resources that the clients can use up. Think of it as "connection pooling for Web Services."

The first step in implementing this tactic is to create an HttpClientFactory object in your project's Startup class in the ConfigureServices method and add it to your application's services collection. All you need is this code (and, yes, I realize that the method's name doesn't do a good job of reflecting what it does):

services.AddHttpClient();

Then, in the constructor for any controller that needs an HttpClient, you can ask for the factory by its interface (IHttpClientFactory). This following example grabs the HttpClientFactory out of the services collection and stuffs it into a field to be used by the methods in the controller:

public class TodoListController: Controller
{
  public TodoListController(IHttpClientFactory factory, ... )
 {
  this.factory = factory;

Now, whenever you need an HttpClient object, you just get it from the factory's Create method, like this:

HttpClient hc = factory.CreateClient();

Posted by Peter Vogel on 09/12/2019 at 12:27 PM0 comments


.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.

Upcoming Events