c# - (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
谢谢大家观看!
解决方案
该问题是由以下问题引起的: - 第三方提供商会在您的令牌前自动添加“Bearer”。
这个片段:
internal JsonServiceClient Api => new JsonServiceClient(ApiUrl)
{
BearerToken = $"Bearer {GenerateAccessToken()}"
};
改为:
internal JsonServiceClient Api => new JsonServiceClient(ApiUrl)
{
BearerToken = GenerateAccessToken()
};
解决问题。我最初生成的是“Bearer Bearer (token)”,这就是为什么我会得到一个 422 UNPROCESSABLE ENTITY(发送错误的数据)。
谢谢大家的帮助!
推荐阅读
- python - 如何通过 ForeignKey 检查 django-guardian get_objects_for_user 权限
- reactjs - ReactJs 中是否有可用的捆绑库,我们可以将其包含在任何网站中并利用 ReactJs 组件
- php - Symfony/Doctrine 试图在没有密码的情况下保持登录用户
- java - 将 MongoDB 查询结果保存到 Java 中的不同变量中
- c++ - 为什么使用指令与封闭在命名空间中不能识别朋友功能?
- google-apps-script - 尝试获取有效的电子邮件消息 ID
- android - 如何访问由 broadcastReceiver 返回的 parsed_variables
- java - 此类未定义 IdClass
- node.js - 如何用玩笑在模拟函数中断言类的属性
- laravel - 类 '...\Input' 未找到