PlanSolve is still in pre-alpha – Features may change or break. Feedback welcome!

.NET SDK

Official .NET SDK for the Shift Assignment Solver. Full C# and F# support with async/await patterns and strong typing.

Installation

Package Installation

NuGet Package Manager

Install-Package PlanSolve.ShiftSolver

dotnet CLI

dotnet add package PlanSolve.ShiftSolver

PackageReference

<PackageReference Include="PlanSolve.ShiftSolver" Version="1.0.0" />

Basic Example

Simple Shift Assignment

using PlanSolve.ShiftSolver;
using PlanSolve.ShiftSolver.Models;

var solver = new ShiftSolverClient("your-api-key-here");

var request = new ShiftAssignmentRequest
{
    Name = "Hospital Shift Assignment",
    Description = "Weekly shift assignment for hospital staff",
    Contracts = new List<Contract>
    {
        new Contract
        {
            Name = "FULL_TIME",
            MaxHours = "PT40H",
            MinHours = "PT32H",
            MaxConsecutiveWorkDays = 5
        }
    },
    Shifts = new List<Shift>
    {
        new Shift
        {
            Name = "morning_shift",
            From = DateTime.Parse("2024-01-15T06:00:00"),
            To = DateTime.Parse("2024-01-15T14:00:00"),
            RequiredSkills = new List<string> { "nursing", "patient_care" },
            Value = 3
        }
    },
    Employees = new List<Employee>
    {
        new Employee
        {
            Name = "Alice Johnson",
            ContractType = "FULL_TIME",
            Skills = new List<string> { "nursing", "patient_care", "emergency" },
            Availability = new List<DateTime> { DateTime.Parse("2024-01-15") }
        }
    }
};

try
{
    var result = await solver.SolveAsync(request);
    Console.WriteLine($"Optimization completed: {result.Id}");
}
catch (ShiftSolverException ex)
{
    Console.WriteLine($"Optimization failed: {ex.Message}");
}

Advanced Examples

Skill-Based Assignment

Advanced Skills Matching
var request = new ShiftAssignmentRequest
{
    // ... basic setup
    Shifts = new List<Shift>
    {
        new Shift
        {
            Name = "emergency_shift",
            From = DateTime.Parse("2024-01-15T22:00:00"),
            To = DateTime.Parse("2024-01-16T06:00:00"),
            RequiredSkills = new List<string> { "emergency", "critical_care" },
            Value = 2,
            Priority = 1
        }
    },
    Employees = new List<Employee>
    {
        new Employee
        {
            Name = "Dr. Smith",
            ContractType = "FULL_TIME",
            Skills = new List<string> { "emergency", "critical_care", "surgery" },
            Availability = new List<DateTime> { DateTime.Parse("2024-01-15") },
            Preferences = new List<string> { "emergency_shift" }
        },
        new Employee
        {
            Name = "Nurse Johnson",
            ContractType = "PART_TIME",
            Skills = new List<string> { "nursing", "patient_care" },
            Availability = new List<DateTime> { DateTime.Parse("2024-01-15") }
        }
    },
    Weights = new OptimizationWeights
    {
        RequiredSkills = 1000,
        ShiftPreferences = 100,
        WorkloadBalance = 50
    }
};

Fairness Rules

Workload Distribution
var request = new ShiftAssignmentRequest
{
    // ... basic setup
    Fairness = new FairnessRules
    {
        FairnessBuckets = new List<FairnessBucket>
        {
            new FairnessBucket
            {
                Employees = new List<string> { "Alice", "Bob", "Carol" },
                Shifts = new List<string> { "night_shift", "weekend_shift" },
                MaxAssignments = 2
            }
        },
        WorkloadDistribution = new WorkloadDistribution
        {
            TargetHoursPerEmployee = 40,
            Tolerance = 4
        }
    }
};

Contract Compliance

Multiple Contract Types
var request = new ShiftAssignmentRequest
{
    // ... basic setup
    Contracts = new List<Contract>
    {
        new Contract
        {
            Name = "FULL_TIME",
            MaxHours = "PT40H",
            MinHours = "PT32H",
            MaxConsecutiveWorkDays = 5,
            MaxShiftsPerDay = 1,
            MinRestBetweenShifts = "PT11H",
            MaxWorkingDays = 5
        },
        new Contract
        {
            Name = "PART_TIME",
            MaxHours = "PT24H",
            MinHours = "PT16H",
            MaxConsecutiveWorkDays = 3,
            MaxShiftsPerDay = 1,
            MinRestBetweenShifts = "PT11H",
            MaxWorkingDays = 3
        }
    }
};

API Patterns

Async/Await vs Tasks

Both Patterns Supported
// Async/await pattern
public async Task<ShiftAssignmentResult> SolveAsync(ShiftAssignmentRequest request)
{
    try
    {
        var result = await solver.SolveAsync(request);
        return result;
    }
    catch (RateLimitExceededException ex)
    {
        // Wait and retry
        await Task.Delay(TimeSpan.FromMinutes(1));
        return await solver.SolveAsync(request);
    }
}

// Task-based pattern
solver.SolveAsync(request)
    .ContinueWith(task =>
    {
        if (task.IsCompletedSuccessfully)
        {
            Console.WriteLine("Success: " + task.Result.Id);
        }
        else if (task.IsFaulted)
        {
            Console.WriteLine("Error: " + task.Exception?.Message);
        }
    });

Error Handling

Comprehensive Error Handling
try
{
    var result = await solver.SolveAsync(request);
}
catch (ShiftSolverException ex)
{
    switch (ex)
    {
        case ValidationException validationEx:
            Console.WriteLine($"Validation error: {validationEx.Details}");
            break;
        case InsufficientCreditsException creditsEx:
            Console.WriteLine($"Not enough credits: {creditsEx.Remaining}");
            break;
        case RateLimitExceededException rateEx:
            Console.WriteLine($"Rate limit exceeded, retry in: {rateEx.RetryAfter}");
            break;
        default:
            Console.WriteLine($"Unexpected error: {ex.Message}");
            break;
    }
}

Dependency Injection

ASP.NET Core Integration

// Program.cs or Startup.cs
services.AddShiftSolver(options =>
{
    options.ApiKey = Configuration["PlanSolve:ApiKey"];
    options.BaseUrl = Configuration["PlanSolve:BaseUrl"];
    options.Timeout = TimeSpan.FromMinutes(5);
});

// In your service or controller
public class ShiftService
{
    private readonly IShiftSolverClient _solver;

    public ShiftService(IShiftSolverClient solver)
    {
        _solver = solver;
    }

    public async Task<ShiftAssignmentResult> OptimizeShiftsAsync(ShiftAssignmentRequest request)
    {
        return await _solver.SolveAsync(request);
    }
}

.NET Features

Strong Typing

Full compile-time type checking with strongly-typed models for all request and response objects.

Async/Await Support

Native async/await patterns for non-blocking API calls and modern .NET development practices.

Dependency Injection

First-class support for .NET dependency injection containers and service registration.

Configuration

Easy integration with .NET configuration system for API keys and settings management.

Ready to Get Started?

Install the NuGet package and start building optimized shift assignments into your .NET application.