Introduction
Today, I would like to share some of my experiences from my earlier job experiences. Clinical Decision Support Systems (CDSS) are essential tools in modern healthcare, designed to enhance medical decision-making by leveraging patient data, clinical knowledge, and artificial intelligence. With the rise of machine learning and big data, AI-powered CDSS can significantly improve diagnostic accuracy, treatment planning, and patient outcomes.
In this article, we’ll explore how to design and implement a Clinical Decision Support System using C# and .NET, integrated with AI models, healthcare datasets, and a multi-database backend including DynamoDB, MongoDB, and Amazon Redshift. This hybrid architecture allows the system to perform real-time operations, flexible data management, and advanced analytics.
What is Clinical Decision Support?
A Clinical Decision Support System (CDSS) is a health information technology system that is designed to provide physicians and other health professionals with clinical decision-making support. These systems analyze data within electronic health records (EHRs) to provide prompts and reminders to assist healthcare providers in implementing evidence-based clinical guidelines.
Common Examples
- Suggesting drug dosages based on patient weight and kidney function
- Alerting physicians of potential drug interactions
- Recommending diagnostic tests based on presenting symptoms
- Ranking likely diagnoses for differential consideration
Architecture Overview
![Architecture Overview]()
Components
- User Interface: ASP.NET Core frontend for clinical input/output
- FHIR Data Layer: Interface to EHR systems via HL7 FHIR APIs
- AI Engine: ONNX or ML.NET integrated for real-time diagnosis support
- Database Layer
- DynamoDB for fast session/log storage
- MongoDB for flexible clinical notes and rules
- Redshift for analytics and reporting
- Audit and Override Logging: Stores override logs and outcome decisions
Multi-Database Architecture
MongoDB: Clinical Notes & Rules Engine
public class ClinicalNote
{
public string Id { get; set; }
public string PatientId { get; set; }
public string NoteText { get; set; }
public DateTime CreatedAt { get; set; }
}
Used to store variable-length physician notes and dynamically evolving medical rules.
DynamoDB: Decision Logs
[DynamoDBTable("CDSDecisionLogs")]
public class DecisionLog
{
[DynamoDBHashKey]
public string PhysicianId { get; set; }
[DynamoDBRangeKey]
public DateTime Timestamp { get; set; }
[DynamoDBProperty]
public string AIRecommendation { get; set; }
[DynamoDBProperty]
public string FinalDecision { get; set; }
}
Stores real-time logs of decisions, overrides, and outcomes.
Amazon Redshift: Reporting and Analytics
-- Example Redshift query
SELECT
diagnosis,
COUNT(*) AS total,
AVG(age) AS avg_age
FROM
clinical_diagnoses
GROUP BY diagnosis
ORDER BY total DESC;
Used to track diagnostic trends, treatment effectiveness, and demographic breakdowns.
FHIR Integration
FHIR (Fast Healthcare Interoperability Resources) is a standardized way of representing and exchanging healthcare information electronically. We'll use the Hl7.Fhir.R4 NuGet package.
Step 1. Install FHIR SDK.
Install-Package Hl7.Fhir.R4
Step 2. Read Patient and Observation Data
using Hl7.Fhir.Rest;
using Hl7.Fhir.Model;
public class FhirService
{
private readonly FhirClient _client;
public FhirService(string fhirEndpoint)
{
_client = new FhirClient(fhirEndpoint);
}
public Patient GetPatientById(string id)
{
return _client.Read<Patient>($"Patient/{id}");
}
public List<Observation> GetPatientObservations(string patientId)
{
var bundle = _client.Search<Observation>(new string[]
{
$"patient=Patient/{patientId}"
});
return bundle.Entry.Select(e => (Observation)e.Resource).ToList();
}
}
Step 3. Map FHIR to Local PatientInput.
public static PatientInput ConvertFromFhir(Patient fhirPatient, List<Observation> observations)
{
var input = new PatientInput
{
Age = (int)((DateTimeOffset.Now - fhirPatient.BirthDateElement.ToDateTimeOffset()).TotalDays / 365),
Gender = fhirPatient.Gender.ToString(),
LabResults = observations.ToDictionary(
obs => obs.Code.Text ?? obs.Code.Coding.FirstOrDefault()?.Display,
obs => obs.Value.ToString()
),
Symptoms = new List<string>() // Could be pulled from Condition or QuestionnaireResponse in real EHR
};
return input;
}
Note. You could also extract conditions, allergies, and medications using FHIR endpoints Condition, AllergyIntolerance, and MedicationStatement.
Example Scenario: Symptom-Based Treatment Recommendations
Let’s assume a CDSS use case for diagnosing and recommending treatment options for a patient presenting with symptoms like fever, cough, and fatigue.
Model
public class PatientInput
{
public int Age { get; set; }
public string Gender { get; set; }
public List<string> Symptoms { get; set; }
public Dictionary<string, string> LabResults { get; set; }
}
Integrating AI with ML.NET or ONNX
AI Inference Service
public class AIModelService
{
private readonly InferenceSession _session;
public AIModelService(string modelPath)
{
_session = new InferenceSession(modelPath);
}
public string PredictDiagnosis(PatientInput input)
{
// Simplified conversion logic
var tensor = new DenseTensor<float>(new[] { 1, input.Symptoms.Count });
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("input", tensor)
};
using var results = _session.Run(inputs);
return results.First().AsEnumerable<string>().First();
}
}
Rule-Based Recommendation Engine
public class RecommendationEngine
{
private static readonly Dictionary<string, List<string>> TreatmentMap = new()
{
{ "Flu", new List<string> { "Rest", "Hydration", "Antivirals" } },
{ "COVID-19", new List<string> { "Isolation", "Monitoring O2", "Antivirals" } },
{ "Common Cold", new List<string> { "Rest", "Vitamin C", "Decongestants" } },
};
public List<string> GetTreatments(string diagnosis)
{
return TreatmentMap.ContainsKey(diagnosis) ? TreatmentMap[diagnosis] : new List<string> { "Consult Specialist" };
}
}
Controller Example with Logging
public async Task<IActionResult> DiagnoseFromFhir(string patientId)
{
var fhirPatient = _fhirService.GetPatientById(patientId);
var observations = _fhirService.GetPatientObservations(patientId);
var input = ConvertFromFhir(fhirPatient, observations);
var diagnosis = _aiService.PredictDiagnosis(input);
var treatments = _recommendationEngine.GetTreatments(diagnosis);
// Log decision to DynamoDB
var log = new DecisionLog
{
PhysicianId = User.Identity.Name,
Timestamp = DateTime.UtcNow,
AIRecommendation = diagnosis,
FinalDecision = diagnosis // Could differ based on user override
};
await _dynamoContext.SaveAsync(log);
ViewBag.Diagnosis = diagnosis;
ViewBag.Treatments = treatments;
return View("DiagnosisResult");
}
Conclusion
This article demonstrated my experiences from earlier projects I designed and architected how to build an AI-powered Clinical Decision Support System using C#, .NET, and a multi-database architecture.
- MongoDB for unstructured and rule-based data
- DynamoDB for the real-time session and decision-logging
- Redshift for advanced analytics and reporting
Combined with FHIR integration and AI inference, this approach creates a powerful, scalable, and secure solution for clinical environments.