带OData的ASPNET Core中的自定义参数绑定属性

时间:2019-07-08 16:38:00

标签: asp.net-core asp.net-core-mvc model-binding

我在此处发布了关于Ricks“原始请求正文”属性的实现...

https://weblog.west-wind.com/posts/2013/dec/13/accepting-raw-request-body-content-with-aspnet-web-api

...我正在将解决方案转换为.Net Core ...

有人知道如何在aspNet Core中实现OData控制器参数上的绑定属性吗?

编辑:

以防万一,这是我要转换的代码...

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Core.Api
{
    /// <summary>
    /// An attribute that captures the entire content body and stores it
    /// into the parameter of type byte[].
    /// </summary>
    /// <remarks>
    /// The parameter marked up with this attribute should be the only parameter as it reads the
    /// entire request body and assigns it to that parameter.    
    /// </remarks>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
    public sealed class RawBodyAttribute : ParameterBindingAttribute
    {
        public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
        {
            if (parameter == null) throw new ArgumentException("Invalid parameter");
            return new RawBodyParameterBinding(parameter);
        }
    }

    public class RawBodyParameterBinding : HttpParameterBinding
    {
        public RawBodyParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor) { }

        public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            var binding = actionContext.ActionDescriptor.ActionBinding;
            if(binding.ParameterBindings.Count(pb => pb.GetType() == typeof(RawBodyParameterBinding)) != 1)
                throw new InvalidOperationException("Exactly one parameter must be marked with the RawBody attribute in the action signature.");

            var type = binding.ParameterBindings.First(pb => pb.GetType() == typeof(RawBodyParameterBinding)).Descriptor.ParameterType;

            if (type == typeof(string))
            {
                return actionContext.Request.Content
                        .ReadAsStringAsync()
                        .ContinueWith((task) => SetValue(actionContext, task.Result));
            }
            else if(type == typeof(byte[]))
            {
                return actionContext.Request.Content
                    .ReadAsByteArrayAsync()
                    .ContinueWith((task) => SetValue(actionContext, task.Result));
            }

            throw new InvalidOperationException("Only byte[] or string values are supported for [RawBody] parameters");
        }

        public override bool WillReadBody
        {
            get { return true; }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您需要实现自己的属性和活页夹。

  1. RawBodyAttribute

    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class RawBodyAttribute : Attribute, IBindingSourceMetadata
    {
        public BindingSource BindingSource => RawBodyBindingSource.RawBody;
    }
    
  2. RawBodyBindingSource

    public class RawBodyBindingSource : BindingSource
    {
        public static readonly BindingSource RawBody = new RawBodyBindingSource(
            "RawBody",
            "RawBody",
            true,
            true
        );
    
        public RawBodyBindingSource(string id, string displayName, bool isGreedy, bool isFromRequest) 
            : base(id, displayName, isGreedy, isFromRequest)
        {
        }
    
        public override bool CanAcceptDataFrom(BindingSource bindingSource)
        {
            return bindingSource == Body || bindingSource == this;
        }
    }
    
  3. RawBodyModelBinder

    public class RawBodyModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {           
    
            using (StreamReader reader = new StreamReader(bindingContext.HttpContext.Request.Body, Encoding.UTF8))
            {
                var model = reader.ReadToEnd();
                bindingContext.Result = ModelBindingResult.Success(model);
            }
    
            return Task.CompletedTask;
        }
    }
    
  4. RawBodyModelBinderProvider

    public class RawBodyModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.BindingInfo.BindingSource != null
                && context.BindingInfo.BindingSource.CanAcceptDataFrom(RawBodyBindingSource.RawBody))
            {
                return new RawBodyModelBinder();
            }
            else
            {
                return null;
            }
        }
    }
    
  5. 注册

    services.AddMvc(options =>
    {
        options.ModelBinderProviders.Insert(0, new RawBodyModelBinderProvider());
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
  6. 用例

    public IActionResult Post([RawBody]string value)
    {
        return Ok(value);
    }
    
相关问题