Подтвердить что ты не робот

Исключить тип из проверки модели (пример DbGeography), чтобы исключить IsufficientExecutionStackException

UPDATE: для версии tl; dr пропустите снизу


У меня довольно простой подкласс JsonConverter, который я использую с Web API:

public class DbGeographyJsonConverter : JsonConverter
{
    public override bool CanConvert(Type type)
    {
        return typeof(DbGeography).IsAssignableFrom(type);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var value = (string)reader.Value;

        if (value.StartsWith("POINT", StringComparison.OrdinalIgnoreCase))
        {
            return DbGeography.PointFromText(value, DbGeography.DefaultCoordinateSystemId);
        }
        else if (value.StartsWith("POLYGON", StringComparison.OrdinalIgnoreCase))
        {
            return DbGeography.FromText(value, DbGeography.DefaultCoordinateSystemId);
        }
        else //We don't want to support anything else right now.
        {
            throw new ArgumentException();
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, ((DbGeography)value).AsText());
    }
}

Проблема заключается в том, что после возврата ReadJson приложение никогда не возвращает связанный объект к методу действий, поскольку он, похоже, застревает в бесконечном цикле проверки.

Здесь верхняя часть стека вызовов при приостановке выполнения:

System.Web.Http.dll! System.Web.Http.Metadata.Providers.AssociatedMetadataProvider.GetMetadataForPropertiesImpl.AnonymousMethod__0() Строка 40 С#     System.Web.Http.dll! System.Web.Http.Metadata.ModelMetadata.Model.get() Строка 85 С#     System.Web.Http.dll! System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(System.Web.Http.Metadata.ModelMetadata метаданные, System.Web.Http.Validation.DefaultBodyModelValidator.ValidationContext validationContext, контейнер объекта) Строка 94 С#     System.Web.Http.dll! System.Web.Http.Validation.DefaultBodyModelValidator.ValidateProperties(System.Web.Http.Metadata.ModelMetadata метаданные, System.Web.Http.Validation.DefaultBodyModelValidator.ValidationContext validationContext) Строка 156 С#     System.Web.Http.dll! System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(System.Web.Http.Metadata.ModelMetadata метаданные, System.Web.Http.Validation.DefaultBodyModelValidator.ValidationContext validationContext, контейнер объекта) Строка 130 С#     System.Web.Http.dll! System.Web.Http.Validation.DefaultBodyModelValidator.ValidateElements(System.Collections.IEnumerable model, System.Web.Http.Validation.DefaultBodyModelValidator.ValidationContext validationContext) Строка 176 С#

После этого повторяющийся образ вызовов по умолчаниюBodyModelValidator.Validation * повторяется снова и снова. Каждый раз, когда я приостанавливаю выполнение, он, кажется, находится примерно на той же глубине, поэтому он, похоже, не становится рекурсивно глубже.

Если я заставляю JsonConverter возвращать null, элемент управления возвращается к методу действия контроллера API, я предполагаю, что ничего не проверять.

У меня нет мозговых соков, чтобы понять это. Что я делаю неправильно?


ОБНОВЛЕНИЕ: Когда мозговые соки несколько пополнялись, я прошел через большую часть кода и, похоже, при проверке модели DefaultBodyModelValidator сверлит путь вниз в SqlTypesAssembly и получает застрял в цикле, считывая атрибуты где-то. Я не очень хочу узнать, где именно, потому что я не хочу, чтобы сверление DefaultBodyModelValidator в экземплярах типа DbGeography начиналось с.

Нет причин для валидации модели, чтобы развернуться в классе DbGeography. Мне нужно выяснить, как получить метод MediaTypeFormatterCollection.IsTypeExcludedFromValidation для возврата true для typeof(DbGeography), что приведет к тому, что DefaultBodyModelValidator выполнит неглубокую проверку на любых экземплярах DbGeography. Итак, теперь вопрос: как я могу исключить тип из проверки модели? Метод ShouldValidateType DefaultBodyModelValidator отмечен как виртуальный, но нет ли способа добавить исключенный тип при запуске?

4b9b3361

Ответ 1

Является ли эта проблема ошибкой или ограничением веб-API, я не знаю, но здесь мое обходное решение:

Сначала нам нужно подклассифицировать DefaultBodyModelValidator и переопределить метод ShouldValidateType.

public class CustomBodyModelValidator : DefaultBodyModelValidator
{
    public override bool ShouldValidateType(Type type)
    {
        return type!= typeof(DbGeography) && base.ShouldValidateType(type);
    }
}

Теперь в методе global.asax Application_Start добавьте

GlobalConfiguration.Configuration.Services.Replace(typeof(IBodyModelValidator), new CustomBodyModelValidator());

и что он. Теперь в экземплярах типа DbGeography будет выполняться неглубокая проверка, и все прекрасно связывается.

Ответ 2

Просто была точно такая же проблема, но затем с настраиваемым типом. После довольно много повторного поиска оказалось, что это вполне логично со знанием этой темы. Пользовательский класс имел общедоступное свойство readonly, которое возвращало другой экземпляр того же класса. Валидатор выполняет все свойства класса (даже если вы вообще не выполняете проверку) и получает значение. Если ваш класс возвращает новый экземпляр того же класса, это происходит снова и снова и... Похоже, что свойство StartPoint в классе географии имеет эту же проблему. https://msdn.microsoft.com/en-us/library/system.data.spatial.dbgeography.startpoint(v=vs.110).aspx

Ответ 3

Ответ joelmdev ведет меня в правильном направлении, но с моей конфигурацией WebApi в MVC и WebApi 5.2.3 новый валидатор не будет вызываться при размещении в Global.asax.

Решение заключалось в том, чтобы поместить его в мой метод WebApiConfig.Register с другими маршрутами WebApi: config.Services.Replace(typeof(IBodyModelValidator), new CustomBodyModelValidator());