Исключить тип из проверки модели (пример 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
отмечен как виртуальный, но нет ли способа добавить исключенный тип при запуске?
Ответы
Ответ 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());