diff --git a/DotnetSdkContrib.sln b/DotnetSdkContrib.sln
index 91f68f30..ea55d3c5 100644
--- a/DotnetSdkContrib.sln
+++ b/DotnetSdkContrib.sln
@@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.Contrib.Provide
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenFeature.Contrib.Providers.Flagsmith.Test", "test\OpenFeature.Contrib.Providers.Flagsmith.Test\OpenFeature.Contrib.Providers.Flagsmith.Test.csproj", "{C3BA23C2-BEC3-4683-A64A-C914C3D8037E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenFeature.Contrib.Providers.Harness", "src\OpenFeature.Contrib.Providers.Harness\OpenFeature.Contrib.Providers.Harness.csproj", "{C16E48D2-6116-47C6-8F21-09195DCFE03C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -61,6 +63,10 @@ Global
{C3BA23C2-BEC3-4683-A64A-C914C3D8037E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3BA23C2-BEC3-4683-A64A-C914C3D8037E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3BA23C2-BEC3-4683-A64A-C914C3D8037E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C16E48D2-6116-47C6-8F21-09195DCFE03C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C16E48D2-6116-47C6-8F21-09195DCFE03C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C16E48D2-6116-47C6-8F21-09195DCFE03C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C16E48D2-6116-47C6-8F21-09195DCFE03C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -74,5 +80,6 @@ Global
{4041B63F-9CF6-4886-8FC7-BD1A7E45F859} = {B6D3230B-5E4D-4FF1-868E-2F4E325C84FE}
{47008BEE-7888-4B9B-8884-712A922C3F9B} = {0E563821-BD08-4B7F-BF9D-395CAD80F026}
{C3BA23C2-BEC3-4683-A64A-C914C3D8037E} = {B6D3230B-5E4D-4FF1-868E-2F4E325C84FE}
+ {C16E48D2-6116-47C6-8F21-09195DCFE03C} = {0E563821-BD08-4B7F-BF9D-395CAD80F026}
EndGlobalSection
EndGlobal
diff --git a/src/OpenFeature.Contrib.Providers.Harness/HarnessAdapter.cs b/src/OpenFeature.Contrib.Providers.Harness/HarnessAdapter.cs
new file mode 100644
index 00000000..ff6ae0c7
--- /dev/null
+++ b/src/OpenFeature.Contrib.Providers.Harness/HarnessAdapter.cs
@@ -0,0 +1,63 @@
+using io.harness.cfsdk.client.dto;
+using OpenFeature.Model;
+
+namespace OpenFeature.Contrib.Providers.Harness;
+
+///
+/// HarnessAdapter is the .NET adapter for the Harness feature flag SDK
+/// It provides functions to convert the OpenFeature EvaluationContext to
+/// a harness target, and functions to convert the Harness evaluation result
+/// to a OpenFeature ResolutionDetails.
+///
+public static class HarnessAdapter
+{
+ ///
+ /// Convert the Harness evaluation result to a OpenFeature ResolutionDetails.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ResolutionDetails HarnessResponse(string flagKey, T defaultValue)
+ {
+ /*
+ * string flagKey, T value, ErrorType errorType = ErrorType.None, string reason = null,
+ string variant = null, string errorMessage = null
+ */
+ return new ResolutionDetails(
+ flagKey,
+ defaultValue);
+ }
+
+ ///
+ /// Convert the OpenFeature EvaluationContext to a harness target.
+ ///
+ ///
+ ///
+ public static Target CreateTarget(EvaluationContext context)
+ {
+ // Get the identifier, if it is missing or empty return null
+ if (context.TryGetValue("identifier", out var identifier) != true || identifier.IsString != true)
+ {
+ return null;
+ }
+
+ // Get the name, if it is missing or empty return null
+ if (context.TryGetValue("name", out var name) != true || name.IsString != true)
+ {
+ return null;
+ }
+
+ // Create a target (different targets can get different results based on rules)
+ // TODO we need to deal with target attributes
+ // .Attributes(new Dictionary(){{"email", "demo@harness.io"}})
+ Target target = Target.builder()
+ .Name(name.AsString)
+ .Identifier(identifier.AsString)
+ .build();
+ return target;
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/OpenFeature.Contrib.Providers.Harness/OpenFeature.Contrib.Providers.Harness.csproj b/src/OpenFeature.Contrib.Providers.Harness/OpenFeature.Contrib.Providers.Harness.csproj
new file mode 100644
index 00000000..4adf98cc
--- /dev/null
+++ b/src/OpenFeature.Contrib.Providers.Harness/OpenFeature.Contrib.Providers.Harness.csproj
@@ -0,0 +1,23 @@
+
+
+ OpenFeature.Contrib.Providers.Harness
+ 0.0.1
+ $(VersionNumber)
+ $(VersionNumber)
+ $(VersionNumber)
+ Harness Feature Flag provider for .NET
+ https://www.harness.io/products/feature-flags
+ https://github.com/open-feature/dotnet-sdk-contrib
+ Dave Johnston
+
+
+
+
+
+
+
+
+ latest
+
+
+
diff --git a/src/OpenFeature.Contrib.Providers.Harness/Provider.cs b/src/OpenFeature.Contrib.Providers.Harness/Provider.cs
new file mode 100644
index 00000000..b59dcbec
--- /dev/null
+++ b/src/OpenFeature.Contrib.Providers.Harness/Provider.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Threading.Tasks;
+using io.harness.cfsdk.client.api;
+using OpenFeature.Model;
+
+namespace OpenFeature.Contrib.Providers.Harness;
+
+
+///
+/// HarnessProvider is the .NET provider implementation for the Harness feature flag SDK
+///
+public class Provider : FeatureProvider
+{
+ private const string HarnessProviderName = "Harness Provider";
+
+ private readonly Metadata _metadata = new (HarnessProviderName);
+ private readonly ICfClient _client;
+
+ ///
+ /// Constructor of the Harness provider.
+ ///
+ public Provider(ICfClient client)
+ {
+ _client = client;
+ }
+
+ ///
+ public override Metadata GetMetadata()
+ {
+ return this._metadata;
+ }
+
+ ///
+ public override Task> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null)
+ {
+ var result = _client.boolVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue);
+ return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result));
+ }
+
+ ///
+ public override Task> ResolveStringValue(string flagKey, string defaultValue, EvaluationContext context = null)
+ {
+ var result = _client.stringVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue);
+ return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result));
+ }
+
+ ///
+ public override Task> ResolveIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null)
+ {
+ var result = _client.numberVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue);
+ return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, Convert.ToInt32(result)));
+ }
+
+ ///
+ public override Task> ResolveDoubleValue(string flagKey, double defaultValue, EvaluationContext context = null)
+ {
+ var result = _client.numberVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue);
+ return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result));
+ }
+
+ ///
+ public override Task> ResolveStructureValue(string flagKey, Value defaultValue, EvaluationContext context = null)
+ {
+ // TODO need to implement this
+ return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, defaultValue));
+ }
+
+
+}
\ No newline at end of file