首页 > 解决方案 > (422) 带有 ServiceStack 路由的不可处理实体

问题描述

我计划使用 ServceStack 的 C# 路由功能连接到基于 JSON 的 API。似乎在尝试这样做时我得到了一个“422 Unprocessable Entity”,而实际上我应该得到一个 JSON 响应。不过,此错误消息很有趣,因为它会重复多次(精确 8 次),并显示消息无法解析错误响应状态错误响应系统.IndexOutOfRangeException:索引超出了数组的范围。下面的完整堆栈跟踪。

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

这是我当前的设置:

应用主机.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

谢谢大家观看!

标签: c#servicestack

解决方案


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

这个片段:

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

改为:

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

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

谢谢大家的帮助!


推荐阅读