深入理解.NET Core的基元(二) - 共享框架

原文:Deep-dive into .NET Core primitives, part 2: the shared framework
作者:Nate McMaster
譯文:深入理解.NET Core的基元(二) - 共享框架
作者: Lamond Lu

本篇是之前翻譯過的《深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll文件》的后續(xù)宿亡,這個(gè)系列作者暫時(shí)只寫了3篇菇篡,雖然有一些內(nèi)容和.NET Core 3.0已經(jīng)不兼容了,但是大部分的原理還都是相通的骗绕,所以后面的第三篇我也會(huì)翻譯盾舌。

前言

image

自.NET Core 1.0起淮菠,共享框架(Shared Framework)就已經(jīng)成為了.NET Core的重要組成部分爹耗。自.NET Core 2.1起奔滑,ASP.NET Core就已經(jīng)作為共享框架的第一次出現(xiàn)艾岂。你可能從來注意過這一點(diǎn),但是在設(shè)計(jì)它的時(shí)候朋其,我們經(jīng)歷了許多反復(fù)和持續(xù)的討論王浴。在本篇文章中,我們將深入共享框架并討論一些開發(fā)人員經(jīng)常遇到的一些陷阱梅猿。

基礎(chǔ)部分

.NET Core應(yīng)用可以在兩種模式下運(yùn)行氓辣, 分別是框架依賴模式(Framework - Dependent) 和獨(dú)立運(yùn)行模式(Self Contained) 。在我的Macbook上袱蚓,一個(gè)最小的可獨(dú)立運(yùn)行的ASP.NET Core網(wǎng)站應(yīng)用钞啸,大約擁有350個(gè)文件,文件大小總共是93MB。相對(duì)的体斩,一個(gè)最小的框架依賴應(yīng)用梭稚,大約5個(gè)文件,文件大小總共239KB絮吵。

你可以如下命令行生成基于兩種不同模式的應(yīng)用弧烤。

dotnet new web
dotnet publish --runtime osx-x64 --output bin/self_contained_app/
dotnet publish --output bin/framework_dependent_app/
image

當(dāng)程序運(yùn)行的時(shí)候,他們的功能是一樣的蹬敲。那么這兩種模式有什么區(qū)別么暇昂?其實(shí)正如官網(wǎng)文檔中的解釋:

框架依賴部署(framework-dependant deployment) 依賴目標(biāo)中安裝的.NET Core共享組件。獨(dú)立部署(self-contained deployment)不依賴目標(biāo)系統(tǒng)中安裝的共享組件伴嗡,程序所需的所有組件都已經(jīng)包含在當(dāng)前應(yīng)用程序中急波。

這篇官方文檔(https://docs.microsoft.com/en-us/dotnet/core/deploying/)中很好的解釋了不同模式的優(yōu)勢(shì)。

PS: 作者當(dāng)時(shí)寫這邊文章的時(shí)候, 沒有引入Framework-dependent executables (FDE)闹究,有興趣的同學(xué)可以自行查看幔崖。

共享框架

這里,簡(jiǎn)單的說渣淤,.NET Core的共享框架就是一個(gè)程序集(*.dll文件)集合的目錄赏寇,這些程序集不需要出現(xiàn)在你的.NET Core的應(yīng)用目錄中。這個(gè)目錄是.NET Core的共享系統(tǒng)范圍版本的一部分价认,通常你可以在C:\Program Filres\dotnet\shared中發(fā)現(xiàn)它嗅定。

當(dāng)你運(yùn)行dotnet.exe WebApi1.dll命令時(shí),.NET Core宿主程序會(huì)

  • 嘗試發(fā)現(xiàn)你的應(yīng)用依賴的程序集名稱和版本
  • 在某些固定位置中嘗試查找該程序集

這些程序集可以在許多不同的位置被發(fā)現(xiàn)了用踩,包含且不限于共享框架渠退。在我之前的文章中,我主要解釋了如果通過deps.jsonruntimeconfig.json文件配置宿主程序的行為脐彩。希望了解更多的同學(xué)碎乃,可以查看那篇文章。

.NET Core宿主程序會(huì)讀取*.runtimeconfig.json文件來確定加載哪個(gè)版本的共享框架惠奸。這個(gè)文件的內(nèi)容類似:

{
  "runtimeOptions": {
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "2.1.1"
    }
  }
}

這里梅誓,共享框架名稱只是一個(gè)名字。按照約定佛南,這個(gè)名字應(yīng)該是以.App結(jié)尾的梗掰,但是實(shí)際上它可以是任何字符串,例如"FooBananaShark"嗅回。

對(duì)于共享框架的版本及穗,這里只是配置了一個(gè)最低的版本。.NET Core宿主程序會(huì)根據(jù)配置绵载,加載對(duì)應(yīng)版本的共享框架埂陆,或者更高版本的共享框架苛白,但是它永遠(yuǎn)不會(huì)加載比指定版本低的共享框架。

那么焚虱,我到底安裝了哪些共享框架呢丸氛?

運(yùn)行dotnet --list-runtimes, 你就可以看到你電腦中安裝了哪些共享框架,以及它們的版本和文件位置著摔。

對(duì)比Microsoft.NETCore.App, AspNetCore.App以及AspNetCore.All

這里,以.NET Core 2.2為例定续。

框架名稱 描述
Microsoft.NETCore.App 基礎(chǔ)運(yùn)行時(shí)谍咆。它主要提供了System.ObjectList<T>私股、string類摹察,以及內(nèi)存管理,文件管理倡鲸,網(wǎng)絡(luò)I/O, 線程管理等功能
Microsoft.AspNetCore.App 默認(rèn)Web運(yùn)行時(shí)供嚎。它主要提供了使用API創(chuàng)建Web服務(wù)器的功能,這里主要包含Kestral, Mvc, SignalR, Razor, 以及EF Core的部分功能峭状。
Microsoft.AspNetCore.All 與第三方的集成庫(kù)克滴。它追加了EF Core + Sqlite的支持,以及一些擴(kuò)展功能优床, 例如Redis, Azure Key Valut等劝赔。(在.NET Core 3.0中已經(jīng)不再使用)

共享框架與Nuget包的關(guān)系

.NET Core SDK生成了runtimeconfig.json文件。在.NET Core 1和2中胆敞,SDK使用了項(xiàng)目配置中的兩部分來確定runtimeconfig.json文件中框架部分內(nèi)容着帽。

  • MicrosoftNETPlatformLibrary屬性。對(duì)于所有.NET Core項(xiàng)目移层,它默認(rèn)是Microsoft.NETCore.App仍翰。
  • Nuget包管理工具的還原結(jié)果集,結(jié)果集中可能包含了相同名稱的包

這里針對(duì)所有的.NET Core項(xiàng)目观话, .NET Core SDK都會(huì)添加一個(gè)隱式的包來引用Microsoft.NETCore.App予借。ASP.NET Core通過修改默認(rèn)配置MicrosoftNETPlatformLibrary, 將其改為Microsoft.AspNetCore.App

但是這里需要注意匪燕,Nuget包管理工具不提供任何共享框架!不提供任何共享框架! 不提供任何共享框架! 重要的事情說三遍_蕾羊。Nuget包管理工具只提供編譯器使用的一些API,以及少量SDK帽驯。共享框架的獲取來源可以是運(yùn)行時(shí)安裝器 https://aka.ms/dotnet-download龟再, 或者捆綁在Visual Studio中,Docker鏡像中尼变,以及一些Azure服務(wù)器中利凑。

版本前滾策略

正如我上面提到的浆劲,runtimeconfig.json只是指定了一個(gè)最小版本。實(shí)際使用的版本會(huì)依賴于一個(gè)版本前滾策略(詳細(xì)內(nèi)容可以參閱官方文檔哀澈。例如

  • 如果應(yīng)用使用的共享框架最小版本是2.1.0, 那么程序最高會(huì)加載的共享框架版本是2.1.*牌借。

針對(duì)這一部分,可以參見《深入理解.NET Core的基元(三):深入理解runtimeconfig.json》

作者:《深入理解.NET Core的基元(三):深入理解runtimeconfig.json》后續(xù)會(huì)補(bǔ)上

分層的共享框架

在.NET Core 2.1版本中引入了分層共享框架的特性割按。

共享框架可以依賴于其他共享框架膨报。引入此特性是為了支持ASP.NET Core, 這個(gè)特性可以將程序包的運(yùn)行時(shí)存儲(chǔ)轉(zhuǎn)換為一個(gè)共享框架。

如果你查看一下$DOTNET_ROOT/shared/Microsoft.AspNetCore.All/$version/文件夾适荣,你會(huì)發(fā)現(xiàn)一個(gè)名為Microsoft.AspNetCore.All.runtimeconfig.json的文件现柠,其內(nèi)容如下

$ cat /usr/local/share/dotnet/shared/Microsoft.AspNetCore.All/2.1.2/Microsoft.AspNetCore.All.runtimeconfig.json
{
  "runtimeOptions": {
    "tfm": "netcoreapp2.1",
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "2.1.2"
    }
  }
}

多級(jí)檢索

在.NET Core 2.0中引入了多級(jí)檢索特性。

宿主程序在啟動(dòng)時(shí)會(huì)探查多個(gè)位置弛矛,以尋找合適的共享框架够吩。程序首先會(huì)查找dotnet根目錄,即包含一個(gè)dotnet.exe可執(zhí)行文件的目錄丈氓。這里我們可以通過配置DOTNET_ROOT的環(huán)境變量來覆蓋此配置周循。根據(jù)此配置,程序檢索的第一個(gè)目錄是:

$DOTNET_ROOT/shared/$name/$version

如果這個(gè)目錄不存在万俗,宿主程序會(huì)嘗試使用多級(jí)檢索機(jī)制湾笛,檢索預(yù)定的全局路徑列表。這個(gè)機(jī)制可以通過設(shè)置全局變量DOTNET_MULTILEVEL_LOOKUP=0來關(guān)閉闰歪。默認(rèn)情況下迄本,預(yù)定的全局路徑列表如下:

OS Location
Windows C:\Program Files\dotnet (64位進(jìn)程) C:\Program Files (x86)\dotnet (32位進(jìn)程) (查看源代碼)
macOS /usr/local/share/dotnet (查看源代碼)
Unix /usr/share/dotnet (查看源代碼)

最終宿主程序會(huì)在找到的全局目錄中檢索以下目錄

$GLOBAL_DOTNET_ROOT/shared/$name/$version

ReadyToRun特性

共享框架中的程序集,都是經(jīng)過crossgen工具預(yù)優(yōu)化過的课竣。使用這個(gè)工具可以生成"ReadyToRun"版本的程序集嘉赎,這些程序集都是針對(duì)指定操作系統(tǒng)和CPU架構(gòu)優(yōu)化過的。這里主要的性能提升是于樟,減少了JIT在啟動(dòng)時(shí)準(zhǔn)備代碼所花費(fèi)的時(shí)間公条。

Crossgen相關(guān)文檔:https://github.com/dotnet/coreclr/blob/v2.1.3/Documentation/building/crossgen.md

一些陷阱

我相信每個(gè).NET Core程序員都會(huì)遇到以下陷阱中的一部分。我將盡力解釋這些問題是如何產(chǎn)生的迂曲。

Http Error 502.5 Process Failure

image

到目前為止靶橱,開發(fā)人員,最常遇到的陷阱是在IIS中或者Azure Web Services中托管ASP.NET Core應(yīng)用程序路捧。這個(gè)問題通常發(fā)生在開發(fā)人員升級(jí)了一個(gè)項(xiàng)目关霸,或者當(dāng)應(yīng)用部署的時(shí)候,目標(biāo)機(jī)器沒有更新杰扫。這個(gè)錯(cuò)誤的真正原因通常是應(yīng)用所需版本的共享框架找不到队寇,導(dǎo)致.NET Core應(yīng)用程序無法正常啟動(dòng)。當(dāng)dotnet無法啟動(dòng)應(yīng)用程序時(shí)章姓,IIS會(huì)返回HTTP 502.5的錯(cuò)誤佳遣,但是不會(huì)顯示內(nèi)部的錯(cuò)誤消息识埋。

"The specified framework was not found"

It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '2.1.3' was not found.
  - Check application dependencies and target a framework version installed at:
      /usr/local/share/dotnet/
  - Installing .NET Core prerequisites might help resolve this problem:
      http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
  - The .NET Core framework and SDK can be installed from:
      https://aka.ms/dotnet-download
  - The following versions are installed:
      2.1.1 at [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
      2.1.2 at [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]

這個(gè)錯(cuò)誤通常出現(xiàn)在HTTP 502.5錯(cuò)誤之后,或者Visual Studio Test Explorer故障零渐。

如上所述窒舟,當(dāng)runtimeconfig.json文件指定了一個(gè)框架名稱和版本,但是經(jīng)過多級(jí)檢索特性和前滾策略之后诵盼,主機(jī)依然無法找到一個(gè)合適的框架版本的時(shí)候惠豺,就會(huì)出現(xiàn)以上錯(cuò)誤。

升級(jí)Microsoft.AspNetCore.App程序集的Nuget包

Microsoft.AspNetCore.App程序集的Nuget包风宁,并不提供共享框架耕腾。它只是提供了C#/F#編譯器使用的一些API以及少量SDK. 所以你必須要單獨(dú)下載并安裝共享框架。

同時(shí)杀糯,由于前滾策略,你并不需要更新Nuget包的版本苍苞,來讓你的程序運(yùn)行在新版本的共享框架中固翰。

這可能是ASP.NET Core團(tuán)隊(duì)的一個(gè)設(shè)計(jì)失誤,我們無法將共享框架作為Nuget包出現(xiàn)在項(xiàng)目文件中羹呵。共享框架所提供的程序包并不是通常意義上的程序包骂际。與大部分程序包不同,它們不是自給自足的冈欢。我們希望當(dāng)項(xiàng)目使用<PackageReference>時(shí)歉铝,Nuget能夠安裝所需的所有引用,但是令人沮喪的是凑耻,這些特殊程序包的設(shè)計(jì)偏離我們期望的模式太示。當(dāng)然,現(xiàn)在我們已經(jīng)得到了各種建議來解決這個(gè)問題香浩。我希望它能早日實(shí)現(xiàn)类缤。

<PackageReference Include="Microsoft.AspNetCore.App" />

在ASP.NET Core 2.1的新項(xiàng)目模板和文檔中,微軟向開發(fā)人員展示了邻吭,他們只需要在項(xiàng)目文件中添加如下的一行代碼餐弱。

<PackageReference Include="Microsoft.AspNetCore.App" />

其他的<PackageReference>引用代碼都必須要包含Version屬性。只有當(dāng)項(xiàng)目文件是以<Project Sdk="Microsoft.NET.Sdk.Web">開頭的囱晴,那么以上這句與版本無關(guān)的程序包引用才會(huì)起作用膏蚓,并且這里只對(duì)Microsoft.AspNetCore.{App, All}程序集包起作用。Web SDK將根據(jù)項(xiàng)中的其他配置, 例如:<TargetFramework><RuntimeIdentifier>畸写, 來自動(dòng)選擇一個(gè)合適的程序包版本驮瞧。

如果你在包引用的部分加入的Version屬性,并指定了版本枯芬,或者你沒有使用Web SDK作為項(xiàng)目文件的開頭剧董,則無法使用此功能幢尚。這里我很難推薦一個(gè)好的解決方案,因?yàn)樽詈玫膶?shí)現(xiàn)方式是基于你對(duì)此的理解水平和項(xiàng)目類型的翅楼。

發(fā)布修剪(Publish Trimming)

當(dāng)你使用dotnet publish命令發(fā)布一個(gè)框架依賴的應(yīng)用時(shí)尉剩,SDK會(huì)使用Nuget的還原結(jié)果(restore result)來決定哪些程序集應(yīng)該出現(xiàn)在發(fā)布目錄中。有一些程序集是通過Nuget程序集包拷貝的毅臊,而有一些就不是理茎,因?yàn)樗麄円呀?jīng)出現(xiàn)在共享框架中。

這很容易產(chǎn)生一些錯(cuò)誤管嬉,因?yàn)锳SP.NET Core作為共享框架和Nuget程序包都是可用的皂林。項(xiàng)目發(fā)布修剪特性會(huì)嘗試通過圖形數(shù)學(xué)來檢查依賴傳遞,以及升級(jí)等蚯撩,并以此選擇正確的程序包文件础倍。

下面我們以如下的項(xiàng)目引用為例:

<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.9" />

MVC實(shí)際上是Microsoft.AspNetCore.App的一部分,但是當(dāng)調(diào)用dotnet publish命令發(fā)布項(xiàng)目后胎挎,你會(huì)發(fā)現(xiàn)你的項(xiàng)目選用了升級(jí)后的Microsoft.AspNetCore.Mvc.dll程序包沟启,這個(gè)程序包比Microsoft.AspNetCore.App中包含的2.1.1版本要高,所以最終Microsoft.AspNetCore.Mvc.dll會(huì)被拷貝到發(fā)布目錄中犹菇。

這就不太理想了德迹,因?yàn)殡S著你的應(yīng)用程序大小不斷增長(zhǎng),你永遠(yuǎn)得不到ReadyToRun優(yōu)化版本的Microsoft.AspNetCore.Mvc.dll揭芍。

PS: 這個(gè)問題以前很少注意到胳搞,不過真的很常見。

混淆目標(biāo)框架的別稱與共享框架

如果簡(jiǎn)單認(rèn)為"netcoreapp2.0" == "Microsoft.NETCore.App, v2.0.0", 你就大錯(cuò)特錯(cuò)了称杨。目標(biāo)框架別稱(Target Framework Moniker簡(jiǎn)稱TFM)只通過項(xiàng)目文件中<TargetFramework>節(jié)點(diǎn)指定的肌毅。"netcoreapp2.0"只是希望以人類友好的方式來表達(dá)你要使用哪個(gè)版本的.NET Core。

TFM的陷阱在于它的名稱太短了姑原。它不能表達(dá)出多種共享框架芽腾,特定補(bǔ)丁的版本控制,版本前滾页衙,輸出類型以及是獨(dú)立發(fā)布還是框架依賴發(fā)布等內(nèi)容摊滔。SDK會(huì)嘗試從TFM推斷許多設(shè)置,但是無法推斷所有內(nèi)容店乐。

所以艰躺,更準(zhǔn)確的說“netcoreapp2.0”意味著"Microsoft.NETCore.App v2.0.0及以上版本"。

混淆項(xiàng)目配置

最后一個(gè)陷阱和項(xiàng)目配置有關(guān)眨八。在這里有很多術(shù)語和配置名稱腺兴,它們不總是一致的。這些術(shù)語非常令人困惑廉侧,因此页响,如果混淆了這些術(shù)語篓足,也沒有關(guān)系,那不是你的錯(cuò)闰蚕。

下面栈拖,我就列出一些常見的項(xiàng)目設(shè)置及其實(shí)際含義。

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <!--
    實(shí)際意義:
      * 從Nuget包解析編譯引用時(shí)使用的API集合的版本
  -->

  <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
  <!--
    實(shí)際意義:
      * 使用兩個(gè)不同的API集合版本進(jìn)行編譯没陡。但這并不代表多層共享框架
  -->

  <MicrosoftNETPlatformLibrary>Microsoft.AspNetCore.App</MicrosoftNETPlatformLibrary>
  <!--
    實(shí)際意義:
      * 最頂層的共享框架名稱
  -->

  <RuntimeFrameworkVersion>2.1.2</RuntimeFrameworkVersion>
  <!--
    實(shí)際意義:
      * 指定了Microsoft.AspNetCore.App程序包的版本涩哟,這個(gè)版本就是最小的共享框架版本
  -->

  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  <!--
    實(shí)際意義:
      * 操作系統(tǒng)種類 + CPU架構(gòu)
  -->

  <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
  <!--
    實(shí)際意義:
      * 運(yùn)行此項(xiàng)目可能使用的操作系統(tǒng)種類和CPU架構(gòu)列表,你必須要通過RuntimeIdentifier配置選擇其中一個(gè)
  -->

</PropertyGroup>

<ItemGroup>

  <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.2" />
  <!--
    實(shí)際意義:
      * 使用Microsoft.AspNetCore.App作為共享框架
      * 最低版本2.1.2
  -->

  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
  <!--
    實(shí)際意義:
      * 引用Microsoft.AspNetCore.Mvc程序包
      * 實(shí)際版本2.1.2
  -->

  <FrameworkReference Include="Microsoft.AspNetCore.App" />
  <!--
    實(shí)際意義:
      * 使用Microsoft.AspNetCore.App作為共享框架.
  -->

</ItemGroup>

總結(jié)

共享框架作為.NET Core的可選功能盼玄,盡管存在缺陷贴彼,但是我認(rèn)為對(duì)于絕大部分用戶來說,這是一個(gè)合理的默認(rèn)設(shè)置埃儿。我依然認(rèn)為對(duì)于.NET Core開發(fā)人員來說器仗,了解背后的原理是一件好事,希望本文是對(duì)共享框架功能的良好概述童番。我盡可能的關(guān)聯(lián)了一些官網(wǎng)文檔和指南精钮,以便你可以找到更多的信息。如果還有其他問題妓盲,請(qǐng)?jiān)谙旅姘l(fā)表評(píng)論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末专普,一起剝皮案震驚了整個(gè)濱河市悯衬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌檀夹,老刑警劉巖筋粗,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異炸渡,居然都是意外死亡娜亿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門蚌堵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來买决,“玉大人,你說我怎么就攤上這事吼畏《匠啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵泻蚊,是天一觀的道長(zhǎng)躲舌。 經(jīng)常有香客問我,道長(zhǎng)性雄,這世上最難降的妖魔是什么没卸? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任羹奉,我火速辦了婚禮,結(jié)果婚禮上约计,老公的妹妹穿的比我還像新娘诀拭。我一直安慰自己,他們只是感情好病蛉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布炫加。 她就那樣靜靜地躺著,像睡著了一般铺然。 火紅的嫁衣襯著肌膚如雪俗孝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天魄健,我揣著相機(jī)與錄音赋铝,去河邊找鬼。 笑死沽瘦,一個(gè)胖子當(dāng)著我的面吹牛革骨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播析恋,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼良哲,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了助隧?” 一聲冷哼從身側(cè)響起筑凫,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎并村,沒想到半個(gè)月后巍实,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哩牍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年棚潦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝昆。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丸边,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荚孵,到底是詐尸還是另有隱情原环,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布处窥,位于F島的核電站嘱吗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谒麦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一俄讹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绕德,春花似錦患膛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至臣咖,卻和暖如春跃捣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夺蛇。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工疚漆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刁赦。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓娶聘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親甚脉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丸升,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容