ASP.NET Web Api: Unwrapping HTTP Error Results and Model State Dictionaries Client-Side

Posted on September 28 2014 08:42 PM by jatten in ASP.Net, ASP.NET MVC, C#, CodeProject   ||   Comments (0)

404 on wall-320When working with ASP.NET Web Api from a .NET client, one of the more confounding things can be handling the case where errors are returned from the Api. Specifically, unwrapping the various types of errors which may be returned from a specific API action method, and translating the error content into meaningful information for use be the client.

How we handle the various types of errors that may be returned to our Api client applications can be very dependent upon specific application needs, and indeed, the type of client we are building.

Image by Damien Roué  |  Some Rights Reserved

In this post we'll look at some general types of issues we might run into when handing error results client-side, and hopefully find some insight we can apply to specific cases as they arise.

Understanding HTTP Response Creation in the ApiController

Most Web Api Action methods will return one of the following:

  • Void: If the action method returns void, the HTTP Response created by ASP.NET Web Api will have a 204 status code, meaning "no content."
  • HttpResponseMessage: If the Action method returns an HttpResponseMessage, then the value will be converted directly into an HTTP response message. We can use the Request.CreateResponse() method to create instances of HttpResponseMessage, and we can optionally pass domain models as a method argument, which will then be serialized as part of the resulting HTTP response message.
  • IHttpActionResult: Introduced with ASP.NET Web API 2.0, the IHttpActionResult interface provides a handy abstraction over the mechanics of creating an HttpResponseMessage. Also, there are a host of pre-defined implementations for IHttpActionResult defined in System.Web.Http.Results, and the ApiController class provides helper methods which return various forms of IHttpActionResult, usable directly within the controller.
  • Other Type: Any other return type will need to be serialized using an appropriate media formatter.

For more details on the above, see Action Results in Web API 2 by Mike Wasson.

From Web Api 2.0 onward, the recommended return type for most Web Api Action methods is IHttpActionResult unless this type simply doesn't make sense.

Create a New ASP.NET Web Api Project in Visual Studio

To keep things general and basic, let's start by spinning up a standard ASP.NET Web Api project using the default Visual Studio Template. If you are new to Web Api, take a moment to review the basics, and get familiar with the project structure and where things live.

Make sure to update the Nuget packages after you create the project.

Create a Basic Console Client Application

Next, let's put together a very rudimentary client application. Open another instance of Visual Studio, and create a new Console application. Then, use the Nuget package manager to install the ASP.NET Web Api Client Libraries into the solution.

We're going to use the simple Register() method as our starting point to see how we might need to unwrap some errors in order to create a more useful error handling model on the client side.

The Register Method from the Account Controller

If we return to our Web Api project and examine the Register() method, we see the following:

The Register() method from AccountController:
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
 
    var user = new ApplicationUser() 
    { 
        UserName = model.Email, 
        Email = model.Email 
    };
 
    IdentityResult result = await UserManager.CreateAsync(user, model.Password);
 
    if (!result.Succeeded)
    {
        return GetErrorResult(result);
    }
    return Ok();
}

 

In the above, we can see that there are a number of options for what might be returned as our IHttpActionResult.

First, if the Model state is invalid, the BadRequest() helper method defined as part of the ApiController class will be called, and will be passed the current ModelStateDictionary. This represents simple validation, and no additional processes or database requests have been called.

If the Mode State is valid, the CreateAsync() method of the UserManager is called, returning an IdentityResult. If the Succeeded property is not true, then GetErrorResult() is called, and passed the result of the call to CreateAsync().

GetErrorResult() is a handy helper method which returns the appropriate IHttpActionResult for a given error condition.

The GetErrorResult Method from AccountController
private IHttpActionResult GetErrorResult(IdentityResult result)
{
    if (result == null)
    {
        return InternalServerError();
    }
    if (!result.Succeeded)
    {
        if (result.Errors != null)
        {
            foreach (string error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }
        if (ModelState.IsValid)
        {
            // No ModelState errors are available to send, 
            // so just return an empty BadRequest.
            return BadRequest();
        }
        return BadRequest(ModelState);
    }
    return null;
}

 

From the above, we can see we might get back a number of different responses, each with a slightly different content, which should assist the client in determining what went wrong.

Making a Flawed Request - Validation Errors

So, let's see some of the ways things can go wrong when making a simple POST request to the Register() method from our Console client application.

Add the following code to the console application. Note that we are intentionally making a flawed request. We will pass a valid password and a matching confirmation password, but we will pass an invalid email address. We know that Web Api will not like this, and should kick back a Model State Error as a result.

Flawed Request Code for the Console Client Application:
static void Main(string[] args)
{
    // This is not a valid email address, so the POST should fail:
    string email = "john";
    string password = "Password@123";
    string confirmPassword = "Password@123";
 
    HttpResponseMessage result = 
        Register(email, password, confirmPassword);
 
    if(result.IsSuccessStatusCode)
    {
        Console.WriteLine(
            "The new user {0} has been successfully added.", email);
    }
    else
    {
        Console.WriteLine(result.ReasonPhrase);
    }
    Console.Read();
}
 
 
public static HttpResponseMessage Register(
    string email, string password, string confirmPassword)
{
    //Attempt to register:
    using (var client = new HttpClient())
    {
        var response =
            client.PostAsJsonAsync("http://localhost:51137/api/Account/Register",
 
            // Pass in an anonymous object that maps to the expected 
            // RegisterUserBindingModel defined as the method parameter 
            // for the Register method on the API:
            new
            {
                Email = email,
                Password = password,
                ConfirmPassword = confirmPassword
            }).Result;
        return response;
    }
}

If we run our Web Api application, wait for it to spin up, and then run our console app, we see the following output:

Console output from the flawed request:
Bad Request

 

Well, that's not very helpful.

If we de-serialize the response content to a string, we see there is more information to be had. Update the Main() method as follows:

De-serialize the Response Content:
static void Main(string[] args)
{
    // This is not a valid email address, so the POST should fail:
    string email = "john";
    string password = "Password@123";
    string confirmPassword = "Password@123";
 
    HttpResponseMessage result = 
        Register(email, password, confirmPassword);
 
    if(result.IsSuccessStatusCode)
    {
        Console.WriteLine(
            "The new user {0} has been successfully added.", email);
    }
    else
    {
        string content = result.Content.ReadAsStringAsync().Result;
        Console.WriteLine(content);
    }
    Console.Read();
}

 

Now, if we run the Console application again, we see the following output:

Output from the Console Application with De-Serialized Response Content:
{"Message":"The request is invalid.","ModelState":{"":["Email 'john' is invalid."]}}

 

Now, what we see above is JSON. Clearly the JSON object contains a Message property and a ModelState property. But the ModelState property, itself another JSON object, contains an unnamed property, an array containing the error which occurred when validating the model.

Since a JSON object is essentially nothing but a set of key/value pairs, we would normally expect to be able to unroll a JSON object into a Dictionary<string, object>. However, the nameless property(ies) enumerated in the ModelState dictionary on the server side makes this challenging.

Unwrapping such an object using the Newtonsoft.Json library is doable, but slightly painful. Equally important, an error returned from our API may, or may not have a ModelState dictionary associated with it.

Another Flawed Request - More Validation Errors

Say we figured out that we need to provide a valid email address when we submit our request to the Register() method. Suppose instead, we are not paying attention and instead enter two slightly different passwords, and also forget that passwords have a minimum length.

Modify the code in the Main() method again as follows:

Flawed Request with Password Mismatch:
{
    "Message":"The request is invalid.",
    "ModelState": {
        "model.Password": [
            "The Password must be at least 6 characters long."],
        "model.ConfirmPassword": [
            "The password and confirmation password do not match."]
    }
}

 

In this case, it appears the items in the ModelState Dictionary are represented by valid key/value pairs, and the value for each key is an array.

Server Errors and Exceptions

We've seen a few examples of what can happen when the model we are passing with our POST request is invalid. But what happens if our Api is unavailable?

Let's pretend we finally managed to get our email and our passwords correct, but now the server is off-line.

Stop the Web Api application, and then re-run the Console application. Of course, after a reasonable server time-out, our client application throws an AggregateException.

What's an AggregateException? Well, it is what we get when an exception occurs during execution of an async method. If we pretend we don't know WHY our request failed, we would need to dig down into the InnerExceptions property of the AggregateException to find some useful information.

In the context of our rudimentary Console application, we will implement some top-level exception handling so that our Console can report the results of any exceptions like this to us.

Update the Main() method once again, as follows:

Add Exception Handling to the Main() Method of the Console Application:
static void Main(string[] args)
{
    // This is not a valid email address, so the POST should fail:
    string email = "john@example.com";
    string password = "Password@123";
    string confirmPassword = "Password@123";
 
    // Add a Try/Catch in case something goes wrong and the server throws:
    try
    {
        HttpResponseMessage result =
            Register(email, password, confirmPassword);
 
        if (result.IsSuccessStatusCode)
        {
            Console.WriteLine(
                "The new user {0} has been successfully added.", email);
        }
        else
        {
            string content = result.Content.ReadAsStringAsync().Result;
            Console.WriteLine(content);
        }
    }
    catch (AggregateException ex)
    {
        Console.WriteLine("One or more exceptions has occurred:");
        foreach (var exception in ex.InnerExceptions)
        {
            Console.WriteLine("  " + exception.Message);
        }
    }
    Console.Read();
}

 

If we run our console app now, while our Web Api application is offline, we get the following result:

Console Output with Exception Handling and Server Time-Out:
One or more exceptions has occurred:
  An error occurred while sending the request.

 

Here, we are informed that "An error occurred while sending the request" which at least tells us something, and averts the application crashing due to an unhandled AggregateException.

Unwrapping and Handling Errors and Exceptions in Web Api

We've seen a few different varieties of errors and exceptions which may arise when registering a user from our client application.

While outputting JSON from the response content is somewhat helpful, I doubt it's what we are looking for as Console output. What we need is a way to unwrap the various types of response content, and display useful console messages in a clean, concise format that is useful to the user.

While I was putting together a more in-depth, interactive console project for a future article, I implemented a custom exception, and a special method to handle these cases.

ApiException - a Custom Exception for Api Errors

Yeah, yeah, I know. Some of the cases above don't technically represent "Exceptions" by the hallowed definition of the term. In the case of a simple console application, however, a simple, exception-based system makes sense. Further, unwrapping all of our Api errors up behind a single abstraction makes it easy to demonstrate how to unwrap them.

Mileage may vary according to the specific needs of YOUR application. Obviously, GUI-based applications may extend or expand upon this approach, relying less on Try/Catch and throwing exceptions, and more upon the specifics of the GUI elements available.

Add a class named ApiException to the Console project, and add the following code:

ApiException - a Custom Exception
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
 
namespace ApiWithErrorsTest
{
    public class ApiException : Exception
    {
        public HttpResponseMessage Response { get; set; }
        public ApiException(HttpResponseMessage response)
        {
            this.Response = response;
        }
 
 
        public HttpStatusCode StatusCode
        {
            get
            {
                return this.Response.StatusCode;
            }
        }
 
 
        public IEnumerable<string> Errors
        {
            get
            {
                return this.Data.Values.Cast<string>().ToList();
            }
        }
    }
}

 

Unwrapping Error Responses and Model State Dictionaries

Next, let's add a method to our Program which accepts an HttpResponseMessage as a method argument, and returns an instance of ApiException. Add the following code the the Program class of the Console application:

Add the CreateApiException Method the to Program Class:
public static ApiException CreateApiException(HttpResponseMessage response)
{
    var httpErrorObject = response.Content.ReadAsStringAsync().Result;
 
    // Create an anonymous object to use as the template for deserialization:
    var anonymousErrorObject = 
        new { message = "", ModelState = new Dictionary<string, string[]>() };
 
    // Deserialize:
    var deserializedErrorObject = 
        JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);
 
    // Now wrap into an exception which best fullfills the needs of your application:
    var ex = new ApiException(response);
 
    // Sometimes, there may be Model Errors:
    if (deserializedErrorObject.ModelState != null)
    {
        var errors = 
            deserializedErrorObject.ModelState
                                    .Select(kvp => string.Join(". ", kvp.Value));
        for (int i = 0; i < errors.Count(); i++)
        {
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(i, errors.ElementAt(i));
        }
    }
    // Othertimes, there may not be Model Errors:
    else
    {
        var error = 
            JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
        foreach (var kvp in error)
        {
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(kvp.Key, kvp.Value);
        }
    }
    return ex;
}

 

In the above, we get a sense for what goes into unwrapping an HttpResponseMessage which contains a mode state dictionary.

When the response content includes a property named ModeState, we unwind the ModelState dictionary using the magic of LINQ. We knit the string key together with the contents of the value array for each item present, and then add each item to the exception Data dictionary using an integer index for the key.

If no ModelState property is present in the response content, we simply unwrap the other errors present, and add them to the Data dictionary of the exception.

Error and Exception Handling in the Example Application

We've already added some minimal exception handling at the top level of our application. Namely, we have caught and handled AggregateExceptions which may be thrown by async calls to our api, which are not handled deeper in the call stack.

Now that we have added a custom exception, and a method for unwinding certain types error responses, let's add some additional exception handling, and see if we can do a little better, farther down.

Update the Register() method as follows:

Add Handle Errors in the Register() Method:
public static HttpResponseMessage Register(
    string email, string password, string confirmPassword)
{
    //Attempt to register:
    using (var client = new HttpClient())
    {
        var response =
            client.PostAsJsonAsync("http://localhost:51137/api/Account/Register",
  
            // Pass in an anonymous object that maps to the expected 
            // RegisterUserBindingModel defined as the method parameter 
            // for the Register method on the API:
            new
            {
                Email = email,
                Password = password,
                ConfirmPassword = confirmPassword
            }).Result;
 
        if(!response.IsSuccessStatusCode)
        {
            // Unwrap the response and throw as an Api Exception:
            var ex = CreateApiException(response);
            throw ex;
        }
        return response;
    }
}

 

You can see here, we are examining the HttpStatusCode associated with the response, and if it is anything other than successful, we call our CreateApiException() method, grab the new ApiException, and then throw.

In reality, for this simple console example we likely could have gotten by with creating a plain old System.Exception instead of a custom Exception implementation. However, for anything other than the simplest of cases, the ApiException will contain useful additional information.

Also, the fact that it is a custom exception allows us to catch ApiException and handle it specifically, as we will probably want our application to behave differently in response to an error condition in an Api response than we would other exceptions.

Now, all we need to do (for our super-simple example client, anyway) is handle ApiException specifically in our Main() method.

Catch ApiException in Main() Method

Now we want to be able to catch any flying ApiExceptions in Main(). Our Console application, shining example of architecture and complex design requirements that it is, pretty much only needs a single point of error handling to properly unwrap exceptions and write them out as console text!

Add the following code to Main() :

Handle ApiException in the Main() Method:
static void Main(string[] args)
{
    // This is not a valid email address, so the POST should fail:
    string email = "john@example.com";
    string password = "Password@123";
    string confirmPassword = "Password@123";
 
    // Add a Try/Cathc in case something goes wrong and the server throws:
    try
    {
        HttpResponseMessage result =
            Register(email, password, confirmPassword);
        if (result.IsSuccessStatusCode)
        {
            Console.WriteLine(
                "The new user {0} has been successfully added.", email);
        }
        else
        {
            string content = result.Content.ReadAsStringAsync().Result;
            Console.WriteLine(content);
        }
    }
    catch (AggregateException ex)
    {
        Console.WriteLine("One or more exceptions has occurred:");
        foreach (var exception in ex.InnerExceptions)
        {
            Console.WriteLine("  " + exception.Message);
        }
    }
    catch(ApiException apiEx)
    {
        var sb = new StringBuilder();
        sb.AppendLine("  An Error Occurred:");
        sb.AppendLine(string.Format("    Status Code: {0}", apiEx.StatusCode.ToString()));
        sb.AppendLine("    Errors:");
        foreach (var error in apiEx.Errors)
        {
            sb.AppendLine("      " + error);
        }
        // Write the error info to the console:
        Console.WriteLine(sb.ToString());
    }
    Console.Read();
}

 

All we are doing in the above is unwinding the ApiException and transforming the contents for the Data dictionary into console output (with some pretty hackey indentation).

Now let's see how it all works.

Running Through More Error Scenarios with Error and Exception Handling

Stepping all the way back to the beginning, lets see what happens now if we try to register a user with an invalid email address.

Change our registration values in Main() back to the following:

// This is not a valid email address, so the POST should fail:
string email = "john";
string password = "Password@123";
string confirmPassword = "Password@123";

 

Run the Web Api application once more. Once it has properly started, run the Console application with the modified registration values. The output to the console should look like this:

Register a User with Invalid Email Address:
An Error Occurred:
Status Code: BadRequest
Errors:
  Email 'john' is invalid.

 

Similarly, if we use a valid email address, but password values which are both too short, and also do not match, we get the following output:

Register a User with Invalid Password:
An Error Occurred:
Status Code: BadRequest
Errors:
  The Password must be at least 6 characters long.
  The password and confirmation password do not match.

 

Finally, let's see what happens if we attempt to register the same user more than once.

Change the registration values to the following:

Using Valid Registration Values:
string email = "john@example.com";
string password = "Password@123";
string confirmPassword = "Password@123";

 

Now, run the console application twice in a row. The first time, the console output should be:

Console Output from Successful User Registration:
The new user john@example.com has been successfully added.

 

The next time, however, an error result is returned from our Web Api:

Console Output from Duplicate User Registration:
An Error Occurred:
Status Code: BadRequest
Errors:
  Name john@example.com is already taken.. Email 'simon@example.com' is already taken.

 

Oh No You did NOT Use Exceptions to Deal with Api Errors!!

Oh, yes I did . . . at least, in this case. This is a simple, console-based application in which nearly every result needs to end up as text output. Also, I'm just a rebel like that, I guess. Sometimes.

The important thing to realize is how to get the information we need out of the JSON which makes up the response content, and that is not as straightforward as it may seem in this case. How different errors are dealt with will, as always, need to be addressed within terms best suited for your application.

In a good many cases, treating Api errors as exceptions, to me, has merit. Doing so most likely will rub some architecture purists the wrong way (many of the errors incoming in response content don't really meet the textbook definition of "exception"). That said, for less complex .NET-based Api Client applications, unwrapping the errors from the response content, and throwing as exceptions to be caught by an appropriate handler can save on a lot of duplicate code, and provides a known mechanism for handling problems.

In other cases, or for your own purposes, you may choose to re-work the code above to pull out what you need from the incoming error response, but otherwise deal with the errors without using exceptions. Register() (and whatever other methods you use to call into your Api) might, in the case of a simple console application, return strings, ready for output. In this case, you could side-step the exception issue.

Needless to say, a good bit of the time, you will likely by calling into your Web Api application not from a desktop .NET application, but instead from a web client, probably using Ajax or something.

That's a Long and Crazy Post about Dealing with Errors - Wtf?

Well, I am building out a more complex, interactive console-based application in order to demo some concepts in upcoming posts. One of the more irritating aspects of that process was figuring out a reasonable way to deal with the various issues that may arise, when all one has to work with is a command line interface to report output to the user.

This was part of that solution (ok, in the application I'm building, things are a little more complex, a little more organized, and there's more to it. But here we saw some of the basics).

But . . . Can't We Just do it Differently on the Server?

Well . . . YES!

In all likelihood, you just might tune up how and what you are pushing out to the client, depending upon the nature of your Web Api and the expected client use case. In this post, I went with the basic, default set-up (and really, we only looked at one method). But, depending upon how your Api will be used, you might very will handle errors and exceptions differently on the server side, which may impact how you handle things on the client side.

Additional Resources and Items of Interest

 

Posted on September 28 2014 08:42 PM by jatten     

Comments (0)

ASP.NET Identity 2.0: Introduction to Working with Identity 2.0 and Web API 2.2

Posted on September 21 2014 07:09 PM by jatten in ASP.Net, ASP.NET MVC, C#, CodeProject   ||   Comments (2)

Lock-320In recent posts, I've covered a lot of ground using ASP.NET Identity 2.0 in the context of an MVC application. Since it's RTM in March of this year, Identity 2.0 has offered a substantial expansion of the Authentication/Authorization . toolset available to MVC applications.

Similarly, Identity 2.0 expands the Identity management tools available through ASP.NET Web Api. The same flexibility and extensibility are available, although things work just a little differently.

In this post, I'm going to take a quick tour of a basic Identity 2.0-based Web Api application, and look at some basic usage examples. If you are an experienced web developer, there is probably nothing new for you here – this is intended to be a bit of a 101 level introduction. If you are new to Identity 2.0 and/or ASP.NET Web Api you will likely find some of this information useful.

Image by Universal Pops  |  Some Rights Reserved

In the next few posts, we'll take a closer look at using Identity 2.0 with Web Api. We'll see how to extend the Identity model, similar to what we did with Identity 2.0 for MVC. We'll create a more easily extensible Identity/Web Api project. We will also explore various Authentication and Authorization schemes, and develop a better understanding of effective Web Api security.

For a review of what we have covered on using Identity 2.0 in the context of an ASP.NET MVC project, see:

For now, we'll take a high-level look at the basic Web Api project template shipped with Visual Studio, and get familiar with the basic structure.

Getting Started - Create a New ASP.NET Web Api Project

As of Visual Studio 2013 Update 3, WebApi 2.0 and Identity 2.0 are part of the out-of-the-box Web Api project template. While this default project template is a bit cluttered for my tastes, it is a good starting point to get familiar with the basics.

We are going to create a basic Web Api project in visual studio, and then update the various Nuget packages. In part, because we generally want to tbe using the latest package versions, but in particular because we want to work with the latest release of Web Api (version 2.2 as of this writing, released in July 2014).

First, do File => New Project, and then select ASP.NET Web Application:

Create a New Web Application Project:

New Project

Update the Nuget Packages for the Solution

Then, Open the Nuget Package Manager and update the Nuget packages for the solution. Select "Update" from the sidebar on the left, then "Update All":

Update Nuget Packages for Solution:

update-nuget-packages

When you get partway through the update process, you will be greeted by a scary-looking window warning you that some project files are about to be overwritten. These are .cshtml View files, and SHOULD be overwritten, as they are being updated to work with the new libraries.

Resolve File Conflicts by Clicking “Yes to All”:

nuget-file-conflict-yes-to-all

View files, you say? I thought we were making a Web Api project?

We are. But as I said, the default Web Api project includes a bit 'o MVC, for the "Help" page, and a basic home page. More on this in a bit.

Run and Test the Default Web Api Project

Now that we have created a new Web Api project, let's give it a quick test spin and see if everything is working property.

Open another instance of Visual Studio, and create a console application. Next, use the Nuget package manager to install the Web Api Client Libraries:

Install Web Api Client Libraries into Console Application:

install-webapi-client-libraries-in-console-app

After the installation is complete, check for updates. Then, add the following code to the Program.cs file (be sure to add System.Net.Http and Newtonsoft.Json to the using statements at the top of the class):

Example code to run against Web Api Application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
 
namespace TestApi
{
    class Program
    {
        static void Main(string[] args)
        {
            string userName = "john@example.com";
            string password = "Password@123";
            var registerResult = Register(userName, password);
 
            Console.WriteLine("Registration Status Code: {0}", registerResult);
 
            string token = GetToken(userName, password);
            Console.WriteLine("");
            Console.WriteLine("Access Token:");
            Console.WriteLine(token);
            Console.Read();
        }
 
 
        static string Register(string email, string password)
        {
            var registerModel = new 
            { 
                Email = email, 
                Password = password, 
                ConfirmPassword = password 
            };
            using (var client = new HttpClient())
            {
                var response =
                    client.PostAsJsonAsync(
                    "http://localhost:62069/api/Account/Register", 
                    registerModel).Result;
                return response.StatusCode.ToString();
            } 
        }
 
 
        static string GetToken(string userName, string password)
        {
            var pairs = new List<KeyValuePair<string, string>>
                        {
                            new KeyValuePair<string, string>( "grant_type", "password" ), 
                            new KeyValuePair<string, string>( "username", userName ), 
                            new KeyValuePair<string, string> ( "Password", password )
                        };
            var content = new FormUrlEncodedContent(pairs);
            using (var client = new HttpClient())
            {
                var response = 
                    client.PostAsync("http://localhost:62069/Token", content).Result;
                return response.Content.ReadAsStringAsync().Result;
            }
        }
    }
}

 

Now, Run your Web Api application. Once it has finished starting up, run the new Console application.

What we are going to do here is POST content representing a new user to the Register() method defined on the AccountsController of our Api. Next, we will make a call to the Token endpoint of our Api and retrieve an access token, which we can use to authenticate ourselves during subsequent calls to our Api.

If you aren't quite sure what is happening in the code above, don't worry about it for the moment. We'll look more closely at what is going on here (and what this "token" business is all about) in a bit. For the moment, let's just see if our application works.

If all went as expected, our console output should look something like this:

Console Output from Register and GetTokenDictionary Methods:
resitration Status Code: OK
Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm","token_type":"bearer","expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

 

Congratulations! You have just registered a user, and retrieved an access token from your new Web Api application.

What you see in the console output is, first, the result from registering a new user. After that you see what looks like a gob of Json because, well, it is. We de-serialized the response content into a string, and an ginormous blob of JSON is what we get for that.

If you look close, you can see first the access_token property, and there at the end are a few other properties, such as token_type, a time until the token expires, userName, and a few other properties. We will be looking more closely at tokens shortly.

Now that we see everything is working, let's take a look at how the Web Api application is structured, and identify the important pieces we need to be aware of when working with Web Api and Identity. Then we'll learn a little more about this token business. 

Important Note: The code above is strictly to see if our application starts up and runs, and as an example of obtaining an access token. In reality, you would always want to implement SSL before sending/receiving Bearer tokens in this manner.

Web Api Project Structure - Overview

As mentioned previously, the default project template contains some fluff we may or may not wish to use in a "real" Web Api project. There is a folder named "Areas" which contains a bunch of stuff for managing a "help" page, there is a Views folder containing, well, a few .cshtml Views, and a few other folders mostly supporting the MVC side of our project, such as the Content folder, fonts folder, Etc. For the moment, it is safe to say we can ignore the following project folders (although they may be useful later on, depending upon your needs):

VS Web Api Project Folders we can Ignore (for now):

  • Areas folder
  • Content folder
  • Fonts folder
  • Scripts folder
  • Views folder

On the other hand, while we are getting started with Web Api and Identity 2.0, the following folders DO Matter to us, and form a critical part of the project structure. We need to be familiar with these in order to extend/adapt/customize the default project to our needs:

VS Web Api Project Folders we ARE Interested in:

  • App-Start folder
  • Controllers folder
  • Models folder
  • Providers folder

The App_Start Folder

The App_Start folder contains various configuration items which need to happen at… application startup. Of particular interest to us, from the context of an Identity-based Web Api application, are the files named IdentityConfig.cs, WebApiConfig.cs, and Startup.Auth.cs.

As the names of these files imply, these are each respectively where we might setup and/or modify configuration options for each of the services indicated. IdentityConfig.cs and Startup.Auth.cs are where we configure most of the authentication and authorization options for our application. WebApiConfig.cs is where we set up our default routes for incoming requests.

The Controllers Folder

This should be familiar to any who have worked with a basic MVC project before. However, note that controllers in a Web Api application are not the same as controllers in an MVC application - Web Api controllers all inherit from the ApiController base class, whereas the familiar MVC controller inherits from the Controller base class.

Controllers are where we process incoming Http requests, and either return the requested resource, or respond with the appropriate Http status code. We'll get a closer look at this soon.

The Models Folder

In a Web Api application, much like an MVC application, we define the business entities used by our application in terms of Models, ViewModels, and BindingModels. The Models folder is generally where we will find the business objects we need to make our application work.

As a general rule, Models represent core business objects, often persisted in our back-end data store. ViewModels generally represent the data required for use by a user of our Api. BindingModels are similar to Viewmodels, but they generally represent incoming data, and are used by the controller to deserialize incoming content from Xml or Json into objects our application can use.

The Providers Folder

In the default Visual Studio Web Api Solution, the Providers folder contains a single class, the ApplicationOAuthProvider. In the default configuration, this class is consumed by the ConfigureAuth() method defined on Startup.Auth, and defines how Authentication and Authorization tokens are handled.

Identity 2.0 and hence, Web Api 2.2 rely heavily on Owin as the default Authorization and Authentication middleware.

Default Identity Models for Web Api

If we start with the IdentityModels.cs file, we can see there isn't much going on here. We have a basic ApplicationUser class, and the ApplicationDbContext, and that's it:

The Identity Models Class:
public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager, string authenticationType)
    {
        // Note the authenticationType must match the one defined in 
        // CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
  
        // Add custom user claims here
        return userIdentity;
    }
}
  
  
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
  
    
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

 

The AccountViewModels.cs and AccountBindingModels.cs files contain the various ViewModels and BindingModels used by the AccountController methods. Pop those open and get a feel for what's there. The ViewModels represent what our Api expects to serialize and push OUT as content with a response, and the BindingModels generally represent data we expect to RECEIVE as content in an HTTP request, after being de-serialized by the appropriate format provider.

AccountController - an ApiController

Next let's take a look at AccountController. We won't walk through the code for this here in the post, but take a quick look at the various methods in this class. Many will look suspiciously similar to the AccountController in an MVC project. However, there are some important differences.

First off,  note that the methods on AccountController return either a data entity of some sort (such as the UserInfoViewModel returned by the GetUserInfo() method), or they return an instance of IHttpActionResult.

In other words, as we already suspected, Action methods on a Web Api controller don't return Views. They ultimately return HttpResponse messages (with some downstream assistance from the controller itself), with any content encoded in the response body.

By way of comparison, we find that the HomeController, also in the Controllers folder, inherits from the familiar Controller base class, and the Action methods defined on HomeController return the standard ActionResult, generally Views. That's because HomeController, here, is included to support the MVC component of our Web Api. We can ignore HomeController for now, as in currently doesn't provide access to any of our Api Methods.

Identity Configuration

In the App_Start folder, open the IdentityConfig.cs file. There's a lot less going on here than in the similar file found in a standard ASP.NET MVC project. Essentially, the only thing that happens here is that the ApplicationUserManager is defined for the Web Api Application. However, there are some important configuration items taking place here.

The ApplicationUserManager Class Defined in IdentityConfig.cs
    public static ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(
            new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
  
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
                dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}

 

In this file, we define the password requirements for our application, as well as place potential constraints on user names and email addresses.

While not included in the default implementation for a Web Api project, this is also where we might define two-factor authentication providers for email or SMS text, and also where we might define email account confirmation configuration.

If we wanted to extend the Identity implementation in our Web Api application to include Roles, and some database initialization, this file is where we would most likely define and configure a RoleManager and DbInitializer.

Startup Authentication and Authorization Configuration

The primary authentication and authorization strategy in Web Api is token-based. We'll look closer at what this means momentarily, but for now, assume that in order to access any secured portion of your Api, you will need to present an access token as part of any incoming Http Request.

In the Startup.Auth.cs file, we se where configuration for authentication processing is performed. We see that the Startup.Auth.cs file contains a partial class, Startup, which extends the default Startup class defined at the root level of our project.

If we take a look at the latter (the Startup class at the root level of the project) we see a single method call, to the ConfigureAuth() method:

The Core Startup Class:
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }
}

 

The ConfigureAuth() method is defined on the partial class in Startup.Auth.cs:

The ConfigureAuth Method from Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
    // Configure the db context and user manager to use a single instance per request
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
  
    // Enable the application to use a cookie to store information for the signed in user
    // and to use a cookie to temporarily store information about a 
    // user logging in with a third party login provider
    app.UseCookieAuthentication(new CookieAuthenticationOptions());
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
  
    // Configure the application for OAuth based flow
    PublicClientId = "self";
    OAuthOptions = new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/Token"),
        Provider = new ApplicationOAuthProvider(PublicClientId),
        AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
        AllowInsecureHttp = true
    };
  
    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);
  
    // Uncomment the following lines to enable logging in with 
    // third party login providers
    //app.UseMicrosoftAccountAuthentication(
    //    clientId: "",
    //    clientSecret: "");
  
    //app.UseTwitterAuthentication(
    //    consumerKey: "",
    //    consumerSecret: "");
  
    //app.UseFacebookAuthentication(
    //    appId: "",
    //    appSecret: "");
  
    //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
    //{
    //    ClientId = "",
    //    ClientSecret = ""
    //});
}

 

In this method, we configure options for cookie and token authentication, and, optionally, allow sign-in via various third-party providers such as Facebook or Twitter.

Of particular interest to us is the highlighted line configuring the application to use Bearer tokens. We'll find out why this is important soon enough. For now, realize that the Startup.Auth.cs file is where you configure the authorization and authentication options for the application as a whole, and determine what your application will, and won't, accept as credentials.

Token Authentication and Bearer Tokens

The standard Visual Studio Web Api template is configured to use OAuth bearer tokens as a primary means of authentication. Bearer Tokens are exactly what the name implies - Web Api will consider the bearer of the token to be properly authenticated (provided the token is not expired, per the configuration settings in Startup.Auth.cs).

This can have some serious security implications. If a malicious actor were able to intercept a client request and get hold of the Bearer Token from the request header, they would then be able to gain access as an authenticated Api user.

For this reason, if you are planning to deploy a Web Api application using the default Bearer Token authentication scheme, it is critical that the production application implement SSL/TSL(Meaning, HTTPS) to encrypt and protect traffic between the client an  your Api.

If we take another look at the console output when we ran our application earlier, we the information we grabbed from the token:

Contents of the Default Access Token:
registration Status Code: OK
Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm", "token_type":"bearer" ,"expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

 

We see that the token_type property identifies this as a Bearer token.

To use a rather cliché example, Bearer tokens can be compared to currency - they are valid for whoever presents them.

The examples we have used to this point, and for the rest of this article will be using standard HTTP. While you are developing your application or trying on the examples, this is fine. However, if you are going to deploy a production application you will most definitely want to implement SSL/TSL, or investigate alternative authentication/authorization schemes.

We will take a closer look at Tokens, and alternate authentication mechanisms in an upcoming post.

Using Token Authentication and Accessing Web Api from a Client Application

We've already seen how to obtain a basic bearer token from our Api. Now let's take a more detailed look at grabbing a token, and then making some requests against the basic, default Web Api project.

First, let's change up our code a little bit. What we want to do is pull apart the JSON token into a Dictionary<string, string> so we can get at the access_token property. It is this we need to submit in the header of subsequent Api requests in order to authenticate ourselves.

Change the GetToken() method as follows, so that instead of returning s string, it returns a Dictionary. Let's also rename it as GetTokenDictionary() to better reflect what it does:

The New GetTokenDictionary() Method:
static Dictionary<string, string> GetTokenDictionary(
    string userName, string password)
{
    var pairs = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>( "grant_type", "password" ), 
                    new KeyValuePair<string, string>( "username", userName ), 
                    new KeyValuePair<string, string> ( "Password", password )
                };
    var content = new FormUrlEncodedContent(pairs);
 
    using(var client = new HttpClient())
    {
        var response =
            client.PostAsync("http://localhost:62069/Token", content).Result;
        var result = response.Content.ReadAsStringAsync().Result;
 
        // Deserialize the JSON into a Dictionary<string, string>
        Dictionary<string, string> tokenDictionary =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
        return tokenDictionary;
    }
}

 

Now let's update the Main() method to use our new dictionary, and write the various token properties out individually to the console:

Update Main() Method to Consume Deserialized Token Information:
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("resitration Status Code: {0}", registerResult);
 
    //string token = GetToken(userName, password);
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
    Console.Read();
}

 

If we run the two applications now, we see the console output looks a little different:

Console Output Using the GetTokenDictionary() Method:
Registration Status Code: BadRequest
 
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: zPrC7-CyHljhkPYQIDawhu7kgRd86p7oSJpRqHGifuANmEtM61syU5t6ciPGJrA3RX
I9u79IIOFaV3w5_GAQeF28DlUnc2HSkCxZsnqaYojLWfJ6gc8gfUlZo76SeJ7iO7MT6fdo8C5XgM_Geq
yun_8ykut9N456F41dI5PrrR6CyNc0ss_hy9OzdxnoqUdERglooNUrEcEt7WdZ9FHJ-cAi15fVPfV4z4
dUZZylrIyHuNSLVReet-zL769IEPvhgYixrp_hMgGQ6lDx8YMPTWvK_SVbe4W89DrHl1PbqfkiVgbJgJ
M09kmmIytNCFl_ua_GOdx1WyxXfPv0TLOmAgPX3klI4r_pglZl1QA0vihTN7zLsP2bkxIbMCBac3kq8z
4JT1JalxZ0OgArkW-Gy2qZJ-o-mPATCPUXLHtEd3z4lze17ECuCJyZzfLts3NN-hJgNwbmcqvGNvcakp
Y6SQ6U_ACdBJ3Q2JgZZeWf75pDupjeQbMhTqAPWUq9n35k
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Wed, 17 Sep 2014 02:55:45 GMT
.expires: Wed, 01 Oct 2014 02:55:45 GMT

 

First of all, why does it say "Bad Request" for our registration status code? We haven't changed THAT part of the code at all . . .  and there is the problem.

We have already registered a user named john@example.com, and Web Api has tossed back a validation error (the details of which are actually buried in the response content, but we'll worry about that later).

We can ignore that for now.

The next part of our console output is what we're interested in. Notice that, while the big, encrypted access_token still looks like a big blob of gibberish, our token as a whole is nicely split into its component properties on each line.

Now, let's try to access some of the Identity information from our Api. If we take a look at the AccountController in our Web Api project, we see there is a controller method named GetUserInfo() . Because our GetUserInfo() is decorated with the [Route] attribute “UserInfo" and our account controller [Route] attribute specifies a route of “api/Account” we know we can access this  method using the route “<host>/api/Account/UserInfo.”

Add the following static method to the Program class in our console application:

Add a GetUserInfo() Method to the Program Class:
static string GetUserInfo()
{
    using(var client = new HttpClient())
    {
        var response = 
            client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

 

This simple method uses an instance of HttpClient to access the GetUserInfo() method on our AccountController, reads the response content as a string, and returns the result.

Now, we can call this method from the Main() method of our Console program and see what we get back. Update the Main() method of the Program class as follows:

Add a Call to GetUserInfo() to the Main() Method of the Program Class:
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("Registration Status Code: {0}", registerResult);
 
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
 
    Console.WriteLine("Getting User Info:");
    Console.WriteLine(GetUserInfo());
}

 

Now, start your Web Api project again, wait for it to spin up completely, and then run the console application. Your console output should look something like this:

Console Output After Updating Client with Call to GetUserInfo() Method:
Registration Status Code: BadRequest
 
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: c47uW0q-1qsIm88et81YqFzGz0Nt2GflLZJ3nLLDUPIS8epwMiBMkG9lCmF7-Rk8Ji
KA33JJkgtFl-3mjn78N-iQcX2pLxEsYf4h65njj2BaSRCSheCyfWY5WcS2MPipRFfwr1e-wx49R4Awo3
DHk2nJmMe_ARIASzw7Ger4gpJgNrqxt8B4QWcJyjgrr7RwK95alKQ4MY-ZlzJyNdWthdCSeykTvzLJQ-
rGjH7KT-SYwknyt62Fm2bwE7WzcudFgs1RIq8HDzuPiM9Fx9dBLhhPT2sCq8iV1dDFrCTnDsNoLA5ncG
y9BncGFb5fmkqibP1tV8k2xW0OxqaAuVz4jaS212--o2P9JQ5kCmC6gSYH0faBgNva3SV8uZnM64YoyY
gJ3i_lOql0pxxjtqJYUYQLYSDwzYVJXXl_PiKLHGrjZhtn480kzSdfkgdv1i-jiqap2ymzIeJjGcd6Tm
fePqCXeiKLUEO3FsOJ4VeRkXFXEkXpFBbuGWIe6N64M4M3
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 00:56:49 GMT
.expires: Sun, 05 Oct 2014 00:56:49 GMT
 
Getting User Info:
{"Message":"Authorization has been denied for this request."}

 

But . . . wait. What happened? The last line, the result of our call to GetUserInfo() says authorization has been denied. What are we missing?

Notice that our AccountController class is decorated with an [Authorize] attribute in the class declaration. As you probably already realize, this mean that not just any old body can call into the AccountController. The class itself is decorated with the [Authorize] Attribute, so by default only authorized users can call Action methods defined on the class using HTTP. The Register() method has been decorated with an [AllowAnonymous] attribute, so unauthorized/unregistered users can register. but the rest of the methods are not accessible to unauthorized users.

In our case, despite the fact that we have actually obtained an access token from our Web Api by calling the Token endpoint of the Web Api application, we have not actually provided the token with our request to GetUserInfo().

Setting the Default Access Token For Web Api Requests

In order to create pass a token in with our HTTP requests, we can use the DefaultRequestHeaders property of HttpClient like so:

Set the Default Authorization Header for Client Requests:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = 
    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

 

We can modify the GetUserInfo() method on our Program class like so:

Set Default Authorization Header on Request for GetUserInfo() Method:
static string GetUserInfo(string token)
{
    using(var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = 
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
 
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

 

Notice we are now passing an access token in as a method argument, specifying that it is a Bearer token, and then using that token to set in our default Authorization header.

Now, we simply need to pass that token to the method when we call it from Main() :

Pass the Access Token to GetUserInfo() when Calling from Main():
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("Registration Status Code: {0}", registerResult);
 
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
 
    Console.WriteLine("Getting User Info:");
    Console.WriteLine(GetUserInfo(token["access_token"]));
}

 

Take note – we are not passing in the entire token dictionary returned from the GetToken() method here – only the actual access_token itself. In this code, we are pulling it out of our token dictionary using the ”access_token” key when we pass it as an argument to the GetUserInfo() method.

If we run the Console application now, we get the following:

Running the Console Application and Passing a Proper Auth Token:
Registration Status Code: BadRequest
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: ygYowtlVKbwyd3J9Lown2Py2IcMEwGgjfS5YAbJJjlhADh4HURG6upqIah4zQjqLgH
MjlyuiwKEcpzDv95Y0OpIqGO5pU_I4MmHNnLttMFORDFo-u4B0q9KUsiGskHjt_q25cIy5ZZNAejmA4B
u8qJKuxWagK33-XlQYMD_USVTShfUFkjMpi7IxffPmjpzWl5ipUzxnu4t-4LpR87QuWwIv7novf_o8Sl
9EAXc7ySqDZ0SzB1WgtDK4or7oLeIFMkouwOD9PK-E3FJTTmfpPtXT6RIdL93FEYM5oxgxTiHSLt_cRL
1Mb5kyIILcl6dCR7OuGn_8QN3jabKOmXg5q5XE52m--BMzJwUESTzXjDge-_2XoNWI09jTki9RXWg2fV
PL7DIhSwSfIff8AE0hiZm2cvEYaqPHzej221TKI_YX9DQGOrtmfLLpxx_lmtfbN1rbnwYYSa51d_vPDV
yzsfZbC2vA-xzxWJS3LP4Qm_I8ZvJp-JKVu47Q-Y5Z0ZG_
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 02:23:36 GMT
.expires: Sun, 05 Oct 2014 02:23:36 GMT
 
Getting User Info:
{"Email":"john@example.com","HasRegistered":true,"LoginProvider":null}

 

Now, that’s more like it.

Clean Up that Damn Code!

You may have notices that our examples have begun to take on some “code smells.” Well, for one, these are just examples, dammit. However, we can immediately see some opportunities to clean things up a bit, do a little refactoring.

How you would actually approach this would totally depend upon your specific project needs. But we can see right away that every time we go to access our Web Api from our client, we need an instance of HttpClient . Also, it is very likely that more often than not, we will need to be including an Auth token as part of our request.

We might add a static factory method, CreateClient() to handle this for us, and then call this from each of our client methods:

Add a CreateClient() Method (for example):
static HttpClient CreateClient(string accessToken = "")
{
    var client = new HttpClient();
    if(!string.IsNullOrWhiteSpace(accessToken))
    {
        client.DefaultRequestHeaders.Authorization = 
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
    return client;            
}

 

Now, if a token is provided, the default Authorization header will be added. If not, an HttpClient will be returned without Authorization header.

Now, our GetUserInfo() method from the Console application might look like this:

Modified GetUserInfo() method:
static string GetUserInfo(string token)
{
    using(var client = CreateClient(token))
    {
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

 

We still have the using block, and we really only saved one line of code. However, the initialization of the HttpClient, and the setting of the access token now all happen in the same place.

A Note About Security, Bearer Tokens, and SSL

As mentioned earlier, an ASP.NET Web Api project uses Bearer tokens out of the box when using the default Visual Studio project template. In order to implement proper security, Api’s which use this sort of authentication should ALWAYS use SSL/TLS, especially when accepting user credentials in order to provide the access token at the Token endpoint.

What the Default ASP.NET Web Api Project does NOT Have

You may notice that there are no Role management methods, no RolesAdminController (or even a UserAdminController) in the basic Identity-based Web Api project. In fact, there are no Roles at all at this early stage. The AccountController contains methods sufficient to Register a new user, perform some basic management (such as changing passwords), and not much else.

If we want role-based authorization in our Web Api project, we will need to add it ourselves. Similarly, if we want a little more admin flexibility via our Api (or even using a few MVC pages within the application for GUI-based Administration), we will also need to add that ourselves.

Last, before we charge in adding Roles and such, we will want to examine whether Role-Based Authorization is the best fit for our needs. Identity 2.0, and Web Api easily support Claims-Based Authorization, which offers some distinct advantages for more complex authorization scenarios.

We will look at all of this, and more, in upcoming posts.

Looking Deeper into Identity 2.0 and Web Api

In this post, we’ve taken a very broad look at the structure of a Web Api 2.2 project, and where the major pieces of the Identity 2.0 framework fit. We’ve looked at using Bearer tokes as the default authentication mechanism, how to retrieve a token from your Api Token endpoint, and how to perform some very basic Api access.

In upcoming posts we will:

  • Look more closely at Token-based authentication and authorization, and how it relates to the familiar Users and Roles model we are familiar with
  • Extend Identity 2.0 models in the context of ASP.NET Web Api
  • Serializing and de-serializing Model data to and from HTTP requests and responses
  • Customizing Identity Management for Web Api
  • Creating an Authentication Service using Identity 2.0 and ASP.NET Web Api

This has been basically the 101-level introduction to using Identity 2.0 and ASP.NET Web Api. There is more to come, and a lot to understand in order to get the most out of the ASP.NET Identity framework in a Web Api context, and to properly secure a Web Api.

Additional Resources and Items of Interest

 

Posted on September 21 2014 07:09 PM by jatten     

Comments (2)

C#: Building a Useful, Extensible .NET Console Application Template for Development and Testing

Posted on September 7 2014 02:26 PM by jatten in C#, CodeProject   ||   Comments (1)

charles-degaulle-airport-500How often do you find yourself tossing together a console application for the purpose of trying out code, "testing" in the sense of seeing what works best, or, possibly, as a means to demo some library of function?

I do, a lot. And I usually end up with some horrid mess which, while never intended for public use, still becomes a pain to deal with.

In preparing material for another post, I found myself once again working with the Console, hacking together some demonstration code to illustrate working with the Identity in the context of WebApi. The premise was to create a console application to demonstrate remote identity management via WebApi, and once again I found myself throwing together a minimal, ugly series of Console.WriteLine(sometext) statements, and in general writing code that was "illustration-only." And, Ugly as sin.

Image by Christopher Rose  | Some Rights Reserved

I wanted to put something together which functioned a little more like a shell terminal a la the Linux Bash. You know, enter a command, tell the computer to do something, the on to the next. Interactive.

How do I make the C# Console behave like a Shell, at least within the context of my application?

Lest you have any illusions, no, I am not trying to write a shell. But when working with my little demo and testing applications, I thought it would be nice if the console environment behaved in some (at least, reasonably) familiar, interactive ways, and without having to write a bunch of boilerplate code every time.

What I came up with is pretty functional for half an afternoon's work. It's basic, and easily extensible. Most importantly, it makes if easy to plug in some code and go, be it for testing purposes, and to demo a library. Or, possibly, you just might find you need a console-based application, and this may solve your problem.

Source Code on GitHub

We're going to build out the structure of this application framework here in the post. However, you can also clone the completed source from Github:

Building Blocks

The goal here was not to emulate a fully-functioning Shell or terminal. I wanted to be able to:

  • Run the program, be greeted with a prompt (customizable, in this case), and then enter commands corresponding to various methods defined in a specific area of the application.
  • Receive feedback (where appropriate), error messages, and such
  • Easily add/remove commands
  • Generally be able to quickly put together a functioning console application, with predictable and familiar interactive behavior, without re-inventing the wheel every time. 

We are going to set up the basic input/output functionality first. It will be easier to understand the basic structure of the program if we start with some very basic program flow, then move on to command parsing, and finally command execution.

Console Basics - The Interactive Input and Output Loop

Before the console can do anything else, it needs to be able to take input from the user, and provide feedback where needed. We are all familiar with Console.Write() or Console.WriteLine(), and also Console.Read() and Console.ReadLine(). However, these methods in and of themselves are utilitarian at best, and don't quite get us to the interactive Input/output loop we are looking for.

Also, the .NET Console does not directly afford us the ability to add a custom prompt.

We'll start with a very basic, but functional skeleton which will set up the basic input/output loop, and provide us with a means of adding a text prompt for input:

The Basic Interactive Console Skeleton Code:
class Program
{
    static void Main(string[] args)
    {
        Console.Title = typeof(Program).Name;
  
        // We will add some set-up stuff here later...
        Run();
    }
    static void Run()
    {
        while (true)
        {  
            var consoleInput = ReadFromConsole();
            if (string.IsNullOrWhiteSpace(consoleInput)) continue;
  
            try
            {
                // Execute the command:
                string result = Execute(consoleInput);
      
                // Write out the result:
                WriteToConsole(result);
            }
            catch (Exception ex)
            {
                // OOPS! Something went wrong - Write out the problem:
                WriteToConsole(ex.Message);
            }
        }
    }
  
  
    static string Execute(string command)
    {
        // We'll make this more interesting shortly:
        return string.Format("Executed the {0} Command", command);
    }
  
  
    public static void WriteToConsole(string message = "")
    {
        if(message.Length > 0)
        {
            Console.WriteLine(message);
        }
    }
  
  
    const string _readPrompt = "console> ";
    public static string ReadFromConsole(string promptMessage = "")
    {
        // Show a prompt, and get input:
        Console.Write(_readPrompt + promptMessage);
        return Console.ReadLine();
    }
}

 

We can see in the above that execution is quickly passed from the entry point Main() method to the Run() method. In just a little bit, we'll be adding some configuration and set-up code to main, which needs to run once, upon application startup.

Once execution is in our Run() method, we begin to see how our basic interactive IO loop works. Before we look at Run() , however, let's look at the other two methods we see, at the bottom of the class. WriteToConsole() and ReadFromConsole() look suspiciously like Console.WriteLine() and Console.ReadLine() and in fact, we wrap those two methods within each of our own.

The primary purpose of the ReadFromConsole() method is to show a prompt, and collect user input. Note the use of Console.Write() as opposed to Console.WriteLine() here. This way, our custom prompt is displayed on the same line that input will occur. For some unknown reason, the .NET Console does not provide a means of adding or customizing the standard prompt, so this is how we have to do things.

9/8/2014 NOTE: Thanks to a few intrepid commenters from r/csharp on Reddit, I have been saved from my own stupidity here. I had originally set up the Run() method discussed below with a recursive call to itself to create the interactive "loop" we are seeking. This would have created, over time, a big fat balloon of a memory leak. I have now repaired the damage before the universe collapsed in on itself, and updated the code in this post.

See I am a Programmer, and I can Complicate the #@$% out of a Ball Bearing for an examination of this idiocy…

Instead, we are going to use the (should have been obvious!) while loop.

Now, back to that Run() method. It is easy to see how things work here. Once control is passed to the Run() method, ReadFromConsole() is called, and the program awaits input from the user. Once text has been entered, control returns to Run().

Now, back to the Run() method. The Run() method features what is essentially an infinite while loop. Control is passed to ReadFromConsole() to get input from the user. When control returns (when the user hits Enter), the input is examined. If the string returned is null or empty, the loop resumes from the top again.

The next call from within Run() is to the Execute() method, which doesn't actually DO anything just yet, but we'll flesh that out in a minute. For the moment, execute returns the result of whatever command was called back to Run(). If something goes wrong, any exception thrown during Execute() will be caught in the catch block, and (hopefully!) a meaningful message will be displayed, informing the user about the nature of the problem.

Finally, Run() calls itself, recursively, thus completing our interactive loop, and the process starts anew.

When control once again returns to Run() from WriteToConsole(), the loop resumes.

Run the Bare-Bones IO Loop

If we run our little application at this point, we see that it doesn't do much besides take input, repeat what we told it to do back to us, and return to the input prompt. But for now, that's the point - getting the interactive IO loop in place.

Console Application with Minimal IO loop at Start-up:

io-loop-only-console-open

If we go ahead and type a "command" in and hit enter:

Console Application with Minimal IO Loop After Entering a Command:

io-loop-only-execute-command-text

As we can see - not terribly interesting yet, with the exception that we can now interact with our console in a familiar way. We'll fix that soon.

Basic Application Architecture

With the basic IO loop in place, we now need to take a look at how to set things up architecturally. Recall one of the primary goals of the project is to make it easy to plug in commands or sets of commands.

We will achieve this by creating a special project folder and namespace, Commands. We will enforce some (arbitrary, but good for consistency) rules for how commands will be provided to the project.

  • Methods representing Console commands will be defined as public static methods which always return a string, and are defined on public static classes.
  • Classes containing methods representing Console commands will be located in the Commands namespace, and in the Commands folder.
  • There will always be a static class named DefaultCommands from which methods may be invoked from the Console directly by name. For many console project, this will likely be sufficient.
  • Commands defined on classes other than DefaultCommands will be invoked from the console using the familiar dot syntax: ClassName.CommandName.

We will execute commands from the terminal and call our Command methods using Reflection. Yeah, I know - we're supposed to be hyper-sensitive about possible performance penalties when using reflection. In our case, this is negligible. Most of the so-called heavy lifting  will be done at application startup. Also, it's 2014. Computers are fast.

We'll look more closely at the Reflection aspect in a bit. For now, understand how this plays into how we parse text entered by the user into Commands and Arguments.

Parsing Console Input into Commands and Arguments

Now that we can interact with our console in a meaningful way, let's look at parsing the text input from the console into some sort of meaningful structure of commands and arguments.

Here, we need to make some decisions. For the purpose of this very basic application template, I made some assumptions:

  • The text entered will always consist of a command followed by zero or more arguments, separated by spaces.
  • Quoted text will be preserved as a single string argument, and may contain spaces.
  • Text arguments without spaces will be treated as strings, quotes are optional.

To manage to collection of commands and arguments, we're going to build a ConsoleCommand class:

The ConsoleCommand Class:
public class ConsoleCommand
{
    public ConsoleCommand(string input)
    {
        // Ugly regex to split string on spaces, but preserve quoted text intact:
        var stringArray = 
            Regex.Split(input, 
                "(?<=^[^\"]*(?:\"[^\"]*\"[^\"]*)*) (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
  
        _arguments = new List<string>();
        for (int i = 0; i < stringArray.Length; i++)
        {
            // The first element is always the command:
            if (i == 0)
            {
                this.Name = stringArray[i];
  
                // Set the default:
                this.LibraryClassName = "DefaultCommands";
                string[] s = stringArray[0].Split('.');
                if (s.Length == 2)
                {
                    this.LibraryClassName = s[0];
                    this.Name = s[1];
                }
            }
            else
            {
                var inputArgument = stringArray[i];
                string argument = inputArgument;
  
                // Is the argument a quoted text string?
                var regex = new Regex("\"(.*?)\"", RegexOptions.Singleline);
                var match = regex.Match(inputArgument);
  
                if (match.Captures.Count > 0)
                {
                    // Get the unquoted text:
                    var captureQuotedText = new Regex("[^\"]*[^\"]");
                    var quoted = captureQuotedText.Match(match.Captures[0].Value);
                    argument = quoted.Captures[0].Value;
                }
                _arguments.Add(argument);
            }
        }
    }
  
    public string Name { get; set; }
    public string LibraryClassName { get; set; }
  
    private List<string> _arguments;
    public IEnumerable<string> Arguments
    {
        get
        {
            return _arguments;
        }
    }
}
 

To achieve proper parsing of all this, we will need to engage everyone's favorite, Regular Expressions. That big, long, ugly Regular Expression near the top of the ConsoleCommand class is used to parse incoming text by splitting the text string where spaces occur, but to leave quoted text string intact.

I am not a Regex genius, and I found this Regular Expression on stack overflow, in an answer by someone who clearly IS a Regex Genius.

That is a big constructor method, and could possibly be refactored into a few smaller methods. But maybe not. In any case, let's take a look at what happens here:

Parse the Command from the Input Text

  • The string passed as the constructor argument is first split into a string array, delimited by spaces, with the exception that quoted text is preserved intact (the quotes are also preserves as part of the string, but we'll take care of that momentarily).
  • We then iterate over the array elements. One of the assumptions we have made about our program is that the first element will always be a command, so we grab element 0 on our first pass and assume it is the command.

Recall from earlier that we have some rules about command names:

  • We will always have a set of default commands available to our Console directly using the corresponding method name as defined on the class DefaultCommands.
  • We MAY have commands defined on other special classes within the Commands namespace, but from the console, we need to access any of these with the ClassName.CommandName dot notation.

At this point in our constructor is where we implement this rule. Our constructor code assumes that, time, a Console application will likely be using the default commands class, and assigns the LibraryClassName property as "DefaultCommands" accordingly. Then, the code checks to see if the command can be split on a period. If so, the new string array resulting from the check will have two elements, so the LibraryClassName property is set to match the first array element in the array (element[0]). The second array element is then assumed to be the actual command name, and is assigned to the Command property accordingly.

Parse the Arguments from the Input Text

Once the command has been properly parsed, and the LibraryClassName and Command properties have been set, we complete the iteration by parsing the arguments:

  • Each array element that is not element[0] is examined (once again using Regex, but not as bad this time) to see if it is a quoted string.
  • If the element is a quoted string, the text between the quotes is extracted, and added in its entirety to the Arguments list.
  • Otherwise, the string element is simply added to the Arguments list as-is.

Update the Run() Method to Use ConsoleCommand Class

Now that we have an object to represent a command issued by the user from the console, let's update our Run() and Execute() methods to use that. In Run() we will create an instance of our ConsoleCommand class, and then pass that to Execute():

Update Run Method to Consume ConsoleCommand Class:
static void Run()
{
    while (true)
    {  
        var consoleInput = ReadFromConsole();
        if (string.IsNullOrWhiteSpace(consoleInput)) continue;
        try
        {
            // Create a ConsoleCommand instance:
            var cmd = new ConsoleCommand(consoleInput);
            // Execute the command:
            string result = Execute(cmd);
            // Write out the result:
            WriteToConsole(result);
        }
        catch (Exception ex)
        {
            // OOPS! Something went wrong - Write out the problem:
            WriteToConsole(ex.Message);
        }
    }
}

 

And we will modify the signature of the Execute() method to accept an argument of type ConsoleCommand (and make a silly modification to the body code for simple demo purposes at this point):

Update Execute Method to Consume ConsoleCommand Class:
static string Execute(ConsoleCommand command)
{
    // We'll make this more interesting shortly. 
  
    // For now, output the command details:
    var sb = new StringBuilder();
    sb.AppendLine(string.Format("Executed the {0}.{1} Command", 
        command.LibraryClassName, command.Name));
    for(int i = 0; i < command.Arguments.Count(); i++)
    {
        sb.AppendLine(ConsoleFormatting.Indent(4) + 
            string.Format("Argument{0} value: {1}", i, command.Arguments.ElementAt(i)));
    }
    return sb.ToString();
}

 

Run the Application with Command Parsing in Place

If we run the application now, we can see, from the values written to the console, how our input is being parsed. We can input some reasonable approximation of a command with arguments, and view the result:

Command and Arguments are Parsed and Displayed:

command-parsing-execute-command

Now that we can effectively parse commands and arguments, how are we going to define commands available to our program, validate the arguments, and execute? Why, Reflection, of course.

Using Reflection to Load and Validate Commands and Arguments

We have set up our application structure specifically so we can easily use Reflection to load information about the commands we wish to make available to our application, and also to execute commands from the Console. This way, when we wish to add or change the commands available, all we need do is add the relevant code within the Commands folder/namespace, and our application will properly load everything it needs.

Let's recall the rules we established for defining commands within our application:

  • Methods representing Console commands will be defined as public static methods which always return a string, and are defined on public static classes.
  • Classes containing methods representing Console commands will be located in the Commands namespace, and in the Commands folder.
  • There will always be a static class named DefaultCommands from which methods may be invoked from the Console directly by name. For many console project, this will likely be sufficient.
  • Commands defined on classes other than DefaultCommands will be invoked from the console using the familiar dot syntax: ClassName.CommandName.

If we haven't already, add a folder to the project named Commands. Within this folder we will define at least one static class and name it DefaultCommands. It is within this class that we will define the core set of commands available to our application. Commands within this class will be invokeable from the Console using only the method name, no need to prefix with the class name using dot notation.

As an aside, some thought should be put into naming the methods we define as our commands. Short, easily remembered (and easily typed) method names will go a long way towards the usability factor of any Console application.

For now, we will set up a couple trivial commands as default commands to use while we work out the details:

Add the DefautCommands Class in the Commands Folder:
// All console commands must be in the sub-namespace Commands:
namespace ConsoleApplicationBase.Commands
{
    // Must be a public static class:
    public static class DefaultCommands
    {
        // Methods used as console commands must be public and must return a string
  
        public static string DoSomething(int id, string data)
        {
            return string.Format(
                "I did something to the record Id {0} and save the data {1}", id, data);
        }
  
  
        public static string DoSomethingElse(DateTime date)
        {
            return string.Format("I did something else on {0}", date);
        }
    }
}

While it may not seem intuitive at first, any command available to our console returns a string because, well, that's what the console can use. It may be an empty string, but a string nonetheless. This gives us a consistent return type to work with, easily consumed by our console.

The assumption here is that most of the real work to be done by any command will likely be sourced off into other classes or libraries. Once the command has completed its work, what our Console application is interested in is either a result it can display, or an empty string.

I my case, most of the time when a command succeeds, we either have asked for output to be displayed, or instructed the application to perform some function which succeeds or fails, but does not produce output. In the former case, we expect to see the results of our request. In the latter, we are going to assume that no feedback indicates successful execution, and return an empty string. If something goes wrong in the latter case, feedback will inform us of the details.

Loading Commands at Application Startup

First, we need to add a reference to System.Reflection in the using statements of our Program class:

Add System.Reflection to Using Statements:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

 

Next, we need to add a couple variables for use by the code we will be adding next. First, we want a constant defining the full Command namespace, and next we want a static dictionary to hold key-value pairs representing the classes defined in our Commands namespace. Each dictionary entry will use the class name as a key, and the value will be a nested dictionary containing information about the methods defined within that class.

Add Class-Level Variables to Program Class:
class Program
{
    const string _commandNamespace = "ConsoleApplicationBase.Commands";
    static Dictionary<string, Dictionary<string, IEnumerable<ParameterInfo>>> _commandLibraries;
  
    // ... The rest of the Program class code ...
}

 

Next, let's update our Main() method as follows:

Updated Main() method Loading Command Information Using Reflection:
static void Main(string[] args)
{
    Console.Title = typeof(Program).Name;
  
    // Any static classes containing commands for use from the 
    // console are located in the Commands namespace. Load 
    // references to each type in that namespace via reflection:
    _commandLibraries = new Dictionary<string, Dictionary<string, 
            IEnumerable<ParameterInfo>>>();
  
    // Use reflection to load all of the classes in the Commands namespace:
    var q = from t in Assembly.GetExecutingAssembly().GetTypes()
            where t.IsClass && t.Namespace == _commandNamespace
            select t;
    var commandClasses = q.ToList();
  
    foreach (var commandClass in commandClasses)
    {
        // Load the method info from each class into a dictionary:
        var methods = commandClass.GetMethods(BindingFlags.Static | BindingFlags.Public);
        var methodDictionary = new Dictionary<string, IEnumerable<ParameterInfo>>();
        foreach (var method in methods)
        {
            string commandName = method.Name;
            methodDictionary.Add(commandName, method.GetParameters());
        }
        // Add the dictionary of methods for the current class into a dictionary of command classes:
        _commandLibraries.Add(commandClass.Name, methodDictionary);
    }
    Run();
}

 

We load the information we need into the _commandLibrariesDictionary as follows:

  • We load all the Types contained in the _commandNamespace into a IEnumerable<Type> using Linq
  • Iterate over each Type in the list, use the GetMethods() method to retreive an IEnumerable<MethodInfo> for the methods in the class which meet the criteria specified in the call to GetMethods() (in this case, methods which are both public and static).
  • We create a Dictionary<string, IEnumerable<ParameterInfo>> for each method on a given class, and add a key-value pair for the method. The key, in this case, is the method name, and the corresponding value for each key is the IEnumerable<ParameterInfo> for the method.
  • Add each of these dictionaries, in nested fashion, into the _commandLibrariesDictionary and use the class name as the key.

With this in place, we can now update our Execute() method, and begin to get it doing something useful.

Executing Console Commands Using Reflection

Once again, we need to do a lot within this method, and there is likely potential for refactoring here. Within the Execute() method, we need to accomplish, broadly, three things:

  • Validate that the command passed in corresponds to a class and method defined in our Commands namespace
  • Make sure that all required method arguments are provided with the command.
  • Make sure that the arguments passed from the Console are all properly converted to the Type specified in the method signature (coming from the Console, all arguments are passed as strings).
  • Set up to execute the command using Reflection
  • Return the result of the execution, or catch exceptions and return a meaningful exception message.
Updated Execute() Method:
  
    // Validate the command name:
    if(!_commandLibraries.ContainsKey(command.LibraryClassName))
    {
        return badCommandMessage;
    }
    var methodDictionary = _commandLibraries[command.LibraryClassName];
    if (!methodDictionary.ContainsKey(command.Name))
    {
        return badCommandMessage;
    }
    
    // Make sure the corret number of required arguments are provided:
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
    var methodParameterValueList = new List<object>();
    IEnumerable<ParameterInfo> paramInfoList = methodDictionary[command.Name].ToList();
  
    // Validate proper # of required arguments provided. Some may be optional:
    var requiredParams = paramInfoList.Where(p => p.IsOptional == false);
    var optionalParams = paramInfoList.Where(p => p.IsOptional == true);
    int requiredCount = requiredParams.Count();
    int optionalCount = optionalParams.Count();
    int providedCount = command.Arguments.Count();
  
    if (requiredCount > providedCount)
    {
        if (requiredCount > providedCount)
        {
            return string.Format(
                "Missing required argument. {0} required, {1} optional, {2} provided",
                requiredCount, optionalCount, providedCount);
        }
    }
  
    // Make sure all arguments are coerced to the proper type, and that there is a 
    // value for every emthod parameter. The InvokeMember method fails if the number 
    // of arguments provided does not match the number of parameters in the 
    // method signature, even if some are optional:
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
    if (paramInfoList.Count() > 0)
    {
        // Populate the list with default values:
        foreach (var param in paramInfoList)
        {
            // This will either add a null object reference if the param is required 
            // by the method, or will set a default value for optional parameters. in 
            // any case, there will be a value or null for each method argument 
            // in the method signature:
            methodParameterValueList.Add(param.DefaultValue);
        }
  
        // Now walk through all the arguments passed from the console and assign 
        // accordingly. Any optional arguments not provided have already been set to 
        // the default specified by the method signature:
        for (int i = 0; i < command.Arguments.Count(); i++)
        {
            var methodParam = paramInfoList.ElementAt(i);
            var typeRequired = methodParam.ParameterType;
            object value = null;
            try
            {
                // Coming from the Console, all of our arguments are passed in as 
                // strings. Coerce to the type to match the method paramter:
                value = CoerceArgument(typeRequired, command.Arguments.ElementAt(i));
                methodParameterValueList.RemoveAt(i);
                methodParameterValueList.Insert(i, value);
            }
            catch (ArgumentException ex)
            {
                string argumentName = methodParam.Name;
                string argumentTypeName = typeRequired.Name;
                string message = 
                    string.Format(""
                    + "The value passed for argument '{0}' cannot be parsed to type '{1}'", 
                    argumentName, argumentTypeName);
                throw new ArgumentException(message);
            }
        }
    }
  
    // Set up to invoke the method using reflection:
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
    Assembly current = typeof(Program).Assembly;
  
    // Need the full Namespace for this:
    Type commandLibaryClass = 
        current.GetType(_commandNamespace + "." + command.LibraryClassName);
  
    object[] inputArgs = null;
    if (methodParameterValueList.Count > 0)
    {
        inputArgs = methodParameterValueList.ToArray();
    }
    var typeInfo = commandLibaryClass;
  
    // This will throw if the number of arguments provided does not match the number 
    // required by the method signature, even if some are optional:
    try
    {
        var result = typeInfo.InvokeMember(
            command.Name, 
            BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, 
            null, null, inputArgs);        
        return result.ToString();
    }
    catch (TargetInvocationException ex)
    {
        throw ex.InnerException;
    }
}

 

As we can see, we use the InvokeMember() method to execute our command. A good deal of the code above deals with setting up for this. There are a few things to be aware of here.

First off, we need to make sure the text passed as the the LibraryClassName and the Command Name properties are both valid, and correspond to appropriate objects within our Commands namespace. If not, we want to return the error information to the console immediately.

Next, we need to be aware of matching our arguments to method parameters. Some things to deal with here:

Our methods may have zero or more parameters defined within the method signature. Some may be required, and some may be "optional" (meaning they have been provided with default values within the method signature itself). In all cases, we want to fail immediately if the number of arguments provided doesn't at least match the number of required method parameters. So we check for that using reflection.

The InvokeMember() method attempts to match the requested method by matching the method name, and also by matching the method signature to the number of arguments provided as part of the call. Because of this, even though some of the parameters specified within the target method signature may be optional, InvokeMember() still needs to have arguments for them. Therefore, we need to provide values for ALL the parameters in the method, optional or not.

To accomplish this, we iterate once over the complete list of method parameters contained in paramInfoList, and add a corresponding object to methodParametersValueList. In the case of optional method parameters, the default value from the method signature will be used. All other values will be added simply as empty objects.

Once we have a value in methodParametersValueList for every corresponding method parameter, we can walk through the arguments passed in from the Console, coerce them to the proper type required by the parameter, and swap them into the list at the proper index.

We do the type coercion using the CoerceArgument() method discussed momentarily.

Once the list of arguments needed to call the method are assembled, we use InvokeMethod() to call into our command and return the result of the call as a string.

Coercing Console Arguments to the Proper Type

Note the call to CoerceArgument() about midway through our revised Execute() method. We need to be able to parse the incoming string representation of our argument values to the proper type required by the corresponding method parameter.

There may be more elegant ways to write this method, but this is pretty straightforward boiler plate code. The switch statement examines the type passed in and attempts to parse the string value to that type. If the method succeeds, the value is returned as an object. If the method fails, an ArgumentException is thrown, and caught by the calling code.

Add the following method to the Program class:

The CoerceArgument() Method:
static object CoerceArgument(Type requiredType, string inputValue)
{
    var requiredTypeCode = Type.GetTypeCode(requiredType);
    string exceptionMessage = 
        string.Format("Cannnot coerce the input argument {0} to required type {1}", 
        inputValue, requiredType.Name);
  
    object result = null;
    switch (requiredTypeCode)
    {
        case TypeCode.String:
            result = inputValue;
            break;
        case TypeCode.Int16:
            short number16;
            if (Int16.TryParse(inputValue, out number16))
            {
                result = number16;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Int32:
            int number32;
            if (Int32.TryParse(inputValue, out number32))
            {
                result = number32;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Int64:
            long number64;
            if (Int64.TryParse(inputValue, out number64))
            {
                result = number64;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Boolean:
            bool trueFalse;
            if (bool.TryParse(inputValue, out trueFalse))
            {
                result = trueFalse;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Byte:
            byte byteValue;
            if (byte.TryParse(inputValue, out byteValue))
            {
                result = byteValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Char:
            char charValue;
            if (char.TryParse(inputValue, out charValue))
            {
                result = charValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.DateTime:
            DateTime dateValue;
            if (DateTime.TryParse(inputValue, out dateValue))
            {
                result = dateValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Decimal:
            Decimal decimalValue;
            if (Decimal.TryParse(inputValue, out decimalValue))
            {
                result = decimalValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Double:
            Double doubleValue;
            if (Double.TryParse(inputValue, out doubleValue))
            {
                result = doubleValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.Single:
            Single singleValue;
            if (Single.TryParse(inputValue, out singleValue))
            {
                result = singleValue;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.UInt16:
            UInt16 uInt16Value;
            if (UInt16.TryParse(inputValue, out uInt16Value))
            {
                result = uInt16Value;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.UInt32:
            UInt32 uInt32Value;
            if (UInt32.TryParse(inputValue, out uInt32Value))
            {
                result = uInt32Value;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        case TypeCode.UInt64:
            UInt64 uInt64Value;
            if (UInt64.TryParse(inputValue, out uInt64Value))
            {
                result = uInt64Value;
            }
            else
            {
                throw new ArgumentException(exceptionMessage);
            }
            break;
        default:
            throw new ArgumentException(exceptionMessage);
    }
    return result;
}

 

Now, before we take this for another test spin, let's add one more silly demonstration method to our set of default commands. Add the following method, which includes and optional method parameter, to the DefaultCommands class:

Add a Method with Optional Parameters to Default Commands:
public static string DoSomethingOptional(int id, string data = "No Data Provided")
{
    var result = string.Format(
        "I did something to the record Id {0} and save the data {1}", id, data);
  
    if(data == "No Data Provided")
    {
        result = string.Format(
        "I did something to the record Id {0} but the optinal parameter "
        + "was not provided, so I saved the value '{1}'", id, data);
    }
    return result;
}

 

This will give us an opportunity to examine the behavior of our application when a method with an optional parameter is called.

Running the Console Application and Executing Commands

We now have what should be a working prototype of our Console Application Template. While the current example commands are simplistic, we can run this current version and make sure things are functioning as expected.

When we run the application, we have three commands to choose from. We enter the command name, followed by the arguments, separated by spaces. Recall that in cases where we wish to enter strings with spaces, we need to use quotes.

Our current method signatures look like this:

Reminder: Sample Method Signatures:
DoSomething(int id, string data)
DoSomethingElse(DateTime date)
DoSomethingOptional(int id, string data = "No Data Provided")

 

We'll start with the DoSomething() method. The method signature requires an id argument of type int, and a data argument of type string. We might enter something like this at the console:

Example Console Input for the DoSomething Command:
console> DoSomething 23 "My Data"

 

If we enter that, we see what happens:

Execute the DoSomething() method:

execute-dosomething-command

We can do similarly for the DoSomethingElse() command, which expects a date argument:

Execute the DoSomethingElse() Command:

execute-dosomethingelse-command

Likewise, the DoSomethingOptional() Command (we will provide the second, optional argument this pass):

Execute the DoSomethingOptional() Command:

execute-dosomethingoptional-with-optionalparam-command

If we enter the DoSomethingOptional() Command again, but this time omit the optional second argument, the command still executes, using the default value provided in our original method signature:

Execute the DoSomethingOptional() Command Omitting Optional Argument:

execute-dosomethingoptional-without-optionalparam-command

In this last case, we can see that command execution uses the default value defined in the method signature for the optional parameter, and takes the alternate execution path indicated by the conditional we implemented in the method itself.

Adding Additional Classes and Commands to the Commands Namespace

Depending upon our application requirements, the DefaultCommands class may not be sufficient to our needs. For any number of reasons, we may want to break our commands out into discreet classes. As we have seen, we have set up our Console application to handle this, so long as we observe the rules we defined.

Let's add a little bit business logic, and a new commands class to our application.

Add a Models Folder to your project, and add the following code in a file named SampleData.cs:

The SampleData Code File:
namespace ConsoleApplicationBase.Models
{
    // We'll use this for our examples:
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  
  
    public static class SampleData
    {
        private static List<User> _userData;
        public static List<User> Users
        {
            get
            {
                // List will be initialized with data the first time the
                // static property is accessed:
                if(_userData == null)
                {
                    _userData = CreateInitialUsers();
                }
                return _userData;
            }
        }
  
  
        // Some test data:
        static List<User> CreateInitialUsers()
        {
            var initialUsers = new List<User>()
            {
                new User { Id = 1, FirstName = "John", LastName = "Lennon" },
                new User { Id = 2, FirstName = "Paul", LastName = "McCartney" },
                new User { Id = 3, FirstName = "George", LastName = "Harrison" },
                new User { Id = 4, FirstName = "Ringo", LastName = "Starr" },
            };
            return initialUsers;
        }
    }
}

 

Here, we are going to use the SampleData class as a mock database, and work against that with a couple new commands. We can now add a Users class to our Commands namespace and folder.

Add A Users Class to the Commands Namespace

Add a class named Users to the Commands folder in Solution Explorer. Make sure it is in the Commands namespace:

The Users Command class:
public static class Users
{
    public static string Create(string firstName, string lastName)
    {
        Nullable<int> maxId = (from u in SampleData.Users
                              select u.Id).Max();
        int newId = 0;
        if(maxId.HasValue)
        {
            newId = maxId.Value + 1;
        }
  
        var newUser = new User 
        { 
            Id = newId, 
            FirstName = firstName, 
            LastName = lastName 
        };
        SampleData.Users.Add(newUser);
        return "";
    }
  
  
    public static string Get()
    {
        var sb = new StringBuilder();
        foreach(var user in SampleData.Users)
        {
            sb.AppendLine(ConsoleFormatting.Indent(2) 
                + string.Format("Id:{0} {1} {2}", 
                user.Id, user.FirstName, user.LastName));
        }
        return sb.ToString();
    }
}

 

Above, we have added two rather simplistic methods, Users.Create() and Users.Get(). We had to take some liberties faking up an auto-incrementing Id for the new users, but you get the idea.

With that, we can now try out our application with an added commands library. Recall that to call commands other than those defined in our DefaultCommands class, we need to user the dot syntax ClassName.CommandName.

Running the Project with Additional Command Classes

We can now invoke our User-related commands from the Console. The Console syntax for these two new commands would be similar to:

Console Syntax for the Users.Get() Method:
Users.Get

 

Console Syntax for the Users.Create() Method:
Users.Create Joe Strummer

 

If we run the application and execute the Users.Get() command, we get the following result:

Execute Users.Get() Command from the Console:

execute-users-get-command

Above, we see what we'd expect - the sample data we cooked up. If we then execute the Create() command, and then follow that up by executing Get() again, we see the added user data:

Execute Users.Create() Followed by Users.Get():

execute-users-create-then-users-get

Exception Handling for Console Command Execution

I don't claim to have handled every exception case we might run into here, but I believe I've provided a good start. The goal is to handle exceptions and errors and provide useful feedback to the user to know what went wrong, and how to correct things.

Note, however, that using InvokeMember adds a few minor wrinkles to the exception handling equation:

Invoke member catches any Exceptions thrown by the target method, and then throws a new TargetInvocationException. Our code needs to catch TargetInvocationException and retreive the inner exception  to obtain meaningful information about what happened.

Therefore, carefully thinking through how exceptions are defined and processed by your command code, and any code called by your command code is in order. The goal is to pass meaningful exception messages up through the call stack such that, when TargetInvocationException is caught, there will be sufficient meaningful information present to display on the Console.

TargetInvocationException Always Breaks at the Exception Source

Unlike the standard experience in Visual Studio, where user-handled exceptions are, well, handled according to how the code is written, when using InvokeMember, Visual Studio always breaks at the exception source, regardless of any exception handling in the code. In other words, user-handled exceptions thrown within the context of a call via InvokeMember will always cause  VS to drop into debug mode, unless you employ certain workarounds in your VS settings. More information about this in this StackOverflow Answer by Jon Skeet.

The upside of all that is, when the application .exe is run normally, exceptions sourced by calls to InvokeMember propagate normally up the call stack, and messages will be output correctly to the console.

Next Steps - Building Out a Real Console Application

Of course, the commands we have defined here are simplistic, used for demonstration and to make sure our application, in its nascent form, is working correctly in terms of parsing out commands and arguments, and then executing those commands.

As we plug in some actual business logic, there are some things we want to bear in mind.

The purpose of each command defined within the Commands namespace is primarily to receive instruction from the console, and essentially act as the go-between for the console and the business layer of an application. In other words, like controllers in an ASP.NET MVC application, most of the business logic (and work) performed by our application proper would likely not occur within the command itself.

The command receives input from the console in terms of arguments, and a directive to execute. The code within the command should then call out to whatever other methods or libraries it needs in order to do the work requested, receive the result, and then translate to the desired console output string (if any).

Think of it as MVC for the Console

Within certain limits, what we are trying to achieve here is essentially an MVC-like separation of concerns. The classes within the Commands namespace provide a function similar to that performed by Controllers in an MVC application. The Commands we define on those classes work in a similar manner to Controller actions.

in both cases, the function of the class is to be an intermediary between the presentation layer of the application (in our case, the "presentation layer" is the Console) and the Models that make up the business logic.

We can easily add additional Command classes and methods, and our application framework will properly "discover" them, provided we adhere to the rules we defined at the beginning (or, of course, we can change the rules to suit our needs).

It's Not Done…

Most of the basic application structure is in place here, but really, there is a lot more that could be done, depending upon how extensive your needs are.

I certainly haven't exhaustively tested things here (in fact, you'll note, there are no tests at all!), and there are myriad areas ripe with potential for improvement.

The basic idea, for me, was to get some sort of basic structure in place so that, whether I am trying out ideas, demoing library code, or actually building a real console application, I can plug in the code I want to work with and go. Without messing with, or thinking much about writing to and from the console itself.

Ideas, Issues, and Pull Requests Welcome!

The project code for this is hosted on my Github account, and I welcome all suggestions, Issues, and Pull Requests.

Additional Resources and Items of Interest

 

Posted on September 7 2014 02:26 PM by jatten     

Comments (1)

About the author

My name is John Atten, and my "handle" on many of my online accounts is xivSolutions. I am Fascinated by all things technology and software development. I work mostly with C#, JavaScript/Node, and databases of many flavors. Actively learning always. I dig web development. I am always looking for new information, and value your feedback (especially where I got something wrong!). You can email me at:

jatten at typecastexception dot com

Web Hosting by