C# run httplistener to act as service application asynchronously in console, semaphoreslim allow the max concurrent number
1.Run Visual Studio 2026 as Administrator;
2.Install-Package Newtonsoft.json;
using Newtonsoft.Json;
using System.Net;
using System.Text;
using System.Xml;
namespace ConsoleApp1
{
internal class Program
{
static async Task Main(string[] args)
{
await ListenHttpRequestAsync();
}
static async Task ListenHttpRequestAsync()
{
HttpListener httpListener = new HttpListener();
string prefix = "http://*:8080/";
httpListener.Prefixes.Add(prefix);
try
{
httpListener.Start();
Console.WriteLine($"{DateTime.Now},Http service started,address:{prefix}");
Console.WriteLine($"{DateTime.Now},sample:http://localhost:8080/getbookslist?count=1000");
Console.WriteLine($"{DateTime.Now},press Ctrl+C to stop service!");
while (true)
{
HttpListenerContext context = await httpListener.GetContextAsync();
await ProcessRequestAsync(context);
}
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now},start service failed:{ex.Message}");
Console.WriteLine($"If no permission.please run as administrator or update the port as greater than 1024");
}
finally
{
httpListener?.Close();
}
}
private static SemaphoreSlim concurrentLimit = new SemaphoreSlim(10,10);
private static async Task ProcessRequestAsync(HttpListenerContext context)
{
bool isAcquired = await concurrentLimit.WaitAsync(30000);
if (!isAcquired)
{
context.Response.StatusCode = 503;
string errorMsg = "{\"error\":\"Server busy, please retry later\"}";
byte[] buffer = Encoding.UTF8.GetBytes(errorMsg);
context.Response.ContentType = "application/json";
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
context.Response.OutputStream.Close();
return;
}
if (context?.Request?.Url?.AbsolutePath?.Contains("/favicon.ico") == true)
{
return;
}
try
{
int count = ParseCountFromRequest(context.Request);
if (count <= 0)
{
return;
}
string jsonStr = await GetJsonStrAsync(count);
context.Response.ContentType = "application/json;charset=utf-8";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.StatusCode = 200;
byte[] buffer = Encoding.UTF8.GetBytes(jsonStr);
context.Response.ContentLength64 = buffer.Length;
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
Console.WriteLine($"{DateTime.Now},request from:{context?.Request?.Url?.ToString()}," +
$"Thread Id:{Thread.CurrentThread.ManagedThreadId},length:{jsonStr.Length}\n\n");
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.Now},Process request failed:{ex.Message}");
context.Response.StatusCode = 500;
string errorMsg = $"{{\"error\":\"{ex.Message}\"}}";
byte[] buffer = Encoding.UTF8.GetBytes(errorMsg);
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
}
finally
{
if(isAcquired)
{
concurrentLimit.Release();
}
context.Response.OutputStream?.Close();
}
}
private static int ParseCountFromRequest(HttpListenerRequest request)
{
int cnt = 0;
string path = request.Url.AbsolutePath;
Console.WriteLine($"{DateTime.Now},request path:{request.Url.ToString()}");
if (path == "/getbookslist")
{
if (request.QueryString != null)
{
string countParam = request.QueryString["count"];
if (!string.IsNullOrWhiteSpace(countParam))
{
if (!int.TryParse(countParam, out cnt) || cnt < 1)
{
cnt = 0;
}
}
}
}
else if (path == "/getbook")
{
cnt = 100;
}
return cnt;
}
private static int id = 1;
private static (int, int) GetStartEnd(int interval)
{
int end = Interlocked.Add(ref id, interval);
int start = end - interval;
return (start, end);
}
static async Task<string> GetJsonStrAsync(int cnt = 1000000)
{
return await Task.Run(() =>
{
List<Book> bksList = new List<Book>();
var (start, end) = GetStartEnd(cnt);
for (int i = start; i < end; i++)
{
bksList.Add(new Book()
{
Id = i,
Name = $"Name_{i}",
ISBN = $"ISBN_{i}",
Author = $"Author_{i}",
Comment = $"Comment_{i}",
Content = $"Content_{i}",
Summary = $"Summary_{i}",
Title = $"Title_{i}",
Topic = $"Topic_{i}"
});
}
Console.WriteLine($"{DateTime.Now},Id bwtween:[{bksList.FirstOrDefault()?.Id}] and [{bksList.LastOrDefault()?.Id}]");
string jsonStr = JsonConvert.SerializeObject(bksList,Newtonsoft.Json.Formatting.None);
return jsonStr;
});
}
}
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string ISBN { get; set; }
public string Author { get; set; }
public string Comment { get; set; }
public string Content { get; set; }
public string Summary { get; set; }
public string Title { get; set; }
public string Topic { get; set; }
}
}
http://localhost:8080/getbookslist?count=10000

Consume by WPF
<Window x:Class="WpfApp3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp3" mc:Ignorable="d" Title="{Binding MainTitle}" WindowState="Maximized"> <Window.DataContext> <local:MainVM/> </Window.DataContext> <Grid> <DataGrid ItemsSource="{Binding BooksCollection}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.CacheLength="5,5" VirtualizingPanel.CacheLengthUnit="Item" ScrollViewer.IsDeferredScrollingEnabled="True" ScrollViewer.CanContentScroll="True" EnableRowVirtualization="True" EnableColumnVirtualization="True" UseLayoutRounding="True" SnapsToDevicePixels="True" AutoGenerateColumns="True" CanUserAddRows="False"> <DataGrid.Resources> <Style TargetType="DataGridRow"> <Setter Property="FontSize" Value="30"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="FontSize" Value="50"/> <Setter Property="Foreground" Value="Red"/> </Trigger> </Style.Triggers> </Style> </DataGrid.Resources> </DataGrid> </Grid> </Window> using Newtonsoft.Json; using System.Collections.ObjectModel; using System.ComponentModel; using System.Net.Http; using System.Runtime.CompilerServices; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace WpfApp3 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class MainVM : INotifyPropertyChanged { HttpClient client; string originalUrl = "http://localhost:8080/getbookslist?count="; private DispatcherTimer tmr; private bool isLoading = false; public MainVM() { if(!DesignerProperties.GetIsInDesignMode(new DependencyObject())) { client = new HttpClient(); Task.Run(async () => { await InitBooksCollectionAsync(); }); InitTmr(); } } private void InitTmr() { tmr = new DispatcherTimer(); tmr.Interval = TimeSpan.FromSeconds(10); tmr.Tick += async (s, e) => { await InitBooksCollectionAsync(); }; tmr.Start(); } private async Task InitBooksCollectionAsync(int cnt=1000000) { if(isLoading) { return; } isLoading = true; MainTitle = $"{DateTime.Now},loading..."; BooksCollection?.Clear(); try { string requestUrl = $"{originalUrl}{cnt}"; string jsonStr = await client.GetStringAsync(requestUrl); if (string.IsNullOrWhiteSpace(jsonStr)) { return; } List<Book>? bksList = JsonConvert.DeserializeObject<List<Book>>(jsonStr); if (bksList != null && bksList.Any()) { await Application.Current?.Dispatcher?.InvokeAsync(() => { BooksCollection = new ObservableCollection<Book>(bksList); MainTitle = $"{DateTime.Now}," + $"loaded {booksCollection.Count} items," + $"First Id:{BooksCollection[0]?.Id}," + $"Last Id:{BooksCollection[^1]?.Id}"; }, System.Windows.Threading.DispatcherPriority.Background); } } catch (Exception ex) { #if DEBUG System.Diagnostics.Debug.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}"); #else System.Diagnostics.Trace.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}"); #endif } finally { isLoading = false; } } private string mainTitle=$"{DateTime.Now}"; public string MainTitle { get { return mainTitle; } set { if(value!=mainTitle) { mainTitle = value; OnPropertyChanged(); } } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection; } set { if(value!=booksCollection) { booksCollection = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propName="") { var handler = Volatile.Read(ref PropertyChanged); if(handler==null) { return; } handler?.Invoke(this, new PropertyChangedEventArgs(propName)); } } public class Book { public int Id { get; set; } public string Name { get; set; } public string ISBN { get; set; } public string Author { get; set; } public string Comment { get; set; } public string Content { get; set; } public string Summary { get; set; } public string Title { get; set; } public string Topic { get; set; } } }



//The While true and await Task.Delay() instead of Timer to ensure completion
public class MainVM : INotifyPropertyChanged
{
HttpClient client;
string originalUrl = "http://localhost:8080/getbookslist?count=";
private DispatcherTimer tmr;
private bool isLoading = false;
public MainVM()
{
if(!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
client = new HttpClient();
//Task.Run(async () =>
//{
// await InitBooksCollectionAsync();
//});
//InitTmr();
Task.Run(async () =>
{
await LoadDataFromServerRelentless();
});
}
}
private void InitTmr()
{
tmr = new DispatcherTimer();
tmr.Interval = TimeSpan.FromSeconds(10);
tmr.Tick += async (s, e) =>
{
await InitBooksCollectionAsync();
};
tmr.Start();
}
private async Task LoadDataFromServerRelentless(int cnt=100000)
{
while(true)
{
try
{
await InitBooksCollectionAsync(cnt);
await Task.Delay(10000);
}
catch (Exception ex)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}");
#else
System.Diagnostics.Trace.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}");
#endif
}
}
}
private async Task InitBooksCollectionAsync(int cnt=1000000)
{
if(isLoading)
{
return;
}
isLoading = true;
MainTitle = $"{DateTime.Now},loading...";
await Application.Current?.Dispatcher?.InvokeAsync(() =>
{
BooksCollection?.Clear();
},DispatcherPriority.Background);
try
{
string requestUrl = $"{originalUrl}{cnt}";
string jsonStr = await client.GetStringAsync(requestUrl);
if (string.IsNullOrWhiteSpace(jsonStr))
{
return;
}
List<Book>? bksList = JsonConvert.DeserializeObject<List<Book>>(jsonStr);
if (bksList != null && bksList.Any())
{
await Application.Current?.Dispatcher?.InvokeAsync(() =>
{
BooksCollection = new ObservableCollection<Book>(bksList);
MainTitle = $"{DateTime.Now}," +
$"loaded {booksCollection.Count} items," +
$"First Id:{BooksCollection[0]?.Id}," +
$"Last Id:{BooksCollection[^1]?.Id}";
}, System.Windows.Threading.DispatcherPriority.Background);
}
}
catch (Exception ex)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}");
#else
System.Diagnostics.Trace.WriteLine($"{DateTime.Now},{ex?.Message},{ex?.StackTrace?.ToString()}");
#endif
}
finally
{
isLoading = false;
}
}
private string mainTitle=$"{DateTime.Now}";
public string MainTitle
{
get
{
return mainTitle;
}
set
{
if(value!=mainTitle)
{
mainTitle = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<Book> booksCollection;
public ObservableCollection<Book> BooksCollection
{
get
{
return booksCollection;
}
set
{
if(value!=booksCollection)
{
booksCollection = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName="")
{
var handler = Volatile.Read(ref PropertyChanged);
if(handler==null)
{
return;
}
handler?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}





浙公网安备 33010602011771号