[英]ASP.NET Core 6 Web API - How do I check if the action with given ActionDescriptor requires authentication?
[英]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,例如 POCO,或者只是一個值類型,例如您在此處的字符串參數; 相同的基本過程適用於兩者。 這就是您在刪除參數時沒有收到錯誤的原因,也是您已經有效回答問題的原因。
擁有參數的唯一目的或好處是讓它參與 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.