TWiG #1: JWTs, AutoMapper, FluentValidation, CreatedAtActionResult and pain with VS Code

5 minute read

Welcome to This Week in GeoToast (TWiG) #1. To keep myself honest with working on GeoToast, I thought it would be good to write a weekly progress of my work on the project, as well as the good and the frustrating things which I experienced this week.

The Good

JWT integration is super easy

To secure the API for GeoToast, I am using JSON Web Tokens (abbreviated as JWT and pronounced as “jot”). The JWT middleware in ASP.NET Core makes it super easy to secure APIs using JWTs, and a lot of my work at Auth0 has been focused on developing our Quickstarts and Samples using this technology. I am very familiar with it, and securing the API with the JWT middleware took seconds.

BTW, if you want to use JWTs to secure your own Web API, then please check out the following Auth0 quickstarts:

Also read up more about our upcoming API Authorization.

AutoMapper rocks on .NET Core

Kudos to Jimmy Bogard for his awesome work on AutoMapper. I am using it for mapping between the models used in my API and the Entity Framework models.

Integration is much easier than I remember it used to be with ASP.NET MVC and Web API before.

Install the Fluent Validation NuGet packages:

Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

The AutoMapper package provides all the AutoMapper goodness, and the AutoMapper.Extensions.Microsoft.DependencyInjection package provides integration with the DI Framework.

Next, register AutoMapper with the DI container:

public void ConfigureServices(IServiceCollection services)
{
    services.AutoMapper();
}

This will, among other things, scan your assemblies for mapping profiles to register and also register the IMapper interface with the DI container.

Next up you can go ahead and create your mapping profiles:

public class WebsiteProfile : Profile
{
    public WebsiteProfile()
    {
        CreateMap<Website, WebsiteReadModel>();
        CreateMap<WebsiteCreateModel, Website>();
    }
}

And finally, to use AutoMapper in your controllers you can inject an instance of the IMapper interface in the constructor, and use that to map between classes:

public class WebsiteController
{
    private readonly GeoToastDbContext _dbContext;
    private readonly IMapper _mapper;
    
    public WebsiteController(GeoToastDbContext dbContext, IMapper mapper)
    {
        _dbContext = dbContext;
        _mapper = mapper;
    }
    
    [HttpPost]
    public async Task Post([FromBody]WebsiteCreateModel model)
    {
        var website = _mapper.Map<Website>(model);

        _dbContext.Websites.Add(website);
        await _dbContext.SaveChangesAsync();
    }
}

Simple as that!

Fluent Validation available for ASP.NET Core

I was happy to see that Fluent Validation is available for ASP.NET Core. To use it, install the Fluent Validation NuGet package for ASP.NET Core:

Install-Package FluentValidation.AspNetCore -pre

Register Fluent Validation with the DI Container, and tell it to scan the assembly containing the Startup class for any validators:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc()
        .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
}

Add validators:

public class WebsiteCreateModel
{
    public string Name { get; set; }

    public string Url { get; set; }
}

public class WebsiteCreateModelValidator : AbstractValidator<WebsiteCreateModel>
{
    public WebsiteCreateModelValidator()
    {
        RuleFor(x => x.Name).NotEmpty();
        RuleFor(x => x.Url).NotEmpty();
    }
}

And then all you need to do is check ModelState.IsValid in your controller to see whether there are model errors and return an appropriate result:

[HttpPost]
public async Task<IActionResult> Post([FromBody]WebsiteCreateModel model)
{
    if (ModelState.IsValid)
    {
        // Save the model ...
    }
    
    // Should probably return something better - like the actual errors? :P Will get to improving this
    return BadRequest(); 
}

Hat tip to this StackOverflow answer

The CreatedAtActionResult result

I like the new CreatedAtActionResult which can be returned by API endpoints. Let’s say I have an endpoint which returns a single instance of a resource:

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    // Code omitted for brevity...
}

In my POST method which creates a new instance, I can then return a CreatedAtActionResult, and tell it that the resource which was just created can be found at the endpoint above.

So for example:

[HttpPost]
public async Task<IActionResult> Post([FromBody]WebsiteCreateModel model)
{
    if (ModelState.IsValid)
    {
        // Code omitted for brevity...

        return CreatedAtAction("Get", new { id = website.Id }, _mapper.Map<WebsiteReadModel>(website));
    }
    
   // Code omitted for brevity...
}

In Postman, when I POST to the endpoint defined above to create a new instance, it will return a Location header which indicates where the new resource can be located:

The Frustrating

No Resharper

I am very used to my Visual Studio and Resharper. I am finding it currently very frustrating to not be able to use some of the productivity features offered by it, and I believe it makes me a slower coder. I am sticking to VS Code though, and will report in the future on plugins which can replicate some of the VS+Resharper productivity goodness.

Breakpoints not hit in VS Code

I actually knew about this one before, but it tripped me up again. The problem is that with the default project template, the VS Code debugger will not break on breakpoints. The solution is simple - just add "debugType": "portable" to the "buildOptions" section of your project.json file

  ...
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },
  ...

For more helpful information on debugger .NET Core apps with VS Code, you can also see this blog post.

Debugging in VS Code not loading configuration

When I debugged my application using VS Code, the web API calls I made in Postman all of a sudden started returning 500 (Internal Server Error) responses.

This is the debug output inside VS Code:

So the error I got was related to the JWT middleware which could not load the OIDC configuration from the OIDC Discovery document:

System.InvalidOperationException: IDX10803: Unable to obtain configuration from: ‘https:///.well-known/openid-configuration’.

The URL from which it tried to load the configuration is wrong. It should have tried to load it from https:/geotoast-dev.auth0.com//.well-known/openid-configuration. That value of geotoast-dev.auth0.com is read from the appsettings.json file which lead me to believe that for some or other reason, when running the application from the debugger, the appsettings.json file was not read.

A Google search led me to this StackOverflow answer which resolved my problem.

The problem was that my project was not located in the root of the folder which I loaded in VS Code. Instead, my folder structure looked as follows:

So my project is located in the \src\GeoToast folder. Following the advice in that StackOverflow answer, I changed the configuration in my launch.json file, so the cwd attribute points to the folder of my project:

VS Code IntelliSense inside event handlers not working properly..?

It seems that sometimes the Intellisense in VS Code will not list the available properties and methods for an object. I am trying to get a proper reproducible sample of the circumstances when this happens. When I do, I will post details.

Stay Tuned

Stay tuned for more status updates on GeoToast. The project is open source and hosted on GitHub at https://github.com/RockstarLabs/GeoToast.

Did you notice an error? Please help me and the other readers by heading over to the GitHub repo for this blog and submit a Pull Request with the corrections.