【问题标题】:Custom parameter binding attributes in aspnet Core with OData带有 OData 的 aspnet Core 中的自定义参数绑定属性
【发布时间】:2019-07-09 17:52:43
【问题描述】:

我有一个 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; }
        }
    }
}

【问题讨论】:

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


    【解决方案1】:

    您需要实现自己的属性和绑定器。

    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);
      }
      

    【讨论】:

    • 只有微软才能通过要求开发人员编写比以前版本更多的代码来做出更好的事情。这太残酷了!
    • 原来你可以直接阅读控制器动作中的请求正文,这将保存所有这些......至少很好......你知道这种方法是否适用于文件发送涛?
    猜你喜欢
    • 2020-09-04
    • 2015-09-18
    • 1970-01-01
    • 2021-05-05
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    相关资源
    最近更新 更多