将模型的属性别名别名为asp.net-core中的其他名称

时间:2019-05-27 13:51:30

标签: c# asp.net-core

我希望为我的请求对象属性的名称加上别名,以便这些请求都可以工作并且都转到同一个控制器:

myapi/cars?colors=red&colors=blue&colors=greenmyapi/cars?c=red&c=blue&c=green

对于请求对象:

public class CarRequest {
    Colors string[] { get; set; }
}

有没有人能够使用新的ModelBinder解决此问题而不必从头开始编写ModelBindings?

Here is a similar problem for an older version of asp.netalso here

1 个答案:

答案 0 :(得分:0)

好的。我写了一个模型活页夹。并且必须在客户端库中包含或引用一个属性,并将其放置在该属性上。改进后,我将对其进行更新。我尚未对此进行正确的测试。

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
//using my models
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;

namespace Mynamespaceforthewebproject
{
    public class AliasModelBinder : ComplexTypeModelBinder
    {
        public AliasModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory)
            : base(propertyBinders, loggerFactory)
        {
        }

        protected override Task BindProperty(ModelBindingContext bindingContext)
        {
            var containerType = bindingContext.ModelMetadata.ContainerType;
            if (containerType != null)
            {
                var propertyType = containerType.GetProperty(bindingContext.ModelMetadata.PropertyName);
                var attributes = propertyType.GetCustomAttributes(true);
                var aliasAttribute = attributes.SingleOrDefault(attr => attr is BindingAliasAttribute) as BindingAliasAttribute;

                if (aliasAttribute != null)
                {
                    bindingContext.ValueProvider = new AliasValueProvider(bindingContext.ValueProvider,
                        new Alias {OriginalPropertyName = bindingContext.ModelName, AliasName = aliasAttribute.Alias});
                }
            }

            return base.BindProperty(bindingContext);
        }
    }

    public class AliasValueProvider : IValueProvider
    {
        private readonly IValueProvider _provider;
        private readonly Alias _alias;

        public AliasValueProvider(IValueProvider provider, Alias alias)
        {
            _provider = provider;
            _alias = alias;
        }

        public bool ContainsPrefix(string prefix)
        {
            if (prefix == _alias.OriginalPropertyName)
            {
                return _provider.ContainsPrefix(_alias.OriginalPropertyName) ||
                       _provider.ContainsPrefix(_alias.AliasName);
            }

            return _provider.ContainsPrefix(prefix);
        }

        public ValueProviderResult GetValue(string key)
        {
            if (key == _alias.OriginalPropertyName)
            {
                var original = _provider.GetValue(_alias.OriginalPropertyName);
                return original.Values.Any() ? original : _provider.GetValue(_alias.AliasName);
            }

            return _provider.GetValue(key);
        }
    }

    public class Alias
    {
        public string OriginalPropertyName { get; set; }
        public string AliasName { get; set; }
    }

    public class AliasModelBinderProvider<T> : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.Metadata.ModelType == typeof(T))
            {
                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));
                }

                return new AliasModelBinder(propertyBinders,
                    (ILoggerFactory)context.Services.GetService(typeof(ILoggerFactory)));
            }

            return null;
        }
    }
}

并在客户项目中

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class BindingAliasAttribute : Attribute
{
    public string Alias { get; }

    public BindingAliasAttribute(string alias)
    {
        Alias = alias;
    }
}

和一个看起来像这样的对象:

public class SomeRequest
{
    [BindingAlias("id")]
    public long[] SomeFooIdsForFooing{ get; set; }
}

导致请求看起来像这样:

api/controller/action?SomeFooIdsForFooing=1&SomeFooIdsForFooing=2

api/controller/action?id=1&id=2