European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core 10.0 Hosting - HostForLIFE :: ASP.NET Core Service Lifetimes: Transient, Scoped, and Singleton

clock June 26, 2025 07:56 by author Peter

Dependency Injection (DI) is a potent feature in ASP.NET Core that aids programmers in creating loosely linked, tested, and maintainable applications. Understanding how services are handled over time is a crucial component of this system, and this is where Service Lifetimes enter the picture.

A Service Lifetime determines how long an instance of a service will live once it's created by the built-in IoC (Inversion of Control) container.

When a service is registered in the Program.cs (or Startup.cs in older versions), we must specify its lifetime. This decision directly affects.

  • When the service instance is created
  • How long will it be reused
  • Whether it's shared across requests, users, or components

"How long will the instance of the service live?" and "When will a new instance be created?"

There are 3 built-in lifetimes.

Lifetime Description
Transient New instance every time it is requested.
Scoped One instance per HTTP request (or scope).
Singleton One instance for the entire lifetime of the application..

Before diving into service lifetimes, it's very important to understand the core concepts.

Before diving into service lifetimes, it's very important to understand the core concepts.

  • Dependency Injection (DI)
  • Inversion of Control (IoC)

What is Dependency Injection (DI)?
Dependency Injection is a design pattern used to provide an object’s dependencies from the outside, instead of creating them inside the object itself.
Dependency = Another class or object that your class needs to function.
Injection = Supplying those dependencies externally.

Imagine you're a chef who needs ingredients to cook.

  • Without DI, the chef goes out to the farm, harvests the vegetables, and then cooks.
  • With DI, someone delivers the fresh ingredients to the chef so they can focus on cooking.

DI = Someone gives you what you need. You don’t fetch it yourself.
Without DI (tight coupling)
public class Car
{
    private Engine _engine = new Engine();  // Car creates its own engine

    public void Drive()
    {
        _engine.Start();
    }
}


Problem

  • Hard to test
  • Can’t swap the Engine with the electric engine easily
  • Tight coupling

With DI (loose coupling)
public class Car
{
    private readonly IEngine _engine;

    public Car(IEngine engine)  // Engine is "injected" from outside
    {
        _engine = engine;
    }

    public void Drive()
    {
        _engine.Start();
    }
}


Now we can,

  • Inject any IEngine implementation
  • Test easily (mock the engine)
  • Change logic without touching the Car class

What is Inversion of Control (IoC)?
Inversion of Control is a broader principle. It means that the control of creating and managing objects is inverted — from the class to a container or framework. In simpler terms.
Instead of our code controlling how things are created, the framework (like ASP.NET Core) does it for us.

Example of IoC
We register services in a container.
services.AddScoped<ICarService, CarService>();

Then our controller.
public class HomeController : Controller
{
    private readonly ICarService _carService;

    public HomeController(ICarService carService) // Injected by framework
    {
        _carService = carService;
    }
}


We didn’t create CarService the IoC container did and gave it to us!

Relationship Between DI and IoC

Concept Meaning Who Manages Creation
IoC Inverting object creation/control Framework/Container
DI A way to implement IoC by injecting dependencies The framework injects what you need

So, Dependency Injection is a technique used to achieve Inversion of Control.

  • IoC: Framework creates and manages the object
  • DI: The Controller gets the service it needs without creating it

Why Are Service Lifetimes Important?
Choosing the correct service lifetime is essential for,

  • Memory management: Avoid unnecessary object creation
  • Performance optimization: Reuse objects when appropriate
  • Thread safety prevents state corruption in multi-user scenarios
  • Correct behavior, especially when services maintain data like a database context
  • Prevents data leaks by isolating instances.
  • Promotes cleaner architecture via proper dependency reuse.

Types of Service Lifetimes in .NET Core
.NET provides three main service lifetimes.

  • Transient: A new instance is created every time the service is requested.
  • Scoped: A single instance is created per HTTP request and shared within that request.
  • Singleton: A single instance is created once and shared across the entire application.

Choosing the correct lifetime ensures better performance, resource management, and application behavior.

Where Are Lifetimes Defined?
Lifetimes are defined when registering services in the Program.cs file.
builder.Services.AddTransient<IMyService, MyService>();   // Transient
builder.Services.AddScoped<IMyService, MyService>();      // Scoped
builder.Services.AddSingleton<IMyService, MyService>();   // Singleton

Service Lifetime Differences in ASP.NET Core

Feature / Criteria Transient Scoped Singleton
Object Creation Every time it is requested Once per HTTP request Once for the entire application
Shared Between Never shared Shared within one request Shared across all requests and components
Reuse Behavior New instance for every injection Same instance reused during one request Same instance reused everywhere
Lifetime Ends Immediately after use End of the HTTP request When the app shuts down
Thread-Safety Required No (short-lived) No (request-specific) Yes (used by multiple threads)
Testing Use Case Best for isolated tests Good for per-request logic Good for app-level state
Best For Lightweight, stateless services Entity Framework DbContext, per-user logic Logging, Caching, Configuration
Common Pitfall High object creation cost Cannot be injected into a Singleton Memory leaks or shared state issues

Best Practices for Choosing Service Lifetimes in .NET

Scenario Recommended Lifetime Real Example Explanation
Stateless utility like a formatter/calculator Transient PriceFormatterService Creates a new instance each time — ideal for small, stateless services like currency formatting or calculations.
Database access, user session services Scoped ApplicationDbContext, UserService Ensures consistency within a single HTTP request — needed for services handling DB transactions or per-user data.
Global logger, configuration, and caching Singleton LoggerService, ConfigProvider Created once and reused across the app — perfect for shared logic like logging or reading global settings.

What Happens If We Choose the Wrong Lifetime?

1. Scoped Service Injected into Singleton

  • Problem: Scoped services (like DbContext) are created per request. A Singleton lives for the entire app.
  • What Happens: .NET throws a runtime error InvalidOperationException.
  • Why: A Singleton can't depend on something that changes per request.

2. Storing Large Data in a Singleton

  • Problem: Singleton services stay alive for the app's entire lifetime.
  • What Happens: If you store large data (e.g., thousands of records), it causes memory leaks or slow performance.
  • Why: Data is never released from memory.

3. Using Transient for Expensive or Stateful Services

  • Problem: Transient creates a new instance every time.
  • What Happens: Extra memory usage, duplicate work (like database connections or API calls), and inconsistent behavior.
  • Why: Data/state is not shared between calls.

4. Expecting Transient or Scoped to Act Like Singleton

  • Problem: Assuming the service "remembers" data across requests or injections.ASP.NET Core Service Lifetimes: Transient, Scoped, and Singleton
  • What Happens: Data is lost or reset unexpectedly.
  • Why: Scoped lasts only one request, and Transient lasts only one use.

Conclusion
Understanding Service Lifetimes in .NET is essential for building efficient, scalable, and maintainable applications. By mastering Dependency Injection and properly choosing between Transient, Scoped, and Singleton lifetimes, you can control how services behave, improve app performance, and avoid bugs related to memory leaks or shared state. Always start with Transient unless your scenario calls for Scoped or Singleton. Use Scoped for request-based operations like database access, and use Singleton cautiously for shared logic like configuration or logging, while ensuring thread safety. With the right service lifetime choices and a solid understanding of DI and IoC, your ASP.NET Core applications will be more testable, modular, and cleanly architected.

HostForLIFE ASP.NET Core 10.0 Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: Monitoring of Entity Framework Changes

clock June 23, 2025 09:10 by author Peter

We shall study Entity Framework Change Tracking in this article. Now, let's get going.

Comprehending Change Tracking

EF Core uses a technology called change tracking to monitor modifications made to your entities. This aids EF Core in figuring out which SQL commands must be run in order to maintain database changes.

Example
using (var context = new AppDbContext())
  {
      var employee = context.Employees.FirstOrDefault(e => e.EmployeeId == 101);
      employee.City = "Mumbai";

      // EF Core tracks the change in the City property.
  }


Managing the State of Entities
EF Core tracks the state of each entity (Added, Unchanged, Modified, Deleted) to determine the operations to be performed during SaveChanges.
using (var context = new AppDbContext())
  {
      var employee = context.Employees.FirstOrDefault(e => e.EmployeeId == 101);
      context.Entry(employee).State = EntityState.Modified;
      context.SaveChanges();

      // The state is set to Modified, prompting and UPDATE command
  }

Using No-Tracking Queries
No-tracking queries improve performance for read-only operations by not tracking the entities in the context. This reduces memory usage and speeds up query execution.
using (var context = new AppDbContext())
  {
      var employees = context.Employees.AsNoTracking().ToList();

      // No change tracking is performed, ideal for read-only operations
  }


Benefits of No-Tracking Queries

  • Performance: Faster queries and lower memory footprint.
  • Scalability: Better for large-scale read operations.
  • Simplicity: Reduces overhead when changes to entities are not needed


using (var context = new AppDbContext())
  {
      var employees = context.Employees.AsNoTracking().FirstOrDefault(e => e.EmployeeId == 101);

      // Efficiently retrieves the post without tracking it's state
  }


Summary

  • Change Tracking: Tracks changes to determine necessary database operations.
  • Entity State Management: Manages entity states for accurate database updates.
  • No-Tracking Queries: Optimizes performance for read-only operations.

In this article, I have tried to cover how to handle Entity Framework Change Tracking.

HostForLIFE ASP.NET Core 10.0 Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: LINQ's FirstOrDefault and SingleOrDefault: Important Distinctions and Applications

clock June 17, 2025 08:06 by author Peter

In this article, we explore the key differences between FirstOrDefault and SingleOrDefault in LINQ. You'll learn how each method behaves, the scenarios where they are best applied, and when to choose one over the other. By the end, you’ll gain clarity on how to use them effectively to write cleaner and more efficient LINQ queries in your C# applications. Understanding the correct usage of these methods helps you avoid common runtime errors, improve application performance, and maintain predictable code behavior. Always perform null checks when working with reference types, and use SingleOrDefault() cautiously in performance-critical sections of your code.

In this short and simple guide, we’ll explain the key differences, show you when to use each one, and help you avoid common mistakes in real-life coding situations.

What is FirstOrDefault()?
FirstOrDefault() returns the first element of a sequence or the default value (e.g., null for reference types) if no element is found.

Use Cases

  • When multiple results are expected, but you want just the first match.
  • When the sequence can be empty.
  • When performance is a concern and early exit is ideal.

Code Example
var firstProduct = products.FirstOrDefault(p => p.Price > 100);

What is SingleOrDefault()?
SingleOrDefault() returns exactly one element that matches the condition or the default value if no match is found. It throws an exception if more than one element is found.
var uniqueProduct = products.SingleOrDefault(p => p.Id == 101);

Use Cases

  • When you expect only one matching result.
  • Ideal for unique identifiers, like primary keys.
  • Use it when data integrity is important and duplicates are unexpected.

FirstOrDefault vs. SingleOrDefault

Feature FirstOrDefault SingleOrDefault
Returns First match or default Single match or default
Throws if multiple matches? ❌ No ✅ Yes
Use case First matching item Exactly one expected match
Performance Stops at the first match Scans all items to validate uniqueness


Performance Considerations

  • FirstOrDefault() stops evaluating after the first match — faster on large datasets.
  • SingleOrDefault() must scan the entire sequence to ensure there's only one match — slower if the collection is large.

Best Practices

  • Use SingleOrDefault(): only when data constraints guarantee that at most one element can satisfy the condition.
  • Prefer FirstOrDefault(): When multiple matches are possible and you only need the first occurrence, or can handle a missing result.
  • Always perform a null check: after using either method when working with reference types to prevent NullReferenceException.
  • Minimize the use of SingleOrDefault(): In performance-sensitive operations, it must evaluate the entire collection to ensure uniqueness.

Summary
In LINQ, both FirstOrDefault() and SingleOrDefault() are used to retrieve elements from a collection, but they serve different purposes. FirstOrDefault() returns the first matching element or a default value if none is found—ideal when multiple matches are possible. On the other hand, SingleOrDefault() ensures only one match exists and throws an exception if multiple results are found, making it suitable for unique identifiers or strict data constraints.

HostForLIFE ASP.NET Core 10.0 Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: How to Build ASP.NET Core Background Tasks?

clock June 10, 2025 08:23 by author Peter

A crucial prerequisite for contemporary ASP.NET Core applications is background processing, particularly for those that use microservices. Background services are crucial for tasks like email sending, Kafka message processing, cron-type processes, and managing lengthy workflows.

With the introduction of the Generic Host and robust improvements in .NET 6, 7, and 8, ASP.NET Core now provides powerful patterns through:

  • IHostedService
  • BackgroundService
  • Worker Service templates

This article dives deep into how to design, build, and optimize background services for production.

Worker Services vs Hosted Services: What’s the Difference?

Feature IHostedService BackgroundService Worker Service Template
Interface-based Yes Yes (abstracts IHostedService) Yes (project template-based)
Long-running support Needs manual implementation Provides an infinite loop (ExecuteAsync) Yes
Best for Short-lived or event-based tasks Long-running background jobs Standalone background apps

Setting Up a Worker Service Project

You can create a worker service using.
dotnet new worker -n EmailBackgroundService

This creates a ready-to-run worker template using the Generic Host.

The Program.cs in .NET 8+ is minimal.
var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        services.AddHostedService<EmailSenderWorker>();
    })
    .Build();

await host.RunAsync();


Creating a Custom BackgroundService
Here’s a simple example of a background worker.
public class EmailSenderWorker : BackgroundService
{
    private readonly ILogger<EmailSenderWorker> _logger;

    public EmailSenderWorker(ILogger<EmailSenderWorker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Sending queued emails at: {time}", DateTimeOffset.Now);
            await SendPendingEmails();
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }

    private Task SendPendingEmails()
    {
        // Implement actual email logic here
        return Task.CompletedTask;
    }
}

Advanced Hosted Services with IHostedService
When you need fine-grained control over start/stop behavior (e.g., for message queue consumers).
public class KafkaConsumerService : IHostedService
{
    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Connect to Kafka and begin consuming
        return Task.Run(() => ConsumeMessages(cancellationToken), cancellationToken);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // Cleanup, disconnect
        return Task.CompletedTask;
    }

    private void ConsumeMessages(CancellationToken cancellationToken)
    {
        // Poll Kafka and process messages
    }
}


Managing Multiple Background Services

You can register multiple services easily.
services.AddHostedService<EmailSenderWorker>();
services.AddHostedService<KafkaConsumerService>();
services.AddHostedService<DataSyncWorker>();


Each runs independently inside the host.

Handling Exceptions & Graceful Shutdown

To avoid crashing the entire app due to unhandled exceptions in workers.
try
{
    await SomeBackgroundTask();
}
catch (Exception ex)
{
    _logger.LogError(ex, "An error occurred.");
}


For graceful shutdown, ensure your workers respond to the CancellationToken from ExecuteAsync.

Dependency Injection in Background Services
Services are injected normally.
public class DataSyncWorker : BackgroundService
{
    private readonly IDataService _dataService;

    public DataSyncWorker(IDataService dataService)
    {
        _dataService = dataService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await _dataService.SyncExternalData();
    }
}

Scheduling and Cron-like Jobs
For scheduled tasks, consider:

  • Quartz.NET for CRON jobs.
  • Hangfire for background jobs with retry support.
  • Or a Timer-based service with Task.Delay.

Example using the Cronos package.
var cron = CronExpression.Parse("0 */5 * * * *");
var next = cron.GetNextOccurrence(DateTimeOffset.Now);

Logging, Metrics & Observability
Integrate with:

  • Serilog / Seq for structured logging
  • Prometheus for metrics
  • OpenTelemetry for traces and spans

Production Tips
Always handle exceptions gracefully

  • Use scoped services inside BackgroundService via IServiceScopeFactory
  • Monitor using health checks (IHealthCheck)
  • Separate retry logic (e.g., use Polly)
  • Set max concurrency (e.g., in queues) to prevent overload

Conclusion
ASP.NET Core’s Hosted Services and Worker Services provide powerful primitives for executing background tasks in a clean, reliable, and scalable way. Whether you're building message consumers, email dispatchers, or data processors, background services allow you to decouple, scale, and manage your application’s background logic like a pro. Happy coding!

HostForLIFE ASP.NET Core 10.0 Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: Knowing C#'s GUID, UUID, and ULID

clock June 2, 2025 09:11 by author Peter

Ensuring the uniqueness of identifiers across systems, sessions, or records is a crucial challenge when creating distributed systems and databases. Popular methods for creating unique IDs include ULID (Universally Unique Lexicographically Sortable Identifier), UUID (Universally Unique Identifier), and GUID (Globally Unique Identifier).

In this article, you'll discover.

What GUID, UUID, and ULID are,

  • Their differences and use cases,
  • How to implement them in C#, and
  • A performance-oriented analysis of their suitability for specific applications.

What are GUID, UUID, and ULID?
1. GUID (Globally Unique Identifier)
A GUID is a 128-bit unique identifier widely used in Microsoft-based systems. While GUID is a term Microsoft uses, it is essentially a UUID (as specified in RFC 4122). By nature, GUIDs guarantee uniqueness across distributed systems by relying on either randomness or timestamp-based generation strategies.

Format: GUIDs are typically represented as a 36-character hexadecimal string with hyphens.
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Example: f47ac10b-58cc-4372-a567-0e02b2c3d479

Key Properties

  • Uniqueness: Globally unique across systems.
  • Randomness: Commonly generated with UUID v4 (random generation).

Primary Use Cases

  • Unique Primary Keys in distributed databases.
  • Globally unique API keys, session tokens, and resource identifiers.
  • Identification of components/resources in Microsoft technologies like COM (.NET Class IDs).

2. UUID (Universally Unique Identifier)
A UUID is an international standard for generating unique 128-bit identifiers, defined under RFC 4122. Conceptually, GUID and UUID are nearly identical, though UUID strictly follows the RFC and is widely used across non-Microsoft frameworks.

Format: UUID adopts the same format as GUID.
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Example: 550e8400-e29b-41d4-a716-446655440000

Key Properties

  • Cross-platform Compatibility: Supported by programming languages like Python, Java, Go, and Node.js.
  • Determinism: Using UUID v3/v5 allows deterministic generation for the same inputs.

Primary Use Cases

  • Unique IDs in distributed services and databases.
  • Assigning identifiers to resources in cross-platform systems.
  • APIs and microservices need universal identifiers.

3. ULID (Universally Unique Lexicographically Sortable Identifier)
A ULID is a 128-bit identifier designed to overcome the shortcomings of GUID/UUID in sorting scenarios. ULIDs embed timestamp information into the identifier, making them lexicographically sortable (i.e., they can be sorted naturally based on their textual representations).

Format: Base32-encoded string without special characters.

01GZHT44KMWWT5V2Q4RQ6P8VWT

First 48 bits: Millisecond timestamp (ensures natural ordering).
Last 80 bits: Random entropy.

Key Properties

  • Ordered: Unlike GUID/UUID, ULIDs are naturally sortable because the timestamp is embedded upfront.
  • Readable: Fewer characters than UUID (Base32 encoding instead of Base16/Hex).

Primary Use Cases

  • Log and Event Tracking: Create lexicographically ordered event logs.
  • High-Frequency Inserts: Reduce database index fragmentation compared to GUIDs/UUIDs.
  • Human-readable, unique IDs.

Comparing GUID, UUID, and ULID: Features and Suitability

Aspect GUID UUID ULID
Bit Size 128 bits 128 bits 128 bits
Encoding Hexadecimal Hexadecimal Base32
Sorting Not Sortable Not Sortable Lexicographically Sortable
Contains Timestamp? Optional Optional Yes
Write Performance High Fragmentation in DB Index High Fragmentation in DB Index Low Fragmentation (Sequential IDs)
Primary Use Microsoft systems Cross-platform, API, databases Logging, time-ordered systems

Use Cases for GUID, UUID, and ULID
When to Use GUID

  • Microsoft Ecosystems: COM components, .NET assemblies, and Azure Services utilize GUIDs extensively.
  • Distributed Databases: Ensures unique keys even when records are written independently across systems.
  • Session Tracking: Use a GUID to assign globally unique session IDs.

When to Use UUID

  • Cross-Platform Compatibility: Works across distributed applications and languages like Python, Java, .NET.
  • APIs and Microservices: Generate identifiers for resources shared across multiple systems.
  • Randomized Unique IDs: UUID v4 is ideal for cases requiring uniqueness without predictable patterns.

When to Use ULID

  • Logging Systems: Generate sortable, unique IDs to track events or logs while maintaining a time correlation.
  • Performance Analysis for Databases

Database Indexing

  • GUID/UUID: IDs generated randomly (e.g., v4) lead to non-sequential inserts in clustered indexes, resulting in index fragmentation.
  • ULID: ULID's sequential nature (timestamp) ensures that inserts are ordered naturally, reducing index fragmentation.

Example Performance Metrics (MySQL/PostgreSQL)

Metric GUID/UUID ULID
Insert Speed Slower (Random Inserts) Faster (Sequential Inserts)
Index Fragmentation High Low
Query Performance Moderate Better
Storage 16 bytes per ID 16 bytes per ID

Implementing GUID, UUID, and ULID in C#

1. GUID in C#
The System.Guid class provides built-in support for creating GUIDs.
using System;

class Program
{
    static void Main()
    {
        Guid guid = Guid.NewGuid();
        Console.WriteLine($"Generated GUID: {guid}");
    }
}


2. UUID in C#
In .NET Core and Framework, Guid is already a UUID generator (v4 by default).
using System;

class Program
{
    static void Main()
    {
        // Generate a UUID (same as GUID)
        Guid uuid = Guid.NewGuid();
        Console.WriteLine($"Generated UUID (v4): {uuid}");
    }
}


3. ULID in C#
The .NET ecosystem does not natively support ULIDs, but several libraries like Ulid can be used.
Steps
Install UlidSharp from NuGet
dotnet add package Ulid

Generate ULID
class Program
{
    static void Main()
    {
        // Generate a ULID
        var ulid = Ulid.NewUlid();
        Console.WriteLine($"Generated ULID: {ulid}");
    }
}

Test Samples

Best Practices
GUID/UUID

  • Avoid using GUIDs/UUIDs as a primary key in clustered indexes unless uniqueness is more critical than performance.
  • Where possible, consider surrogate keys for better performance.

ULID

  • Use ULIDs in time-sensitive applications or logs.
  • Ideal for high-concurrency, high-volume systems like IoT devices or analytics workloads.

Conclusion
GUID, UUID, and ULID each offer distinct advantages based on the application's requirements. If you're developing in the Microsoft ecosystem or need universal uniqueness, GUIDs/UUIDs are excellent. If your application requires ordering, low index fragmentation, and better performance for high-insert workloads, ULID is a superior option.
By understanding the strengths and limitations of each, you can optimize your systems for unique identifier performance, scalability, and order requirements!

HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 



European ASP.NET Core Hosting - HostForLIFE :: An Example of a .NET core MAUI with a SQLite Database Login Page

clock May 26, 2025 09:11 by author Peter

We'll talk about creating a basic SQLite DB application with a login page here, using MAUI (Multi-platform App UI). The SQLite Database will be used to develop logic using a SQLite helper class. First, we'll use Visual Studio 2022 to build an MAUI App project. The project will produce a single home page similar to the one below.

Following that, some basic login and registration xaml pages will be created. The SQLiteHelper class for database activity will then be created. Install the NuGet package's Microsoft.Data.Sqlite package.

public class SQLiteHelper
{
    private string dbPath;
    public SQLiteHelper()
    {
        dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "users.db");
        InitializeDatabase();
    }
    private void InitializeDatabase()
    {
        using var connection = new SqliteConnection($"Data Source={dbPath}");
        connection.Open();
        var command = connection.CreateCommand();
        command.CommandText =
        @"
            CREATE TABLE IF NOT EXISTS Users (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Username TEXT NOT NULL,
                Password TEXT NOT NULL
            );
        ";
        command.ExecuteNonQuery();
    }
}


Login page Example given below.
public partial class LoginPage : ContentPage
{
    private SQLiteHelper dbHelper = new();
    public LoginPage()
    {
        InitializeComponent();
    }
    private void OnLoginClicked(object sender, EventArgs e)
    {
        if (dbHelper.ValidateUser(UsernameEntry.Text, PasswordEntry.Text))
            DisplayAlert("Success", "Login successful!", "OK");
        else
            DisplayAlert("Error", "Invalid credentials.", "OK");
    }
    private void OnGoToRegisterClicked(object sender, EventArgs e)
    {
        Navigation.PushAsync(new RegisterPage());
    }
}

Go to App.xaml.cs page adds the Login page as main page like launch view as mention below example
namespace MauiApp1
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            //MainPage = new AppShell();
            MainPage = new NavigationPage(new LoginPage());
        }
    }
}


Output

HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: Using C# 13 to Create a "Pooled" Dependency Injection Lifetime

clock May 22, 2025 09:14 by author Peter

It supports the notion of Inversion of Control (IoC), which facilitates better testability, simpler code maintenance, and a clear division of responsibilities. A key component of the contemporary ASP.NET Core application architecture is dependency injection, or DI. Three common service lifetimes are supported by ASP.NET Core's lightweight, extensible container for injecting dependencies:

  • Transient: An instance of the service is created every time it is requested. This is suitable for lightweight, stateless applications.
  • Scoped: A single instance is created per HTTP request or per scope. This is ideal for services that maintain state throughout a single operation.
  • Singleton: Use singletons for stateless services that are more expensive to instantiate or manage shared state safely across threads.

These durations are adequate for the majority of situations, but you might require a hybrid behavior—a service that does not survive for the full application lifetime but avoids frequent allocations like a singleton. This is especially important in high-throughput systems where strict control over garbage collection pressure, memory allocation, and performance is required.

Through the ObjectPool and ObjectPoolProvider APIs in the Microsoft.Extensions,.NET presents the idea of object pooling in order to meet this requirement. namespace for ObjectPool. By keeping a pool of pre-allocated objects, object pooling enables you to reuse object instances effectively, lowering memory load and enhancing performance for frequently used resources.

In this article, we’ll go beyond the default service lifetimes and demonstrate how to implement a custom "Pooled" lifetime registration. We’ll explore how to integrate ObjectPool<T> with the ASP.NET Core DI system, taking advantage of new features in C# 13 and .NET 9 to build a robust, performant, and reusable solution. You'll learn how to:

  • Utilize object pooling to define a custom service lifetime.
  • Cleanly register and configure pooled services.
  • Pooling in multithreaded environments should follow best practices.
  • You should avoid common pitfalls such as thread safety issues and misuse of objects.
As a result of this course, you will be able to create performant services with hybrid lifetime behavior that bridge the gap between transient and singleton design patterns.

When to Use Object Pooling?

When creating and destroying objects frequently would result in excessive resource consumption and memory pressure, object pooling is an effective performance optimisation technique. We maintain a pool of reusable objects and serve them on demand instead of instantiating new objects repeatedly.

When the following conditions are met, use object pooling:
  • Object creation is expensive: A pool can significantly reduce CPU and memory overhead if an object involves non-trivial setup (e.g., allocating large arrays, loading configuration, or initialising resources).
  • Objects are short-lived and used frequently: Pooling can prevent constant allocation and garbage collection cycles when a particular type is repeatedly required during the application's lifespan, but only for short bursts (e.g., during each request, batch operation, or parsing cycle).
  • Objects that are thread-safe or can be reset easily: The objects should be stateless, thread-safe, or able to be safely reset to a clean state before reuse in order to ensure consistency and prevent unpredictable behavior.
Common Real-World Examples
Object pooling is highly effective in the following use cases:
  • StringBuilder instances: Creating new StringBuilder instances each time can be wasteful, especially in tight loops and logging.
  • Memory buffers (e.g., byte[] arrays): Network I/O, file I/O, and serialization processes use memory buffers for network I/O, file I/O, and serialization. The reuse of buffers reduces GC pressure and maintains throughput.
  • Parsers or serializer: When handling data streams or messages repeatedly, objects such as JsonSerializer, XmlReader, or custom parsers can benefit from pooling.
Best Practices
  • Reset before reuse: When returning objects to the pool, ensure they are reset to a known state before reuse. This prevents data leaks.
  • Avoid pooling complex dependencies: Objects with deep dependency trees or significant shared states should not be pooled unless explicitly designed to be so.
  • Benchmark before adopting: To validate object pools' benefits, benchmark their performance before and after introducing one.
In the right context-especially for high-throughput, memory-sensitive applications-object pooling can yield significant performance gains with minimal trade-offs.

Step-by-Step: Implementing Object Pooling in ASP.NET Core with DI
The use of object pooling is a proven strategy for reducing memory allocations and garbage collection overhead in .NET applications. Let's walk through how to set up and use object pooling in a clean, reusable manner using Microsoft.Extensions.ObjectPool.

Step 1: Install the Required NuGet Package

It is necessary to install Microsoft's official object pooling library before you can get started:
dotnet add package Microsoft.Extensions.ObjectPool

or if using NuGet Package Manager Console
NuGet\Install-Package Microsoft.Extensions.ObjectPool

In .NET applications, this package provides the foundational interfaces and default implementations for managing object pools.

Step 2: Define the Pooled Service
Suppose we have a service that performs intensive in-memory string operations using StringBuilder, which is expensive to allocate repeatedly.
using System.Text;

namespace PooledDI.Core.Services;
public class StringProcessor
{
    private readonly StringBuilder _builder = new();

    public string Process(string input)
    {
        _builder.Clear();
        _builder.Append(input.ToUpperInvariant());
        return _builder.ToString();
    }
}


Why Pool It?
When the StringBuilder object is used repeatedly at scale, internal buffers are allocated, which can be expensive. Pooling StringProcessor reduces these allocations and improves performance.

Step 3: Create a Custom PooledObjectPolicy<T>
An object pool must know how to create and reset objects. This is achieved through a custom PooledObjectPolicy<t> implementation:</t>
using Microsoft.Extensions.ObjectPool;
using PooledDI.Core.Services;

namespace PooledDI.Core.Policies;

public class StringProcessorPolicy : PooledObjectPolicy<StringProcessor>
{
    public override StringProcessor Create() => new StringProcessor();

    public override bool Return(StringProcessor obj)
    {

        return true;
    }



}


Best Practice
Ensure sensitive or inconsistent data is cleaned or reset before returning an object to the pool.

Step 4: Register the Pooled Service with Dependency Injection
Although ASP.NET Core's built-in DI container doesn't provide a "pooled" lifetime, we can achieve the same effect by injecting an ObjectPool<t>.</t>

In order to encapsulate the logic of registration, create an extension method as follows:
using Microsoft.Extensions.ObjectPool;

namespace PooledDI.Api.Services;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddPooled<TService, TPolicy>(this IServiceCollection services)
        where TService : class
        where TPolicy : PooledObjectPolicy<TService>, new()
    {
        services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
        services.AddSingleton<ObjectPool<TService>>(sp =>
        {
            var provider = sp.GetRequiredService<ObjectPoolProvider>();
            return provider.Create(new TPolicy());
        });

        return services;
    }
}


Register your pooled service in Program.cs  as follows:
builder.Services.AddPooled<StringProcessor, StringProcessorPolicy>();

Best Practice

Create a singleton pool to ensure consistent reuse across requests, while consumers can be scoped or transient.

Step 5: Consume the Pooled Service
Pooled objects should be injected into services where they are needed. Get() to fetch an object and Return() to add it back to the pool.
using Microsoft.Extensions.ObjectPool;

namespace PooledDI.Core.Services;

public class ProcessingService
{
    private readonly ObjectPool<StringProcessor> _pool;

    public ProcessingService(ObjectPool<StringProcessor> pool)
    {
        _pool = pool;
    }

    public string Execute(string input)
    {
        var processor = _pool.Get();

        try
        {
            return processor.Process(input);
        }
        finally
        {
            _pool.Return(processor);
        }
    }
}


Last but not least, register the service that consumes the data:
builder.Services.AddScoped<ProcessingService>();

Best Practice
When an exception occurs, always use a try-finally block to ensure the object is returned to the pool.

With just a few steps, you've implemented efficient object pooling

In ASP.NET Core, Microsoft.Extensions.ObjectPool provides:
  • Allotments for heavy or frequently used services have been reduced.
  • Implemented a clean, extensible integration pattern with the DI container.
  • Performance-sensitive applications benefit from improved throughput.
Best Practices for Using Object Pooling in .NET
When implemented thoughtfully and correctly, object pooling can yield significant performance improvements. To ensure your implementation is safe, efficient, and maintainable, follow these best practices:

Avoid Mutable Shared State
Why it Matters
If the object's internal state is not reset, it can lead to data leaks, race conditions, and unpredictable behavior.

Best Practice
If the object maintains state (such as a StringBuilder or buffer), clear or reset it explicitly before returning it to the pool.
using System.Text;

namespace PooledDI.Core.Services;

public sealed class ZiggyProcessor
{
    private readonly StringBuilder _sb = new();

    public void Append(string value) => _sb.Append(value);

    public string Finish()
    {
        var result = _sb.ToString();
        _sb.Clear();
        return result;
    }



    internal void Reset() => _sb.Clear();
}


Use Policies to Reset Objects Cleanly
Why it Matters
Pooled object policies give you the ability to control how objects are cleaned up before reuse.

Best Practice
Finish() should implement reset logic to ensure the object is returned to a safe, known state.
public string Finish()
{
    var result = _sb.ToString();
    _sb.Clear();
    return result;
}


Pool Only Performance-Critical or Expensive Objects
Why it Matters
Using pooling for cheap, lightweight objects may actually hurt performance due to its complexity and overhead.

Best Practice
Limit object pooling to high-cost objects that are instantiated frequently, such as large buffers, parsers, serializers, or reusable builders. Don't pool trivial data types or objects that are rarely used.

Ensure Thread Safety

Why it Matters
A pooled object that isn't thread-safe can cause race conditions or data corruption if multiple threads access it concurrently.

Best Practice
  • In most cases, pooled objects should be used in single-threaded, isolated scopes (e.g., for HTTP requests).
  • Ensure that shared objects are thread-safe or use locking mechanisms carefully if they must be shared across threads.
Use DefaultObjectPoolProvider
Why it Matters
Due to its efficient internal data structures, the DefaultObjectPoolProvider is optimized for high-throughput scenarios.

Best Practice
Use the DefaultObjectPoolProvider unless you have a very specific requirement for a custom implementation. It provides excellent performance for typical workloads out of the box.
builder.Services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();

Bonus Tips
Benchmark: Verify the performance gains of your application before and after introducing object pooling.
Monitor: Consider rethinking the pooling strategy if pooled objects are rarely reused or leak memory.
Combine: Use performance profilers like dotTrace or PerfView to understand hotspots in object allocation.

In ASP.NET Core applications, you can safely integrate object pooling to optimize resource utilization, reduce garbage collection pressure, and improve throughput by adhering to these best practices.

Advanced Technique: Pooling Services That Implement Interfaces
As in real-world applications, services are often registered by interface to provide abstraction, testability, and flexibility. But how can object pooling be integrated into this model?

You will learn how to wrap pooled objects behind an interface, enabling clean dependency injection while still benefiting from reuse and memory efficiency.

Step 1: Define a Service Interface

Defining an interface for your service contract is the first step:
namespace PooledDI.Core.Interfaces;
public interface IStringProcessor
{
    string Process(string input);
}

The interface allows you to inject the service rather than a concrete class, which is ideal for unit testing and clean coding.

Step 2: Create a Wrapper That Uses Object Pooling

A class implementing the desired interface needs to wrap the pool access logic since object pooling manages a concrete type (e.g., StringProcessor).
using Microsoft.Extensions.ObjectPool;
using PooledDI.Core.Interfaces;

namespace PooledDI.Core.Services;

public class PooledStringProcessor : IStringProcessor
{
    private readonly ObjectPool<StringProcessor> _pool;

    public PooledStringProcessor(ObjectPool<StringProcessor> pool)
    {
        _pool = pool;
    }

    public string Process(string input)
    {
        var processor = _pool.Get();
        try
        {
            return processor.Process(input);
        }
        finally
        {
            _pool.Return(processor);
        }
    }
}

Best Practice
If an exception occurs, always wrap pooled object access in a try-finally block to ensure it is returned to the pool.

Step 3: Register the Interface Wrapper with DI
The wrapper implementation should be registered as the concrete type for your interface:
builder.Services.AddScoped<IStringProcessor, PooledStringProcessor>();

The pool itself should also be registered using the utility method you used earlier or manually:
builder.Services.AddPooled<StringProcessor, StringProcessorPolicy>();


Why This Matters
  • Testability: Your classes depend on IStringProcessor instead of the pooled implementation, making them easier to test.
  • Encapsulation: By encapsulating the object pooling logic, consumers remain unaware of the object pooling logic.
  • Reuse with Safety: A wrapper ensures that pooled objects are properly managed throughout their lifecycle.
Optional: Factory-Based Approach for Complex Cases
For most scenarios, the wrapper approach shown above is the best method for managing pooled objects or adding lazy resolution. If you need to manage more than one type of pooled object or introduce lazy resolution, you can inject a factory or delegate for the interface.

For scalable enterprise .NET applications, wrapping pooled objects behind interfaces maintains clean architecture, testability, and performance.

Summary

With the introduction of modern language features in C# 13 and the continued evolution of .NET 9, developing memory-efficient, high-performance applications has never been simpler. The built-in Dependency Injection (DI) container in ASP.NET Core does not natively support a "pooled" object lifetime, but the Microsoft.Extensions.ObjectPool package fills that void.

You can benefit from object pooling by integrating it into your service architecture in the following ways:
  • Memory allocations for expensive or frequently-used objects should be reduced.
  • Performance-critical workloads can improve throughput and responsiveness.
  • Maintain control over the object lifecycle, ensuring safe reusability through PooledObjectPolicy<t>.</t>
In a number of scenarios, this technique excels, including:
  • Manipulating strings with StringBuilder
  • In-memory data transformation
  • Our parsers and serializers are tailored to your needs
  • Using computational helpers or reusable buffers
In conjunction with solid architectural patterns (such as DI and interface-based design), object pooling can become a powerful optimisation tool.

Final Thoughts
  • Consider pooling for objects that are expensive, short-lived, and reusable.
  • Reset and cleanup logic should always be implemented properly.
  • For clean, testable code, wrap pooled services behind interfaces.
  • Reuse objects efficiently and thread-safely with DefaultObjectPoolProvider.
With these principles, you can build highly efficient .NET applications that scale gracefully under load without sacrificing code clarity or maintainability. I have uploaded the code to my GitHub Repository. If you have found this article useful please click the like button.

HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: How to Fix v3 API Downtime Problems with NuGet Package Manager?

clock May 14, 2025 07:57 by author Peter

If you're working with NuGet in Visual Studio and encountering issues due to the NuGet v3 API being temporarily unavailable, you're not alone. Many developers have experienced downtime with the NuGet v3 API, leading to errors and hindering package management workflows. Fortunately, there is a quick workaround to resolve these issues.

Recognizing the Issue
Installing, updating, and managing third-party libraries and tools in projects is made simple for developers by NuGet, a well-liked package management for.NET. One of the main resources for managing and retrieving these packages is the NuGet v3 API. However, developers may encounter challenges when trying to restore or manage packages because of sporadic outages or connectivity problems with the NuGet v3 API.

A timeout or an inability to retrieve the required resources from the v3 API are common ways that the issue appears. When you're in the thick of development and require access to particular packages, this becomes really challenging.

Steps to Switch to NuGet v2 API

  • Open Visual Studio
    • Launch Visual Studio, the IDE you are using for your .NET projects.
  • Navigate to NuGet Package Manager Settings
    • Go to Tools in the top menu.
    • Select NuGet Package Manager.
    • Choose Package Manager Settings.
  • Change the Package Source URL
    • In the settings window, go to Package Sources.
    • You'll see the default NuGet source listed as https://api.nuget.org/v3/index.json.
    • Change this URL to https://www.nuget.org/api/v2/ to switch to the v2 API.
  • Save and Close
    • After updating the URL, click OK to save your settings.
  • Rebuild Your Project
    • Clean your project and rebuild it. This will allow NuGet to start using the v2 API to restore and manage packages.

Once these steps are completed, NuGet will automatically use the v2 API, bypassing the downtime issues caused by the v3 API.

Why Switch to NuGet v2 API?

The v2 API is older but still very reliable for managing packages. It allows for smoother transitions in cases of downtime, ensuring that your workflow remains uninterrupted. By using the v2 API, you can avoid the issues caused by API unavailability and continue your development efforts.

Additional Tips

  • Clear the NuGet Cache: If you face persistent issues even after switching the source, clearing the NuGet cache might help. This ensures that NuGet doesn’t use any outdated or corrupted cached data.
  • To clear the cache, go to:
    • Tools -> NuGet Package Manager -> Package Manager Settings -> Clear All NuGet Cache(s)
  • Check NuGet Status: Keep an eye on the official NuGet status page to see when the v3 API is back online. The NuGet team regularly updates the page with the status of their API services.
  • Revert Back to v3 Once Restored: Once the v3 API is back up and running, you can switch the URL back to the default v3 URL to take advantage of its enhanced features, such as better performance and newer functionalities.

Conclusion
Package management for your project may come to a complete stop if the NuGet v3 API goes down. However, you can carry on with your development without any disruptions if you swiftly transition to the v2 API as a temporary fix. This straightforward procedure guarantees that your workflow is unaffected while you wait for the v3 API to reactivate. To reduce interruptions to your development process, always maintain your NuGet settings current and monitor the state of the NuGet services.

HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 



European ASP.NET Core Hosting - HostForLIFE :: Constructing a Secure SQL Injection Test Form with C# and ASP.NET

clock May 5, 2025 08:50 by author Peter

This blog post will discuss how to use C# and ASP.NET Web Forms to create a secure SQL injection testing website. This project is perfect for implementing input sanitization, error handling, and parameterized queries as well as learning about fundamental SQL injection protection measures.

Technologies Used

  • ASP.NET Web Forms (ASPX)
  • C# (Code-Behind)
  • SQL Server
  • ADO.NET with SqlHelper (Application Block)
  • Bootstrap 5 (Frontend UI)

Goal of This Application

  • Provide a login form that is intentionally structured to test SQL injection patterns.
  • Detect and block malicious inputs from both query string and form fields.
  • Log all suspicious activity.
  • Redirect users to a custom error page when SQL injection attempts are detected.

1. ASPX Page Code (Frontend Form)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SqlInjection.aspx.cs" Inherits="TaskPractices.SqlInjection" %>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>SQL Injection Test</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />

    <style>
        body {
            background-color: #f8f9fa;
            padding: 50px;
        }

        .container {
            max-width: 500px;
            margin: auto;
        }

        .warning {
            color: red;
            font-size: 0.9rem;
        }
    </style>
</head>
<body>
    <div class="container border p-4 bg-white rounded shadow">
        <h3 class="text-center mb-4">SQL Injection Test Form</h3>
        <form runat="server">
            <div class="mb-3">
                <label for="username" class="form-label">Username</label>
                <input type="text" class="form-control" id="username" name="username" placeholder="Enter username" runat="server" />
            </div>

            <div class="mb-3">
                <label for="password" class="form-label">Password</label>
                <input type="password" class="form-control" id="password" name="password" placeholder="Enter password" runat="server" />
            </div>

            <asp:Button class="btn btn-primary w-100" Text="Login" ID="loginbtn" OnClick="loginbtn_Click" runat="server" />

            <p class="warning mt-3">
                ?? This form is for testing purposes only. Ensure backend uses parameterized queries.
            </p>
        </form>
    </div>
</body>
</html>

2. Code-Behind: SQL Injection Detection and Login Logic

using AppBlock;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TaskPractices.Allkindoflog;

namespace TaskPractices
{
    public partial class SqlInjection : System.Web.UI.Page
    {
        public string[] BlackList = new string[]
        {
            "@@", "/*", "*/", "function", "truncate ", "alter", "begin", "create", "cursor",
            "delete ", "exec", "<script>", "</script>", "script", "execute", "fetch", "insert ",
            "kill", "drop", "sysobjects", "syscolumns", "update ", "document.cookie", "'", ":",
            "--", "%", "=", " or ", ">", "<", "exec(", " del", "chr", "asc", "update "
        };

        public string[] chars = new string[]
        {
            "@@", "/*", "*/", "function", "truncate ", "alter", "begin", "create", "cursor",
            "delete ", "exec", "<script>", "</script>", "script", "execute", "fetch", "insert ",
            "kill", "drop ", "sysobjects", "syscolumns", "update ", "document.cookie", "'", ":",
            " or ", ">", "<", "exec(", " del", "chr", "asc", "update "
        };

        public string strURLRewrited = "";
        string sqlcon = ConfigurationManager.ConnectionStrings["Sqlconnection"].ToString();

        protected void Page_Load(object sender, EventArgs e)
        {
            strURLRewrited = Request.RawUrl;
            sqlInjection1();
            RemoveSpecialChars(strURLRewrited);
        }

        private bool CheckStringForSQL(string pStr)
        {
            if (string.IsNullOrEmpty(pStr) || pStr.CompareTo("") == 0)
                return false;

            string lstr = pStr.ToLower();

            foreach (string item in BlackList)
            {
                if (lstr.ToUpper() == item.ToUpper())
                    return true;
            }

            return false;
        }

        public void sqlInjection1()
        {
            try
            {
                string ErrorPage = "/ErrorPage/ErrorPage-Demo1.aspx";

                // Form data check
                for (int i = 0; i < Request.Form.Count; i++)
                {
                    if (CheckStringForSQL(Request.Form[i]))
                    {
                        Log.errorlog(Request.Form[i], strURLRewrited);
                        Response.Redirect(ErrorPage);
                    }
                }

                // Query string check
                for (int i = 0; i < Request.QueryString.Count; i++)
                {
                    if (CheckStringForSQL(Request.QueryString[i]))
                    {
                        Log.errorlog(Request.QueryString[i], strURLRewrited);
                        Response.Redirect(ErrorPage);
                    }
                }
            }
            catch (Exception ex)
            {
                Response.Write(ex.Message);
            }
        }

        public void RemoveSpecialChars(string str)
        {
            foreach (string c in chars)
            {
                if (str.Contains(c))
                {
                    Log.errorlog(str, strURLRewrited);
                    Response.Redirect("/ErrorPage/ErrorPage-Demo1.aspx");
                }
            }
        }

        protected void loginbtn_Click(object sender, EventArgs e)
        {
            DataSet ds = new DataSet();

            try
            {
                SqlParameter[] param = {
                    new SqlParameter("@PAN", username.Value.Trim()),
                    new SqlParameter("@EMAIL", password.Value.Trim())
                };

                string sql = "SELECT * FROM ClientData (NOLOCK) WHERE PAN=@PAN AND EMAIL=@EMAIL";
                ds = SqlHelper.ExecuteDataset(sqlcon, CommandType.Text, sql, param);

                if (ds != null && ds.Tables[0].Rows.Count > 0)
                {
                    HttpContext.Current.Session["ClientCode"] = ds.Tables[0].Rows[0]["ClientId"].ToString().Trim();
                    HttpContext.Current.Session["ClientFname"] = ds.Tables[0].Rows[0]["Name"].ToString().Trim();
                    HttpContext.Current.Session["Pan"] = ds.Tables[0].Rows[0]["PAN"].ToString().Trim();
                    HttpContext.Current.Session["Email"] = ds.Tables[0].Rows[0]["EMAIL"].ToString().Trim();

                    ScriptManager.RegisterStartupScript(this, typeof(string), "Message", "alert('Login successfully');", true);
                }
                else
                {
                    ScriptManager.RegisterStartupScript(this, typeof(string), "Message", "alert('User Not Exists !');", true);
                }
            }
            catch (Exception ex)
            {
                ScriptManager.RegisterStartupScript(this, typeof(string), "Message", $"alert('{ex.Message}');", true);
            }
        }
    }
}

Key Takeaways

  • Always use parameterized queries instead of string concatenation to prevent SQL injection.
  • Implement input sanitization and validation on both the server and client sides.
  • Maintain a blacklist of harmful SQL keywords to filter user input.
  • Redirect to custom error pages and log malicious attempts for analysis.

Improvements You Can Add

  • Use a whitelist approach for known safe characters.
  • Integrate logging with tools like ELMAH or Serilog.
  • Use Stored Procedures instead of inline queries for extra safety.
  • Replace hard-coded blacklists with centralized config-based filters.

Conclusion
This project helps demonstrate SQL injection defense in a hands-on way using ASP.NET. It’s a great way to test and validate your security practices while building safe and user-friendly forms. Would you like a downloadable PDF of this documentation?


HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: The Greatest Option for Reactive Systems in C#.NET 9 is Akka.NET

clock April 28, 2025 08:46 by author Peter

In a world where software needs to be message-driven, elastic, resilient, and responsive, traditional thread-based and monolithic designs frequently break under complexity or stress. Reactive systems excel in this situation, and Akka.NET makes it not only feasible but also pleasurable to design them in C# with.NET 9. Originally created for the JVM and then transferred to.NET, Akka.NET is an open-source toolkit built on the actor paradigm. It makes it simple to create distributed, concurrent, and fault-tolerant systems.

This post will explain why Akka.NET is the greatest option for developing reactive systems in.NET 9 and provide a step-by-step demonstration of a practical example.

Why Choose Akka.net for Reactive Systems?
Akka.NET is an open-source .NET framework that implements the actor model — a proven approach to building concurrent systems. Each actor is an independent unit that processes messages asynchronously and maintains its own internal state.

Core Features of Akka.NET
Asynchronous by default: Actors process messages concurrently without locking.

  • Resilient architecture: Supervision strategies handle failures gracefully.
  • Scalable: Easily scale horizontally using Akka.Cluster and Cluster.Sharding.
  • Decoupled components: Built on message passing, not shared state.
  • Built-in support for persistence, routing, and remote messaging.

Akka.NET allows you to build applications that are not only scalable and efficient but also fault-tolerant by design.

Step-by-Step: Building a Reactive System with Akka.NET
Let’s create a simple reactive banking system where.

  • Users can deposit, withdraw, and check their balance.
  • Each operation is handled as a message by an actor.

Step 1. Create a New Console App
dotnet new console -n AkkaReactiveBank
cd AkkaReactiveBank


Step 2. Add Akka.NET NuGet Package
dotnet add package Akka

Step 3. Define Actor Messages
Create a new file BankMessages.cs.
public record Deposit(decimal Amount);
public record Withdraw(decimal Amount);
public record CheckBalance;


These represent the commands sent to the actor.

Step 4. Create the Bank Actor
Create a new file BankActor.cs.
using Akka.Actor;
using System;

public class BankActor : ReceiveActor
{
    private decimal _balance;

    public BankActor()
    {
        Receive<Deposit>(msg => HandleDeposit(msg));
        Receive<Withdraw>(msg => HandleWithdraw(msg));
        Receive<CheckBalance>(_ => HandleCheckBalance());
    }

    private void HandleDeposit(Deposit msg)
    {
        _balance += msg.Amount;
        Console.WriteLine($"[Deposit] Amount: {msg.Amount}, New Balance: {_balance}");
    }

    private void HandleWithdraw(Withdraw msg)
    {
        if (_balance >= msg.Amount)
        {
            _balance -= msg.Amount;
            Console.WriteLine($"[Withdraw] Amount: {msg.Amount}, Remaining Balance: {_balance}");
        }
        else
        {
            Console.WriteLine("[Withdraw] Insufficient funds.");
        }
    }

    private void HandleCheckBalance()
    {
        Console.WriteLine($"[Balance] Current Balance: {_balance}");
    }
}


Step 5. Set Up the Actor System in the Program.cs
Replace the content of the Program.cs.
using Akka.Actor;
class Program
{
    static void Main(string[] args)
    {
        using var system = ActorSystem.Create("BankSystem");

        var bankActor = system.ActorOf<BankActor>("Bank");

        bankActor.Tell(new Deposit(1000));
        bankActor.Tell(new Withdraw(200));
        bankActor.Tell(new CheckBalance());

        Console.ReadLine();
    }
}

Step 6. Run the Application
dotnet run

Output
[Deposit] Amount: 1000, New Balance: 1000
[Withdraw] Amount: 200, Remaining Balance: 800
[Balance] Current Balance: 800


You’ve just created a reactive banking system with Akka.NET in .NET 9.

HostForLIFE ASP.NET Core Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in