我尝试使用在这里找到的建议,但在我的情况下最终失败了。
尽管文件夹开始变得更少,但仍然有一些垃圾随机留在那里。
我的情况是:我正在加载证书以在HttpClient中使用,似乎它被卡在HttpClient内部。
我已经实现了所有东西的超类(X509Certificate2,HttpClientHandler,HttpClient)来简化工作,但是一些Dispose()方法从未被调用过。
也许这与HttpClient池有关,但它似乎被设计成会失败 - 无论你做什么,都会在其他地方出现问题。
所以我决定编写一个服务,在一段时间后删除它们,最终我成功地保持了文件夹的清洁。
这是我的解决方案:
public class AutoResetX509Certificate2 : X509Certificate2
{
string autoGeneratedFile = "";
const string keyFolder = @"C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys";
public AutoResetX509Certificate2(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) : base(rawData, password, keyStorageFlags)
{
var uniqueName = ((System.Security.Cryptography.RSACng)this.PrivateKey).Key.UniqueName;
autoGeneratedFile = Path.Combine(keyFolder, uniqueName);
AddFileToDeletion(autoGeneratedFile);
StartAutoResetService();
}
public AutoResetX509Certificate2(byte[] rawData) : base(rawData)
{
var uniqueName = ((System.Security.Cryptography.RSACng)this.PrivateKey).Key.UniqueName;
autoGeneratedFile = Path.Combine(keyFolder, uniqueName);
AddFileToDeletion(autoGeneratedFile);
StartAutoResetService();
}
protected override void Dispose(bool disposing)
{
StopAutoResetService();
base.Dispose(disposing);
}
private void AddFileToDeletion(string path)
{
var folder = Path.Combine(keyFolder, "!deletionTrack");
Directory.CreateDirectory(folder);
var fi = new FileInfo(path);
var file = Path.Combine(folder, fi.Name);
File.WriteAllText(file, "");
}
static System.Timers.Timer timer = new() { Enabled = false, Interval = 5000 };
static bool isTimerBusy = false;
internal static void StartAutoResetService()
{
lock (timer)
{
if (!timer.Enabled)
{
timer.Elapsed += Timer_Elapsed;
timer.Enabled = true;
}
}
}
internal static void StopAutoResetService()
{
lock (timer)
{
timer.Enabled = false;
timer.Elapsed -= Timer_Elapsed;
}
}
private static void RunAutoReset()
{
var folder = Path.Combine(keyFolder, "!deletionTrack");
var di = new DirectoryInfo(folder);
if (di.Exists)
{
var olders = di.GetFiles().Where(fi => DateTime.Now.Subtract(fi.CreationTime).TotalSeconds > 30).ToList();
foreach (var old in olders)
{
var certPath = Path.Combine(keyFolder, old.Name);
if (File.Exists(certPath)) File.Delete(certPath);
old.Delete();
}
}
}
private static void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (isTimerBusy) return;
isTimerBusy = true;
try
{
RunAutoReset();
}
catch(Exception)
{
}
finally
{
isTimerBusy = false;
}
}
}
你只需要使用那个类(AutoResetX509Certificate2)来加载你的证书,而不是使用X509Certificate2。
var clientCert = new AutoResetX509Certificate2(pfxBytes, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
请注意,我已经实现了我需要的两个构造函数,如果你需要另一个,你需要像这两个一样自己实现。
EphemeralKeySet
,似乎他们只在 .Net Core 中添加了它,原因不明。我会继续深入挖掘。 - Michael Brown