DEV Community

RITHVIK SHAGA
RITHVIK SHAGA

Posted on

Building WebSessionForge: A Multi-Session WebView2 Browser & Proxy Testing Platform in .NET 8

I wanted to build something that would let me experiment with multiple isolated browser sessions, while also giving me control over the network environment behind each session.

That led to WebSessionForge — a Windows desktop application built with C# and .NET 8 that combines WebView2 browser sessions, proxy management, proxy health monitoring, proxy rotation, failure recovery, and structured runtime logging.

GitHub: https://github.com/shagarithvik/WebSessionForge


What Is WebSessionForge?

WebSessionForge is a browser-session and network testing platform.

It provides a central desktop interface for creating and managing multiple WebView2 sessions while independently managing their network assignments.

The core idea is:

                 WebSessionForge
                       │
          ┌────────────┼────────────┐
          │            │            │
          ▼            ▼            ▼
      Session 1    Session 2    Session N
          │            │            │
          ▼            ▼            ▼
       WebView2      WebView2      WebView2
          │            │            │
          ▼            ▼            ▼
       Proxy A      Proxy B      Proxy N
Enter fullscreen mode Exit fullscreen mode

The interesting engineering challenge isn't simply opening multiple browsers.

It is coordinating:

  • Browser lifecycle
  • Session isolation
  • Proxy allocation
  • Proxy health
  • Proxy rotation
  • Failure recovery
  • Concurrent operations
  • Runtime observability

Why I Built It

Browser automation becomes complicated when network infrastructure is part of the test.

A session can fail because:

  • A proxy becomes unavailable
  • A provider returns malformed data
  • A connection times out
  • A browser session encounters an error
  • Multiple sessions compete for the same proxy
  • Network conditions change during execution

I wanted these responsibilities separated instead of putting everything into one large automation class.

The resulting architecture became:

Browser Sessions
       │
       ├── Session lifecycle
       │
       ├── Proxy assignment
       │
       ├── Proxy health
       │
       ├── Failure recovery
       │
       └── Logging
Enter fullscreen mode Exit fullscreen mode

Technology Stack

Component Technology
Language C#
Framework .NET 8
Desktop UI WPF
Browser Microsoft Edge WebView2
Configuration JSON
Proxy input CSV / Provider endpoints
Logging JSONL
Platform Windows 10/11

Architecture

The application is organized around several major components:

                         ┌─────────────────────┐
                         │   WebSessionForge   │
                         │     WPF Dashboard   │
                         └──────────┬──────────┘
                                    │
              ┌─────────────────────┼─────────────────────┐
              │                     │                     │
              ▼                     ▼                     ▼
       Session Manager        Proxy Manager           Logger
              │                     │                     │
              │              ┌──────┴──────┐              │
              │              │             │              │
              ▼              ▼             ▼              ▼
        WebView2        CSV Import    Providers       JSONL Logs
        Sessions             │             │
              │              └──────┬──────┘
              │                     │
              └──────────────┬──────┘
                             ▼
                       Proxy Pool
Enter fullscreen mode Exit fullscreen mode

The main principle is separation of responsibilities.


🔧 Concrete Implementation Walkthrough

This is where the architecture becomes practical.

The following walkthrough shows how the major pieces fit together conceptually in C#.

The exact class names and implementation details may evolve as the project develops; the snippets illustrate the intended implementation pattern.


1. Define a Proxy Model

Everything starts with a common representation for a proxy.

Instead of passing strings throughout the application, represent a proxy as an object.

public sealed class ProxyInfo
{
    public string Host { get; init; } = string.Empty;
    public int Port { get; init; }

    public string Scheme { get; init; } = "http";

    public string? Username { get; init; }
    public string? Password { get; init; }

    public string? Provider { get; init; }

    public TimeSpan? Latency { get; set; }

    public bool IsHealthy { get; set; }

    public int FailureCount { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Now every subsystem can work with the same structure.

For example:

CSV
 │
 ▼
ProxyInfo
 │
 ├── Health Checker
 ├── Proxy Pool
 ├── Session Manager
 └── Logger
Enter fullscreen mode Exit fullscreen mode

This is much cleaner than passing raw strings between services.


2. Normalize Proxy Input

Different proxy sources can produce different formats.

For example:

http://host:8080
Enter fullscreen mode Exit fullscreen mode

or:

host,8080,http,user,password
Enter fullscreen mode Exit fullscreen mode

The importer converts these into the same internal model.

Conceptually:

ProxyInfo ParseProxy(string value)
{
    // Parse scheme, host, port and optional credentials.
    // Normalize the result into ProxyInfo.
}
Enter fullscreen mode Exit fullscreen mode

The important design principle is:

Normalize at the boundary.

Once a proxy enters the application, the rest of the system should not care where it came from.


3. Build the Proxy Pool

The proxy manager maintains the available proxies.

Conceptually:

private readonly List<ProxyInfo> _proxies = new();
Enter fullscreen mode Exit fullscreen mode

Adding a proxy becomes:

public void Add(ProxyInfo proxy)
{
    if (!_proxies.Any(p =>
        p.Host == proxy.Host &&
        p.Port == proxy.Port &&
        p.Scheme == proxy.Scheme))
    {
        _proxies.Add(proxy);
    }
}
Enter fullscreen mode Exit fullscreen mode

This gives the application a central location for:

  • Deduplication
  • Health state
  • Assignment
  • Release
  • Replacement

4. Health Check the Proxy

A proxy shouldn't automatically become available just because it was parsed successfully.

The health-check layer tests connectivity.

A simplified conceptual implementation is:

public async Task<bool> CheckAsync(
    ProxyInfo proxy,
    CancellationToken cancellationToken)
{
    try
    {
        using var client = CreateClient(proxy);

        using var response = await client.GetAsync(
            TestEndpoint,
            cancellationToken);

        proxy.IsHealthy = response.IsSuccessStatusCode;

        return proxy.IsHealthy;
    }
    catch
    {
        proxy.IsHealthy = false;
        proxy.FailureCount++;

        return false;
    }
}
Enter fullscreen mode Exit fullscreen mode

The actual implementation needs to account for the proxy protocol and appropriate timeout behavior.

The important flow is:

Proxy
  │
  ▼
Connectivity Test
  │
 ┌┴─────────┐
 ▼          ▼
Healthy    Failed
 │          │
 ▼          ▼
Pool       Remove/Retry
Enter fullscreen mode Exit fullscreen mode

5. Reserve a Proxy for a Session

Once healthy proxies exist, sessions need to obtain them safely.

A simple conceptual abstraction is:

public ProxyInfo? Acquire()
{
    lock (_sync)
    {
        var proxy = _proxies
            .FirstOrDefault(p =>
                p.IsHealthy &&
                !IsReserved(p));

        if (proxy == null)
            return null;

        Reserve(proxy);

        return proxy;
    }
}
Enter fullscreen mode Exit fullscreen mode

The important part here is synchronization.

Without it, two sessions could perform:

Session A → find Proxy A
Session B → find Proxy A
Enter fullscreen mode Exit fullscreen mode

before either session marks it as reserved.

With synchronized allocation:

Proxy Pool
    │
    ├── Proxy A → Session 1
    ├── Proxy B → Session 2
    └── Proxy C → Available
Enter fullscreen mode Exit fullscreen mode

This becomes particularly important as the number of concurrent sessions increases.


6. Create a WebView2 Session

A session manager can then create a browser environment for the assigned session.

Conceptually:

public sealed class BrowserSession
{
    public string Id { get; }
    public ProxyInfo? Proxy { get; }

    public BrowserSession(
        string id,
        ProxyInfo? proxy)
    {
        Id = id;
        Proxy = proxy;
    }
}
Enter fullscreen mode Exit fullscreen mode

The lifecycle becomes:

Create Session
      │
      ▼
Acquire Proxy
      │
      ▼
Create WebView2 Environment
      │
      ▼
Initialize Browser
      │
      ▼
Navigate
Enter fullscreen mode Exit fullscreen mode

WebView2 itself then becomes the browser execution layer, while the session manager controls the higher-level lifecycle.


7. Keep Session State Separate

Each session should have an identity.

For example:

var sessionId = $"session-{index}";
Enter fullscreen mode Exit fullscreen mode

The session can then be associated with:

Session ID
Proxy
Browser Environment
Status
Created Time
Log File
Enter fullscreen mode Exit fullscreen mode

That makes it possible to answer questions like:

Which proxy was assigned to Session 4 when the failure occurred?

This becomes extremely useful during debugging.


8. Start Multiple Sessions

The dashboard can coordinate multiple sessions.

Conceptually:

for (int i = 0; i < sessionCount; i++)
{
    var session = await sessionManager.CreateAsync(
        $"session-{i + 1}");

    sessions.Add(session);
}
Enter fullscreen mode Exit fullscreen mode

In a production implementation, these operations need proper asynchronous lifecycle management rather than blindly creating everything at once.

The overall flow becomes:

Dashboard
    │
    ▼
Session Manager
    │
    ├── Session 1
    ├── Session 2
    ├── Session 3
    └── Session N
Enter fullscreen mode Exit fullscreen mode

9. Handle Proxy Failure

Suppose Session 2 is currently using Proxy B.

A network operation fails.

The session manager can perform:

Session 2
   │
   ▼
Network Failure
   │
   ▼
Mark Proxy B Failed
   │
   ▼
Release Proxy B
   │
   ▼
Acquire Replacement
   │
   ▼
Proxy C
Enter fullscreen mode Exit fullscreen mode

Conceptually:

public async Task<bool> ReplaceProxyAsync(
    BrowserSession session)
{
    Release(session.Proxy);

    var replacement = Acquire();

    if (replacement == null)
        return false;

    session.SetProxy(replacement);

    return true;
}
Enter fullscreen mode Exit fullscreen mode

The exact WebView2 reconfiguration strategy depends on the session lifecycle and browser environment implementation.

The important architectural idea is that proxy failure is handled by the session/proxy layers rather than the UI.


10. Implement Rotation

Rotation can be represented as an asynchronous background operation.

Conceptually:

while (!cancellationToken.IsCancellationRequested)
{
    await Task.Delay(rotationInterval, cancellationToken);

    await RotateSessionAsync(session);
}
Enter fullscreen mode Exit fullscreen mode

The rotation process is:

Wait
 │
 ▼
Rotation Due
 │
 ▼
Release Current Proxy
 │
 ▼
Acquire Replacement
 │
 ▼
Update Session
 │
 ▼
Log Event
 │
 ▼
Continue
Enter fullscreen mode Exit fullscreen mode

A jitter value can be applied around the configured interval when the testing scenario requires variation.


11. Structured Logging

Instead of writing arbitrary strings:

"proxy failed"
Enter fullscreen mode Exit fullscreen mode

the application can record structured events.

Conceptually:

await logger.WriteAsync(new
{
    Timestamp = DateTimeOffset.UtcNow,
    Event = "ProxyFailure",
    SessionId = session.Id,
    Proxy = proxy.Host,
    Port = proxy.Port
});
Enter fullscreen mode Exit fullscreen mode

The result can be stored as JSONL:

{
  "timestamp": "2026-10-02T12:00:00Z",
  "event": "ProxyFailure",
  "sessionId": "session-2",
  "proxy": "proxy.example",
  "port": 8080
}
Enter fullscreen mode Exit fullscreen mode

Now logs can be filtered programmatically.

For example:

All failures
All events for Session 2
All proxy rotations
All health-check failures
Enter fullscreen mode Exit fullscreen mode

12. Connect the UI

The WPF dashboard acts as the orchestration layer.

Conceptually:

MainWindow
    │
    ├── Start
    │      ↓
    │   SessionManager
    │
    ├── Stop
    │      ↓
    │   SessionManager
    │
    ├── Proxy Status
    │      ↓
    │   ProxyManager
    │
    ├── Browser Matrix
    │      ↓
    │   Active Sessions
    │
    └── Logs
           ↓
        Logger
Enter fullscreen mode Exit fullscreen mode

The UI should display state rather than contain the business logic itself.

That distinction becomes increasingly important as the project grows.


13. Configuration-Driven Behavior

Runtime settings belong in configuration rather than hardcoded constants.

For example:

{
  "SessionCount": 6,
  "RotationMinutes": 5,
  "RotationJitterSeconds": 30,
  "ProxyHealthTimeoutSeconds": 10,
  "ProviderRefreshMinutes": 5,
  "ProviderUrls": [],
  "Headless": false
}
Enter fullscreen mode Exit fullscreen mode

The application can load this during startup:

var json = await File.ReadAllTextAsync(
    "config/config.json");

var config = JsonSerializer.Deserialize<AppConfig>(json);
Enter fullscreen mode Exit fullscreen mode

The result is passed to the relevant services.

Configuration
      │
      ├── Session Manager
      ├── Proxy Manager
      ├── Health Checker
      └── Provider Manager
Enter fullscreen mode Exit fullscreen mode

This makes behavior reproducible and easier to modify.


14. Complete Runtime Flow

Putting everything together:

                    START
                      │
                      ▼
               Load Configuration
                      │
                      ▼
              Load Proxy Sources
                      │
                      ▼
              Normalize Proxies
                      │
                      ▼
                Health Checks
                      │
             ┌────────┴────────┐
             ▼                 ▼
          Healthy             Failed
             │                 │
             ▼                 ▼
        Proxy Pool          Excluded
             │
             ▼
       Create Session
             │
             ▼
       Acquire Proxy
             │
             ▼
       Create WebView2
             │
             ▼
          Navigate
             │
             ▼
           Monitor
             │
       ┌─────┴──────┐
       ▼            ▼
    Healthy       Failure
       │            │
       │            ▼
       │       Mark Proxy Failed
       │            │
       │            ▼
       │       Acquire Replacement
       │
       ▼
   Rotation Due
       │
       ▼
   Rotate Proxy
       │
       ▼
     Continue
Enter fullscreen mode Exit fullscreen mode

This is the core of WebSessionForge.


Proxy Provider Pipeline

Provider integration follows the same architecture.

Provider URL
     │
     ▼
HTTP Request
     │
     ▼
Response
     │
     ▼
Format Detection
     │
 ┌───┼──────────┐
 ▼   ▼          ▼
JSON Text     Object
 │    │          │
 └────┴──────────┘
          │
          ▼
      Proxy Parser
          │
          ▼
      ProxyInfo[]
          │
          ▼
      Proxy Manager
Enter fullscreen mode Exit fullscreen mode

The provider layer therefore doesn't need to know anything about browser sessions.

It simply supplies normalized proxy objects.


Failure Isolation

One of the most important architectural goals is preventing one failure from cascading into everything else.

For example:

Proxy A fails
     │
     ▼
Session 1 affected
     │
     ├── Proxy A marked failed
     ├── Proxy A removed
     └── Replacement requested
Enter fullscreen mode Exit fullscreen mode

Instead of:

Proxy A fails
     │
     ▼
Entire application crashes
Enter fullscreen mode Exit fullscreen mode

The system treats failures as local events whenever possible.


Browser Matrix Implementation Concept

The browser matrix is essentially a presentation layer over the active sessions.

Conceptually:

Observable Session Collection
          │
          ▼
      Browser Matrix
          │
    ┌─────┼─────┐
    ▼     ▼     ▼
 Session Session Session
    1      2      3
Enter fullscreen mode Exit fullscreen mode

Each visual container can host the corresponding WebView2 control.

This provides an easy way to inspect the state of multiple sessions without losing the central dashboard.


Observability Architecture

The logging architecture can be visualized as:

Session Manager ──────┐
                      │
Proxy Manager ────────┤
                      ├──► Logger ───► JSONL
Health Checker ───────┤
                      │
Provider Manager ─────┘
Enter fullscreen mode Exit fullscreen mode

This is useful because logging remains centralized.

A session doesn't need to know where logs are stored.

It simply emits an event.

The logger handles persistence.


Performance Considerations

Multiple WebView2 instances are considerably more expensive than simple HTTP clients.

Resource consumption depends on:

Session Count
      +
Page Complexity
      +
JavaScript
      +
Network Activity
      +
Proxy Latency
      +
CPU
      +
RAM
Enter fullscreen mode Exit fullscreen mode

For that reason, the recommended development workflow is:

1 session
   ↓
2 sessions
   ↓
4 sessions
   ↓
6 sessions
   ↓
Scale gradually
Enter fullscreen mode Exit fullscreen mode

This makes it easier to identify the point where resource consumption becomes problematic.


Project Structure

The project follows a modular layout:

WebSessionForge/
│
├── Models/
│
├── Providers/
│
├── Services/
│
├── config/
│
├── logs/
│
├── App.xaml
├── App.xaml.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── BrowserWindow.xaml
├── BrowserWindow.xaml.cs
├── WebSessionForge.csproj
├── DOCUMENTATION.md
├── README.md
└── LICENSE
Enter fullscreen mode Exit fullscreen mode

The intended responsibility boundaries are:

Directory Responsibility
Models/ Domain/application models
Providers/ External proxy sources
Services/ Session, proxy, health and logging logic
config/ Runtime configuration
logs/ Runtime event data
*.xaml WPF interface

Configuration

The main configuration file is:

config/config.json
Enter fullscreen mode Exit fullscreen mode

Example:

{
  "SessionCount": 6,
  "RotationMinutes": 5,
  "RotationJitterSeconds": 30,
  "ProxyHealthTimeoutSeconds": 10,
  "ProviderRefreshMinutes": 5,
  "ProviderUrls": [],
  "Headless": false
}
Enter fullscreen mode Exit fullscreen mode

Important options:

Setting Purpose
SessionCount Number of browser sessions
RotationMinutes Proxy rotation interval
RotationJitterSeconds Rotation variation
ProxyHealthTimeoutSeconds Health-check timeout
ProviderRefreshMinutes Provider refresh
ProviderUrls Provider endpoints
Headless Headless configuration

Logging

WebSessionForge uses JSON Lines.

Application logs:

logs/application-YYYY-MM-DD.jsonl
Enter fullscreen mode Exit fullscreen mode

Session logs:

logs/session-1-YYYY-MM-DD.jsonl
logs/session-2-YYYY-MM-DD.jsonl
logs/session-3-YYYY-MM-DD.jsonl
Enter fullscreen mode Exit fullscreen mode

Events can include:

  • Session creation
  • Session termination
  • Proxy assignment
  • Proxy rotation
  • Health checks
  • Failures
  • Retries
  • Recovery
  • Runtime errors

Structured logs make concurrent browser testing much easier to investigate.


Running the Project

Requirements:

  • Windows 10/11
  • .NET 8 SDK
  • Microsoft Edge WebView2 Runtime

Clone:

git clone https://github.com/shagarithvik/WebSessionForge.git
Enter fullscreen mode Exit fullscreen mode

Build:

cd WebSessionForge
dotnet restore
dotnet build
Enter fullscreen mode Exit fullscreen mode

Run:

dotnet run
Enter fullscreen mode Exit fullscreen mode

Publish:

dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:DebugType=None
Enter fullscreen mode Exit fullscreen mode

Testing Scenarios

WebSessionForge is useful for controlled testing of:

Session Isolation

Verify independent browser state.

Proxy Reliability

Observe behavior when a network endpoint becomes unavailable.

Proxy Rotation

Test session behavior when network assignments change.

Failure Recovery

Verify replacement and recovery workflows.

Provider Reliability

Test malformed or unavailable provider responses.

Observability

Reconstruct a test run from structured JSONL events.


What I Learned

Browser sessions are expensive

A browser environment is much heavier than an HTTP client.

Network failures are normal

Proxy infrastructure should be designed around failure.

Health checks are not guarantees

A successful check only tells us that a proxy worked at that particular moment.

Logging matters

Concurrent systems become difficult to debug without structured events.

Separation matters

Keeping the UI, session manager, proxy manager, providers, and logger independent makes the project easier to maintain.


Responsible Use

WebSessionForge is intended for authorized testing and experimentation.

Use it with systems and infrastructure where you have permission.

It should not be used to:

  • Manipulate platform metrics
  • Generate artificial engagement
  • Circumvent access controls
  • Evade anti-bot systems
  • Bypass rate limits
  • Access systems without authorization
  • Abuse third-party infrastructure

The project is intended as a browser-session and QA/testing platform.


Roadmap

Architecture

  • [ ] Further MVVM adoption
  • [ ] Dependency injection
  • [ ] More interfaces
  • [ ] Improved testability

Proxy System

  • [ ] Provider health scoring
  • [ ] Advanced proxy statistics
  • [ ] Better failure classification
  • [ ] Improved validation

Browser Sessions

  • [ ] Improved WebView2 lifecycle
  • [ ] Configurable profiles
  • [ ] Session telemetry
  • [ ] Performance metrics

Testing

  • [ ] Unit tests
  • [ ] Integration tests
  • [ ] Mock proxy provider
  • [ ] Local test infrastructure

Developer Experience

  • [ ] CI/CD
  • [ ] Automated releases
  • [ ] Configuration validation
  • [ ] Exportable reports

Why WebSessionForge?

The name reflects the direction of the project.

WebSession represents the primary unit of the platform.

Forge represents creating and managing controlled browser-session environments.

The project started around proxy-backed browser experimentation, but the architecture is broader:

Browser Sessions
       +
Network Conditions
       +
Testing
       +
Observability
       +
Automation
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

WebSessionForge started as an experiment around multiple browser sessions and proxy management.

It has evolved into a small platform for studying how:

  • Browser environments
  • Network conditions
  • Failure recovery
  • Concurrency
  • Observability

interact in a real desktop application.

The most important lesson has been simple:

Reliable automation isn't just about making something work. It's about making failures understandable and recoverable.

That's the direction I want to continue taking WebSessionForge.


🔗 Project

GitHub:
https://github.com/shagarithvik/WebSessionForge

Author:
Rithvik Shaga

Stack:
C# · .NET 8 · WPF · WebView2

License:
MIT


⭐ Get Involved

The repository is open source.

Feedback and contributions around:

  • Architecture
  • WebView2
  • Session management
  • Proxy infrastructure
  • Reliability
  • Performance
  • Testing
  • Observability

are welcome.

GitHub: https://github.com/shagarithvik/WebSessionForge


Built with C# • .NET 8 • WPF • WebView2

Top comments (0)