-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Firstly, thanks for writing this package!
Issue description
I'm having trouble with a few of the Command and Configuration methods not performing any action - upon closer inspection I found that the problem commands all share the usage of one of the parameter Enums, and are generating the below exception.
System.Collections.Generic.KeyNotFoundException: 'The given key 'System.Enum' was not present in the dictionary.'
I wrote a short test program to isolate the issue:
using CSxAPI;
using CSxAPI.API;
using CSxAPI.API.Data;
var _xAPI = new CSxAPIClient("...", "...", "...")
{
AllowSelfSignedTls = true,
ConsoleTracing = true
};
await _xAPI.Connect();
_xAPI.Status.Video.Layout.LayoutFamily.LocalChanged += LayoutChanged;
await Task.Delay(500);
LayoutNext();
await Task.Delay(500);
_xAPI.Dispose();
async void Layout(
CommandVideoLayoutLayoutFamilySetLayoutFamily layoutFamily,
CommandVideoLayoutLayoutFamilySetTarget target = CommandVideoLayoutLayoutFamilySetTarget.Local)
{
Console.WriteLine($"CiscoCodec Layout({layoutFamily})");
IDictionary<string, object> test = await _xAPI.Command.Video.Layout.LayoutFamily.Set(layoutFamily: (CommandVideoLayoutLayoutFamilySetLayoutFamily)layoutFamily, target: (CommandVideoLayoutLayoutFamilySetTarget)CommandVideoLayoutLayoutFamilySetTarget.Local);
Console.WriteLine(string.Join(", ", test.Select(pair => $"{pair.Key} => {pair.Value}")));
}
void LayoutNext()
{
Layout(CommandVideoLayoutLayoutFamilySetLayoutFamily.Auto);
}
void LayoutChanged(string newValue)
{
Console.WriteLine($"LayoutChanged: {newValue.ToString()}");
}Since we are using async void the unhandled exception crashes the program. Abridged call stack:
[Exception] System.Private.CoreLib.dll!System.ThrowHelper.ThrowKeyNotFoundException<T>(T key) Line 213 C#
[Exception] System.Private.CoreLib.dll!System.Collections.Generic.Dictionary<TKey, TValue>.this[TKey].get(TKey key) Line 199 C#
[Exception] CSxAPI.dll!CSxAPI.API.Serialization.EnumSerializer.Serialize<T>(T deserialized) Line 17 C#
[Exception] CSxAPI.dll!CSxAPI.API.Commands.CSxAPI.API.IVideoLayoutLayoutFamilyCommands.Set(string customLayoutName, CSxAPI.API.Data.CommandVideoLayoutLayoutFamilySetLayoutFamily? layoutFamily, CSxAPI.API.Data.CommandVideoLayoutLayoutFamilySetTarget? target) Line 2212 C#
[Exception] TestCSxAPI.dll!Program.<Main>$.__Layout|0(CSxAPI.API.Data.CommandVideoLayoutLayoutFamilySetLayoutFamily layoutFamily, CSxAPI.API.Data.CommandVideoLayoutLayoutFamilySetTarget target) Line 25 C#
Investigation so far
It appears that the call to ValueSerializer -> EnumSerializer for these parameters is losing the specific type information at some point, and typeof(T) is returning System.Enum in EnumSerializer.Serialize, and thus not finding the correct serialize method for that type.
Relevant generated code snippets:
// Commands.cs
async Task<IDictionary<string, object>> IVideoLayoutLayoutFamilyCommands.Set(string? customLayoutName, CommandVideoLayoutLayoutFamilySetLayoutFamily? layoutFamily, CommandVideoLayoutLayoutFamilySetTarget? target) {
return await this.transport.CallMethod(new[] { "xCommand", "Video", "Layout", "LayoutFamily", "Set" }, new Dictionary<string, object?> { { "CustomLayoutName", customLayoutName }, { "LayoutFamily", ValueSerializer.Serialize<CommandVideoLayoutLayoutFamilySetLayoutFamily>(layoutFamily) }, { "Target", ValueSerializer.Serialize<CommandVideoLayoutLayoutFamilySetTarget>(target) } }).ConfigureAwait(false);
}
// ValueSerializer.cs:
public static string? Serialize(Enum? deserialized) => deserialized is null ? null : EnumSerializer.Serialize(deserialized);
// EnumSerializer.cs:
public static string Serialize<T>(T deserialized) where T: Enum => enumSerializers[typeof(T)].serialize(deserialized);
...
enumSerializers.Add(typeof(CommandVideoLayoutLayoutFamilySetLayoutFamily) ...Possible solution
I have tried some workarounds and the best option appears to be checking the runtime type in EnumSerialiser.Serialize:
public static string Serialize(Enum? deserialized)
{
if (deserialized != null)
{
var type = deserialized.GetType();
return enumSerializers[type].serialize(deserialized);
}
else
return "";
}Due to events.xml I have not been successful in building a working package yet, but I am still working on this and will update if I can verify the fix.
Let me know if you would like me to submit an (untested) pull request.
Working command examples
Command.Audio.Microphones.Mute()Command.Bookings.List(dayOffset: 0)Command.Dial(number: "1234567890")- Feedback registrations
Problem command examples
Command.Video.Layout.LayoutFamily.Set(layoutFamily: CommandVideoLayoutLayoutFamilySetLayoutFamily.Auto, target: CommandVideoLayoutLayoutFamilySetTarget.Local)Configuration.Video.Monitors(ConfigurationVideoMonitors.Single)Command.Video.Selfview.Set(mode: CommandVideoSelfviewSetMode.On)Command.Camera.Ramp(cameraId: 1, pan: CommandCameraRampPan.Right)
I haven't exhaustively tested all commands but the pattern appears to be that each of the problematic commands is called with a typed Enum parameter.
Software versions
Tested with .NET 6.0 and .NET 8.0, compiled with VS2022 on Windows.
Tested all compiled package versions available on nuget.
If you would like me to run any tests in my environment let me know.