mirror of https://github.com/abpframework/abp.git
3 changed files with 128 additions and 0 deletions
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.Data; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
||||
|
{ |
||||
|
public class AbpExtraPropertiesDictionaryModelBinderProvider : IModelBinderProvider |
||||
|
{ |
||||
|
public IModelBinder GetBinder(ModelBinderProviderContext context) |
||||
|
{ |
||||
|
if (context == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(context)); |
||||
|
} |
||||
|
|
||||
|
if (context.Metadata.ModelType != typeof(Dictionary<string, object>)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (!context.Metadata.ContainerType.IsAssignableTo<IHasExtraProperties>()) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var binderType = typeof(DictionaryModelBinder<string, object>); |
||||
|
var keyBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(typeof(string))); |
||||
|
var valueBinder = new AbpExtraPropertyModelBinder(context.Metadata.ContainerType); |
||||
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>(); |
||||
|
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value; |
||||
|
|
||||
|
return (IModelBinder)Activator.CreateInstance( |
||||
|
binderType, |
||||
|
keyBinder, |
||||
|
valueBinder, |
||||
|
loggerFactory, |
||||
|
true /* allowValidatingTopLevelNodes */, |
||||
|
mvcOptions); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
||||
|
{ |
||||
|
public class AbpExtraPropertyModelBinder : IModelBinder |
||||
|
{ |
||||
|
public Type ExtensibleObjectType { get; } |
||||
|
|
||||
|
public AbpExtraPropertyModelBinder(Type extensibleObjectType) |
||||
|
{ |
||||
|
ExtensibleObjectType = extensibleObjectType; |
||||
|
} |
||||
|
|
||||
|
public virtual Task BindModelAsync(ModelBindingContext bindingContext) |
||||
|
{ |
||||
|
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); |
||||
|
if (valueProviderResult == ValueProviderResult.None) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); |
||||
|
|
||||
|
var model = ConvertStringToPropertyType( |
||||
|
bindingContext, |
||||
|
valueProviderResult.FirstValue |
||||
|
); |
||||
|
|
||||
|
bindingContext.Result = ModelBindingResult.Success(model); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
protected virtual object ConvertStringToPropertyType(ModelBindingContext bindingContext, string value) |
||||
|
{ |
||||
|
if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && string.IsNullOrWhiteSpace(value)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var extensionInfo = ObjectExtensionManager.Instance.GetOrNull(ExtensibleObjectType); |
||||
|
if (extensionInfo == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
var propertyName = ExtractExtraPropertyName(bindingContext.ModelName); |
||||
|
if (propertyName == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
var propertyInfo = extensionInfo.GetPropertyOrNull(propertyName); |
||||
|
if (propertyInfo == null) |
||||
|
{ |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
return Convert.ChangeType(value, propertyInfo.Type); |
||||
|
} |
||||
|
|
||||
|
/* modelName is a string like "UserInfo.ExtraProperties[SocialSecurityNumber]" |
||||
|
* This method returns "SocialSecurityNumber" for this example. */ |
||||
|
protected virtual string ExtractExtraPropertyName(string modelName) |
||||
|
{ |
||||
|
//TODO: Use regex(?) and add unit test (by extracting to a helper class)
|
||||
|
var index = modelName.IndexOf(".ExtraProperties[", StringComparison.Ordinal); |
||||
|
if (index < 0) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return modelName.Substring(index + 17, modelName.Length - index - 18); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue