简体   繁体   English

如何禁用特定 ASP.NET Core 5.0 Web ZDB974238714CA8DE6347A 操作的自动 model 绑定?

[英]How do I disable automatic model binding for a specific ASP.NET Core 5.0 Web API action?

I have a third-party proprietary application, for which I need to write an API endpoint in my ASP.NET Core 5.0 web API application.我有一个第三方专有应用程序,为此我需要在我的 ASP.NET 核心 5.0 Z2567A5EC9705EB7AC2C984033E06189D3A8DE6747CEDFA84 应用程序中编写一个 API 端点。

The third party application sends out an HTTP post request, with only binary data in the request body, alongside the content type application/x-www-form-urlencoded or, sometimes, application/octet-stream (kind of random, but the data is the same).第三方应用程序发出一个 HTTP 发布请求,请求正文中只有二进制数据,以及内容类型application/x-www-form-urlencoded或有时是application/octet-stream (有点随机,但数据是一样的)。

My action handler looks like this:我的动作处理程序如下所示:

[Route("~/Validation")]
[ApiController]
public class ValidationController : ControllerBase
{
    [HttpPost("{requestId}")]
    [Consumes(@"application/octet-stream", @"application/x-www-form-urlencoded")]
    [Produces(@"application/octet-stream")]
    public async Task<IActionResult> Validation_Post([FromRoute] string requestId)
    {
        byte[] rawRequestBody = Array.Empty<byte>();
        {
            long streamInitialPos = 0;
            if (Request.Body.CanSeek) // rewind for this read.
            {
                streamInitialPos = Request.Body.Position;
                Request.Body.Seek(0, SeekOrigin.Begin);
            }
            using (var ms = new MemoryStream())
            {
                await Request.Body.CopyToAsync(ms);
                rawRequestBody = ms.ToArray() ?? throw new NullReferenceException();
            }
            if (Request.Body.CanSeek) // rewind to initial position.
                Request.Body.Seek(streamInitialPos, SeekOrigin.Begin);
        }

        // TODO: Handle rawRequestBody data.

        return new FileContentResult(new byte[] { 1 }, @"application/octet-stream")
        {
            EnableRangeProcessing = true,
            LastModified = DateTime.UtcNow
        };
    }

When the third-party application is sending its HTTP post request to my API endpoint, my API application crashes with a System.ArgumentException :当第三方应用程序将其 HTTP 发布请求发送到我的 API 端点时,我的 API 应用程序崩溃并出现System.ArgumentException

Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer: Error: Connection ID "18374686481282236432", Request ID "80000011-0000-ff00-b63f-84710c7967bb": An unhandled exception was thrown by the application.

System.ArgumentException: The key '[omitted binary data]' is invalid JQuery syntax because it is missing a closing bracket. (Parameter 'key')
   at Microsoft.AspNetCore.Mvc.ModelBinding.JQueryKeyValuePairNormalizer.NormalizeJQueryToMvc(StringBuilder builder, String key)
   at Microsoft.AspNetCore.Mvc.ModelBinding.JQueryKeyValuePairNormalizer.GetValues(IEnumerable`1 originalValues, Int32 valueCount)
   at Microsoft.AspNetCore.Mvc.ModelBinding.JQueryFormValueProviderFactory.AddValueProviderAsync(ValueProviderFactoryContext context)
   at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ActionContext actionContext, IList`1 factories)
   at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.TryCreateAsync(ActionContext actionContext, IList`1 factories)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()

Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished HTTP/1.1 POST http://localhost:10891/validation/dummy application/x-www-form-urlencoded 11072 - 500 - - 164.0024ms

The logs are showing that the correct route action is being used.日志显示正在使用正确的路由操作。

How do I disable automatic model binding for only this specific action handler?如何仅为此特定操作处理程序禁用自动 model 绑定?

Reminder: I cannot do any changes to the third-party application.提醒:我无法对第三方应用程序进行任何更改。 I have to handle what I receive.我必须处理我收到的东西。 I know the request content type is wrong.我知道请求内容类型错误。 Please don't make any notes in that regard.请不要在这方面做任何笔记。


Edit: I have found the surface-level cause for this error.编辑:我找到了这个错误的表面原因。 When I remove [FromRoute] string requestId from the function signature, the error will not occur.当我从 function 签名中删除[FromRoute] string requestId时,不会发生错误。 When I reintroduce it, the error occurs again.当我重新引入它时,错误再次发生。

Does not work (causes ASP.NET Core internal exception):不起作用(导致 ASP.NET 内核内部异常):

public async Task<IActionResult> Validation_Post([FromRoute] string requestId)

Does work:是否有效:

public async Task<IActionResult> Validation_Post()

However, I need to access the route variable through Request.RouteValues["requestId"] .但是,我需要通过Request.RouteValues["requestId"]访问路由变量。

Anyway, the question still stands: How do I disable automatic model binding for only this specific action handler?无论如何,问题仍然存在:如何仅为此特定操作处理程序禁用自动 model 绑定?

I think you've actually figured out the solution already—or, at least, identified all of the key components.我认为您实际上已经找到了解决方案——或者,至少,确定了所有关键组件。 Allow me to walk through them so you can assemble them into a solution.请允许我浏览它们,以便您可以将它们组合成一个解决方案。

Disabling Model Binding禁用 Model 绑定

Model binding only occurs when you have parameters on your action—otherwise there is no model to bind to. Model 绑定仅在您的操作有参数时发生 - 否则没有 model 可绑定。 This could be an actual model, such as a POCO, or simply a value type, such as the string parameter you have here;这可能是一个实际的 model,例如 POCO,或者只是一个值类型,例如您在此处的字符串参数; the same basic process applies to both.相同的基本过程适用于两者。 That's why you don't receive the error when you remove the parameter—and also why you've effectively answered your question already.这就是您在删除参数时没有收到错误的原因,也是您已经有效回答问题的原因。

Extracting route values without model binding在没有 model 绑定的情况下提取路由值

The only purpose or benefit to having a parameter is for it to engage in model binding.拥有参数的唯一目的或好处是让它参与 model 绑定。 So if you want to disable model binding, there's no reason to maintain the parameter.因此,如果您想禁用 model 绑定,则没有理由维护该参数。 Without it, you can still use the Request property to extract request values, including form fields, query string parameters, route variables, request headers, &c.没有它,您仍然可以使用Request属性来提取请求值,包括表单字段、查询字符串参数、路由变量、请求标头等。 So, in this case, you can still call eg, Request.RouteValues["requestId"] within your action, as you noted.因此,在这种情况下,您仍然可以在您的操作中调用例如Request.RouteValues["requestId"] ,如您所述。 Making calls directly to the RouteValueDictionary won't trigger the call to the JQueryKeyValuePairNormalizer class, so you won't encounter the same exception.直接调用RouteValueDictionary不会触发对JQueryKeyValuePairNormalizer class 的调用,因此您不会遇到相同的异常。

Potential route ambiguity潜在的路线模糊

That said, depending on how your route and route parameters are defined, you may encounter issues if you're eg, relying on this parameter to disambiguate between other overloads of your action, so that's worth being aware of.也就是说,根据您的路由和路由参数的定义方式,如果您依赖此参数来消除操作的其他重载之间的歧义,则可能会遇到问题,因此值得注意。

The underlying problem根本问题

To return to the core error, however, I'd also recommend evaluating your request data on failed requests to ensure there isn't anything that might be confused with a field name containing a malformed indexer.但是,要返回核心错误,我还建议您评估失败请求的请求数据,以确保没有任何可能与包含格式错误的索引器的字段名称混淆。 From what you describe, I wouldn't expect that to be the case, unless it was somehow trying to parse the binary data as key/value pairs expected of form data, possibly due to the errant content type.根据您的描述,我不希望出现这种情况,除非它以某种方式试图将二进制数据解析为表单数据预期的键/值对,这可能是由于错误的内容类型。 Regardless, the line of code that's throwing the error occurs, specifically, when there is a field containing a [ without a corresponding ] .无论如何, 抛出错误的代码行会发生,特别是当有一个包含[没有相应]的字段时。 For example, it should occur with the following query string:例如,它应该与以下查询字符串一起出现:

?key[0=5

If something like that is a consistent fixture of your incoming requests, that's likely the culprit.如果这样的事情是您传入请求的一致固定装置,那可能是罪魁祸首。 Obviously, you can't do anything about it since you don't control the client, but it'd be useful to isolate so you can offer guidance for future implementations.显然,由于您无法控制客户端,因此您无能为力,但隔离会很有用,因此您可以为未来的实现提供指导。

Maybe this works to disable model binding?也许这可以禁用 model 绑定?

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var factories = context.ValueProviderFactories;
        factories.RemoveType<FormValueProviderFactory>();
        factories.RemoveType<FormFileValueProviderFactory>();
        factories.RemoveType<JQueryFormValueProviderFactory>();
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP.NET Core 6 Web API - 如何检查给定 ActionDescriptor 的操作是否需要身份验证? - ASP.NET Core 6 Web API - How do I check if the action with given ActionDescriptor requires authentication? ASP.NET Core Web API 模型绑定行为更改 - ASP.NET Core Web API Model binding behavior change asp.net core web api 2中的抽象类模型绑定 - Abstract class model binding in asp.net core web api 2 如何防止通过 ASP.NET Core Web API 中的模型绑定设置属性? - How to prevent a property from being set through model binding in ASP.NET Core Web API? ASP.NET Core 列表模型绑定向后兼容旧版 ASP.NET Web API - ASP.NET Core list model binding backward compatibility with legacy ASP.NET Web API 禁用自动模型验证 ASP.NET Core MVC - Disable automatic model validation ASP.NET Core MVC 如何仅为 ASP.NET Core Web Api 中的特定操作更改响应 json 属性名称? - How to change response json property names only for specific action in ASP.NET Core Web Api? 如何在 Asp.Net Core MVC 中进行自定义 model 绑定 - How to do custom model binding in Asp.Net Core MVC 在 ASP.NET Core 5.0 Web API 中实现 DelegatingHandler? - Implement DelegatingHandler in ASP.NET Core 5.0 Web API? 如何自定义 ASP.Net Core 模型绑定错误? - How do I customize ASP.Net Core model binding errors?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM