Внутренняя ошибка сервера в тесте в памяти веб-API ASP.NET

Я получаю «внутреннюю ошибку сервера» (код состояния 500) при тестировании контроллера веб-API ASP.NET в тест в памяти.

[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;
    }
}

Я настроил Visual Studio на прерывание при возникновении любого исключения .Net. Код не останавливается ни при каких исключениях, и я не могу найти в ответе никаких сведений об исключении.

Что мне делать, чтобы узнать, что вызывает «внутреннюю ошибку сервера»?


person Martin Nilsson    schedule 22.05.2012    source источник
comment
На что похожа трассировка стека? Положите это здесь.   -  person Aliostad    schedule 23.05.2012
comment
Ну, это проблема. Я не получаю трассировку стека. Только ответ с надписью Internal Server Error   -  person Martin Nilsson    schedule 23.05.2012
comment
что означает // additional configuration? Вы пропустили какой-то код?   -  person Aliostad    schedule 23.05.2012
comment
Обновленный пост с расширенным комментарием. Но там никаких исключений не выбрасывается. Код достигает var response = ...   -  person Martin Nilsson    schedule 23.05.2012
comment
Что касается меня, я обнаружил, что мне не хватает IncludeErrorDetailPolicy. Как только я включил это в создание hte HttpConfiguration, я смог увидеть ошибку. Надеюсь, это поможет кому-то еще!   -  person oddmeter    schedule 08.10.2013


Ответы (3)


Исключение находится в 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);
}
person Martin Nilsson    schedule 23.05.2012
comment
Как было предложено в другом ответе, вам может потребоваться установить политику сведений об ошибках var config = new HttpConfiguration { IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always}; - person Boris Lipschitz; 09.02.2017

Вам нужно добавить маршрут, чтобы он выглядел примерно так:

        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;

Кстати, в последних битах вы получаете 404 Not Found, как и следовало ожидать.

Хенрик

person Henrik Frystyk Nielsen    schedule 22.05.2012
comment
У меня это уже есть. На самом деле у меня довольно много конфигураций. Маршруты, фильтры, контейнер IoC и так далее. Моя проблема в том, что что-то происходит в конвейере, вызывая внутреннюю ошибку, отправленную обратно, но без информации об этом. - person Martin Nilsson; 23.05.2012
comment
@Martin Nilsson - Хенрик - архитектор WebAPI. Я бы послушал его. - person RickAndMSFT; 31.07.2012

Похоже, вы, возможно, уже нашли свой ответ, но это было не совсем для меня, поэтому я хочу добавить это для других с моей проблемой.

Начнем с того, что это проблема с новыми форматтерами MVC 4. Установка любого из флагов политики ошибок не будет работать (IncludeErrorDetailPolicy, CustomErrors и т. д.), эти средства форматирования игнорируют их и просто возвращают пустую «внутреннюю ошибку сервера» 500.

Я обнаружил это, в конце концов перегрузив средства форматирования и проверив их ответы на наличие ошибок:

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;
    } 
}

На данный момент я использую средства форматирования Xml и Json, которые просто ищут ret.Exception и фиксируют его, поэтому у меня по крайней мере есть данные, если произойдет 500. Я не мог найти элегантный способ сделать так, чтобы ошибка действительно отображалась в ответе html, поскольку Task.Exception уже установлен, и это ДОЛЖНО быть всем, что требуется для передачи исключения.

person Chris Werner    schedule 14.08.2012