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