ASP.NET Core 3.1 Web API(版本控制)和 Swagger UI 在发布到 Azure 后由于 MvcJsonOptions 而失败

Posted

技术标签:

【中文标题】ASP.NET Core 3.1 Web API(版本控制)和 Swagger UI 在发布到 Azure 后由于 MvcJsonOptions 而失败【英文标题】:ASP.NET Core 3.1 web API (versioning) and Swagger UI fails due to MvcJsonOptions once published to Azure 【发布时间】:2019-11-25 17:28:01 【问题描述】:

我最近将 ASP.NET Core 2.2 Web API 项目迁移到 ASP.NET Core 3.1 Preview 3。我使用基于 URL 的 API 版本控制和 Swagger UI 3.0 (Swashbuckle.AspNetCore 5.0.0-rc4)。 Web API 在 Azure 上发布后,我会立即收到以下错误(我不确定 Swagger UI 是否与它有关,但是...)

System.InvalidOperationException:无法比较数组中的两个元素。 ---> System.TypeLoadException:无法从程序集“Microsoft.AspNetCore.Mvc.Formatters.Json”加载类型“Microsoft.AspNetCore.Mvc.MvcJsonOptions”,

提到 Git Hub 中的类似问题,我的理解是该问题已通过预览版 3 得到修复,并且确实在安装 SDK 3.1.100-preview3 后,我在本地开发机器上没有看到此问题。

本地 DEV 机器(一切正常...)

发布到 Azure Web 服务

由于尚不支持该框架,因此我将其发布为自包含 Web api 应用程序。发布成功,但运行时出现以下问题...如何解决此问题?

System.InvalidOperationException: Failed to compare two elements in the array.
 ---> System.TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.MvcJsonOptions' from assembly 'Microsoft.AspNetCore.Mvc.Formatters.Json, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
   at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)
   at System.Reflection.RuntimeConstructorInfo.get_Signature()
   at System.Reflection.RuntimeConstructorInfo.GetParametersNoCopy()
   at System.Reflection.RuntimeConstructorInfo.GetParameters()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c.<CreateConstructorCallSite>b__16_1(ConstructorInfo a, ConstructorInfo b)
   at System.Collections.Generic.ArraySortHelper`1.SwapIfGreater(T[] keys, Comparison`1 comparer, Int32 a, Int32 b)
   at System.Collections.Generic.ArraySortHelper`1.IntroSort(T[] keys, Int32 lo, Int32 hi, Int32 depthLimit, Comparison`1 comparer)
   at System.Collections.Generic.ArraySortHelper`1.IntrospectiveSort(T[] keys, Int32 left, Int32 length, Comparison`1 comparer)
   at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, Comparison`1 comparer)
   --- End of inner exception stack trace ---
   at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, Comparison`1 comparer)
   at System.Array.Sort[T](T[] array, Comparison`1 comparison)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.GetService(IServiceProvider sp, Type type, Type middleware)
   at lambda_method(Closure , Object , HttpContext , IServiceProvider )
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_1.<UseMiddleware>b__2(HttpContext context)

【问题讨论】:

您是否尝试过使用“在目标位置删除其他文件”设置进行部署?当我有一些旧的 DLL 时,我有时会遇到奇怪的问题。 @juunas:是的,我的发布配置文件始终打开“在目标位置删除其他文件”。但除此之外,还有没有其他方法可以彻底删除之前在Azure上发布的web app 2.2,重新开始用3.1发布? 我刚刚将我的 api 更新到 3.1,并且我使用了 v5.0.0-rc4,并且我能够删除同样的错误 你可以通过 Kudu @Ameya 删除服务器上的文件 【参考方案1】:

对于 ASP.NET Core 3.0(和 3.1),请确保您的目标至少是 5.0 版 Swashbuckle.AspNetCore(不是 RC 版)。这应该可以解决该特定问题。

您遇到此问题的原因是 Swagger 之前依赖于 MvcJsonOptions,它是 ASP.NET Core 框架的一部分。 Swagger 加载并尝试找到该类,但它不存在。但是现在由于 ASP.NET Core 框架使用 System.Text.Json 而不是 Newtonsoft.Json 导致编译错误。

关于同一主题,我建议您read this here,它解释了如果您仍想继续使用 Newtonsoft.Json,如何选择加入。

一般来说,Swagger 的实现有一些重大变化。这是关于what is breaking in 4.0 和what is breaking in 5.0 的好文档。

【讨论】:

为升级 NSwag 或 NSwag.MsBuild 以及 Swashbuckle 后的问题添加评论。如果您收到有关无法找到 Microsoft.AspNetCore.Mvc.NewtonsoftJson 版本 5.0.0.0 的错误,即使在将其添加到两个项目之后,您也需要点击此评论中的链接,了解在 NSwag 生成的项目中启用 Newtonsoft 支持。 你的评论@TJL没有链接? 抱歉,这是您答案中的第一个链接 - this one。我花了很长的谷歌路才得到这个答案,这解决了我的 nswag 构建的问题。

以上是关于ASP.NET Core 3.1 Web API(版本控制)和 Swagger UI 在发布到 Azure 后由于 MvcJsonOptions 而失败的主要内容,如果未能解决你的问题,请参考以下文章

Wcf 服务在 .NET Core 3.1 控制台应用程序中工作,但在 ASP.NET Core 3.1 Web API 中无法工作

ASP.NET Core 3.1 / 5 WeatherForecast 示例 Web API 项目引发错误 404

在测试 ASP.Net Core 3.1 Web Api 期间跳过 JWT Auth

我需要在启动时在 ASP .Net Core 3.1 Web API 中执行异步方法

Blazor ASP.Net Core 3.1 Web API 在发布时返回 404 错误

Angular 8 使用 ASP NET Core 3.1 Web Api 时出现 CORS 策略问题