【问题标题】:(422) Unprocessable Entity with ServiceStack Routing(422) 带有 ServiceStack 路由的不可处理实体
【发布时间】:2020-05-31 01:15:11
【问题描述】:

我计划使用 ServceStack 的 C# 路由功能连接到基于 JSON 的 API。似乎在尝试这样做时我得到了一个“422 Unprocessable Entity”,而实际上我应该得到一个 JSON 响应。不过,这个错误消息很有趣,因为它会重复多次(精确 8 次)并显示消息 Could not parse Error ResponseStatus ErrorResponse System.IndexOutOfRangeException: Index was outside the bounds of the array. 完整堆栈跟踪如下。

我尝试了许多配置,其中一种“有效”但消除了此路线设置方式的关键需求之一。在这个项目中,我使用ICacheClient来保存一个会话密钥5分钟,所以我并不总是需要在每次需要的时候调用API。由于 ServiceStack 使用注入来设置我的 ICacheClient 实例,因此它必须是公共的。但是,如果它是公开的,我会收到 422 错误,但如果它不是公开的,我会收到 NullPointer,因为它的引用无法由 ServiceStack 设置。

这是我目前的设置:

AppHost.cs

public class AppHost : AppHostBase
{
    public override void Configure(Container container)
    {
        Log.Info("Starting up...");
        var stopwatch = Stopwatch.StartNew();

        // Add Plugins
        // Add Connection Strings
        container.Register<ICacheClient>(new MemoryCacheClient());
        container.RegisterAs<ApiClientWrapper, IApiClient>();

        stopwatch.Stop();
        Log.Info("Started in {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
    }
}

ApiClientWrapper.cs

public class ApiClientWrapper : IApiClient
{
    // These are set in a Web.config, and work fine.
    private string Username => HostContext.AppSettings.Get<string>("Username");
    private string Password => HostContext.AppSettings.Get<string>("Password");
    private string ApiUrl => HostContext.AppSettings.Get<string>("ApiUrl");

    // This must be public, NULL if private or internal
    public ICacheClient Cache { get; set; }

    private string GenerateAccessToken()
    {
        const string key = "ApiSessionKey";

        var sessionKey = Cache.Get<string>(key);

        if (sessionKey == null)
        {
            using(var client = new JsonServiceClient(ApiUrl))
            {
                var request = new LoginRequest
                {
                    Username = Username,
                    Password = Password
                };
                // Token provided by API
                sessionKey = client.Post(request).AccessToken;
            }
            Cache.Add(key, sessionKey, 5.Minutes());
        }

        return sessionKey;
    }

    internal JsonServiceClient Api => new JsonServiceClient(ApiUrl)
    {
        BearerToken = $"Bearer {GenerateAccessToken()}"
    };

    public List<Price> FindPrices(FindPrices request)
    {   
        /*
         * LatestPricesResponse DTO matches the expected JSON response.
         * The class has the [DataContract] tag, and each property has the [DataMember] tag.
         */
        var response = Api.Get(new LatestPricesRequest());
        response = request.MaxRows.HasValue ? response.Take(request.MaxRows.Value).ToList() : response;
        return response.ToDto();
    }

    [Route("/login", Verb.Post)]
    [DataContract]
    public class LoginRequest : IReturn<LoginResponse>, IPost
    {
        [DataMember(Name = "username")]
        public string Username { get; set; }
        [DataMember(Name = "password")]
        public string Password { get; set; }
    }

    [Route("/latest_prices", Verb.Get)]
    [DataContract]
    public class LatestPricesRequest : IReturn<List<LatestPricesResponse>>, IGet
    {
        [DataMember(Name = "show_details")]
        public string ShowDetails => "no";
    }
}

完整的堆栈跟踪:

2020-05-29 15:52:02.5996 ERROR DEVELOPER-PC ServiceStack.ServiceClientBase.ToWebServiceException  System.Net.WebException: The remote server returned an error: (422) UNPROCESSABLE ENTITY.
   at System.Net.HttpWebRequest.GetResponse()
   at ServiceStack.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request) in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\ServiceClientBase.cs:line 1317  System.Net.WebException: The remote server returned an error: (422) UNPROCESSABLE ENTITY.
   at System.Net.HttpWebRequest.GetResponse()
   at ServiceStack.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request) in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\ServiceClientBase.cs:line 1317
2020-05-29 15:52:02.5996 DEBUG DEVELOPER-PC ServiceStack.ServiceClientBase.ToWebServiceException  Status Code : 422  
2020-05-29 15:52:02.5996 DEBUG DEVELOPER-PC ServiceStack.ServiceClientBase.ToWebServiceException  Status Description : UNPROCESSABLE ENTITY  
2020-05-29 15:52:02.6266 ERROR DEVELOPER-PC Api.AppHost.SetHostConfig  An exception was thrown on "GET" for path "/prices"  422 UNPROCESSABLE ENTITY
Code: UNPROCESSABLE ENTITY, Message: 

2020-05-29 15:52:02.6486 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6486 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6486 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6686 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6686 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6686 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6686 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70
2020-05-29 15:52:02.6736 DEBUG DEVELOPER-PC ServiceStack.WebServiceException.get_ResponseStatus  Could not parse Error ResponseStatus ErrorResponse  System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at ServiceStack.Text.Jsv.JsvTypeSerializer.EatMapKey(ReadOnlySpan`1 value, Int32& i) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvTypeSerializer.cs:line 300
   at ServiceStack.Text.Common.DeserializeTypeRefJsv.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeTypeRefJsv.cs:line 40
   at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJsv(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Common\DeserializeType.cs:line 60
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(ReadOnlySpan`1 value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 102
   at ServiceStack.Text.Jsv.JsvReader`1.Parse(String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\Jsv\JsvReader.Generic.cs:line 81
   at ServiceStack.Text.TypeSerializer.DeserializeFromString[T](String value) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\TypeSerializer.cs:line 67
   at ServiceStack.WebServiceException.get_ResponseStatus() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack.Client\WebServiceException.cs:line 70

感谢大家观看!

【问题讨论】:

  • 您能否升级到最新的v5.8.1 on MyGet 并检查问题是否仍然存在,如果确实存在,您是否可以使用 HTTP 数据包嗅探器更新您的问题以包含导致此异常的完整原始 HTTP 响应Fiddler
  • @myth 我的 ServiceStack 版本在 NuGet 上进行管理,提供的最新版本(包括预发行版)是 v5.8.0。关于原始 HTTP 响应,here it is.
  • 要确定这是否仍然是一个问题,您需要upgrade to v5.8.1 on MyGet 解决类似问题的地方。
  • 这似乎只显示了 GET HTTP 请求,而不是原始的 HTTP 响应。
  • 你是对的,我很抱歉 - 我确实发送了错误的部分。 This 是实际的 HTTP JSON 响应。不幸的是,我的 ServiceStack 密钥(由我的公司提供)与 ServiceStack 的 5.8.1 版本不兼容 - 因此我目前无法选择更新。

标签: c# servicestack


【解决方案1】:

问题是由以下问题引起的: - 第三方提供商会在您的令牌前自动添加“Bearer”。

这个sn-p:

    internal JsonServiceClient Api => new JsonServiceClient(ApiUrl)
    {
        BearerToken = $"Bearer {GenerateAccessToken()}"
    };

改为:

    internal JsonServiceClient Api => new JsonServiceClient(ApiUrl)
    {
        BearerToken = GenerateAccessToken()
    };

解决问题。 我最初生成的是“Bearer Bearer (token)”,这就是为什么我会得到一个 422 UNPROCESSABLE ENTITY(发送错误的数据)。

谢谢大家的帮助!

【讨论】:

    猜你喜欢
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多