346 lines
9.0 KiB
C#
346 lines
9.0 KiB
C#
using System.Globalization;
|
|
using AyCode.Core.Tests.TestModels;
|
|
using AyCode.Services.SignalRs;
|
|
|
|
namespace AyCode.Services.Server.Tests.SignalRs;
|
|
|
|
/// <summary>
|
|
/// Test service with SignalR-attributed methods for testing ProcessOnReceiveMessage.
|
|
/// Uses shared DTOs from AyCode.Core.Tests.TestModels.
|
|
/// </summary>
|
|
public class TestSignalRService2
|
|
{
|
|
#region Primitive Parameter Handlers
|
|
|
|
[SignalR(TestSignalRTags.SingleIntParam)]
|
|
public string HandleSingleInt(int value)
|
|
{
|
|
return $"{value}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.TwoIntParams)]
|
|
public int HandleTwoInts(int a, int b)
|
|
{
|
|
return a + b;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.BoolParam)]
|
|
public bool HandleBool(bool loadRelations)
|
|
{
|
|
return loadRelations;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.StringParam)]
|
|
public string HandleString(string text)
|
|
{
|
|
return $"Echo: {text}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.GuidParam)]
|
|
public Guid HandleGuid(Guid id)
|
|
{
|
|
return id;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.EnumParam)]
|
|
public TestStatus HandleEnum(TestStatus status)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.NoParams)]
|
|
public string HandleNoParams()
|
|
{
|
|
return "OK";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.MultipleTypesParams)]
|
|
public string HandleMultipleTypes(bool flag, string text, int number)
|
|
{
|
|
return $"{flag}-{text}-{number}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.ThrowsException)]
|
|
public void HandleThrowsException()
|
|
{
|
|
throw new InvalidOperationException("Test exception");
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DecimalParam)]
|
|
public decimal HandleDecimal(decimal value)
|
|
{
|
|
return value * 2;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DateTimeParam)]
|
|
public DateTime HandleDateTime(DateTime dateTime)
|
|
{
|
|
return dateTime;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DoubleParam)]
|
|
public double HandleDouble(double value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.LongParam)]
|
|
public long HandleLong(long value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Complex Object Handlers (using shared DTOs)
|
|
|
|
[SignalR(TestSignalRTags.TestOrderItemParam)]
|
|
public TestOrderItem HandleTestOrderItem(TestOrderItem item)
|
|
{
|
|
return new TestOrderItem
|
|
{
|
|
Id = item.Id,
|
|
ProductName = $"Processed: {item.ProductName}",
|
|
Quantity = item.Quantity * 2,
|
|
UnitPrice = item.UnitPrice * 2,
|
|
};
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.TestOrderParam)]
|
|
public TestOrder HandleTestOrder(TestOrder order)
|
|
{
|
|
return order;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.SharedTagParam)]
|
|
public SharedTag HandleSharedTag(SharedTag tag)
|
|
{
|
|
return tag;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Collection Parameter Handlers
|
|
|
|
[SignalR(TestSignalRTags.IntArrayParam)]
|
|
public int[] HandleIntArray(int[] values)
|
|
{
|
|
return values.Select(x => x * 2).ToArray();
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.GuidArrayParam)]
|
|
public Guid[] HandleGuidArray(Guid[] ids)
|
|
{
|
|
return ids;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.StringListParam)]
|
|
public List<string> HandleStringList(List<string> items)
|
|
{
|
|
return items.Select(x => x.ToUpper()).ToList();
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.TestOrderItemListParam)]
|
|
public List<TestOrderItem> HandleTestOrderItemList(List<TestOrderItem> items)
|
|
{
|
|
return items;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.IntListParam)]
|
|
public List<int> HandleIntList(List<int> numbers)
|
|
{
|
|
return numbers.Select(x => x * 2).ToList();
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.BoolArrayParam)]
|
|
public bool[] HandleBoolArray(bool[] flags)
|
|
{
|
|
return flags;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.MixedWithArrayParam)]
|
|
public string HandleMixedWithArray(bool flag, int[] numbers, string text)
|
|
{
|
|
return $"{flag}-[{string.Join(",", numbers)}]-{text}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.NestedListParam)]
|
|
public List<List<int>> HandleNestedList(List<List<int>> nestedList)
|
|
{
|
|
return nestedList;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Extended Array Parameter Handlers
|
|
|
|
[SignalR(TestSignalRTags.LongArrayParam)]
|
|
public long[] HandleLongArray(long[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DecimalArrayParam)]
|
|
public decimal[] HandleDecimalArray(decimal[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DateTimeArrayParam)]
|
|
public DateTime[] HandleDateTimeArray(DateTime[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.EnumArrayParam)]
|
|
public TestStatus[] HandleEnumArray(TestStatus[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DoubleArrayParam)]
|
|
public double[] HandleDoubleArray(double[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.SharedTagArrayParam)]
|
|
public SharedTag[] HandleSharedTagArray(SharedTag[] tags)
|
|
{
|
|
return tags;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DictionaryParam)]
|
|
public Dictionary<string, int> HandleDictionary(Dictionary<string, int> dict)
|
|
{
|
|
return dict;
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.ObjectArrayParam)]
|
|
public object[] HandleObjectArray(object[] values)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Mixed Parameter Handlers
|
|
|
|
[SignalR(TestSignalRTags.IntAndDtoParam)]
|
|
public string HandleIntAndDto(int id, TestOrderItem item)
|
|
{
|
|
return $"{id}-{item?.ProductName}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.DtoAndListParam)]
|
|
public string HandleDtoAndList(TestOrderItem item, List<int> numbers)
|
|
{
|
|
return $"{item?.ProductName}-[{string.Join(",", numbers ?? [])}]";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.ThreeComplexParams)]
|
|
public string HandleThreeComplexParams(TestOrderItem item, List<string> tags, SharedTag sharedTag)
|
|
{
|
|
return $"{item?.ProductName}-{tags?.Count}-{sharedTag?.Name}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.FiveParams)]
|
|
public Task<string> HandleFiveParams(int a, string b, bool c, Guid d, decimal e)
|
|
{
|
|
return Task.FromResult($"{a}-{b}-{c}-{d}-{e.ToString(CultureInfo.InvariantCulture)}");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Async Task<T> Method Tests
|
|
|
|
[SignalR(TestSignalRTags.AsyncTestOrderItemParam)]
|
|
public async Task<TestOrderItem> HandleAsyncTestOrderItem(TestOrderItem item)
|
|
{
|
|
await Task.Delay(1); // Simulate async work
|
|
return new TestOrderItem
|
|
{
|
|
Id = item.Id,
|
|
ProductName = $"Async: {item.ProductName}",
|
|
Quantity = item.Quantity * 3,
|
|
UnitPrice = item.UnitPrice * 3,
|
|
};
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.AsyncStringParam)]
|
|
public async Task<string> HandleAsyncString(string input)
|
|
{
|
|
await Task.Delay(1);
|
|
return $"Async: {input}";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.AsyncNoParams)]
|
|
public async Task<string> HandleAsyncNoParams()
|
|
{
|
|
await Task.Delay(1);
|
|
return "AsyncOK";
|
|
}
|
|
|
|
[SignalR(TestSignalRTags.AsyncIntParam)]
|
|
public async Task<int> HandleAsyncInt(int value)
|
|
{
|
|
await Task.Delay(1);
|
|
return value * 2;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Task.FromResult Tests - Critical for testing non-async methods returning Task
|
|
// PRODUCTION BUG FIX: These methods test the scenario where a method returns Task<T>
|
|
// using Task.FromResult() instead of async/await. Such methods do NOT have
|
|
// AsyncStateMachineAttribute, so the old InvokeMethod implementation would serialize
|
|
// the Task wrapper instead of awaiting and returning the actual result.
|
|
|
|
/// <summary>
|
|
/// Returns Task without async keyword - uses Task.FromResult().
|
|
/// This pattern does NOT have AsyncStateMachineAttribute!
|
|
/// </summary>
|
|
[SignalR(TestSignalRTags.TaskFromResultStringParam)]
|
|
public Task<string> HandleTaskFromResultString(string input)
|
|
{
|
|
return Task.FromResult($"FromResult: {input}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns Task<TestOrderItem> without async keyword.
|
|
/// CRITICAL: This simulates the exact production bug scenario.
|
|
/// </summary>
|
|
[SignalR(TestSignalRTags.TaskFromResultTestOrderItemParam)]
|
|
public Task<TestOrderItem> HandleTaskFromResultTestOrderItem(TestOrderItem item)
|
|
{
|
|
return Task.FromResult(new TestOrderItem
|
|
{
|
|
Id = item.Id,
|
|
ProductName = $"FromResult: {item.ProductName}",
|
|
Quantity = item.Quantity * 2,
|
|
UnitPrice = item.UnitPrice * 2,
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns Task<int> without async keyword.
|
|
/// </summary>
|
|
[SignalR(TestSignalRTags.TaskFromResultIntParam)]
|
|
public Task<int> HandleTaskFromResultInt(int value)
|
|
{
|
|
return Task.FromResult(value * 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns non-generic Task using Task.CompletedTask.
|
|
/// </summary>
|
|
[SignalR(TestSignalRTags.TaskFromResultNoParams)]
|
|
public Task HandleTaskFromResultNoParams()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|