最全的 netcore 3.0 升级实战方案
1、哈嘍大家中秋節(jié)(后)好呀!感覺(jué)已經(jīng)好久沒(méi)有寫文章了,但是也沒(méi)有偷懶喲,我的視頻教程《系列一、NetCore 視頻教程(Blog.Core)》也已經(jīng)錄制八期了,還在每周末同步更新中,歡迎大家多多指教。
2、除此之外呢,我也在平時(shí)的時(shí)間幫朋友開(kāi)發(fā)了一個(gè)小項(xiàng)目,就是使用 .net mvc+vue+ele+mongo 框架寫的項(xiàng)目,之前一直想著用mvc結(jié)合著vue寫,這次也終于上手了,不過(guò)是一個(gè)小的demo,因?yàn)槭桥笥训捻?xiàng)目,所以就不開(kāi)源了。
言歸正傳,?? 從2018年8月就開(kāi)始聽(tīng)說(shuō) netcore 要準(zhǔn)備3.0了,? 到了近期 v3.0.0-preview9 的發(fā)布,官方也最終定稿不會(huì)再更新了,??? 接著馬上 在下周 9月23日至25日 .NET Conf 社區(qū)大會(huì)上,會(huì)正式推出 netcore3.0 版本,?(最后 ? 微軟會(huì)將 .netcore 和 .net 進(jìn)一步融合,推出完美跨平臺(tái) net 5.0 版本,這里暫時(shí)先不說(shuō)),單單從這一年里 netcore 3.0 的快速發(fā)展、迭代以及接受用戶的反饋進(jìn)一步修改中,我們就能感覺(jué)的到,微軟是如何的有希望并且有信心在未來(lái)的發(fā)展中,將微軟系產(chǎn)品進(jìn)一步融入到廣大開(kāi)發(fā)者的心中,我們也要有信心微軟能做到這一點(diǎn)。
在netcore 3.0 馬上要到來(lái)之際,我也要嘗嘗鮮,我肯定不是第一個(gè)吃螃蟹的人,博客園這兩個(gè)月也是一直轟轟烈烈的進(jìn)行 3.0 的更新和迭代,不過(guò)過(guò)程是怎樣的吧,至少結(jié)果目前還是可以的,也可以作為一個(gè)成功案例給大家提供一些建議和思路。
感覺(jué)嘗試就是成功的一半,所以我在中秋節(jié)這兩天,也把 Blog.Core? 項(xiàng)目給提升到了 3.0 版本,大家現(xiàn)在看的我的在線地址(http://apk.neters.club/index.html) 就是netcore 3.0 的,總體看起來(lái),可能沒(méi)有什么差別,而且運(yùn)行中也沒(méi)有發(fā)現(xiàn)任何問(wèn)題,(具體的請(qǐng)看我的后臺(tái)項(xiàng)目:http://vueadmin.neters.club/),不過(guò)這次官方更新的東西還是稍微挺多的,所以我這里就統(tǒng)一做下記錄,方便大家吧,希望每一個(gè)在使用 netcore 的小伙伴都能從這里得到一些幫助,雖然官網(wǎng)也有一些記錄,但是我看了看,英文的可能有些小伙伴不好理解,盡管有中文翻譯版,可是看著不是很通順,而且也不是很全,大家可以看看:地址。
當(dāng)然不僅僅包括下邊的這幾點(diǎn),我還在慢慢更新,如果你使用到了我 blog.core 項(xiàng)目中沒(méi)有用到的技術(shù),并且自己在更新 3.0 的時(shí)候出現(xiàn)了問(wèn)題,可以和我聊聊,我在下邊補(bǔ)充下,爭(zhēng)取達(dá)到一個(gè)最全的解決方案合集。
?
好啦,廢話到此結(jié)束,馬上開(kāi)始今天的遷移報(bào)告內(nèi)容!???
netcore 1.0 到 2.0 主要的是網(wǎng)絡(luò)和云服務(wù)的升級(jí),那 net core 從2.0 到 3.0 更新的是哪些呢?
這里我就簡(jiǎn)單的列舉了下這一年來(lái)netcore 3.0 更新的比較熱門的特性,當(dāng)然還有其他的,因?yàn)楸酒恼轮饕侵v解升級(jí)實(shí)戰(zhàn),所以對(duì)以下特性就不過(guò)多的鋪開(kāi)講解。
性能、性能、性能,重要的地方說(shuō)三遍
在機(jī)器學(xué)習(xí),AI等很好的支持
對(duì)Winform、WPF的支持
gRPC的添加
支持 API 授權(quán)在單頁(yè)面應(yīng)用 (Spa) 中提供身份驗(yàn)證、實(shí)現(xiàn) Open ID Connect 的IdentityServer結(jié)合。
Worker Service 模板,為開(kāi)發(fā)做服務(wù)或監(jiān)控微服務(wù)相關(guān)Bus
Microsoft.Data.SqlClient:獨(dú)立存在于.NET Framework和.NET Core中
ReadyToRun
HttpClient支持HTTP/2
Json.NET 不在內(nèi)置在框架內(nèi),使用System.Text.Json
HostBuilder 替換掉WebHostBuilder
Blazor 是一個(gè)用于使用 .NET 生成交互式客戶端 Web UI 的框架,用c#開(kāi)發(fā)前端
.NET?Framework不支持.NET?Standard 2.1
IL linker
發(fā)布成單個(gè)程序 dotnet publish -r win10-x64 /p:PublishSingleFile=true
那下面我就針對(duì)我的 Blog.Core 項(xiàng)目,坐下遷移的說(shuō)明,一共八個(gè)方面,不是很多,大家可以一一對(duì)比下。
操作前必備:備份文件,這個(gè)很重要,我們要玩兒新花樣,肯定要做好備份文件,可別因?yàn)樯?jí)失敗,而不好回退。
當(dāng)然我的操作是直接操作的 Blog.Core 項(xiàng)目,因?yàn)轫?xiàng)目在 git 上,如果不成功,就直接回退,這種資源管理工具還是很有必要的。
1、安裝SDK
?首先可以查看自己的本地 SDK 是什么版本的,比如我的目前只有 2.1和 2.2 :
所以,如果我們要升級(jí) 3.0 的話,就肯定要安裝指定的 SDK 了,下載地址:https://dotnet.microsoft.com/download/visual-studio-sdks
選擇指定版本的 SDK ,然后進(jìn)行安裝,最后我們就可以看到我們的本地已經(jīng)安裝好了:
?這里我們可以看到我們的 3.0 的 SDK 已經(jīng)安裝好了,最后再做個(gè)驗(yàn)證,就是在我們的 VS 2019 中,查看是否有 3.0 的框架:
竟然沒(méi)有??!!別慌,這里有兩個(gè)方法:
1、工具 -> 選項(xiàng) -> 項(xiàng)目與解決方案 -> 右側(cè),勾選預(yù)覽版(這個(gè)方案是2019 最舊版本的,已取消請(qǐng)忽略)。
2、在工具 -> 選項(xiàng) -> 環(huán)境里(正規(guī)是使用這個(gè)):
然后我們把 vs 重新啟動(dòng)一下,發(fā)現(xiàn)已經(jīng)有了:
安裝好了 SDK,我們就已經(jīng)是成功了一半了,下邊我們就正式開(kāi)始升級(jí)打怪之路。
但是這里還有一個(gè)問(wèn)題,就是打開(kāi)的項(xiàng)目屬性里,雖然有了 3.0 的框架,但是新建的項(xiàng)目,依然沒(méi)有 3.0 的部分,那這個(gè)是為什么呢?
這里網(wǎng)上的方案是:不要用preview8或者9,這兩個(gè)版本出不來(lái)core3.0的選項(xiàng),preview7沒(méi)有問(wèn)題。如果非要用最新版,可以用dotnet new創(chuàng)建項(xiàng)目,或者等下星期的 net core 3.0正式版出來(lái),這樣就不用來(lái)來(lái)回回勾選了。
Tips:感謝 @ 給出建議
https://dotnet.microsoft.com/download/dotnet-core/3.0
這個(gè)頁(yè)面的Tips已經(jīng)說(shuō)了,有可能下周就是Core3.0和VS 2019的16.3一起發(fā)布,猜測(cè)應(yīng)該就是更新就行了,目前我的VS版本是16.2.5
2、更新框架以及所有依賴
剛剛我們已經(jīng)成功的安裝好了 3.0 的 SDK ,那接下來(lái)就是正式開(kāi)始升級(jí)項(xiàng)目,首先呢,就是需要更新我們的目標(biāo)框架,這里有兩種方法:
第一種是直接修改我們的項(xiàng)目文件 .csproj ,修改節(jié)點(diǎn) <TargetFramework>netcoreapp3.0</TargetFramework>,并移除關(guān)于 Aspnetcore 2.2 相關(guān)的包;
第二種就是直接右鍵項(xiàng)目,屬性,應(yīng)用程序,修改目標(biāo)框架到 netcore 3.0 就行,就是上文截圖中顯示的那個(gè),我個(gè)人采用的是這種方法。
記得要把項(xiàng)目從底層開(kāi)始更新,比如從 Model 層和 Common 層開(kāi)始更新,然后最后更新 API 層,就是從下向上,(這里有個(gè)小問(wèn)題,就是出現(xiàn)修改了,CTRL S 保存后,又重新回到2.2了,可以重啟下項(xiàng)目,重啟下vs就行了)。
代碼修改對(duì)比圖:
(netcore 3.0 修改sdk框架)
?接下來(lái),就是把項(xiàng)目中用到的所有nuget包都更新到最新的版本,因?yàn)橛行┦菫榱擞?netcore 3.0,做了相應(yīng)的修改,比如下午說(shuō)到的 swagger ,一定要更新到 5.0+版本。
?到了這里,我們的項(xiàng)目已經(jīng)把框架和依賴升級(jí)完成了,是不是很簡(jiǎn)單,重新編譯,運(yùn)行,這里肯定會(huì)有錯(cuò)誤,別著急,接下來(lái)我們就進(jìn)一步修改 Code 中出現(xiàn)的bug。?
3、宿主機(jī)變化(Program.cs)
netcore 3.0,對(duì) host 做了調(diào)整,底層沒(méi)有發(fā)生太多的變化,這里不細(xì)說(shuō),主要說(shuō)要修改的地方,更新的內(nèi)容,我會(huì)在視頻里,詳細(xì)給大家講解。
在 Program.cs 文件中,修改HostBuilder生成方法,注意在main 方法里引用也要做相應(yīng)的修改。
代碼修改對(duì)比圖:
?(Program.cs 修改 host 宿主機(jī))
CODE:
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseUrls("http://localhost:8081")
//這里是配置log的
.ConfigureLogging((hostingContext, builder) =>
{
builder.ClearProviders();
builder.SetMinimumLevel(LogLevel.Trace);
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
builder.AddConsole();
builder.AddDebug();
});
});
4、Host 環(huán)境變量(Startup.cs)
從上邊我們也可以看得出來(lái),官方更新了 host ,所以自然而然的,也更新了部分的命名空間,這樣就出現(xiàn)了一個(gè)問(wèn)題:
當(dāng)?Microsoft.Extensions.Hosting 在 2.1 中被引入時(shí),某些類型?IHostingEnvironment?和?IApplicationLifetime?是從 Microsoft.AspNetCore.Hosting 復(fù)制的。某些 3.0 更改會(huì)導(dǎo)致應(yīng)用同時(shí)包含 Microsoft.Extensions.Hosting 和 Microsoft.AspNetCore.Hosting 兩個(gè)命名空間。當(dāng)同時(shí)引用兩個(gè)命名空間時(shí),對(duì)這些重復(fù)類型的任何使用都會(huì)導(dǎo)致"不明確的引用"編譯器錯(cuò)誤。
所以官方就對(duì)某些命名空間和類做了修改:
Obsolete types (warning):
Microsoft.Extensions.Hosting.IHostingEnvironmentMicrosoft.AspNetCore.Hosting.IHostingEnvironment
Microsoft.Extensions.Hosting.IApplicationLifetime
Microsoft.AspNetCore.Hosting.IApplicationLifetime
Microsoft.Extensions.Hosting.EnvironmentName
Microsoft.AspNetCore.Hosting.EnvironmentName
New types:
Microsoft.Extensions.Hosting.IHostEnvironmentMicrosoft.AspNetCore.Hosting.IWebHostEnvironment : IHostEnvironment
Microsoft.Extensions.Hosting.IHostApplicationLifetime
Microsoft.Extensions.Hosting.Environments
這個(gè)不用記憶,到時(shí)候使用的時(shí)候,會(huì)有提示的,那我們的項(xiàng)目中,有哪個(gè)地方需要修改呢,就是配置中間件的時(shí)候有一個(gè)環(huán)境變量配置需要修改下:
1、將 IHostingEnvironment env 改成 IWebHostEnvironment env,這個(gè)時(shí)候會(huì)報(bào)錯(cuò),因?yàn)槊臻g變了;
2、所以需要引用新的命名空間:using Microsoft.Extensions.Hosting;
到了這里,我們就完全修改好了宿主機(jī)的部分,現(xiàn)在項(xiàng)目還不能正常的使用,還需要繼續(xù)修改 mvc 部分,別著急,慢慢往下看。
剛剛我們修改了宿主機(jī) host ,啟動(dòng)項(xiàng)目的時(shí)候,還是會(huì)有錯(cuò)誤,主要提示我們的中間件 .UseMvc() 已經(jīng)不能被使用了,3.0后,對(duì)mvc做了較大的修改,主要從兩個(gè)方面,一個(gè)是服務(wù)注冊(cè),一個(gè)是中間件的拆分:
1、MVC 服務(wù)注冊(cè)(Startup.cs)
在 netcore 3.0 中,官方對(duì) mvc 服務(wù)做了細(xì)分,主要有以下幾個(gè)部分:
services.AddMvc();// 我們平時(shí)2.2使用的,最全面的mvc服務(wù)注冊(cè)services.AddMvcCore();// 稍微精簡(jiǎn)的mvc注冊(cè)
services.AddControllers();// 適用于api的mvc部分服務(wù)注冊(cè)
services.AddControllersWithViews();//含有api和view的部分服務(wù)注冊(cè)
services.AddRazorPages();//razor服務(wù)注冊(cè)
我們看出來(lái),如果我們的項(xiàng)目是webapi的,那只需要注冊(cè) .AddControllers() 這個(gè)就夠了,.AddMvc() 里邊服務(wù)太多,會(huì)造成浪費(fèi),而大材小用。
代碼修改對(duì)比圖:
2、MVC 中間件的拆分(Startup.cs)
除了上邊的 mvc 服務(wù)注冊(cè)以外,我們還需要對(duì) UseMvc() 中間件做修改。
官方已經(jīng)正式去掉了Mvc()這個(gè)短路中間件,取代他的是 .UseEndpoints() 方法,我們可以做以下修改:
代碼修改對(duì)比圖:
CODE:
app.UseRouting();//路由中間件// 短路中間件,配置Controller路由
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
到了這里,我們已經(jīng)完成了 netcore 2.2 到 net core 3.0 的最簡(jiǎn)單的升級(jí),如果你想嘗試下,可以自己手動(dòng)建立一個(gè)空的 2.2 項(xiàng)目,實(shí)現(xiàn)到 3.0 的遷移,我們運(yùn)行項(xiàng)目,可以看到已經(jīng)成功的啟動(dòng)起來(lái),還是很成功的。這里要注意下中間件的順序,一般的順序是這樣的:
app.UseStaticFiles();app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chat");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
那是不是到了這里已經(jīng)完成了呢,答案當(dāng)然是否定的,我們的項(xiàng)目不可能這么簡(jiǎn)單,肯定還會(huì)有其他的依賴,還有各種各樣的中間件,那我們?cè)谏?jí)的過(guò)程中,還會(huì)有哪些地方需要做處理呢,就比如下邊的這些。
在 netcore 3.0 中,要求我們使用的是 swagger 5.0 ,而且變化的內(nèi)容也挺多的,但是原理和思路都是一樣的,大家一看就知道了,所以我就直接貼代碼了。
1、代碼修改對(duì)比圖(ConfigureServices)
?這次的修改,主要是服務(wù)的注冊(cè)部分,中間件沒(méi)有變化,所以我們直接在 startup.cs 中的 configureService 中,做下調(diào)整:
這里要注意下,需要引用兩個(gè) Nuget 包:Swashbuckle.AspNetCore 和 Swashbuckle.AspNetCore.Filters
2、修改后的完整代碼
services.AddSwaggerGen(c =>{
typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
{
// swagger文檔配置
c.SwaggerDoc(version, new OpenApiInfo
{
Version = version,
Title = $"{ApiName} 接口文檔",
Description = $"{ApiName} HTTP API " + version,
Contact = new OpenApiContact { Name = ApiName, Email = "Blog.Core@xxx.com", Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") },
License = new OpenApiLicense { Name = ApiName, Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") }
});
// 接口排序
c.OrderActionsBy(o => o.RelativePath);
});
// 配置 xml 文檔
var xmlPath = Path.Combine(basePath, "Blog.Core.xml");
c.IncludeXmlComments(xmlPath, true);
var xmlModelPath = Path.Combine(basePath, "Blog.Core.Model.xml");
c.IncludeXmlComments(xmlModelPath);
c.OperationFilter<AddResponseHeadersFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
// 很重要!這里配置安全校驗(yàn),和之前的版本不一樣
c.OperationFilter<SecurityRequirementsOperationFilter>();
// 開(kāi)啟 oauth2 安全描述
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "JWT授權(quán)(數(shù)據(jù)將在請(qǐng)求頭中進(jìn)行傳輸) 直接在下框中輸入Bearer {token}(注意兩者之間是一個(gè)空格)\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
代碼中,變化比較大的地方,我已經(jīng)用紅色標(biāo)注,某些又做了注解,不過(guò)大部分的內(nèi)容還是和之前是一樣的,相信大家都能看得懂。
?關(guān)于依賴注入框架 Autofac 的變化,整體來(lái)說(shuō)不是很大,主要是在依賴容器的使用上,在 2.2 的時(shí)候,我們是直接修改的的 ConfigureServices ,然后將容器實(shí)例給 return 出去,但是 3.0 之后,ConfigureServices 不能是返回類型了,只能是 void 方法,那我們就不用 return 出去了,官方給我們提供了一個(gè)服務(wù)提供上工廠,我們從這個(gè)工廠里拿,而不是將服務(wù)配置 return 出去。
1、代碼修改對(duì)比圖
?1、首先我們需要在 Program.cs 中的 CreateHostBuilder 中,添加Autofac的服務(wù)工廠:
2、然后在 startup.cs 文件中,新建一個(gè)?ConfigureContainer(ContainerBuilder builder) 的方法,里邊的內(nèi)容就是我們之前寫的 Autofac 的代碼,把之前在 configureService 中的代碼都刪掉。
只不過(guò)我們這里是注入了 builder 的實(shí)例對(duì)象,不用new了,然后也不用 build 容器了,交給了 hotst 幫助我們一起 build。
如果有任何看不懂的,請(qǐng)查看我的 Blog.Core 項(xiàng)目中的代碼。
2、修改后的完整代碼
?Startup.cs 中,新增 ConfigureContainer 方法,刪除 ConfigureService中,所有有關(guān) Autofac 的內(nèi)容:
public void ConfigureContainer(ContainerBuilder builder){
var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
//注冊(cè)要通過(guò)反射創(chuàng)建的組件
//builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();
builder.RegisterType<BlogCacheAOP>();//可以直接替換其他攔截器
builder.RegisterType<BlogRedisCacheAOP>();//可以直接替換其他攔截器
builder.RegisterType<BlogLogAOP>();//這樣可以注入第二個(gè)
// ※※★※※ 如果你是第一次下載項(xiàng)目,請(qǐng)先F6編譯,然后再F5執(zhí)行,※※★※※
#region 帶有接口層的服務(wù)注入
#region Service.dll 注入,有對(duì)應(yīng)接口
//獲取項(xiàng)目絕對(duì)路徑,請(qǐng)注意,這個(gè)是實(shí)現(xiàn)類的dll文件,不是接口 IService.dll ,注入容器當(dāng)然是Activatore
try
{
var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll");
var assemblysServices = Assembly.LoadFrom(servicesDllFile);//直接采用加載文件的方法 ※※★※※ 如果你是第一次下載項(xiàng)目,請(qǐng)先F6編譯,然后再F5執(zhí)行,※※★※※
//builder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces();//指定已掃描程序集中的類型注冊(cè)為提供所有其實(shí)現(xiàn)的接口。
// AOP 開(kāi)關(guān),如果想要打開(kāi)指定的功能,只需要在 appsettigns.json 對(duì)應(yīng)對(duì)應(yīng) true 就行。
var cacheType = new List<Type>();
if (Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
{
cacheType.Add(typeof(BlogRedisCacheAOP));
}
if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
{
cacheType.Add(typeof(BlogCacheAOP));
}
if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
{
cacheType.Add(typeof(BlogLogAOP));
}
builder.RegisterAssemblyTypes(assemblysServices)
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;
// 如果你想注入兩個(gè),就這么寫 InterceptedBy(typeof(BlogCacheAOP), typeof(BlogLogAOP));
// 如果想使用Redis緩存,請(qǐng)必須開(kāi)啟 redis 服務(wù),端口號(hào)我的是6319,如果不一樣還是無(wú)效,否則請(qǐng)使用memory緩存 BlogCacheAOP
.InterceptedBy(cacheType.ToArray());//允許將攔截器服務(wù)的列表分配給注冊(cè)。
#endregion
#region Repository.dll 注入,有對(duì)應(yīng)接口
var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll");
var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces();
}
catch (Exception ex)
{
throw new Exception("※※★※※ 如果你是第一次下載項(xiàng)目,請(qǐng)先對(duì)整個(gè)解決方案dotnet build(F6編譯),然后再對(duì)api層 dotnet run(F5執(zhí)行),\n因?yàn)榻怦盍?#xff0c;如果你是發(fā)布的模式,請(qǐng)檢查bin文件夾是否存在Repository.dll和service.dll ※※★※※" + ex.Message + "\n" + ex.InnerException);
}
#endregion
#endregion
#region 沒(méi)有接口層的服務(wù)層注入
////因?yàn)闆](méi)有接口層,所以不能實(shí)現(xiàn)解耦,只能用 Load 方法。
////注意如果使用沒(méi)有接口的服務(wù),并想對(duì)其使用 AOP 攔截,就必須設(shè)置為虛方法
////var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services");
////builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces);
#endregion
#region 沒(méi)有接口的單獨(dú)類 class 注入
////只能注入該類中的虛方法
builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
.EnableClassInterceptors()
.InterceptedBy(typeof(BlogLogAOP));
#endregion
//這里不要再 build 了
//var ApplicationContainer = builder.Build();
}
program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseUrls("http://localhost:8081")
.ConfigureLogging((hostingContext, builder) =>
{
builder.ClearProviders();
builder.SetMinimumLevel(LogLevel.Trace);
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
builder.AddConsole();
builder.AddDebug();
});
});
3、變化的核心點(diǎn)
就是將我們的Autofac的容器,從 configureService 中,轉(zhuǎn)向了我們的宿主機(jī)中了,步驟是:
1、刪除 ConfigureService 中的所有 Autofac 配置內(nèi)容;
2、將剛剛刪除的配置內(nèi)容,拷貝到新建一個(gè) ConfigureContainer ?方法中;
3、在 ConfigureContainer 方法中,不要進(jìn)行 build 操作,然后 Main 入口方法中的 Build() 去執(zhí)行。
4、在 Program.cs 的 CreateHostBuilder 中,新增服務(wù)工廠實(shí)例。
好了,到現(xiàn)在,我們可以嘗試看看 Autofac 依賴注入框架,已經(jīng)可以正常的使用了。
隨著netcore 3.0 的更新,sqlsugar當(dāng)然也要做相應(yīng)的優(yōu)化處理,主要是為了配合 3.0 做處理,作者凱旋兄還是很負(fù)責(zé)的,及時(shí)做了調(diào)整,目前 sqlsugar 的版本是 5.0.9 ,我們?nèi)绻褂?netcore 3.0 的話,就必須要使用。
1、這個(gè) 5.0.9 的版本,如果不使用的話,可能會(huì)有一個(gè)映射錯(cuò)誤:
?如果遇到了這個(gè)錯(cuò)誤,直接不要問(wèn),更新到最新版本就行。
2、如果更新了以后,發(fā)現(xiàn)還有錯(cuò)誤,一個(gè)《未將對(duì)象引用到對(duì)象的實(shí)例》:
這個(gè)時(shí)候,你可以嘗試重新生成下數(shù)據(jù)庫(kù),好像只需要?jiǎng)?chuàng)建下表結(jié)構(gòu)就行,數(shù)據(jù)可以導(dǎo)入,記得做好生產(chǎn)環(huán)境數(shù)據(jù)庫(kù)備份。
其他還沒(méi)有發(fā)現(xiàn)什么問(wèn)題。
這一塊我也發(fā)現(xiàn)有點(diǎn)兒?jiǎn)栴},好像目前在controller 上配置?[Authorize(Policy = Permissions.Name)] 并不能實(shí)現(xiàn)授權(quán)的目的,就算是用官網(wǎng)的在短路節(jié)點(diǎn)配置也不行, .RequireAuthorization(new AuthorizeAttribute() { Policy = Permissions.Name, });,所以,起作用的還是我的授權(quán)公約過(guò)濾器,并不是加的特性,我還在調(diào)試,如果你正好寫到 netcore 3.0 授權(quán)策略了,請(qǐng)?jiān)u論,不勝感激。
這個(gè)地方其實(shí)很簡(jiǎn)單,剛剛在將 swagger 的時(shí)候,我也說(shuō)到了,有一個(gè)地方需要我們注意, 就是安全校驗(yàn)的配置上,現(xiàn)在發(fā)生了變化,從服務(wù)添加變成了過(guò)濾器:
之前我的 Blog.Core 項(xiàng)目使用了權(quán)限過(guò)濾器公約,這樣就算 controller 沒(méi)有配置 Authorize 的話,也會(huì)默認(rèn)采用這種權(quán)限過(guò)濾器,
但是現(xiàn)在不行了,必須要在每一個(gè) controller 上配置,才能在 swagger 中出現(xiàn)那個(gè) 小鎖 的標(biāo)志,所以我又都在 controller 上,加上了?[Authorize(Permissions.Name)]
如果不配置的話,是沒(méi)有小鎖標(biāo)志,也就不會(huì)啟動(dòng)權(quán)限認(rèn)證的作用的,只有配置了的才有,不僅如此,大家也可以看到,在左側(cè)已經(jīng)把該接口對(duì)應(yīng)的權(quán)限也寫上了:
?在netcore 3.0 中,它內(nèi)置了一個(gè) json 工具—— System.Text.Json,而作為改善 ASP.NET Core 共享框架的工作的一部分,已從 ASP.NET Core 共享框架中刪除Json.NET 。如果你的應(yīng)用程序使用Newtonsoft.Json特定的功能(如 JsonPatch 或轉(zhuǎn)換器),或者如果它是特定于格式 Newtonsoft.Json的類型,那我們就需要重新引用它。
簡(jiǎn)單來(lái)說(shuō),就是 3.0 內(nèi)置了 Text.Json 框架,你可以直接使用,但是我沒(méi)有用這個(gè),因?yàn)槲液孟裰虚g出現(xiàn)了一個(gè)序列化錯(cuò)誤,而且我還要取消默認(rèn)的駝峰命名,所以我還是采用的之前的 Newtonsoft.json,具體的使用方法請(qǐng)看:
1、如果使用 .net core 3.0 內(nèi)置的 System.Text.Json ,配置方法如下:
services.AddMvc().AddJsonOptions(options =>{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
2、如果使用 Newtonsoft.Json ,配置方法如下:
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver = new DefaultContractResolver());
這個(gè)很簡(jiǎn)單,官方中間件取消了? UseSignalR 中間件,而放到了? UseEndpoints 短路中間件中,配置如下:
app.UseRouting();app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/api2/chatHub");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
?CORS變化其實(shí)不大,整體來(lái)說(shuō)和 2.2 一樣的,具體的按照 之前的寫法來(lái)寫就行。
只是已經(jīng)不支持向所有域名開(kāi)放了,所以下邊的 Policy 可以刪除了,其他的不用變化:
c.AddPolicy("AllRequests", policy =>{
policy
.AllowAnyOrigin()//允許任何源
.AllowAnyMethod()//允許任何方式
.AllowAnyHeader()//允許任何頭
.AllowCredentials();//允許cookie
});
然后就是要注意中間件的順序,這里記得還要帶上 policy 的名稱 ,還是 app.UseCors("LimitRequests");:
其他補(bǔ)充中
如果你有其他的用到的,是我沒(méi)有使用到的, 或者我上文沒(méi)有提到的注意點(diǎn),
歡迎想問(wèn)提問(wèn)和反饋,我會(huì)在這里,給你署名寫上,讓更多的小伙伴可以學(xué)會(huì)學(xué)號(hào)。
謝謝。
https://github.com/anjoy8/Blog.Core
https://gitee.com/laozhangIsPhi/Blog.Core
app.UseStaticFiles(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/chat"); endpoints.MapControllerRoute("default",?"{controller=Home}/{action=Index}/{id?}"); });
相關(guān)文章:
原文鏈接:https://www.cnblogs.com/laozhang-is-phi/p/11520048.html
.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總?http://www.csharpkit.com?
總結(jié)
以上是生活随笔為你收集整理的最全的 netcore 3.0 升级实战方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《WTM送书活动:向更遥远的星辰大海起航
- 下一篇: 迫于误解压力,RMS从自由软件基金会与M