8

I get an "internal server error" (status code 500) when testing an ASP.NET Web API controller in an in-memory test.

[TestFixture]
public class ValuesControllerTest
{
    private HttpResponseMessage response;

    [TestFixtureSetUp]
    public void Given()
    {
        var config = new HttpConfiguration
        {
            IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
        };

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { controller = typeof(ValuesController).Name.Replace("Controller", string.Empty), id = RouteParameter.Optional }
        );

        //This method will cause internal server error but NOT throw any exceptions
        //Remove this call and the test will be green
        ScanAssemblies();

        var server = new HttpServer(config);
        var client = new HttpClient(server);
        response = client.GetAsync("http://something/api/values/5").Result;
        //Here response has status code 500

    }

    private void ScanAssemblies()
    {
        PluginScanner.Scan(".\\", IsApiController);
    }

    private bool IsApiController(Type type)
    {
        return typeof (ApiController).IsAssignableFrom(type);
    }

    [Test]
    public void Can_GET_api_values_5()
    {
        Assert.IsTrue(response.IsSuccessStatusCode);
    }
}

public static class PluginScanner
{
    public static IEnumerable<Type> Scan(string directoryToScan, Func<Type, bool> filter)
    {
        var result = new List<Type>();
        var dir = new DirectoryInfo(directoryToScan);

        if (!dir.Exists) return result;

        foreach (var file in dir.EnumerateFiles("*.dll"))
        {
            result.AddRange(from type in Assembly.LoadFile(file.FullName).GetTypes()
                            where filter(type)
                            select type);
        }
        return result;
    }
}

I have configured Visual Studio to break when any .Net exception is thrown. Code is not stopped at any exception nor can I find any exception details in the response.

What should I do to see what's causing the "internal server error"?

5
  • What is the stack trace like? Put that here. Commented May 22, 2012 at 21:32
  • Well, that's the problem. I don't get a stack trace. Only a response saying "Internal Server Error" Commented May 22, 2012 at 21:35
  • what does // additional configuration mean? Have you omitted some code? Commented May 22, 2012 at 21:47
  • Updated post with expanded comment. But no exception is thrown there. The code reaches "var response = ..." Commented May 22, 2012 at 21:53
  • For me, I found I was missing the IncludeErrorDetailPolicy. Once I included that in the creation of hte HttpConfiguration, I was able to see the error. Hope this helps someone else! Commented Oct 8, 2013 at 15:14

3 Answers 3

12

The exception is in Response.Content

if (Response != null && Response.IsSuccessStatusCode == false)
{
    var result = Response.Content.ReadAsStringAsync().Result;
    Console.Out.WriteLine("Http operation unsuccessful");
    Console.Out.WriteLine(string.Format("Status: '{0}'", Response.StatusCode));
    Console.Out.WriteLine(string.Format("Reason: '{0}'", Response.ReasonPhrase));
    Console.Out.WriteLine(result);
}
Sign up to request clarification or add additional context in comments.

1 Comment

As suggested in another answer you might need to set the error detail policy var config = new HttpConfiguration { IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always };
4

You need to add a route so that it looks something like this:

        var config = new HttpConfiguration()
        {
            IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
        };

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

        var server = new HttpServer(config);
        var client = new HttpClient(server);

        HttpResponseMessage response = client.GetAsync("http://somedomain/api/product").Result;

Btw, in the latest bits you get a 404 Not Found as you would expect.

Henrik

2 Comments

I have that allready. In fact, I have quite a lot of configurations. Routes, filters, IoC container and so on. My problem is that something happens in the pipeline causing an internal error sent back but no info about it.
@Martin Nilsson - Henrik is the WebAPI architect. I would listen to him.
1

It sounds like you might have already found your answer, but that wasn't quite it for me so I want to add this for others with my issue.

To start out, it seems to be an issue with the new MVC 4 formatters. Setting any of the error policy flags will not work (IncludeErrorDetailPolicy, CustomErrors, etc), these formatters are ignoring them and just returning and empty "internal server error" 500.

I found this out by eventually overloading the formatters and checking their responses for errors:

public class XmlMediaTypeFormatterWrapper : XmlMediaTypeFormatter
{
    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext transportContext)
    {
        var ret = base.WriteToStreamAsync(type, value, stream, contentHeaders, transportContext);
        if (null != ret.Exception)
            // This means there was an error and ret.Exception has all the error message data you would expect, but once you return below, all you get is a blank 500 error...

        return ret;
    } 
}

For now I am using Xml and Json formatter wrappers that simply look for ret.Exception and capture it so I at least have the data if a 500 happens. I couldn't really find an elegant way to make the error actually show up in the html response since Task.Exception is already set and this SHOULD be all the is required to pass the exception along.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.