Trimming text can be done on client side codes, but I believe it is most suitable on MVC Model Binder since it would be at one place on infrastructure level which would be free from any manual intervention of developer. This would allow every post request to be processed and converted to a trimmed string.
Let us start by creating Model binder
The above will try to trim text if it is not able to do then it would call passed default model binder. In our case, that is SimpleTypeModelBinder which would be explained in the later description.
In MVC Core, each binder needs provider so let's create Provider for the above Model Binder. The primary task here is to filter and execute Binder.
Model binder provider for trimming
It just checks if the request is not for complex types and data type request is of string.
Extension helper method for Provider registration
It tries to find Index of SimpleTypeModelBinder and replaces it with TrimmingModelBinderProvider. This would process string through our custom provider if not then it would fall back to the inbuilt model binder.
After the whole thing is done, it could be hooked into MVC.
Let us start by creating Model binder
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Threading.Tasks;
public class TrimmingModelBinder
: IModelBinder
{
private readonly IModelBinder FallbackBinder;
public TrimmingModelBinder(IModelBinder fallbackBinder)
{
FallbackBinder = fallbackBinder ?? throw new ArgumentNullException(nameof(fallbackBinder));
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != null &&
valueProviderResult.FirstValue is string str &&
!string.IsNullOrEmpty(str))
{
bindingContext.Result = ModelBindingResult.Success(str.Trim());
return Task.CompletedTask;
}
return FallbackBinder.BindModelAsync(bindingContext);
}
}
The above will try to trim text if it is not able to do then it would call passed default model binder. In our case, that is SimpleTypeModelBinder which would be explained in the later description.
In MVC Core, each binder needs provider so let's create Provider for the above Model Binder. The primary task here is to filter and execute Binder.
Model binder provider for trimming
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
public class TrimmingModelBinderProvider
: IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.Metadata.IsComplexType && context.Metadata.ModelType == typeof(string))
{
return new TrimmingModelBinder(new SimpleTypeModelBinder(context.Metadata.ModelType));
}
return null;
}
}
It just checks if the request is not for complex types and data type request is of string.
Extension helper method for Provider registration
public static void AddStringTrimmingProvider(this MvcOptions option)
{
var binderToFind = option.ModelBinderProviders
.FirstOrDefault(x => x.GetType() == typeof(SimpleTypeModelBinderProvider));
if (binderToFind == null)
{
return;
}
var index = option.ModelBinderProviders.IndexOf(binderToFind);
option.ModelBinderProviders.Insert(index, new TrimmingModelBinderProvider());
}
It tries to find Index of SimpleTypeModelBinder and replaces it with TrimmingModelBinderProvider. This would process string through our custom provider if not then it would fall back to the inbuilt model binder.
After the whole thing is done, it could be hooked into MVC.
service.AddMvc(option => option.AddStringTrimmingProvider())
It does not work for complex model having string property. .net core 2.1
ReplyDelete