Skip to content

Instantly share code, notes, and snippets.

@darrelmiller
Created September 11, 2012 13:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save darrelmiller/3698325 to your computer and use it in GitHub Desktop.
Save darrelmiller/3698325 to your computer and use it in GitHub Desktop.
Some Web API techniques
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace WebApiSelfHost
{
class Program
{
static void Main(string[] args)
{
var baseAddress = new Uri("http://localhost:8080/");
var configuration = new HttpSelfHostConfiguration(baseAddress);
configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var host = new HttpSelfHostServer(configuration);
host.OpenAsync().Wait();
Console.WriteLine("Host open. Hit enter to exit...");
Console.Read();
host.CloseAsync().Wait();
}
}
public class Foo
{
public string A { get; set; }
public string B { get; set; }
}
public class Error
{
public string Code { get; set; }
public string Message { get; set; }
}
// Helper class to allow actions that return HttpResponseMessage to easily embed CLR types
public class HttpResponseMessage<T> : HttpResponseMessage
{
public HttpResponseMessage(HttpRequestMessage request, T value)
{
var config = request.GetConfiguration();
var contentNegotiator = config.Services.GetContentNegotiator();
var connegResult = contentNegotiator.Negotiate(
typeof(T), request, config.Formatters
);
request.CreateResponse(HttpStatusCode.Accepted, value);
Content = new ObjectContent<T>(value, connegResult.Formatter);
}
}
// Return a HttpResponseMessage that has a strongly typed payload
public class FooController : ApiController
{
public HttpResponseMessage Get()
{
var value = new Foo()
{
A = "Hello",
B = "World"
};
return new HttpResponseMessage<Foo>(Request, value);
}
}
// Return an error message along with a status code
public class BarController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "You have failed"};
}
}
// Return error message by throwing an exception
public class BazController : ApiController
{
public Foo Get()
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest ) {ReasonPhrase= "You have failed"}) ;
}
}
// Return an error message body by throwing an exception
public class BlahController : ApiController
{
public Foo Get()
{
throw new HttpResponseException(new HttpResponseMessage<Error>(Request,new Error() {Code = "911", Message="You failed"}) {StatusCode = HttpStatusCode.BadRequest} );
}
}
}
@mythz
Copy link

mythz commented Sep 11, 2012

That's ok, by comparison different ways to do error handling in ServiceStack:

 public class BlahService : RestServiceBase<Foo>
 {
     public override object OnGet(Foo request)
     {
         //StatusCode = 400, StatusDesciption = You failed
         throw new ArgumentException("You failed"); 

         //StatusCode = 911, StatusDesciption = You failed
         throw new HttpError { Status = 911, StatusDescription = "You failed" };
    }
 }

Also if you have a FooResponse DTO you also get typed, structured error handling back in the client: https://github.com/ServiceStack/ServiceStack/wiki/Validation e.g:

try 
{
    var client = new JsonServiceClient(BaseUri);
    var response = client.Send<UserResponse>(new User());
} 
catch (WebServiceException webEx) 
{
    /*
      webEx.StatusCode  = 400
      webEx.ErrorCode   = ArgumentNullException
      webEx.Message     = Value cannot be null. Parameter name: Name
      webEx.StackTrace  = (your Server Exception StackTrace - if DebugMode is enabled)
      webEx.ResponseDto = (your populated Response DTO)
      webEx.ResponseStatus   = (your populated Response Status DTO)
      webEx.GetFieldErrors() = (individual errors for each field if any)
    */
}

The error is just a serialized JSON / XML FooResponse DTO so can easily be read by dynamic clients as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment