1. 程式人生 > >asp.net core 2.2升到3.1遇到的問題小記

asp.net core 2.2升到3.1遇到的問題小記

趁著武漢疫情,在家研究原來2.2的框架升級到3.1的問題,在過程中遇到不少坑,好在放假有的是時間,一個一個解決,現做個簡要記錄,供大家參考。
推薦認真看這篇文章

[https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio](https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio)

**其中,主要問題都是原來的包的版本依賴問題!花了很多時間去解決各個引用的包依賴的問題**

1.常見的其他網站都有提,比如:
移除包Microsoft.AspNetCore.App,已經不需要了

2.IHostingEnvironment變成了IWebHostEnvironment

3. 在Microsoft.AspNetCore.Http.HttpRequest.EnableRewind()這個方法,升級為Request.EnableBuffering ()

4.如果出現:
System.TypeLoadException:“Could not load type 'Microsoft.AspNetCore.Mvc.MvcJsonOptions' from assembly 'Microsoft.AspNetCore.Mvc.Formatters.Json, Version=3.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.”

最後升級swagger版本g到最新的5.0得到解決,但是升級swagger,又發現:
IDocumentFilter 更改了介面,
名稱空間也修改了:升級為using Microsoft.OpenApi.Models;
將tag=>OpenApiTag
原來的介面方法修改為:
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)

swagger示例:

```
services.AddSwaggerGen(options =>
{

options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "API介面文件",
Version = "v1",
Description = "API v1",
Contact = new OpenApiContact { Name = "wadereye", Email = "wader129-qq.com" }
});
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "......",
Name = "Authorization",
//這兩個引數均有修改
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});

options.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});

...
});
```

5.如果出現:

System.MissingMethodException:“Method not found: 'Autofac.Builder.DeferredCallback Autofac.ContainerBuilder.RegisterCallback(System.Action`1<Autofac.Core.IComponentRegistry>)'.”

是autofac的版本問題,autofac我一開始更新到5.0,到處報錯,後來檢視5.0的文件,發現更新較多,於是又將相關的autofac 5.0包降到最新的4.9.4,很多問題得以解決。

6.如果你以前用過context.Resource as AuthorizationFilterContext這樣的,在asp.net core 3.0已經不支援了。這個坑了我半天才找到解決方案。
在issue裡找到這篇文章:
[https://github.com/aspnet/AspNetCore.Docs/issues/12564](https://github.com/aspnet/AspNetCore.Docs/issues/12564)

才發現其實在官方2.2升3.1的文章有介紹,只是一開始沒看,原文這樣介紹的:
#### Custom authorization handlers[](https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#custom-authorization-handlers)

If the app uses custom [authorization handlers](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1#authorization-handlers), endpoint routing passes a different resource type to handlers than MVC. Handlers that expect the authorization handler context resource to be of type [AuthorizationFilterContext](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters.authorizationfiltercontext) (the resource type [provided by MVC filters](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-3.1#accessing-mvc-request-context-in-handlers)) will need to be updated to handle resources of type [RouteEndpoint](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.routing.routeendpoint) (the resource type given to authorization handlers by endpoint routing).

MVC still uses `AuthorizationFilterContext` resources, so if the app uses MVC authorization filters along with endpoint routing authorization, it may be necessary to handle both types of resources.

google翻譯如下:
自定義授權處理程式 如果應用使用自定義授權處理程式,則端點路由會將與MVC不同的資源型別傳遞給處理程式。期望授權處理程式上下文資源的型別為AuthorizationFilterContext(由MVC過濾器提供的資源型別)的處理程式將需要更新,以處理RouteEndpoint型別的資源(端點路由提供給授權處理程式的資源型別)。
MVC仍使用AuthorizationFilterContext資源,因此,如果應用程式使用MVC授權過濾器以及端點路由授權,則可能有必要處理兩種型別的資源。

所以獲取的方式變了,很多需要通過endpoint的方式去獲取。

具體的可以通過這篇文章來了解詳細:

[https://damienbod.com/2019/12/02/using-http-request-routes-request-body-and-query-string-parameters-for-authorization-in-asp-net-core/](https://damienbod.com/2019/12/02/using-http-request-routes-request-body-and-query-string-parameters-for-authorization-in-asp-net-core/)


示例程式碼 可以看:
[https://github.com/damienbod/AspNetCoreWindowsAuth](https://github.com/damienbod/AspNetCoreWindowsAuth)


簡要點說:作者建議這樣玩:
(1)在ASP.NET核心中使用HTTP請求路由,請求主體和查詢字串引數進行授權

使用ASP.NET Core Route引數進行授權
An AuthorizationHandler can be used to implement authorization logic in ASP.NET Core. The handler can authorize HTTP requests using a route parameter from where the policy for the requirement used in the handler is defined. The IHttpContextAccessor is used to access the route parameters. The RouteValues property in the request of the HttpContext contains these values. If you know the name of the route value, the value can be retrieved using this key. In this demo, a static text is used to validate the route parameter value. In a real world AuthorizationHandler, the value would be validated against a claim from the token, or queried from a database, or an authorization service. To validate this correctly, something must be used which cannot be manipulated. If using a claim from the access token, then the access token must be validated fully and correctly. The AuthorizationHandler implements the ValuesRouteRequirement which is used in the policy definition.

可以使用AuthorizationHandler在ASP.NET Core中實現授權邏輯。處理程式可以使用route引數授權HTTP請求,從中定義處理程式中使用的需求策略。 IHttpContextAccessor用於訪問路由引數。 HttpContext請求中的RouteValues屬性包含這些值。如果知道路由值的名稱,則可以使用此鍵檢索該值。在此演示中,使用靜態文字來驗證路由引數值。在現實世界中的AuthorizationHandler中,將根據令牌中的宣告對值進行驗證,或者根據資料庫或授權服務對其進行查詢。為了正確驗證這一點,必須使用一些無法操縱的東西。如果使用訪問令牌中的宣告,則必須完全正確地驗證訪問令牌。 AuthorizationHandler實現在策略定義中使用的ValuesRouteRequirement。
```
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace AppAuthorizationService
{
public class ValuesCheckRouteParameterHandler : AuthorizationHandler<ValuesRouteRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;

public ValuesCheckRouteParameterHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValuesRouteRequirement requirement)
{
var routeValues = _httpContextAccessor.HttpContext.Request.RouteValues;

object user;
routeValues.TryGetValue("user", out user);
if ( user.ToString() == "phil")
{
context.Succeed(requirement);
}

return Task.CompletedTask;
}
}
}
```


In the Startup class using the ConfigureServices method, the IAuthorizationHandler services are registered and also the IHttpContextAccessor using the AddHttpContextAccessor method. The policies are defined for the authorization requirements. The demo is an API project example, which uses swagger so the AddControllers extension method is used, with AddNewtonsoftJson.

在使用ConfigureServices方法的Startup類中,將註冊IAuthorizationHandler服務,並使用AddHttpContextAccessor方法來註冊IHttpContextAccessor。為授權要求定義了策略。該演示是一個API專案示例,該示例使用了大張旗鼓,因此將AddControllers擴充套件方法與AddNewtonsoftJson一起使用。
```
public void ConfigureServices(IServiceCollection services)
{
// ...

services.AddHttpContextAccessor();

services.AddSingleton<IAuthorizationHandler, ValuesCheckQueryParameterHandler>();
services.AddSingleton<IAuthorizationHandler, ValuesCheckRequestBodyHandler>();
services.AddSingleton<IAuthorizationHandler, ValuesCheckRouteParameterHandler>();

services.AddAuthorization(options =>
{
options.AddPolicy("protectedScope", policy =>
{
policy.RequireClaim("scope", "native_api");
});
options.AddPolicy("ValuesRoutePolicy", valuesRoutePolicy =>
{
valuesRoutePolicy.Requirements.Add(new ValuesRouteRequirement());
});
options.AddPolicy("ValuesQueryPolicy", valuesQueryPolicy =>
{
valuesQueryPolicy.Requirements.Add(new ValuesCheckQueryParamRequirement());
});
options.AddPolicy("ValuesRequestBodyCheckPolicy", valuesRequestBodyCheckPolicy =>
{
valuesRequestBodyCheckPolicy.Requirements.Add(new ValuesRequestBodyRequirement());
});
});


services.AddControllers()
.AddNewtonsoftJson();
}

```

The policy is then used in the controller in the authorize attribute. In this demo, if the user has the value ‘phil’, the data will be returned, otherwise a 403 is returned, or 401 if no bearer access token is sent in the header of the HTTP request.

然後在控制器的authorize屬性中使用該策略。在此演示中,如果使用者的值為“ phil”,則將返回資料,否則返回403,或者如果在HTTP請求的標頭中未傳送任何承載訪問令牌,則返回401。

 

```
[Authorize("ValuesRoutePolicy")]
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet]
[Route("{user}", Name = nameof(GetWithRouteParam))]
public IActionResult GetWithRouteParam([FromRoute]string user)
{
return Ok($"get this data [{user}] using the route");
}
```

A HttpClient implementation can then make a HTTP request with the route set and the access token added to the headers.

然後,HttpClient實現可以發出帶有路由集並將訪問令牌新增到標頭的HTTP請求

'''
private static async Task CallApiwithRouteValue(string currentAccessToken, string user)
{
_apiClient.SetBearerToken(currentAccessToken);
var response = await _apiClient.GetAsync($"/api/values/{user}");

if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"\n{result}");
}
else
{
Console.WriteLine($"Error: {response.ReasonPhrase}");
}
}
'''

後面還有更詳細的基於querystring的方法,我就不寫了,看一下就明白 了。
另外推薦這幾篇文章也看下:

[https://damienbod.com/2018/04/19/asp-net-core-authorization-for-windows-local-accounts/](https://damienbod.com/2018/04/19/asp-net-core-authorization-for-windows-local-accounts/)

[https://damienbod.com/2018/04/15/supporting-both-local-and-windows-authentication-in-asp-net-core-mvc-using-identityserver4/](https://damienbod.com/2018/04/15/supporting-both-local-and-windows-authentication-in-asp-net-core-mvc-using-identityserver4/)

&n