簡體   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?

我有一個第三方專有應用程序,為此我需要在我的 ASP.NET 核心 5.0 Z2567A5EC9705EB7AC2C984033E06189D3A8DE6747CEDFA84 應用程序中編寫一個 API 端點。

第三方應用程序發出一個 HTTP 發布請求,請求正文中只有二進制數據,以及內容類型application/x-www-form-urlencoded或有時是application/octet-stream (有點隨機,但數據是一樣的)。

我的動作處理程序如下所示:

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

當第三方應用程序將其 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

日志顯示正在使用正確的路由操作。

如何僅為此特定操作處理程序禁用自動 model 綁定?

提醒:我無法對第三方應用程序進行任何更改。 我必須處理我收到的東西。 我知道請求內容類型錯誤。 請不要在這方面做任何筆記。


編輯:我找到了這個錯誤的表面原因。 當我從 function 簽名中刪除[FromRoute] string requestId時,不會發生錯誤。 當我重新引入它時,錯誤再次發生。

不起作用(導致 ASP.NET 內核內部異常):

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

是否有效:

public async Task<IActionResult> Validation_Post()

但是,我需要通過Request.RouteValues["requestId"]訪問路由變量。

無論如何,問題仍然存在:如何僅為此特定操作處理程序禁用自動 model 綁定?

我認為您實際上已經找到了解決方案——或者,至少,確定了所有關鍵組件。 請允許我瀏覽它們,以便您可以將它們組合成一個解決方案。

禁用 Model 綁定

Model 綁定僅在您的操作有參數時發生 - 否則沒有 model 可綁定。 這可能是一個實際的 model,例如 POCO,或者只是一個值類型,例如您在此處的字符串參數; 相同的基本過程適用於兩者。 這就是您在刪除參數時沒有收到錯誤的原因,也是您已經有效回答問題的原因。

在沒有 model 綁定的情況下提取路由值

擁有參數的唯一目的或好處是讓它參與 model 綁定。 因此,如果您想禁用 model 綁定,則沒有理由維護該參數。 沒有它,您仍然可以使用Request屬性來提取請求值,包括表單字段、查詢字符串參數、路由變量、請求標頭等。 因此,在這種情況下,您仍然可以在您的操作中調用例如Request.RouteValues["requestId"] ,如您所述。 直接調用RouteValueDictionary不會觸發對JQueryKeyValuePairNormalizer class 的調用,因此您不會遇到相同的異常。

潛在的路線模糊

也就是說,根據您的路由和路由參數的定義方式,如果您依賴此參數來消除操作的其他重載之間的歧義,則可能會遇到問題,因此值得注意。

根本問題

但是,要返回核心錯誤,我還建議您評估失敗請求的請求數據,以確保沒有任何可能與包含格式錯誤的索引器的字段名稱混淆。 根據您的描述,我不希望出現這種情況,除非它以某種方式試圖將二進制數據解析為表單數據預期的鍵/值對,這可能是由於錯誤的內容類型。 無論如何, 拋出錯誤的代碼行會發生,特別是當有一個包含[沒有相應]的字段時。 例如,它應該與以下查詢字符串一起出現:

?key[0=5

如果這樣的事情是您傳入請求的一致固定裝置,那可能是罪魁禍首。 顯然,由於您無法控制客戶端,因此您無能為力,但隔離會很有用,因此您可以為未來的實現提供指導。

也許這可以禁用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM