An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
Hi @Jonathan ,
I apologize for the delayed response. I have received your sharing regarding the issue.
The core issue is that your current code reads the entire file on every single IP check. This means if 1,000 visitors arrive at the same time, your program opens and reads the file 1,000 times.
I have already tested this on my side and checked the performance.
You can refer to my example code below:
BlockIPManager.cs:
public static class BlockedIPManager
{
private static readonly object _lock = new object();
private static HashSet<string> _blockedIPs = null;
private static readonly string FileName = @"c:\cmp\list11.txt";
public static void Initialize()
{
lock (_lock)
{
_blockedIPs = File.Exists(FileName)
? File.ReadLines(FileName)
.Select(line => line.Trim())
.Where(line => !string.IsNullOrWhiteSpace(line))
.ToHashSet()
: new HashSet<string>();
}
}
public static bool ShouldBlockIP(string ip)
{
if (string.IsNullOrWhiteSpace(ip)) return false;
ip = ip.Trim();
lock (_lock)
{
if (_blockedIPs == null) Initialize();
if (_blockedIPs.Contains(ip))
return true;
_blockedIPs.Add(ip);
File.AppendAllText(FileName, ip + Environment.NewLine);
return false;
}
}
public static void AddBlockIPs(IEnumerable<string> ipList)
{
if (ipList == null) return;
lock (_lock)
{
if (_blockedIPs == null) Initialize();
var newIPs = ipList
.Select(ip => ip?.Trim())
.Where(ip => !string.IsNullOrWhiteSpace(ip)
&& !_blockedIPs.Contains(ip))
.Distinct()
.ToList();
if (newIPs.Count == 0) return;
foreach (var ip in newIPs)
_blockedIPs.Add(ip);
File.AppendAllLines(FileName, newIPs);
}
}
}
Program.cs
using System.Diagnostics;
BlockedIPManager.Initialize();
var sw = Stopwatch.StartNew();
Console.WriteLine("TEST 1: Single IP lookup — IP at TOP of file (10,000 times)");
sw.Restart();
for (int i = 0; i < 10000; i++)
BlockedIPManager.ShouldBlockIP("113.45.67.89");
sw.Stop();
Console.WriteLine("Result: " + sw.ElapsedMilliseconds + " ms");
Console.WriteLine("Average per lookup: " + (sw.Elapsed.TotalMicroseconds / 10000).ToString("F4") + " us");
Console.WriteLine("");
Console.WriteLine("TEST 2: Single IP lookup — IP at BOTTOM of file (10,000 times)");
sw.Restart();
for (int i = 0; i < 10000; i++)
BlockedIPManager.ShouldBlockIP("192.168.1.255");
sw.Stop();
Console.WriteLine("Result: " + sw.ElapsedMilliseconds + " ms");
Console.WriteLine("Average per lookup: " + (sw.Elapsed.TotalMicroseconds / 10000).ToString("F4") + " us");
Console.WriteLine("");
Console.WriteLine("TEST 3: Bulk add 1,000 new IPs");
var bulkIPs = Enumerable.Range(1, 1000)
.Select(i => $"10.10.{i / 256}.{i % 256}")
.ToArray();
sw.Restart();
BlockedIPManager.AddBlockIPs(bulkIPs);
sw.Stop();
Console.WriteLine("Result: " + sw.ElapsedMilliseconds + " ms");
Console.WriteLine("");
Console.WriteLine("TEST 4: Duplicate Protection");
string testIP = "77.77.77.77";
BlockedIPManager.ShouldBlockIP(testIP);
BlockedIPManager.ShouldBlockIP(testIP);
BlockedIPManager.ShouldBlockIP(testIP);
var count = File.ReadAllLines(@"c:\cmp\list11.txt")
.Count(l => l.Trim() == testIP);
Console.WriteLine(testIP + " appears in file: " + count + " time(s) (should be 1)");
Console.WriteLine("");
Console.WriteLine("TEST 5: Functional Check");
bool result1 = BlockedIPManager.ShouldBlockIP("123.45.67.89");
Console.WriteLine("TEST 5a - Existing IP blocked: " + result1);
bool result2 = BlockedIPManager.ShouldBlockIP("8.8.8.8");
Console.WriteLine("TEST 5b - New IP added: " + !result2);
bool result3 = BlockedIPManager.ShouldBlockIP("8.8.8.8");
Console.WriteLine("TEST 5c - Same IP now blocked: " + result3);
Console.ReadLine();
I hope you find this information helpful. Thank you.