Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions SW.Bitween.Api/Resources/Adapters/GetProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ async public Task<object> Handle(string key)
var decodedKey = Uri.UnescapeDataString(key);

// Check if it's a native adapter
if (decodedKey.StartsWith("native.", StringComparison.OrdinalIgnoreCase))
if (decodedKey.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
{
return _nativeAdapterDiscovery.GetNativeAdapterProperties(decodedKey);
return _nativeAdapterDiscovery.GetExpectedStartupValues(decodedKey);
Comment on lines +28 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prefix matching may be too permissive.

NativeAdapterDiscoveryService.NativePrefix is "native" (without a trailing dot). Using StartsWith("native", ...) will match any string beginning with "native", including potentially unintended matches like "nativelyBuilt". The previous hardcoded prefix was likely "native." with a dot to ensure proper delimiter.

Consider updating NativePrefix to include the dot separator or adjusting the check:

🛡️ Proposed fix

In NativeAdapterDiscoveryService.cs:

-public const string NativePrefix = "native";
+public const string NativePrefix = "native.";

Or adjust the check here:

-if (decodedKey.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
+if (decodedKey.StartsWith($"{NativeAdapterDiscoveryService.NativePrefix}.", StringComparison.OrdinalIgnoreCase))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SW.Bitween.Api/Resources/Adapters/GetProperties.cs` around lines 28 - 30, The
prefix match using NativeAdapterDiscoveryService.NativePrefix is too permissive
(NativePrefix is "native") and will match unintended keys like "nativelyBuilt";
update the check so it only matches the delimiter-separated prefix — either
change NativeAdapterDiscoveryService.NativePrefix to include the dot (e.g.,
"native.") or modify the condition in GetProperties to require the separator
(e.g., StartsWith(NativeAdapterDiscoveryService.NativePrefix + ".") or an Equals
on the prefix segment of decodedKey) before calling
_nativeAdapterDiscovery.GetExpectedStartupValues(decodedKey).

}

// Handle serverless adapters
Expand Down
12 changes: 6 additions & 6 deletions SW.Bitween.Api/Resources/Subscriptions/Update.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ public Validate(BitweenDbContext dbContext,IHttpContextAccessor httpContextAcces
var mustProps = Enumerable.Empty<string>();

// Check if it's a native adapter
if (mapperId.StartsWith("native.", StringComparison.OrdinalIgnoreCase))
if (mapperId.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
{
var properties = nativeAdapterDiscovery.GetNativeAdapterProperties(mapperId);
var properties = nativeAdapterDiscovery.GetExpectedStartupValues(mapperId);
mustProps = properties.Where(p => p.Value.EndsWith(" *")).Select(p => p.Key);
}
else
Expand All @@ -146,9 +146,9 @@ public Validate(BitweenDbContext dbContext,IHttpContextAccessor httpContextAcces
var mustProps = Enumerable.Empty<string>();

// Check if it's a native adapter
if (handlerId.StartsWith("native.", StringComparison.OrdinalIgnoreCase))
if (handlerId.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
{
var properties = nativeAdapterDiscovery.GetNativeAdapterProperties(handlerId);
var properties = nativeAdapterDiscovery.GetExpectedStartupValues(handlerId);
mustProps = properties.Where(p => p.Value.EndsWith(" *")).Select(p => p.Key);
}
else
Expand Down Expand Up @@ -183,9 +183,9 @@ public Validate(BitweenDbContext dbContext,IHttpContextAccessor httpContextAcces
var mustProps = Enumerable.Empty<string>();

// Check if it's a native adapter
if (model.ReceiverId.StartsWith("native.", StringComparison.OrdinalIgnoreCase))
if (model.ReceiverId.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
{
var properties = nativeAdapterDiscovery.GetNativeAdapterProperties(model.ReceiverId);
var properties = nativeAdapterDiscovery.GetExpectedStartupValues(model.ReceiverId);
mustProps = properties.Where(p => p.Value.EndsWith(" *")).Select(p => p.Key);
}
else
Expand Down
180 changes: 74 additions & 106 deletions SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,139 +7,107 @@

namespace SW.Bitween
{
public class NativeAdapterDiscoveryService
public class NativeAdapterDiscoveryService(
IEnumerable<INativeInfolinkHandler> nativeHandlers,
IEnumerable<INativeInfolinkReceiver> nativeReceivers,
IEnumerable<INativeInfolinkValidator> nativeValidators,
IEnumerable<INativeAdapter> nativeAdapters)
{
private readonly Dictionary<string, List<NativeAdapterInfo>> _adaptersCache;

public NativeAdapterDiscoveryService()
{
_adaptersCache = new Dictionary<string, List<NativeAdapterInfo>>();
DiscoverNativeAdapters();
}

private void DiscoverNativeAdapters()
public const string NativePrefix = "native";
public Dictionary<string, string> GetExpectedStartupValues(string adapterId)
{
var assemblies = new List<Assembly>() { typeof(DictionaryConverter).Assembly };


var result = new Dictionary<string, string>();

var adapter = nativeAdapters.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase));
if (adapter == null)
return result;

var properties = adapter.StartupValuesType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (var assembly in assemblies)
foreach (var prop in properties)
{
try
{
var types = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract);
var defaultValue = GetDefaultValue(prop);
var hasRequiredAttribute =
prop.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null;
var isRequired = hasRequiredAttribute || (!IsNullableType(prop.PropertyType) && defaultValue == null);

foreach (var type in types)
{
if (typeof(IInfolinkHandler).IsAssignableFrom(type))
{
AddAdapter("handlers", type);
}
else if (typeof(IInfolinkValidator).IsAssignableFrom(type))
{
AddAdapter("validators", type);
}
else if (typeof(IInfolinkReceiver).IsAssignableFrom(type))
{
AddAdapter("receivers", type);
}
}
if (isRequired)
{
result[prop.Name] = $"{prop.Name} *";
}
catch
else
{
// Skip assemblies that can't be loaded or scanned
result[prop.Name] = $"{prop.Name} ({defaultValue ?? "null"})";
}
}

return result;
}


private void AddAdapter(string category, Type type)
public INativeInfolinkHandler GetNativeHandler(string adapterId, Dictionary<string, string> settings)
{
if (!_adaptersCache.ContainsKey(category))
var result =
nativeHandlers.FirstOrDefault(a => a.Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase));
if (result != null)
{
_adaptersCache[category] = new List<NativeAdapterInfo>();
result.InitializeStartupValues(settings);
}

var adapterName = type.Name;//.Replace("Handler", "").Replace("Mapper", "")
//.Replace("Validator", "").Replace("Receiver", "").ToLower();

_adaptersCache[category].Add(new NativeAdapterInfo
{
Key = $"native.{adapterName}",
Name = type.Name,
Type = type,
Category = category
});
return result;
}

public IEnumerable<string> GetNativeAdapters(string prefix)
public INativeInfolinkReceiver GetNativeReceiver(string adapterId, IDictionary<string, string> settings)
{
if (string.IsNullOrEmpty(prefix))
var result =
nativeReceivers.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase));
if (result != null)
{
return _adaptersCache.Values.SelectMany(v => v).Select(a => a.Key);
result.InitializeStartupValues(settings);
}

var category = prefix.ToLower().TrimStart('.');

if (_adaptersCache.TryGetValue(category, out var adapters))
{
return adapters.Select(a => a.Key);
}

return Enumerable.Empty<string>();
}

public NativeAdapterInfo GetNativeAdapterInfo(string adapterId)
{
return _adaptersCache.Values
.SelectMany(v => v)
.FirstOrDefault(a => a.Key.Equals(adapterId, StringComparison.OrdinalIgnoreCase));
return result;
}

public Dictionary<string, string> GetNativeAdapterProperties(string adapterId)
public INativeInfolinkValidator GetNativeValidator(string adapterId, IDictionary<string, string> settings)
{
var adapterInfo = GetNativeAdapterInfo(adapterId);
if (adapterInfo == null)
return new Dictionary<string, string>();

var result = new Dictionary<string, string>();

// Get constructor parameters
var constructor = adapterInfo.Type.GetConstructors()
.FirstOrDefault(c => c.GetParameters().Length > 0);

if (constructor == null)
return result;

// Get the first parameter type (input model)
var inputParameter = constructor.GetParameters().FirstOrDefault();
if (inputParameter == null)
return result;

var inputType = inputParameter.ParameterType;

// Get all properties from the input model
var properties = inputType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (var prop in properties)
var result =
nativeValidators.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase));
if (result != null)
{
var defaultValue = GetDefaultValue(prop);
var hasRequiredAttribute = prop.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null;
var isRequired = hasRequiredAttribute || (!IsNullableType(prop.PropertyType) && defaultValue == null);

if (isRequired)
{
result[prop.Name] = $"{prop.Name} *";
}
else
{
result[prop.Name] = $"{prop.Name} ({defaultValue ?? "null"})";
}
result.InitializeStartupValues(settings);
}

return result;
}
Comment on lines +48 to 82

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's find the NativeAdapterDiscoveryService.cs file and examine it
fd "NativeAdapterDiscoveryService.cs" --type f

Repository: simplify9/Bitween-api

Length of output: 121


🏁 Script executed:

#!/bin/bash
# Search for Name property implementations in native adapters
rg -n "public string Name\s*[={]" --type cs -A 2

Repository: simplify9/Bitween-api

Length of output: 7083


🏁 Script executed:

#!/bin/bash
# Look for INativeInfolinkHandler, INativeInfolinkReceiver, INativeInfolinkValidator implementations
rg -n "class.*implements.*INativeInfolink(Handler|Receiver|Validator)" --type cs -A 3

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Search more broadly for native adapter implementations
rg -n "class.*Native.*Handler|class.*Native.*Receiver|class.*Native.*Validator" --type cs -B 1 -A 5

Repository: simplify9/Bitween-api

Length of output: 694


🏁 Script executed:

#!/bin/bash
# Read the NativeAdapterDiscoveryService to see the complete matching logic
cat -n SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs | head -120

Repository: simplify9/Bitween-api

Length of output: 5489


🏁 Script executed:

#!/bin/bash
# Look for receiver and validator implementations
fd ".*Receiver.*\.cs|.*Validator.*\.cs" --type f | grep -i native

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check the Interfaces.cs to see the interface definitions
cat -n SW.Bitween.NativeAdapters/Interfaces.cs

Repository: simplify9/Bitween-api

Length of output: 651


🏁 Script executed:

#!/bin/bash
# Search for any INativeInfolinkReceiver and INativeInfolinkValidator implementations
rg -n "INativeInfolink(Receiver|Validator)" --type cs -B 2 -A 8

Repository: simplify9/Bitween-api

Length of output: 3975


🏁 Script executed:

#!/bin/bash
# Let's look for actual receiver and validator implementations
fd ".*\.cs" -x grep -l "INativeInfolinkReceiver\|INativeInfolinkValidator" {} \;

Repository: simplify9/Bitween-api

Length of output: 165


🏁 Script executed:

#!/bin/bash
# Check for receiver and validator implementations with their Name properties
rg -n "class.*:.*INativeInfolink(Receiver|Validator)" --type cs -A 10 | head -50

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Search for any implementations of these interfaces more broadly
rg "INativeInfolinkReceiver|INativeInfolinkValidator" --type cs -B 5 -A 5

Repository: simplify9/Bitween-api

Length of output: 3861


🏁 Script executed:

#!/bin/bash
# Check what adapters actually exist in the repository
find . -name "*Adapter*.cs" -o -name "*Handler*.cs" -o -name "*Receiver*.cs" -o -name "*Validator*.cs" | grep -v node_modules

Repository: simplify9/Bitween-api

Length of output: 673


🏁 Script executed:

#!/bin/bash
# Let's check if there are any other implementations by looking at the inheritance
rg "class.*:" --type cs | grep -i "inative"

Repository: simplify9/Bitween-api

Length of output: 208


🏁 Script executed:

#!/bin/bash
# Check the sample implementations
cat -n SW.Bitween.SampleValidator/Handler.cs

Repository: simplify9/Bitween-api

Length of output: 1037


🏁 Script executed:

#!/bin/bash
# Check the sample handler
cat -n SW.Bitween.SampleHandler/Handler.cs

Repository: simplify9/Bitween-api

Length of output: 739


🏁 Script executed:

#!/bin/bash
# Check the sample mapper
cat -n SW.Bitween.SampleMapper/Handler.cs

Repository: simplify9/Bitween-api

Length of output: 747


🏁 Script executed:

#!/bin/bash
# Let's search for where GetNativeHandler, GetNativeReceiver, and GetNativeValidator are called
rg "GetNativeHandler|GetNativeReceiver|GetNativeValidator" --type cs -B 2 -A 2

Repository: simplify9/Bitween-api

Length of output: 4069


🏁 Script executed:

#!/bin/bash
# Search for any class implementing INativeInfolinkReceiver or INativeInfolinkValidator
rg "implements.*INativeInfolink(Receiver|Validator)|:\s*(INativeInfolink(Receiver|Validator))" --type cs

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Get the full context of how adapters are passed to the service
cat -n SW.Bitween.Api/Services/XchangeService.cs | grep -A 5 -B 5 "GetNativeHandler\|GetNativeReceiver\|GetNativeValidator" | head -60

Repository: simplify9/Bitween-api

Length of output: 2291


🏁 Script executed:

#!/bin/bash
# Check the NativeHttpHandler to understand its Name property value
cat -n SW.Bitween.NativeAdapters/HttpHandler/NativeHttpHandler.cs | head -170 | tail -20

Repository: simplify9/Bitween-api

Length of output: 1087


🏁 Script executed:

#!/bin/bash
# Let's look for where adapterId/serverlessId/validatorId strings come from
rg "GetNativeReceiver\|GetNativeValidator" --type cs -B 10 | head -80

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check ReceivingService more carefully to see what value is passed to GetNativeReceiver
cat -n SW.Bitween.Api/Services/ReceivingService.cs | grep -B 20 "GetNativeReceiver"

Repository: simplify9/Bitween-api

Length of output: 1193


🏁 Script executed:

#!/bin/bash
# Search for any other implementations or test files that might show expected adapter IDs
find . -name "*.cs" -type f | xargs grep -l "native\." | head -20

Repository: simplify9/Bitween-api

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Let's verify if there are any tests or integration files that show expected adapter IDs
find . -name "*Test*" -o -name "*test*" -o -name "*spec*" | grep -i adapter

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check for any database or configuration files that might define adapter IDs
fd ".*\.(json|xml|yaml|yml|config)" | xargs grep -l "native\." 2>/dev/null | head -10

Repository: simplify9/Bitween-api

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Let's check the complete NativeHttpHandler to see if it implements multiple interfaces
cat -n SW.Bitween.NativeAdapters/HttpHandler/NativeHttpHandler.cs | head -20

Repository: simplify9/Bitween-api

Length of output: 728


🏁 Script executed:

#!/bin/bash
# Let's check if there are any other native adapter implementations we missed
find . -path ./node_modules -prune -o -type f -name "*.cs" -exec grep -l "INativeInfolink" {} \;

Repository: simplify9/Bitween-api

Length of output: 285


🏁 Script executed:

#!/antml:thinking
Let me reconsider what I've found:

1. I found NativeHttpHandler which implements INativeInfolinkHandler
2. NativeHttpHandler.Name = "native.httpHandler"
3. GetNativeHandler uses a.Name for matching
4. GetNativeReceiver and GetNativeValidator use a.GetType().Name for matching
5. I could not find any implementations of INativeInfolinkReceiver or INativeInfolinkValidator

The review states that GetNativeHandler uses `a.Name` while GetNativeReceiver/GetNativeValidator use `a.GetType().Name`. This is indeed what the code shows.

The inconsistency is real. However, since there are no actual implementations of Receiver or Validator, the impact is unknown. But the inconsistency is still a valid concern for code maintainability and potential future implementations.

The review comment appears to be correct - there IS an inconsistency in the matching logic. Whether this causes actual problems depends on how the adapters are named when they are implemented, but the inconsistency itself is valid to flag.
</thinking>

bash
#!/bin/bash
# Let's see the full list of files in NativeAdapters directory
ls -la SW.Bitween.NativeAdapters/

Repository: simplify9/Bitween-api

Length of output: 660


🏁 Script executed:

#!/bin/bash
# Check ServiceCollectionExtensions to see how adapters are registered
cat -n SW.Bitween.NativeAdapters/ServiceCollectionExtensions.cs

Repository: simplify9/Bitween-api

Length of output: 1248


🏁 Script executed:

#!/bin/bash
# Check the Services directory
ls -la SW.Bitween.NativeAdapters/Services/

Repository: simplify9/Bitween-api

Length of output: 247


🏁 Script executed:

#!/bin/bash
# Check ReflectionExtensions
cat -n SW.Bitween.NativeAdapters/ReflectionExtensions.cs

Repository: simplify9/Bitween-api

Length of output: 1577


🏁 Script executed:

#!/bin/bash
# Let me verify what IDs are actually being passed to these methods
# by checking if there are test files or database initialization scripts
find . -name "*Seed*" -o -name "*Migration*" -o -name "*Test*" | head -20

Repository: simplify9/Bitween-api

Length of output: 831


🏁 Script executed:

#!/an/bash
# Search for where validatorId, MapperId, HandlerId are set
rg "validatorId|MapperId|HandlerId" --type cs -B 2 -A 2 | head -100

Repository: simplify9/Bitween-api

Length of output: 9290


🏁 Script executed:

#!/bin/bash
# One more check - verify the complete method signatures to ensure we have the right picture
cat -n SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs | sed -n '48,82p'

Repository: simplify9/Bitween-api

Length of output: 1587


Inconsistent matching logic between handler, receiver, and validator lookups.

GetNativeHandler matches by the Name property (line 51, e.g., "native.httpHandler"), while GetNativeReceiver and GetNativeValidator match by GetType().Name (lines 63, 75, e.g., "NativeHttpHandler"). This inconsistency could cause lookup failures when implementing receiver or validator adapters if their naming conventions differ between the Name property and type name.

Consider using consistent matching logic across all three methods, or document the expected naming convention clearly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs` around lines 48 -
82, GetNativeHandler matches by the handler's Name property while
GetNativeReceiver and GetNativeValidator match by GetType().Name, causing
inconsistent lookups; change GetNativeReceiver and GetNativeValidator to use the
same matching logic as GetNativeHandler (match adapterId against the component's
Name using StringComparison.OrdinalIgnoreCase) and leave the
InitializeStartupValues(settings) call as-is so all three methods consistently
resolve adapters by their Name property.



public List<string> GetNativeAdapters(string? type)
{
List<INativeAdapter> adapters;

switch (type?.ToLower())
{
case "handlers":
adapters = nativeHandlers.Cast<INativeAdapter>().ToList();
break;
case "receivers":
adapters = nativeReceivers.Cast<INativeAdapter>().ToList();
break;
case "validators":
adapters = nativeValidators.Cast<INativeAdapter>().ToList();
break;
case "mappers":
adapters = nativeHandlers.Cast<INativeAdapter>().ToList();
break;
case null:
adapters = nativeAdapters.ToList();
break;
default:
return new List<string>();
}

return adapters.Select(a => a.GetType().Name).ToList();
}
private string? GetDefaultValue(PropertyInfo property)
{
// Try to get default value from DefaultValueAttribute if it exists
Expand All @@ -156,7 +124,7 @@ public Dictionary<string, string> GetNativeAdapterProperties(string adapterId)

private bool IsNullableType(Type type)
{
return !type.IsValueType ||
return !type.IsValueType ||
Nullable.GetUnderlyingType(type) != null ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
}
Expand All @@ -169,4 +137,4 @@ public class NativeAdapterInfo
public Type Type { get; set; } = null!;
public string Category { get; set; } = string.Empty;
}
}
}
56 changes: 2 additions & 54 deletions SW.Bitween.Api/Services/ReceivingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ async Task RunReceiver(IServiceProvider serviceProvider, string serverlessId,
IDictionary<string, string> startupParameters, int subId)
{
// Check if it's a native adapter
if (serverlessId.StartsWith("native.", StringComparison.OrdinalIgnoreCase))
if (serverlessId.StartsWith(NativeAdapterDiscoveryService.NativePrefix, StringComparison.OrdinalIgnoreCase))
{
var nativeAdapterDiscovery = serviceProvider.GetRequiredService<NativeAdapterDiscoveryService>();
var receiver = InstantiateNativeReceiver(nativeAdapterDiscovery, serverlessId, startupParameters);
var receiver = nativeAdapterDiscovery.GetNativeReceiver(serverlessId, startupParameters);

await receiver.Initialize();
var fileList = (await receiver.ListFiles()).ToList();
Expand Down Expand Up @@ -128,58 +128,6 @@ async Task RunReceiver(IServiceProvider serviceProvider, string serverlessId,
}
}

private IInfolinkReceiver InstantiateNativeReceiver(NativeAdapterDiscoveryService nativeAdapterDiscovery,
string adapterId, IDictionary<string, string> properties)
{
var adapterInfo = nativeAdapterDiscovery.GetNativeAdapterInfo(adapterId);
if (adapterInfo == null)
throw new BitweenException($"Native adapter not found: {adapterId}");

// Get the constructor that takes a parameter
var constructor = adapterInfo.Type.GetConstructors()
.FirstOrDefault(c => c.GetParameters().Length > 0);

if (constructor == null)
throw new BitweenException($"Native adapter {adapterId} must have a constructor that accepts an input model");

// Get the input parameter type
var inputParameter = constructor.GetParameters().First();
var inputType = inputParameter.ParameterType;

// Create an instance of the input model by mapping properties
var inputInstance = Activator.CreateInstance(inputType);

// Map dictionary properties to the input model
foreach (var prop in inputType.GetProperties())
{
// Case-insensitive property lookup
var propEntry = properties.FirstOrDefault(p =>
string.Equals(p.Key, prop.Name, StringComparison.OrdinalIgnoreCase));

if (!string.IsNullOrEmpty(propEntry.Key))
{
var value = propEntry.Value;
try
{
var convertedValue = Convert.ChangeType(value,
Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
prop.SetValue(inputInstance, convertedValue);
}
catch
{
// If conversion fails, set string value directly
if (prop.PropertyType == typeof(string))
prop.SetValue(inputInstance, value);
}
}
}

// Instantiate the adapter with the input model
var adapter = Activator.CreateInstance(adapterInfo.Type, inputInstance);

return (IInfolinkReceiver)adapter;
}


//public void Dispose()
//{
Expand Down
Loading