簡體   English   中英

在ASP.NET Web API中為單個請求更改JsonFormatter

[英]Change JsonFormatter for a single request in ASP.NET Web API

我有一個如下定義的動作過濾器,在我的Web API項目中全局注冊:

public class ResultCasingFilter : IActionFilter
{
    private static JsonMediaTypeFormatter _pascalCasingFormatter;
    private static JsonMediaTypeFormatter _camelCasingFormatter;

    // Constructor that initializes formatters left out for brevity

    public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
    {
        actionContext.RequestContext.Configuration.Formatters.Clear();
        actionContext.RequestContext.Configuration.Formatters.Add(
            ResponseShouldBePascalCased(actionContext)
            ? _pascalCasingFormatter
            : _camelCasingFormatter);
        return continuation();
    }

    private static bool ResponseShouldBePascalCased(HttpActionContext actionContext)
    {
        return actionContext.ActionDescriptor
            .GetCustomAttributes<PascalCasedResultAttribute>().Any();
    }

    public bool AllowMultiple { get { return false; } }
}

這很有效,但我似乎在請求之間受到干擾; 如果我一次向一個具有PascalCasedResultAttribute但沒有一個的動作方法發出一個請求,一切都按預期工作 - 但如果我發出兩個非常接近彼此,兩者有時最終都會使用相同的大小寫。

我將此行為解釋為對actionContext.RequestContext.Configuration.Formatters的更改確實更改了整個應用程序的配置,而不僅僅是當前請求,有時請求重疊。 基本上,我的解決方案基於以下一系列事件:

  1. 請求1選擇其序列化器
  2. 使用最后選擇的序列化器序列化請求1
  3. 請求2選擇其序列化器
  4. 使用最后選擇的序列化器序列化請求2

請注意,如果第二步和第三步更改順序,則會更改行為。 我想要的是相當的

  1. 請求1選擇其序列化器
  2. 使用串行器1序列化請求1
  3. 請求2選擇其序列化器
  4. 使用串行器2序列化請求2

我(或框架)可以在不改變行為的情況下切換2和3的順序。

我怎樣才能做到最好?

問題是你正在改變一個全局變量,它在排序時顯然不一致。

您可以做的是在操作中手動序列化,並根據需要返回字符串。

然后,您可以提供一個標志來選擇在您的請求中使用哪個序列化程序,或者使用cookie來記住客戶的選擇。

我最終做了以下事情:

public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    // Let the action method execute, resulting in a serialized response
    var responseMessage = await continuation();

    if (responseMessage.Content is ObjectContent)
    {
        // Get the message content in its unserialized form, and choose formatter
        var content = responseMessage.Content as ObjectContent;
        var formatter = ResponseShouldBePascalCased(actionContext)
                        ? _pascalCasingFormatter
                        : _camelCasingFormatter;

        // Re-serialize content, with the correctly chosen formatter
        responseMessage.Content = new ObjectContent(content.ObjectType, content.Value, 
                                                    formatter);
    }
    // Return the (possibly) re-serialized message
    return responseMessage;
}

在我得到這個解決方案之前,我跳過的主要障礙是意識到我可以await continuation()讓action方法執行,然后使用響應。

這種方法仍有缺點,如果客戶端要求例如XML,它仍將獲得JSON,因為我手動選擇序列化程序而不查看Accepts標頭。 在我的用例中,我完全沒問題,因為我們只是使用JSON,但是如果它對你很重要,那么你需要更復雜的東西代替我選擇格式化器的三元語句。 (如果有一種簡單的方法只針對已經序列化為給定格式的內容,我很樂意了解它!)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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