Web Api Without MVC

Download full source code.

When building a Web Api application there is much unneeded MVC baggage that comes along with it.

To start with all the css, html and javascript can go, then most of the packages, most of referenced dlls and almost all the C#.

Here are side by side comparisons of what you get and what you need.

All you really need for Web Api is is the Global.asax to call WebApiConfig.Register which sets up the default routes and then a controller to perform an action.

Global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

ValuesController.cs

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] {$"Guid 1: {Guid.NewGuid()}", $"Guid 2: {Guid.NewGuid()}" };
    }
}

Web API 2 Controller with multiple GET methods – part 2

Download WebApi2MultipleGetMethodsDifferByParameterType

A few months ago I wrote a post explaining how to create a controller with multiple GET methods.
In that I used the combination of [RoutePrefix..] and [Route...] to generate routes like

  • http://…/api/values/geta
  • http://…/api/values/getb

Attribute parameter names and type

In this post I will show a different way of achieving multiple GETs by matching the type of parameter passed to the controller with the appropriate method.

In the first example I will match a method to an int being passed in, note the [Route("{id:int}")], this specifies that the expected parameter is named “id” and is an int.

// GET api/values/7
[Route("{id:int}")]
public string Get(int id)
{
    return $"You entered an int - {id}";
}

It is no problem to add another GET method with a [Route("{id:Guid}")]. This works fine because there is no way and int and Guid can be confused.

// GET api/values/AAC1FB7B-978B-4C39-A90D-271A031BFE5D
[Route("{id:Guid}")]
public string Get(Guid id)
{
    return $"You entered a GUID - {id}";
}

Where we start having problems is when the attribute routing system can’t determine which method you were attempting to call because it can’t distinguish an int from a long (or a string, decimal etc.)

For example, if we had another GET method taking a long, it would cause many runtime errors.

// GET api/values/8 - this will not work because it could be an int or a long
// GET api/values/4147483647 - this works because it can ONLY be a long
[Route("{id:long}")]
public string Get(long id)
{
    return $"You entered an long - {id}";
}

If we called http://...api/values/8, the attribute routing system has no way of knowing whether the GET method for the int or the long should be called.

But if we called http://...api/values/4147483647, that number is larger than an int can hold, the attribute routing system knows only one method matches the call.

If you want to have longs and ints in the same controller one of the routes needs to be altered. Note the new route – [Route("large/{id:long}")].

To call it now use http://...api/values/large/8 or http://...api/values/large/4147483647

[Route("large/{id:long}")]
public string Get(long id)
{
    return $"You entered an long - {id}";
}

Download WebApi2MultipleGetMethodsDifferByParameterType

Downloading an in-memory file using Web Api 2

Download full source code

At first you think it’s going to be easy to download a file from Web Api, but as I discovered, it was not.

In my case I wanted to load data from the database, perform some processing and return a subset of the data as a file. This meant I needed to send something that was in memory back to the caller as a file; I was NOT loading a file from the disk.

For simplicity I will skip all the database work and processing and jump to the in-memory object and how to return that.

The code is fairly self explanatory.

using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Web.Http;
using System.Web.Http.Results;

namespace WebApi2DownloadInMemoryFile.Controllers
{
    public class FileDownloadController : ApiController
    {
        public IHttpActionResult Get()
        {
            string someTextToSendAsAFile = "Hello world";
            byte[] textAsBytes = Encoding.Unicode.GetBytes(someTextToSendAsAFile);

            MemoryStream stream = new MemoryStream(textAsBytes);

            HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(stream)
            };
            httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = "WebApi2GeneratedFile.txt"
            };
            httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");

            ResponseMessageResult responseMessageResult = ResponseMessage(httpResponseMessage);
            return responseMessageResult;
        }
    }
}

Download full source code

Fluent Validation with Web Api 2

Full source code here.

I wrote blog post in 2015 on using the Fluent Validation NuGet package for complex validation needs. In the post the validator checked that a create person request had at least one active primary phone and at least one active primary email. Using Fluent Validation this was easy.

The blog post used a simple console application, but I now realize that a lot of people are having difficulty using this in Web API, especially when they have to consume the response from Web Api and look for potential errors from the Fluent Validation package.

I see an approach put forward Matthew Jones, but I don’t like the response rewriting. If you are making a request to a Web Api for a Person, you are no longer getting a Person, you’re getting a ResponsePackage with Person as an object inside.

public class ResponsePackage  
{
    public List Errors { get; set; }

    public object Result { get; set; } 
}

This requires quite a bit of extra work on the client side to get at the Result object. Testing is also complicated because a test calling the action method directly get a different response than a request being rewritten.
The rewriting also applies to all responses from the WebApi.

I propose a slightly different solution.

Step 1

Add the FluentValidation.WebApi NuGet package to the Web Api project and wire it up in the WebApiConfig class.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //Fluent Validation
        config.Filters.Add(new ValidateModelStateFilter());
        FluentValidationModelValidatorProvider.Configure(config);
        
        //snip..    
    }
}
Step 2

Create a model and validator in a Models project.

[Validator(typeof(PersonCreateRequestModelValidator))] 
public class PersonCreateRequestModel
{
    public Guid PersonId { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}
	
public class PersonCreateRequestModelValidator : AbstractValidator
{
    //Simple validator that checks for values in Firstname and Lastname
    public PersonCreateRequestModelValidator()
    {
        RuleFor(r => r.Firstname).NotEmpty();
        RuleFor(r => r.Lastname).NotEmpty();
    }
}

Step 3

Create a client to call the Web Api endpoints. In my example I use a console app, but you could use MVC or another Web Api project.

Create a HttpClient client to call the web service.

private HttpClient GetHttpClient()
{
    var httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri(@"http://localhost:5802/api/");
    httpClient.DefaultRequestHeaders.Accept.Clear();
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    return httpClient;
}

Call the web service using the client and examine the response for success, HttpStatusCode.OK, or failure, any other status code.

private async Task> PostToService(PersonCreateRequestModel model)
{
    var httpClient = GetHttpClient();
    string requestEndpoint = "person"; // full request will be http://localhost:5802/api/person
    HttpResponseMessage response = await httpClient.PostAsJsonAsync(requestEndpoint, model);

    WebApiResponse wrappedResponse;
    
    if (response.StatusCode == HttpStatusCode.OK)
    {
        var id = await response.Content.ReadAsAsync();
        wrappedResponse = new WebApiResponse(id, response.StatusCode);
    }
    else
    {
        var errors = await response.Content.ReadAsStringAsync();
        wrappedResponse = new WebApiResponse(errors, response.StatusCode, true);
    }
    return wrappedResponse;
}

Success or failure I wrap but don’t lose anything from the response from the web service. WebApiResponse is a generic class and as such takes any type. The wrapped response is then returned to the caller to do with as they wish.

public class WebApiResponse
{
    public WebApiResponse(T apiResponse, HttpStatusCode httpStatusCode)
    {
        ApiResponse = apiResponse;
        HttpStatusCode = httpStatusCode;
    }

    public WebApiResponse(string error, HttpStatusCode httpStatusCode, bool isError) // isError is just a way to differentiate the two constructors. If T were a string this constructor would always be called. 
    {
        Error = error;
        HttpStatusCode = httpStatusCode;
    }
    public T ApiResponse { get; set; }
    public HttpStatusCode HttpStatusCode { get; set; }
    public string Error { get; set; }
}

The major benefits I see in the approach are that it is simple, very flexible and does not change anything coming back from the web service.

Full source code here.

Web API 2 Controller with multiple get methods

It seems that every version of Web API changes how it handles default routes or route prefixes or whatever the next name will be.

I’ve written previously on how to handle multiple get methods in Asp.Net 5 Web API.

It’s a little different in Web Api 2.

using System.Web.Http;

namespace WebApiMultipleGets.Controllers
{
    [RoutePrefix("api/values")]
    public class ValuesController : ApiController
    {
        public string Get()
        {
            return "simple get";
        }

        [Route("geta")]
        public string GetA()
        {
            return "A";
        }

        [Route("getb")]
        public string GetB()
        {
            return "B";
        }

        [Route("getc")]
        public string GetC()
        {
            return "C";
        }

        [Route("getd")]
        public string GetD()
        {
            return "D";
        }
    }
}

Value cannot be null. Parameter name: constructor

Using Entity Framework I occasionally get the following error when reading from the database –
exceptionMessage=Value cannot be null.
Parameter name: constructor

My Person class looked like this –

    public class Person
    {
        public Person(string firstname, string lastname)
        {
             Firstname = firstname;
             Lastname = lastname;
        }

        public Guid PersonId { get; set; } 
        public string Firstname { get; set; } 
        public string Lastname { get; set; } 
        public DateTime SomeDate { get; set; }
     }

There is no way for Entity Framework to know how to instantiate this object because there is no empty constructor.

If you are following some of the principles of domain driven design you may not want a public empty constructor, no problem, make it private.

    public class Person
    {
        private Person(){} // Entity Framework queries will work now

        public Person(string firstname, string lastname)
        {
             Firstname = firstname;
             Lastname = lastname;
        }

        public Guid PersonId { get; set; } 
        public string Firstname { get; set; } 
        public string Lastname { get; set; } 
        public DateTime SomeDate { get; set; }
     }

Entity Framework Core and calling a stored procedure

I thought this would be easy, there is a method called ExecuteSqlCommand which takes the stored proc name and an array of parameters. I wanted to pass in two parameters and get one back, no problem, I’ve done this with ADO.Net and Entity Framework 6.

But holy s**t, two hours later and it was nowhere near working and I was very annoyed. ExecuteSqlCommand takes SqlParameters and the constructor for the output parameter is way more confusing than it needs to be. The input SqlParameter takes a name, a type and a value but the output SqlParameter needs eight more constructor params!!

Fortunately, EF Core still supports old style commands –

            DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();

DbCommand still has the ExecuteNonQueryAsync method. Save yourself a major headache and use the cmd.ExecuteNonQueryAsync().

Here is a simple example passing in two parameters and getting one output back.

private async Task ExecuteStoredProc()
{
	DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();

	cmd.CommandText = "dbo.sp_DoSomething";
	cmd.CommandType = CommandType.StoredProcedure;

	cmd.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar) { Value = "Steve" });
	cmd.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar) { Value = "Smith" });

	cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.BigInt) { Direction = ParameterDirection.Output });

	if (cmd.Connection.State != ConnectionState.Open)
	{
		cmd.Connection.Open();
	}

	await cmd.ExecuteNonQueryAsync();

	long id = (long)cmd.Parameters["@Id"].Value;
}

Getting Web API Exception Details from a HttpResponseMessage

The Problem

It’s hard to get the details of an exception from a Web Api response when calling Web Api from a C# program. (Skip to the solution if you don’t care about the background), it even handle inner exceptions!

Some background

If you are working on a Web Api project and testing with a web browser you get a wonderful error page when an exception occurs. It gives you the message, exception message, exception type and the stack trace. Pretty much all you need to get started figuring out what has gone wrong.
Exception in browser

Same thing with fiddler, get a 500 back and you’ll even be treated to a Json version of the above.

Exception in fiddler

What about calling the action method from inside a c# program? Should be easy, you just create a client, setup the query, let it rip and examine the response for a success status and then read the content to get the returned values. Great, works fine.

What if the server threw an exception like the ones shown above, I thought it would be a simple thing to call response.Exception or the like and get all the details. But easy it is not.
I rooted around in the response for a while but found nothing that was simple to use.

The Solution

Instead I have added an extension method to HttpResponseMessage to parse the details of the exception from the Json in the response.Content.

using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace SimpleWebApiClient
{
    public static class HttpResponseMessageExtension
    {
        public static async Task<ExceptionResponse> ExceptionResponse(this HttpResponseMessage httpResponseMessage)
        {
            string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
            ExceptionResponse exceptionResponse = JsonConvert.DeserializeObject<ExceptionResponse>(responseContent);
            return exceptionResponse;
        }
    }

    public class ExceptionResponse
    {
        public string Message { get; set; }
        public string ExceptionMessage { get; set; }
        public string ExceptionType { get; set; }
        public string StackTrace { get; set; }
        public ExceptionResponse InnerException { get; set; }
    }
}

Usage is simple.

    //snip
    HttpResponseMessage response = await httpClient.GetAsync(query).ConfigureAwait(false);
    
    if (response.IsSuccessStatusCode)
        // return the value
    
    // But if an error occurred read the details           
    ExceptionResponse exceptionResponse = response.ExceptionResponse();

    //snip

 

Web API 2 and ninject, how to make them work together

Full source code to download.

I’ve been using ninject for a few years, but every time I use it with Web Api I hit some problem and they usually stem from not including the right nuget packages, not changing the DependencyResolver or (once) forgetting how to make a binding!

For my future self and your reference, here is how it is done.

1. Nuget packages

Add Ninject.Web.WebApi using nuget to your Web Api project.

That will install two other package dependencies:
Ninject
Ninject.Web.Common

To make everything work you need to add one more nuget package
Ninject.Web.Common.WebHost

This will pull down the WebActivatorEx package and add a new class called NinjectWebCommon to your App_Start directory.

2. Edit NinjectWebCommon.cs

NinjectWebCommon.cs is missing a key feature if you want to use ninject to construct the controllers, and I presume that is why you are using ninject inside a Web Api project.

In the CreateKernel() method add the second line shown below. Now ninject will be used to resolve controller dependencies.

RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;

You will need to add a couple of using statements too –

using System.Web.Http;
using Ninject.Web.WebApi;

3. Register some services

To actually register some services we move to the RegisterServices(..) method do some binding.

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ICaclulator>().To<Caclulator>();
}

4. Use it all

And here is the usage in the controller.

    public class ValuesController : ApiController
    {
        private readonly ICaclulator _caclulator;
        public ValuesController(ICaclulator calculator)
        {
            _caclulator = calculator;
        }

        public int Get(int num1, int num2)
        {
            return _caclulator.Add(num1, num2);
        }
    }

Full source code to download.

Entity Framework, checking the connection string of your context

Sometimes when using Entity Framework I want to verify that I’m connected to the database I think I’m connected to.

Here’s how to check in Entity Framework 5, Entity Framework 6 and Entity Framework Core 1 (EF 7)

//Entity Framework 5
myContext.Database.Connection.ConnectionString
//Entity Framework 6
myContext.Database.Connection.ConnectionString
//Entity Framework Core 1
myContext.Database.GetDbConnection().ConnectionString