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.