:::: MENU ::::

Thursday, June 15, 2017

With all of the controversy around project configurations within .NET Core, one thing that has managed to be consistently JSON-based has been the use of application settings configuration files in this new world. While JSON does read incredibly easily, it can very quickly become muddled if you are storing large, complex objects consisting of nested objects and arrays, each with multiple properties of different types, and so on.
Thankfully, you have options. And I don't mean options like going to use XML, I mean that there's a specific framework designed to tackle issues like these and make working with these potentially cumbersome configurations much more manageable.

Enter the Options Framework

The Options framework is a very basic framework that is specifically designed to handle accessing and configuring POCO settings within .NET Core, and it simply couldn't be easier to work with.
Now let's say that you have a configuration file for your application that looks like the following:
{
    "ApplicationLayout": {
        "LayoutChangingEnabled": true,
        "Layouts": [
            {
                "Name": "Standard",
                "Modules": [
                    {
                        "Name": "Foo",
                        "Order": 1
                    },
                    {
                        "Name": "Bar",
                        "Order": 2
                    }
                ]
            },
            {
                "Name": "Detailed",
                "Modules": [
                    {
                        "Name": "Foo",
                        "Order": 1
                    },
                    {
                        "Name": "Bar",
                        "Order": 2
                    },
                    {
                        "Name": "Admin",
                        "Order": 3
                    }
                ]
            }
        ]
    }
}
It's fairly simple. But if you wanted to access any of the individual items, it could potentially get pretty hairy drilling down into nested elements and muddle up your code. Thankfully, this is where the Options framework really shines.
Options will allow you to define a C# class to represent your configuration settings, and it will handle actually binding your existing JSON configuration to this class with just a single line of code. Let's see what this structure might look like for our previous example:
public class ApplicationConfiguration  
{
    public ApplicationLayout Layout { get; set; }            
}

public class ApplicationLayout  
{
    public bool LayoutChangingEnabled { get; set; }
    public Layout[] Layouts{ get; set; }
}

public class Layout  
{
    public string Name { get; set; }
    public Module[] Modules { get; set; }
}

public class Module  
{
    public string Name { get; set; }
    public int Order { get; set; }
}
Now all that we need to do is simply include the Options NuGet package within our application:
Install-Package Microsoft.Extensions.Options  
And then within the Startup.cs file, we can read our configuration file in as expected:
var config = new ConfigurationBuilder()  
    .AddJsonFile("YourConfigurationFile.json")
    .Build();
And then simply wire up an IOptions service that will allow your strongly-typed configuration to now be injected as a service anywhere within your application:
public void ConfigureServices(IServiceCollection services)  
{
    // Omitted for brevity

    services.AddOptions();
    services.Configure<ApplicationConfiguration>(config);
}
With all of these measures in place, you can now simply inject your Options within various locations in your application, allowing you to cleanly access the data that you need from your configuration without drilling down through multiple layers or nested elements:
public class FooController  
{
     private readonly ApplicationConfiguration _options;

     public FooController(IOptions options)
     {
          // Access your options here 
          var canChangeLayout = options.Layout.LayoutChangingEnabled; // "true"
     }
}
Depending on your scenario, you may want to potentially override one of the values present within your settings. This is very easy to do and simply requires the use of a delegate after the initial configuration as seen below:
public void ConfigureServices(IServiceCollection services)  
{
    // Omitted for brevity

    services.Configure<ApplicationConfiguration>(config);

    // Update the configuration
    services.Configure<ApplicationConfiguration>(options =>
    {
        options.Layout.LayoutChangingEnabled = false;
    });
}
There are a variety of other more advanced use cases that you might find helpful depending on the complexity of your application such as using snapshots to detect configuration changes, binding to object graphs, and numerous other features which you can read more about in the documentation.

See Them In Action

The ASP.NET team and several members of the community have worked together to put examples of just about every type of configuration scenario on GitHub if you want to see how they look in action. I'd highly recommend browsing through them if you need to tackle some of the more advanced use-cases (e.g. using in-memory providers, snapshots, object graphs, etc.) within your applications.

Saturday, June 10, 2017

You might be surprised to find that the default asp.net core mvc templates do not handle 404 errors gracefully resulting in the standard browser error screen when a page is not found. This posts looks at the various methods for handling 404 not found errors in asp.net core.

The Problem

Without additional configuration, this is what a (chrome) user will see if they visit a URL that does not exist:
Fortunately, it is very simple to handle error status codes. We'll cover three techniques below.

The Solution

In previous versions of Asp.Net MVC, the primary place for handling 404 errors was in the web.config.
You probably remember the  section which handled 404's from the ASP.NET pipeline as well as  which was lower level and handled IIS 404's. It was all a little confusing.
In .Net core, things are different and there is no need to play around with XML config (though you can still use httpErrors in web.config if you are proxying via IIS and you really want to :-)).
There are really two different situations that we need to handle when dealing with not-found errors.
There is the case where the URL doesn't match any route. In this situation, if we cannot ascertain what the user was looking for, we need to return a generic not found page. There are two common techniques for handling this but first we'll talk about the second situation. This is where the URL matches a route but one or more parameter is invalid. We can address this with a custom view.

Custom Views

An example for this case would be a product page with an invalid or expired id. Here, we know the user was looking for a product and instead of returning a generic error, we can be a bit more helpful and return a custom not found page for products. This still needs to return a 404 status code but we can make the page less generic, perhaps pointing the user at similar or popular products.
Handling these cases is trivial. All we need to do is set the status code before returning our custom view:
public async Task GetProduct(int id)
{
    var viewModel = await _db.Get(id);

    if (viewModel == null)
    {
        Response.StatusCode = 404;
        return View("ProductNotFound");
    }

    return View(viewModel);
}
Of course, you might prefer to wrap this up into a custom action result:
public class NotFoundViewResult : ViewResult
{
    public NotFoundViewResult(string viewName)            
    {
        ViewName = viewName;
        StatusCode = (int)HttpStatusCode.NotFound;
    }
}
This simplifies our action slightly:
public async Task GetProduct(int id)
{
    var viewModel = await _db.Get(id);

    if (viewModel == null)
    {
        return new NotFoundViewResult("ProductNotFound");
    }

    return View(viewModel);
}
This easy technique covers specific 404 pages. Let's now look at generic 404 errors where we cannot work out what the user was intending to view.

Catch-all route

Creating a catch-all route was possible in previous version of MVC and in .Net Core it works in exactly the same way. The idea is that you have a wildcard route that will pick up any URL that has not been handled by any other route. Using attribute routing, this is written as:
[Route("{*url}", Order = 999)]
public IActionResult CatchAll()
{
    Response.StatusCode = 404;
    return View();
}
It is important to specify the Order to ensure that the other routes take priority.
A catch-all route works reasonably well but it is not the preferred option in .Net Core. While a catch-all route will handle 404's, the next technique will handle any non-success status code so you can do the following (probably in an actionfilter in production):
public async Task GetProduct(int id)
{
    ...

    if (RequiresThrottling())
    {
        return new StatusCodeResult(429)
    }

    if (!HasPermission(id))
    {
        return Forbid();
    }

    ...
}

Status Code Pages With Re Execute

StatusCodePagesWithReExecute is a clever piece of Middleware that handles non-success status codes where the response has not already started. This means that if you use the custom view technique detailed above then the 404 status code will not be handled by the middleware (which is exactly what we want).
When an error code such as a 404 is returned from an inner middleware component, StatusCodePagesWithReExecute allows you to execute a second controller action to handle the status code.
You add it to the pipeline with a single command in startup.cs:
app.UseStatusCodePagesWithReExecute("/error/{0}");
...
app.UseMvc();
The order of middleware definition is important and you need to ensure that StatusCodeWithReExecute is registered before any middleware that could return an error code (such as the MVC middleware).
You can specify a fixed path to execute or use a placeholder for the status code value as we have done above.
You can also point to both static pages (assuming that you have the StaticFiles middleware in place) and controller actions.
In this example, we have a separate action for 404. Any other non-success status code hits, the Error action.
[Route("error/404")]
public IActionResult Error404()
{
    return View();
}

[Route("error/{code:int}")]
public IActionResult Error(int code)
{
    // handle different codes or just return the default error view
    return View();
}
Obviously, you can tailor this to your needs. For example, if you are using request throttling as we showed in the previous section then you can return a 429 specific page explaining why the request failed.

Conclusion

Handling specific cases of page not found is best addressed with a custom view and setting the status code (either directly or via a custom action result).
Handling more generic 404 errors (or in fact any non-success status code) can be achieved very easily by using the StatusCodeWithReExecute middleware. Together, these two techniques are the preferred methods for handling non-success HTTP status codes in Asp.Net Core.
By adding StatusCodeWithReExecute to the pipeline as we have done above, it will run for all requests but this may not be what we want all of the time. In the next post we will look at how to handle projects containing both MVC and API actions where we want to respond differently to 404's for each type.

Monday, May 29, 2017

This repository is a simple example of how to use ASP.NET Core Identity without Entity Framework.
I created it to help answer this StackOverflow question back in the early days of ASP.NET Core.
It just uses an in-memory list to store the user data, so it's not intended for real-world use. It's just a simple example to show how the various parts fit together, so that you can use it for inspiration when building your own system.

Going way back to, I think, .NET v3, ASP.NET had this new thing called Membership. Maybe it was a version earlier. I dunno. "Neat," I thought, I can write a provider adhering to this interface and use my existing user and auth structure to plug into this system. Then I saw that the membership and role providers each had about a bazillion (maybe quadbazillion) members to implement, and reality set in that what I already had was working just fine. Some years later, ASP.NET offered Identity, this newer thing that did sort of the same thing. It even made its way into Core.
You don't need it. For real. I'm not saying that it isn't a useful piece of the framework, but you need to stop making it the default for user management. It's not hard or time consuming to build out your own system of user entities and permissions (roles, claims, etc.) as you see fit. The problem, as I see it, is that developers are confusing the act of persisting user information with authentication. I get why that may be, as Identity uses one line of code to both verify a user and sign them in (Core docs show how). But under the covers, there is code that first verifies the user/password against the database, then sets the auth cookie to indicate who the user is for future requests. You can in fact do one without the other.
Why would you do that? Part of it may just be an issue of control, but for me, it's because I want to be very specific about how I structure my user data. I also don't really want to use Entity Framework in many cases (read: most things I port from older apps), and EF is part of the magic of Identity. What I've seen in a number of projects is the use of Identity mixed with a home-grown set of user domain objects and a totally separate database or persistence mechanism. If you're doing all of that plumbing anyway, you definitely don't need the additional overhead of Identity.
Let's use ASP.NET Core as an example, first. In Startup, we use the Configure method to use cookie-based authentication:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
   AutomaticAuthenticate = true
});
In some kind of login method, from our MVC controller, we look up the user in the code that we wrote, with whatever backing store we made, and then sign in. Let's pretend that myUser is some construct we've made up:
var myUser = _myUserLookerUpperService(email, password);
var claims = new List
{
   new Claim(ClaimTypes.Name, myUser.Name)
};
var props = new AuthenticationProperties
{
   IsPersistent = persistCookie,
   ExpiresUtc = DateTime.UtcNow.AddYears(1)
};

var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), props);
The code should be pretty straightforward. Whatever our domain-specific user thingy is, it's something built for us, instead of the generic thing that the Identity framework has created. We use that to construct a set of claims and authentication properties, and then use the built-in Authentication system to sign in with our newly constructed principal. This is what creates the encrypted cookie on the user's browser. It's not as magic as the Identity service, but remember that you're welcome to use any kind of schema that you want to persist user data, and that means you can query it or normalize it (if you must) against any other bits of data you have.
Naturally, you may want to set up some other context, or simply verify that they're still a known-good user on each request. To do that, you can wireup middleware in the Startup's Config method (app.UseMiddleware();). Middleware doesn't use an interface (and I don't know why they chose convention over an interface), but it does expect an Invoke method to do stuff. It's here that you would look up the user based on the identity:
public class MyMiddleware
{
   private readonly RequestDelegate _next;

   public MyMiddleware(RequestDelegate next)
   {
      _next = next;
   }

   public async Task Invoke(HttpContext context)
   {
      var name = context.User.Identity.Name;
      if (!string.IsNullOrWhiteSpace(name))
      {
         var userService = context.RequestServices.GetService();
         var user = userService.GetUserByName(name);
         if (user != null)
         {
            // do stuff here
         }
         else
         {
            // do something about your bad user
         }
      }
      await _next(context);
   }
}
Again, I believe that the Identity framework has some plumbing for this, but if you're a control freak like me, this is better. The official documentation has a really great write up on using this cookie mechanism without Identity.
If you're still using ASP.NET 4.5 and MVC on top of it (or even WebForms), you don't need to use Identity here either. In your MVC action, or your event handler in WebForms, you can use Forms Authentication to do the same work, without any setup (though you can change the cookie name and some other things via web.config):
var user = _myUserLookerUpperService(email, password);
var ticket = new FormsAuthenticationTicket(1, user.Name, DateTime.Now, DateTime.Now.AddDays(30), createPersistentCookie, "");
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
cookie.Expires = DateTime.Now.AddDays(30);
context.Response.Cookies.Add(cookie);
Neat, right? The static FormsAuthentication class also has a SignOut method. Instead of middleware, we can use an IHttpModule or an IActionFilter to act on user data as appropriate.
To circle back, the point here is that Identity is great to spin up some user account persistence and authentication quickly, but if you want to do your own thing, or don't want EF involved, or you're a control freak, understand that you don't need Identity to auth your users.
EDIT 9/6/16: Andrew Lock has a pretty solid outline of how claims-based identities should be used. He goes way more in depth about creating a new principal and signing in the user, but note that he's not getting into the business of persistence here.

Saturday, May 27, 2017

This short post is in response to a comment I received on a post I wrote a while ago, about how to set the hosting environment in ASP.NET Core. It's a question I've heard a couple of times, so thought I'd write it up here.
The question by Denis Zavershinskiy is as follows:
Do you know if there is a way to overwrite environment variable name? For example, I want my CoolProject to take environment name not from ASPNETCORE_ENVIRONMENT but from COOL_PROJ_ENV. Is it possible?
The answer to that question is a little nuanced. If you already have an app deployed, and want to switch the environment for it without changing other apps on that machine, then you can't do it with Environment variables. Those obviously affect the whole environment!
tl;dr; Create a custom configuration object in your Program.cs file, load the environment variable using a custom key, and call UseEnvironment on the WebHostBuilder.
However, if this is a capability you think you will need, you can use a similar approach to the one I use in that post to set the environment using command line arguments.
This approach involves building a new IConfiguration object, and passing that in to the WebHostBuilderon application startup. This lets you load configuration from any source, just as you would in your normal startup method, and pass that configuration to the WebHostBuilder using UseConfiguration. The WebHostBuilder will look for a key named "Environment" in this configuration, and use that as the environment.
For example, if you use the following configuration.
var config = new ConfigurationBuilder()  
    .AddCommandLine(args)
    .Build();

var host = new WebHostBuilder()  
    .UseConfiguration(config)
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseKestrel()
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();
You can pass any setting value with this setup, including the "environment variable":
> dotnet run --environment "MyCustomEnv"

Project TestApp (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.

Hosting environment: MyCustomEnv  
Content root path: C:\Projects\Repos\MyCoolProj\src\MyCoolProj  
Now listening on: http://localhost:5000  
Application started. Press Ctrl+C to shut down.  
This is fine if you can use command line arguments like this, but what if you want to use environment variables? Again, the problem is that they're shared between all apps on a machine.
However, you can use a similar approach, coupled with the UseEnvironment extension method, to set a different environment for each machine. This will override the ASPNETCORE_ENVIRONMENT value, if it exists, with the value you provide for this application alone. No other applications on the machine will be affected.
public class Program  
{
    public static void Main(string[] args)
    {
        const string EnvironmentKey = "MYCOOLPROJECT_ENVIRONMENT";

        var config = new ConfigurationBuilder()
            .AddEnvironmentVariables()
            .Build();

        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseEnvironment(config[EnvironmentKey])
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();

        host.Run();
    }
}
To test this out, I added the MYCOOLPROJECT_ENVIRONMENT key with a value of Staging to the launch.json file VS uses when running the app:
{
  "profiles": {
    "EnvironmentTest": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "MYCOOLPROJECT_ENVIRONMENT": "Staging"
      },
      "applicationUrl": "http://localhost:56172"
    }
  }
}
Running the app using F5, shows that we have correctly picked up the Staging value using our custom environment variable:
Hosting environment: Staging  
Content root path: C:\Users\Sock\Repos\MyCoolProj\src\MyCoolProj  
Now listening on: http://localhost:56172  
Application started. Press Ctrl+C to shut down.  
With this approach you can effectively have a per-app environment variable that you can use to configure the environment for an app individually.

Summary

On shared hosting, you may be in a situation when you want to use a different IHostingEnvironment for multiple apps on the same machine. You can achieve this with the approach outlined in this post, building an IConfiguration object and passing a key to WebHostBuilder.UseEnvironment extension method.