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

 

 

 

 

image

 

 

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; }
    }
}

 

 

 

image

 

image

 

 

 

image

 

 

//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));
        }
    }

 

 

 

image

 

 

image

 

 

image

 

 

image

 

posted @ 2026-06-13 15:18  FredGrit  阅读(2)  评论(0)    收藏  举报