Мне нужно нормализовать строковые данные (заменить некоторые символы друг другом, например: «ی» на «ي» или обрезать их). Для этого я создал следующую привязку модели, как показано ниже:
public class StringModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
var value = Normalize(valueProviderResult.FirstValue);
bindingContext.Result = ModelBindingResult.Success(value);
return Task.CompletedTask;
}
}
Этот биндер работает как для Query
, так и для Route
, но не работает, если я использую атрибут FromBody
. Это не удается, потому что BindModelAsync
никогда не вызывается. Я нашел еще один вопрос, поднятый по этой проблеме здесь и к сожалению нет ответа.
Я попытался расширить ComplexObjectModelBinder
, но это класс sealed
(а также не предоставляет никакого конструктора). Поэтому я попытался расширить ComplexTypeModelBinder
, который помечен как устаревший.
Я скопировал логику из ComplexTypeModelBinderProvider
из исходный код и, к моему удивлению, BindModelAsync
из моих StringModelBinder
теперь принимает звонки. Но все равно не получается, потому что bindingContext.ValueProvider
содержит только провайдера для маршрута и результат остается нулевым.
Мой поставщик связывателя на данном этапе:
public class MyModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
for (var i = 0; i < context.Metadata.Properties.Count; i++)
{
var property = context.Metadata.Properties[i];
propertyBinders.Add(property, context.CreateBinder(property));
}
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new ComplexTypeModelBinder(
propertyBinders,
loggerFactory,
allowValidatingTopLevelNodes: true);
}
if (context.Metadata.ModelType == typeof(string))
{
return new StringModelBinder();
}
return null;
}
}
Я также попытался создать провайдера из тела и изменил свой StringModelBinder
на:
public class StringModelBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
{
var context = new ValueProviderFactoryContext(bindingContext.ActionContext);
await new FormValueProviderFactory().CreateValueProviderAsync(context);
valueProviderResult = context.ValueProviders
.Select(x => x.GetValue(bindingContext.ModelName))
.FirstOrDefault(x => x != ValueProviderResult.None);
if (valueProviderResult == ValueProviderResult.None) return;
}
var value = valueProviderResult.FirstValue.Replace("A", "B");
bindingContext.Result = ModelBindingResult.Success(value);
}
}
Теперь вопрос в том, как лучше всего выполнить эту нормализацию в .Net 5?
Кому может быть интересно: этот вопрос может показаться дублированием, но я не смог найти ничего, связанного с .Net 5, и если есть вопрос, отвечающий на вопрос ComplexTypeModelBinder
, он не подходит для .Net 5, поскольку он устарел.
Middleware
илиActionFilter
означает добавление отражения в жизненный цикл запроса, не повлияет ли это на производительность. Я знаю, что это было бы очень крошечным, но я все еще беспокоюсь об этом. Кроме того, спасибо за вашу поддержку. - person Hamid Mayeli   schedule 02.01.2021