作為團隊里面挖掘機出身的我,怎么能不多挖一些坑好將小伙伴們都埋進去呢,本文來告訴大家一個有趣且簡單的方法,此方法可以將本機的 WCF 玩壞,不敢說真的搞炸本機所有 WCF 應用,但搞炸大部分基于 WCF 的軟體還是沒有問題的,閱讀本文,你可以不僅可以了解到有這樣的逗比方法,更重要的是在你的 WCF 模塊炸掉的時候,你知道要甩鍋給誰
本文如此逗比的方法是由 lsj 小伙伴發現的,但是他不想記錄如此逗比的方法,于是就交給我來水了
在開始之前,咱先來復習如何制作一個簡單的 WCF 服務端和客戶端的方法,用不著官方檔案提供的十分繁瑣的方式,咱直接明了,通過簡單的控制臺,利用WCF實作本機 IPC 行程間通訊
咱將先制作一個簡單的 WCF 行程間通訊的服務端和客戶端兩個控制臺專案,用來演示在管道下的 WCF 應用的運行情況,接著再添加一個用來搗亂的 WCF 服務器端的控制臺專案,讓這個專案影響到原有作業的好好的演示專案
當前是 2021.08.22 社區版本發布了 WCF Core 的 0.2.0 版本,功能上還沒有追平 .NET Framework 的版本,因此本文依然使用 .NET Framework 版本的 WCF 進行演示
先來演示的 WCF 服務端的控制臺應用,咱通過 .NET 5 創建出專案,接著編輯 csproj 檔案,將 net5.0 修改為 net45 從而回傳到 .NET Framework 版本,服務端的 csproj 檔案代碼如下
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net45</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.ServiceModel" />
</ItemGroup>
</Project>
使用 .NET 5 創建專案的優勢是新建出來的專案是 SDK 風格的,方便更改,為了使用上 WCF 在 csproj 上添加 System.ServiceModel 的參考
在 SDK Style 的 csproj 專案檔案上,添加對 WCF 參考的方法是在 csproj 上添加如下代碼
<ItemGroup>
<Reference Include="System.ServiceModel" />
</ItemGroup>
按照慣例,定義型別,此型別將包含一個類和一個介面,類是在服務端運行的,而介面是給客戶端使用的,這部分基礎知識不在本文描述,更多基礎知識請參閱本文最后的由換頭像大大撰寫的入門博客
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class DataService: IDataServer
{
public void Foo(string name)
{
Console.WriteLine(name);
}
}
[ServiceContract]
public interface IDataServer
{
[OperationContract]
void Foo(string name);
}
接著打開 Program.cs 檔案,在此檔案撰寫入口函式,在入口函式啟動服務,如以下代碼
class Program
{
static void Main(string[] args)
{
var dataService = new DataService();
Uri address = new Uri("net.pipe://localhost/MyWCFConnection");
using (ServiceHost host = new ServiceHost(dataService, address))
{
host.Open();
while (true)
{
Thread.Sleep(100);
}
}
}
}
上面代碼使用了 net.pipe://localhost/MyWCFConnection 啟動了使用管道的 WCF 服務
接著采用相同的方法,也是使用 .NET 5 創建控制臺,修改為 .NET Framework 版本的客戶端控制臺
在客戶端控制臺的 csproj 檔案代碼和服務端的相同,放心,在本文最后有所有的源代碼,部分細節還請忽略,在客戶端里面,添加上了剛才定義的 IDataServer 介面,抄代碼即可
在客戶端的入口添加如下代碼,用于連上服務端,然后遠程呼叫服務端的某個方法
class Program
{
static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/MyWCFConnection");
var dataServer = ChannelFactory<IDataServer>.CreateChannel(new NetNamedPipeBinding(),new EndpointAddress(address));
dataServer.Foo("123");
}
}
先啟動服務端,再啟動客戶端,預期是服務端的 DataServer 的 Foo 方法將會被客戶端進行呼叫,被客戶端傳入了 "123" 在服務端的控制臺輸出
接下來開始開發一個用來搗亂的 WCF 控制臺,這是一個 WCF 服務端,這個控制臺應用的 csproj 和上面兩個相同,唯一不同的是在入口程式的定義和運行的方式,在入口里面使用如下代碼啟動服務
class Program
{
static void Main(string[] args)
{
var dataService = new DataService();
Uri address = new Uri("net.pipe://localhost/");
using (ServiceHost host = new ServiceHost(dataService, address))
{
host.Open();
while (true)
{
Thread.Sleep(100);
}
}
}
}
可以看到,以上的寫法是不被推薦的,采用了不加上具體的邏輯的管道
net.pipe://localhost/MyWCFConnection這是通用的方式net.pipe://localhost/這是不符合約定的
接著構建出這個搗亂的應用,使用管理員權限打開他,然后再嘗試啟動原本可以好好干活的演示應用,可以看到演示應用的客戶端炸掉了,提示如下
System.ServiceModel.EndpointNotFoundException:“由于 AddressFilter 在 EndpointDispatcher 不匹配,To 為“net.pipe://localhost/MyWCFConnection”的訊息無法在接收方處理,請檢查發送方和接收方的 EndpointAddresses 是否一致,”
以上的錯誤提示和服務端 WCF 沒有啟動或者在客戶端配置的連接字串和服務端配置的不相同的是一樣的提示方式
原因其實比較復雜一點,簡單說就是 WCF 的連接字串,在通過管道的方式的時候,不是直接作為管道名的,而是將此連接字串映射到某個共享記憶體里面,在共享記憶體里面存放實際的管道名,而上面用來搗亂的應用就是用了不符合約定的方式,讓客戶端在嘗試發現服務端的時候,先碰到了搗亂的應用,又因為權限不足從而失敗,如果此時將演示用的服務端也采用管理員權限運行,而演示用的客戶端依然是非管理員權限運行,那么演示程式還能正常作業
想要寫一個用來搞炸本機大部分的基于 WCF 做 IPC 行程間通訊的搗亂應用,只需要設定 WCF 連接字串為 net.pipe://localhost/ 接著使用管理員運行即可,如運行為服務
這個問題其實是某個用戶報告給我的,經過了 lsj 使用了各個黑科技的方式除錯,加上堆疊網大佬們的回復,了解到了是 DropboxOEM.exe 服務挖的坑,然而除此之外,在堆疊網上面也列出了其他的很多應用也會導致此問題,這個問題其實 WCF 和應用兩邊都有鍋
在 WCF 上,為了安全考慮,反而挖了如此的坑,會讓應用受到了本機內其他在運行的應用的影響,另一方面,其實 WCF 也算背鍋,因為如果應用亂來,導致影響其他應用,似乎在 Win32 設計層面本身就有這樣的問題,如應用自己去刪掉了某個系統關鍵檔案等,只是 WCF 這個鍋不好定位在于,使用 WCF 不屬于唯一方式,這就意味著其他的 IPC 也許能活,給用戶的感覺就是為什么我其他的應用都能作業好好的,就你的應用炸了
另外,我還測驗了其他的組合:
- 演示程式的 WCF 連接字串:
net.pipe://127.0.0.1/MyWCFConnection - 搗亂程式 WCF 連接字串:
"net.pipe://localhost/" - 搗亂程式使用管理員權限運行
結論:炸
后續為了升級到 .NET Core 或 .NET 5 等更高版本的 .NET 我開源了一個追求穩定的 IPC 庫,請看 dotnet-campus/dotnetCampus.Ipc: 本機內多行程通訊庫
當前此開源庫還沒有實際落地,缺乏大量的詭異的用戶環境的適配,預計大概到 2022 的時候,這個庫能更加穩定
本文所有代碼放在github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 cd 命令進入此空檔案夾,在命令列里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 26aa3294d0bc40ba7e312891c958fa170c3d51f0
以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進入 ChigiwejefiKemhakerhawee 檔案夾
此問題也能在堆疊網找到,請看 .net - 3rd party app breaks our WCF application - Stack Overflow
更多 WCF 請參閱:
- wcf入門(1) - huangtengxiao
- wcf入門(2) - huangtengxiao
- wcf入門(3) - huangtengxiao
- wcf入門(4) - huangtengxiao
- wcf入門(5) - huangtengxiao
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/295526.html
標籤:.NET技术
下一篇:設計模式之責任鏈
