Skip to content

Instantly share code, notes, and snippets.

@mattjohnsonpint
Created November 15, 2018 21:55
Show Gist options
  • Save mattjohnsonpint/79dbb529932e06a7f9353d5f8f10169b to your computer and use it in GitHub Desktop.
Save mattjohnsonpint/79dbb529932e06a7f9353d5f8f10169b to your computer and use it in GitHub Desktop.
Path Model Binder for ASP.NET Core
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace MyNameSpace
{
public class PathModelBinderAttribute : ModelBinderAttribute
{
public PathModelBinderAttribute()
: base(typeof(PathModelBinder))
{
}
}
public class PathModelBinder : IModelBinder
{
// Kestrel does not automatically decode %2F to / in parameters, so we need to do it ourselves
// https://github.com/aspnet/KestrelHttpServer/issues/1425
// https://github.com/aspnet/KestrelHttpServer/issues/2946
private static readonly Regex EncodedPathCharRegex = new Regex("%2F", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
if (bindingContext.ModelType != typeof(string))
{
return Task.CompletedTask;
}
var modelName = GetModelName(bindingContext);
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var inputString = valueProviderResult.FirstValue;
if (inputString == null || inputString.IndexOf("%2F", StringComparison.OrdinalIgnoreCase) == -1)
{
bindingContext.Result = ModelBindingResult.Success(inputString);
}
else
{
var outputString = EncodedPathCharRegex.Replace(inputString, "/");
bindingContext.Result = ModelBindingResult.Success(outputString);
}
return Task.CompletedTask;
}
private string GetModelName(ModelBindingContext bindingContext)
{
return string.IsNullOrEmpty(bindingContext.BinderModelName)
? bindingContext.ModelName
: bindingContext.BinderModelName;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment