Mahamudra.Contemporary 4.0.2

dotnet add package Mahamudra.Contemporary --version 4.0.2
                    
NuGet\Install-Package Mahamudra.Contemporary -Version 4.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Mahamudra.Contemporary" Version="4.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Mahamudra.Contemporary" Version="4.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Mahamudra.Contemporary" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Mahamudra.Contemporary --version 4.0.2
                    
#r "nuget: Mahamudra.Contemporary, 4.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Mahamudra.Contemporary@4.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Mahamudra.Contemporary&version=4.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Mahamudra.Contemporary&version=4.0.2
                    
Install as a Cake Tool

Mahamudra Contemporary

Contemporary Banner Photo by Paul Engel on Unsplash

NuGet Package .NET Standard 2.1 MIT License

A robust Task Parallel Library that combines Railway Oriented Programming with parallel execution patterns. Execute collections of tasks concurrently while maintaining functional programming principles and comprehensive error handling.

โœจ Features

  • Parallel Execution: Execute functions concurrently across collections with configurable parallelism
  • Railway Oriented Programming: Built-in Result<T, E> pattern for elegant error handling
  • Comprehensive Logging: Integrated Microsoft.Extensions.Logging support with detailed execution tracking
  • Performance Optimized: Async-first design with efficient memory usage
  • Thread-Safe: Built on ConcurrentDictionary for safe parallel operations
  • .NET Standard 2.1: Compatible with .NET Core 3.1+, .NET 5+, and .NET Framework 4.6.1+

๐Ÿš€ Quick Start

Installation

dotnet add package Mahamudra.Contemporary

Basic Usage

using Mahamudra.Contemporary;
using Microsoft.Extensions.Logging;

// Create factory with optional logging
var factory = new ParallelAsyncFactory(logger);

// Execute async operations in parallel
var results = await factory.ExecuteAsyncResult<int, string>(
    numbers, 
    async number => await ProcessNumberAsync(number)
);

// Handle results using Railway Oriented Programming
var successes = results.Where(r => r.Key is Success<int, string>);
var failures = results.Where(r => r.Key is Failure<int, string>);

๐Ÿ“š API Reference

ParallelAsyncFactory

The async-first class providing true parallel execution with Task.WhenAll() for optimal performance.

Methods
// Execute async function with Result pattern (Railway Oriented)
Task<ConcurrentDictionary<Result<T, string>, M>> ExecuteAsyncResult<T, M>(
    IEnumerable<T> list,
    Func<T, Task<M>> function
)

Parameters:

  • list: Collection of items to process
  • function: Async function to execute for each item

Returns: ConcurrentDictionary where:

  • Key: Result<T, string> - Either Success<T> containing the original item, or Failure<string> with error details
  • Value: M - The result of the function execution (or default for failures)

Behavior: Continues processing all items even if some fail. Failures are captured in the Result pattern.


// Execute async function with fail-fast behavior
Task<ConcurrentDictionary<T, M>> ExecuteAsync<T, M>(
    IEnumerable<T> list,
    Func<T, Task<M>> function
)

Parameters:

  • list: Collection of items to process
  • function: Async function to execute for each item

Returns: ConcurrentDictionary<T, M> with results

Behavior: Throws exception immediately if any item fails. Use when all items must succeed.


ParallelFactory

Synchronous parallel execution using Parallel.ForEach for CPU-bound operations.

Methods
// Execute synchronous function with Result pattern
ConcurrentDictionary<Result<T, string>, M> ExecuteResult<T, M>(
    IEnumerable<T> list,
    Func<T, M> function
)

Parameters:

  • list: Collection of items to process
  • function: Synchronous function to execute for each item

Returns: ConcurrentDictionary with Railway Oriented results

Behavior: Synchronous parallel execution, captures all errors.


// Execute synchronous function with fail-fast behavior
ConcurrentDictionary<T, M> Execute<T, M>(
    IEnumerable<T> list,
    Func<T, M> function
)

Parameters:

  • list: Collection of items to process
  • function: Synchronous function to execute for each item

Returns: ConcurrentDictionary<T, M> with results

Behavior: Throws exception immediately on first failure.


// Execute async function synchronously with Result pattern
ConcurrentDictionary<Result<T, string>, M> ExecuteAsyncResult<T, M>(
    IEnumerable<T> list,
    Func<T, Task<M>> function
)

Parameters:

  • list: Collection of items to process
  • function: Async function to execute synchronously for each item

Returns: ConcurrentDictionary with Railway Oriented results

Behavior: Converts async operations to sync using ToSync() extension method.


// Execute async function synchronously with fail-fast behavior
ConcurrentDictionary<T, M> ExecuteAsync<T, M>(
    IEnumerable<T> list,
    Func<T, Task<M>> function
)

Parameters:

  • list: Collection of items to process
  • function: Async function to execute synchronously for each item

Returns: ConcurrentDictionary<T, M> with results

Behavior: Synchronous execution of async functions, throws on first error.


Constructors

// Default constructor (uses NullLogger)
ParallelAsyncFactory()
ParallelFactory()

// Constructor with custom logger
ParallelAsyncFactory(ILogger logger)
ParallelFactory(ILogger logger)

When to Use Which Class?

Use Case Recommended Class Reason
I/O-bound operations (HTTP, DB, File I/O) ParallelAsyncFactory True async parallelism, better performance
CPU-bound operations ParallelFactory Optimized thread pool usage
Legacy synchronous code ParallelFactory Native synchronous execution
Modern async APIs ParallelAsyncFactory Native async/await support

Fail-Fast vs Railway Oriented

Mode Method Behavior Use When
Fail-Fast ExecuteAsync() / Execute() Stops on first error, throws exception All items must succeed (transactions, critical operations)
Railway Oriented ExecuteAsyncResult() / ExecuteResult() Processes all items, captures errors Partial success acceptable (batch processing, data imports)

๐Ÿ’ก Examples

Processing a List of URLs

var urls = new[] { "https://api1.com", "https://api2.com", "https://api3.com" };
var factory = new ParallelAsyncFactory(logger);

var results = await factory.ExecuteAsyncResult<string, HttpResponseMessage>(
    urls,
    async url => await httpClient.GetAsync(url)
);

// Process successful responses
foreach (var success in results.Where(r => r.Key is Success<string, string>))
{
    var originalUrl = ((Success<string, string>)success.Key).Value;
    var response = success.Value;
    Console.WriteLine($"โœ… {originalUrl}: {response.StatusCode}");
}

// Handle failures
foreach (var failure in results.Where(r => r.Key is Failure<string, string>))
{
    var error = ((Failure<string, string>)failure.Key).Error;
    Console.WriteLine($"โŒ Error: {error}");
}

Data Processing Pipeline

var dataIds = Enumerable.Range(1, 100);
var processor = new ParallelAsyncFactory(logger);

var processedData = await processor.ExecuteAsyncResult<int, ProcessedResult>(
    dataIds,
    async id => await ProcessDataAsync(id)
);

var successCount = processedData.Count(r => r.Key is Success<int, string>);
var errorCount = processedData.Count(r => r.Key is Failure<int, string>);

Console.WriteLine($"Processed: {successCount} successful, {errorCount} failed");

CPU-Bound Operations

// Use ParallelFactory for CPU-intensive tasks
var numbers = Enumerable.Range(1, 1000);
var factory = new ParallelFactory(logger);

var results = factory.ExecuteResult<int, bool>(
    numbers,
    number => IsPrime(number)  // Synchronous CPU-bound operation
);

var primeCount = results.Count(r => r.Key is Success<int, string> && r.Value);
Console.WriteLine($"Found {primeCount} prime numbers");

Database Batch Operations

var userIds = await GetUserIdsAsync();
var factory = new ParallelAsyncFactory(logger);

// Update users in parallel with error handling
var updateResults = await factory.ExecuteAsyncResult<int, bool>(
    userIds,
    async userId =>
    {
        await dbContext.Users
            .Where(u => u.Id == userId)
            .ExecuteUpdateAsync(u => u.SetProperty(x => x.LastUpdated, DateTime.UtcNow));
        return true;
    }
);

// Log failures for retry
var failures = updateResults.Where(r => r.Key is Failure<int, string>);
foreach (var failure in failures)
{
    var error = ((Failure<int, string>)failure.Key).Error;
    logger.LogError($"Failed to update user: {error}");
}

Microservice Orchestration

public class OrderService
{
    private readonly ParallelAsyncFactory _factory;
    private readonly HttpClient _httpClient;

    public async Task<OrderResult> ProcessOrderAsync(Order order)
    {
        var services = new[] { "inventory", "payment", "shipping" };

        // Call multiple microservices in parallel
        var results = await _factory.ExecuteAsyncResult<string, ServiceResponse>(
            services,
            async serviceName => await CallServiceAsync(serviceName, order)
        );

        // Check if all services succeeded
        if (results.All(r => r.Key is Success<string, string>))
        {
            return OrderResult.Success();
        }

        // Rollback on any failure
        var failures = results
            .Where(r => r.Key is Failure<string, string>)
            .Select(r => ((Failure<string, string>)r.Key).Error);

        await RollbackServicesAsync(order);
        return OrderResult.Failed(failures);
    }
}

Fail-Fast Example

// Use ExecuteAsync when all items MUST succeed
try
{
    var criticalTasks = new[] { "task1", "task2", "task3" };
    var factory = new ParallelAsyncFactory(logger);

    var results = await factory.ExecuteAsync<string, bool>(
        criticalTasks,
        async task => await ExecuteCriticalTaskAsync(task)
    );

    Console.WriteLine("All critical tasks completed successfully!");
}
catch (Exception ex)
{
    // Immediate failure - transaction can be rolled back
    logger.LogError($"Critical task failed: {ex.Message}");
    await RollbackTransactionAsync();
}

๐Ÿ”ง Configuration

Logging

The library integrates with Microsoft.Extensions.Logging. Configure your logger as usual:

// In Startup.cs or Program.cs
services.AddLogging(builder => 
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Information);
});

// Inject into your service
public class MyService
{
    public MyService(ILogger<MyService> logger)
    {
        _factory = new ParallelAsyncFactory(logger);
    }
}

๐Ÿ“Š Performance

Performance comparison between synchronous parallel execution and async parallel execution:

Method Mean Error StdDev Allocated
ExecuteParallelResult 731.6 ms 15,086.4 ms 826.9 ms 307.29 KB
ExecuteAsyncResult 206.5 ms 243.0 ms 13.32 ms 270.69 KB

Async execution shows ~3.5x better performance with lower memory allocation.

๐Ÿงช Testing

Run the test suite:

dotnet test

Example test demonstrating error handling:

[TestMethod]
public async Task ExecuteAsyncResult_HandlesPartialFailures()
{
    var items = new[] { 1, 2, 3, 4, 5 };
    var results = await factory.ExecuteAsyncResult<int, int>(
        items,
        async x => x == 3 ? throw new Exception("Test error") : x * 2
    );

    var successes = results.Where(r => r.Key is Success<int, string>);
    var failures = results.Where(r => r.Key is Failure<int, string>);

    Assert.AreEqual(4, successes.Count());
    Assert.AreEqual(1, failures.Count());
    Assert.AreEqual(16, successes.Sum(s => s.Value)); // 2+4+8+10 (3 failed, so 6 not included)
}

๐ŸŽฏ Best Practices

1. Choose the Right Factory

// โœ… GOOD: Use ParallelAsyncFactory for I/O operations
var factory = new ParallelAsyncFactory(logger);
var results = await factory.ExecuteAsyncResult(urls, async url => await httpClient.GetAsync(url));

// โŒ BAD: Using ParallelFactory for I/O (blocks threads unnecessarily)
var factory = new ParallelFactory(logger);
var results = factory.ExecuteAsyncResult(urls, async url => await httpClient.GetAsync(url));

2. Handle Results Properly

// โœ… GOOD: Check result type before casting
foreach (var result in results)
{
    if (result.Key is Success<int, string> success)
    {
        var value = success.Value;
        var output = result.Value;
        // Process success
    }
    else if (result.Key is Failure<int, string> failure)
    {
        var error = failure.Error;
        // Handle error
    }
}

// โŒ BAD: Casting without checking
var success = (Success<int, string>)result.Key; // May throw InvalidCastException

3. Use Railway Pattern for Batch Operations

// โœ… GOOD: Process all items, collect errors for retry
var results = await factory.ExecuteAsyncResult(items, async item => await ProcessAsync(item));
var failures = results.Where(r => r.Key is Failure<T, string>);
await RetryFailedItemsAsync(failures);

// โŒ BAD: Fail-fast for batch operations loses progress
try
{
    var results = await factory.ExecuteAsync(items, async item => await ProcessAsync(item));
}
catch
{
    // Lost all progress, must restart from beginning
}

4. Configure Appropriate Logging

// โœ… GOOD: Use structured logging
services.AddLogging(builder =>
{
    builder.AddConsole();
    builder.AddFilter("Mahamudra.Contemporary", LogLevel.Information);
});

// ๐Ÿ’ก TIP: Use Debug level for detailed execution tracking
builder.AddFilter("Mahamudra.Contemporary", LogLevel.Debug);

5. Avoid Shared Mutable State

// โŒ BAD: Shared mutable state causes race conditions
var counter = 0;
await factory.ExecuteAsyncResult(items, async item =>
{
    counter++; // Race condition!
    return await ProcessAsync(item);
});

// โœ… GOOD: Use immutable patterns or thread-safe collections
var processed = await factory.ExecuteAsyncResult(items, async item => await ProcessAsync(item));
var counter = processed.Count(r => r.Key is Success<T, string>);

โ“ FAQ

Q: What's the difference between ParallelAsyncFactory and ParallelFactory?

A: ParallelAsyncFactory uses true async parallelism with Task.WhenAll(), making it ideal for I/O-bound operations (HTTP, database, file operations). ParallelFactory uses Parallel.ForEach, which is optimized for CPU-bound synchronous operations. For most modern applications with async APIs, use ParallelAsyncFactory.

Q: When should I use ExecuteAsync vs ExecuteAsyncResult?

A: Use ExecuteAsync() (fail-fast) when all items must succeed, such as transactional operations where partial completion is unacceptable. Use ExecuteAsyncResult() (Railway pattern) for batch operations where you want to process as many items as possible and handle failures separately.

Q: How do I control the degree of parallelism?

A: Currently, the library uses default .NET parallelism settings:

  • ParallelAsyncFactory: All tasks start simultaneously (bounded by system resources)
  • ParallelFactory: Uses Parallel.ForEach default partitioning

For custom control, wrap your operations:

var semaphore = new SemaphoreSlim(10); // Max 10 concurrent operations
await factory.ExecuteAsyncResult(items, async item =>
{
    await semaphore.WaitAsync();
    try
    {
        return await ProcessAsync(item);
    }
    finally
    {
        semaphore.Release();
    }
});

Q: Can I use this library without Microsoft.Extensions.Logging?

A: Yes! Both factories work without logging. Use the default constructor, which provides a NullLogger:

var factory = new ParallelAsyncFactory(); // No logging required

Q: How do I retry failed operations?

A:

var results = await factory.ExecuteAsyncResult(items, async item => await ProcessAsync(item));

// Extract failed items
var failedItems = results
    .Where(r => r.Key is Failure<T, string> failure)
    .Select(r => ((Failure<T, string>)r.Key).Error);

// Retry with exponential backoff
await RetryWithBackoffAsync(failedItems);

Q: Is this library thread-safe?

A: Yes! Results are stored in ConcurrentDictionary, which is thread-safe. However, your lambda functions must also be thread-safe. Avoid shared mutable state within your functions.

Q: What .NET versions are supported?

A: The library targets .NET Standard 2.1, making it compatible with:

  • .NET Core 3.0+
  • .NET 5, 6, 7, 8+
  • .NET Framework 4.6.1+ (with .NET Standard 2.1 support)

๐Ÿ” Troubleshooting

Problem: Deadlocks when using ParallelFactory with async operations

Cause: Using ToSync() on async operations can cause deadlocks in certain contexts (e.g., ASP.NET synchronization contexts).

Solution: Use ParallelAsyncFactory instead:

// โŒ BAD: May deadlock
var factory = new ParallelFactory();
var results = factory.ExecuteAsyncResult(items, async item => await ProcessAsync(item));

// โœ… GOOD: Use async factory
var factory = new ParallelAsyncFactory();
var results = await factory.ExecuteAsyncResult(items, async item => await ProcessAsync(item));

Problem: High memory usage with large collections

Cause: Processing millions of items simultaneously can exhaust memory.

Solution: Batch your operations:

var batchSize = 1000;
var batches = items.Chunk(batchSize);

foreach (var batch in batches)
{
    var results = await factory.ExecuteAsyncResult(batch, async item => await ProcessAsync(item));
    await ProcessResultsAsync(results);
}

Problem: Can't distinguish between different failure types

Cause: The library captures exception messages as strings.

Solution: Use custom error codes in your functions:

await factory.ExecuteAsyncResult(items, async item =>
{
    try
    {
        return await ProcessAsync(item);
    }
    catch (HttpRequestException)
    {
        throw new Exception($"HTTP_ERROR:{item}");
    }
    catch (TimeoutException)
    {
        throw new Exception($"TIMEOUT:{item}");
    }
});

Problem: Results dictionary key collision

Cause: Processing duplicate items with Railway pattern can cause key conflicts.

Solution: Ensure items are unique, or transform items to include unique identifiers:

var uniqueItems = items.Select((item, index) => new { Index = index, Item = item });
var results = await factory.ExecuteAsyncResult(uniqueItems, async x => await ProcessAsync(x.Item));

๐Ÿš€ Real-World Use Cases

E-commerce: Product Catalog Updates

public class ProductSyncService
{
    private readonly ParallelAsyncFactory _factory;
    private readonly IProductRepository _repository;

    public async Task<SyncResult> SyncProductsAsync(IEnumerable<string> productIds)
    {
        var results = await _factory.ExecuteAsyncResult(
            productIds,
            async productId =>
            {
                var externalData = await _externalApi.GetProductAsync(productId);
                await _repository.UpdateAsync(productId, externalData);
                return true;
            }
        );

        return new SyncResult
        {
            TotalProcessed = results.Count,
            Successful = results.Count(r => r.Key is Success<string, string>),
            Failed = results.Count(r => r.Key is Failure<string, string>),
            FailedIds = results
                .Where(r => r.Key is Failure<string, string>)
                .Select(r => ((Failure<string, string>)r.Key).Error)
                .ToList()
        };
    }
}

Data Migration: Legacy System to Modern Architecture

public class MigrationService
{
    public async Task<MigrationReport> MigrateCustomersAsync()
    {
        var legacyCustomers = await _legacyDb.GetAllCustomersAsync();
        var factory = new ParallelAsyncFactory(_logger);

        var results = await factory.ExecuteAsyncResult(
            legacyCustomers,
            async customer =>
            {
                // Transform legacy data model
                var modernCustomer = TransformCustomer(customer);

                // Validate business rules
                await _validator.ValidateAsync(modernCustomer);

                // Insert into new system
                await _modernDb.InsertCustomerAsync(modernCustomer);

                return modernCustomer.Id;
            }
        );

        await GenerateMigrationReportAsync(results);
        return BuildMigrationReport(results);
    }
}

DevOps: Health Check Monitoring

public class HealthCheckService
{
    public async Task<HealthReport> CheckAllServicesAsync()
    {
        var endpoints = _configuration.GetServiceEndpoints();
        var factory = new ParallelAsyncFactory(_logger);

        var results = await factory.ExecuteAsyncResult(
            endpoints,
            async endpoint =>
            {
                var stopwatch = Stopwatch.StartNew();
                var response = await _httpClient.GetAsync(endpoint.Url);
                stopwatch.Stop();

                return new HealthCheck
                {
                    Service = endpoint.Name,
                    Status = response.IsSuccessStatusCode ? "Healthy" : "Unhealthy",
                    ResponseTime = stopwatch.ElapsedMilliseconds
                };
            }
        );

        return BuildHealthReport(results);
    }
}

Financial: Portfolio Rebalancing

public class PortfolioService
{
    public async Task<RebalanceResult> RebalancePortfoliosAsync(IEnumerable<int> portfolioIds)
    {
        var factory = new ParallelAsyncFactory(_logger);

        // Use fail-fast for financial operations
        try
        {
            var results = await factory.ExecuteAsync(
                portfolioIds,
                async portfolioId =>
                {
                    using var transaction = await _dbContext.Database.BeginTransactionAsync();

                    var portfolio = await _repository.GetPortfolioAsync(portfolioId);
                    var trades = CalculateRebalancingTrades(portfolio);

                    foreach (var trade in trades)
                    {
                        await _tradingService.ExecuteTradeAsync(trade);
                    }

                    await transaction.CommitAsync();
                    return true;
                }
            );

            return RebalanceResult.Success(results.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError($"Rebalancing failed: {ex.Message}");
            await RollbackAllTransactionsAsync();
            return RebalanceResult.Failed(ex.Message);
        }
    }
}

โšก Performance Tips

1. Batch Large Collections

// Instead of processing 1 million items at once
var results = await factory.ExecuteAsyncResult(millionItems, ProcessAsync);

// Batch into manageable chunks
const int batchSize = 1000;
var allResults = new ConcurrentBag<Result>();

foreach (var batch in millionItems.Chunk(batchSize))
{
    var batchResults = await factory.ExecuteAsyncResult(batch, ProcessAsync);
    foreach (var result in batchResults)
    {
        allResults.Add(result);
    }
}

2. Use SemaphoreSlim for Rate Limiting

// Limit concurrent API calls to avoid rate limits
var semaphore = new SemaphoreSlim(10); // Max 10 concurrent

var results = await factory.ExecuteAsyncResult(items, async item =>
{
    await semaphore.WaitAsync();
    try
    {
        return await _apiClient.CallAsync(item);
    }
    finally
    {
        semaphore.Release();
    }
});

3. Optimize Memory with ValueTuple

// Instead of creating classes for results
var results = await factory.ExecuteAsyncResult(
    items,
    async item => new { Id = item.Id, Status = await ProcessAsync(item) }
);

// Use ValueTuple for better memory efficiency
var results = await factory.ExecuteAsyncResult(
    items,
    async item => (item.Id, await ProcessAsync(item))
);

4. Pre-allocate Resources

// Create HttpClient once (not per request)
private static readonly HttpClient _httpClient = new HttpClient();

public async Task ProcessUrlsAsync(IEnumerable<string> urls)
{
    var factory = new ParallelAsyncFactory(_logger);
    var results = await factory.ExecuteAsyncResult(
        urls,
        async url => await _httpClient.GetStringAsync(url)
    );
}

5. Use ConfigureAwait(false) in Libraries

// In library code, avoid capturing synchronization context
var results = await factory.ExecuteAsyncResult(
    items,
    async item =>
    {
        var data = await FetchDataAsync(item).ConfigureAwait(false);
        return await ProcessDataAsync(data).ConfigureAwait(false);
    }
);

๐Ÿ“ฆ Version History

This project follows Semantic Versioning. For detailed changelog, see the Releases page.

Current Version: 3.0.2

Major Changes:

  • 3.0.x: .NET Standard 2.1 support, GitVersion integration
  • 2.x: Railway Oriented Programming pattern integration
  • 1.x: Initial parallel execution capabilities

๐Ÿค Contributing

Contributions are welcome! Please follow these guidelines:

Getting Started

  1. Fork the repository

    git clone https://github.com/YOUR_USERNAME/mahamudra-contemporary.git
    
  2. Create a feature branch

    git checkout -b feature/your-feature-name
    
  3. Make your changes

    • Follow existing code style and conventions
    • Add XML documentation comments for public APIs
    • Ensure code is thread-safe
  4. Add tests for new functionality

    cd tests/UnitTests/UnitTestsContemporary
    # Add test methods to appropriate test class
    
  5. Run the test suite

    dotnet test
    
  6. Build and verify

    dotnet build --configuration Release
    
  7. Submit a pull request

    • Describe what your changes do
    • Reference any related issues
    • Ensure CI/CD pipeline passes

Contribution Guidelines

  • Code Quality: Maintain high code quality with proper error handling
  • Testing: All new features must include unit tests
  • Documentation: Update README.md for user-facing changes
  • Breaking Changes: Avoid breaking changes in minor/patch versions
  • Performance: Run benchmarks for performance-critical changes

Railway Oriented Programming

Parallel Programming in .NET

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

MIT License Summary

Copyright (c) 2025 Mahamudra Contemporary Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

๐Ÿ™ Acknowledgments

  • Railway Oriented Programming pattern by Scott Wlaschin
  • Task Parallel Library by Microsoft .NET Team
  • Banner photo by Paul Engel on Unsplash
  • Community contributors and testers

๐Ÿ“ž Support

๐ŸŒŸ Star History

If you find this library useful, please consider giving it a star on GitHub! It helps others discover the project.


Repository: https://github.com/janmaru/mahamudra-contemporary NuGet Package: Mahamudra.Contemporary License: MIT Current Version: 3.0.2

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.2 246 12/23/2025
4.0.1 47 12/23/2025
3.0.2 71 7/31/2025
3.0.1 178 2/2/2022
2.3.1 294 8/23/2020
2.2.1 303 8/22/2020
2.1.1 308 8/22/2020
2.0.1 248 8/17/2020
1.5.0 392 8/13/2020
1.4.0 303 8/13/2020
1.2.0 250 8/12/2020
1.0.0 646 8/12/2020

Updated to .NET Standard 2.1 with improved performance and Railway Oriented Programming patterns.