using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
public string Name { get; set; }
public string ShortName { get; set; }
public MarketType MarketType { get; set; }
public Dictionary<string, string> SpecifierValues { get; set; }
public string ShortNamePattern { get; set; }
public string NamePattern { get; set; }
public class SignalRMessageSetting
public bool GenerateShortName { get; set; }
public bool EnableMarketsSyncStateSlim { get; set; }
public interface ISettingService
Task<SignalRMessageSetting> GetSignalRMessageSettingAsync();
public interface IEventNotificationService
Task SendMarketsAsync(IEnumerable<Market> markets, Guid eventId, bool enableMarketsSyncStateSlim);
public static class NameUtils
public static string GenerateShortNameFromNamePattern(string pattern, List<Team> teams, List<Player> players, List<Roster> roster, Dictionary<string, string> specifierValues)
if (string.IsNullOrWhiteSpace(pattern))
throw new ArgumentException("Pattern cannot be null or whitespace.", nameof(pattern));
return pattern + "_" + string.Join("_", specifierValues.Values);
public List<Team> Teams { get; set; } = new List<Team>();
public List<Player> Players { get; set; } = new List<Player>();
public List<Roster> Roster { get; set; } = new List<Roster>();
public class MarketDataProcessor
private readonly ISettingService _settingService;
private readonly IEventNotificationService _eventNotificationService;
private readonly ILogger _logger;
private readonly bool _isInMultiLive;
private readonly Guid _eventId;
private readonly EventData _event;
public MarketDataProcessor(ISettingService settingService, IEventNotificationService eventNotificationService, ILogger logger, bool isInMultiLive, Guid eventId, EventData @event)
_settingService = settingService ?? throw new ArgumentNullException(nameof(settingService));
_eventNotificationService = eventNotificationService ?? throw new ArgumentNullException(nameof(eventNotificationService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_isInMultiLive = isInMultiLive;
_event = @event ?? throw new ArgumentNullException(nameof(@event));
public async Task SendSignalRMarketsInternalAsync(IEnumerable<Market> markets)
throw new ArgumentNullException(nameof(markets));
SignalRMessageSetting setting = await _settingService.GetSignalRMessageSettingAsync();
if (_isInMultiLive && setting.GenerateShortName)
foreach (var market in markets)
if (string.IsNullOrWhiteSpace(market.ShortName))
string pattern = string.IsNullOrWhiteSpace(market.MarketType?.ShortNamePattern)
? market.MarketType?.NamePattern
: market.MarketType.ShortNamePattern;
if (string.IsNullOrWhiteSpace(pattern))
throw new InvalidOperationException($"Both ShortNamePattern and NamePattern are null or whitespace for market type: {market.MarketType}");
market.ShortName = NameUtils.GenerateShortNameFromNamePattern(pattern, _event.Teams, _event.Players, _event.Roster, market.SpecifierValues);
catch (ArgumentException ex)
_logger.LogError(ex, "Error generating short name for market {MarketName}: {Message}", market.Name, ex.Message);
market.ShortName = market.Name;
catch (InvalidOperationException ex)
_logger.LogError(ex, "Error generating short name for market {MarketName}: {Message}", market.Name, ex.Message);
market.ShortName = market.Name;
_logger.LogError(ex, "Unexpected error generating short name for market {MarketName}: {Message}", market.Name, ex.Message);
market.ShortName = market.Name;
await _eventNotificationService.SendMarketsAsync(markets, _eventId, setting.EnableMarketsSyncStateSlim);
public static async Task Main(string[] args)
var settingService = new MockSettingService();
var eventNotificationService = new MockEventNotificationService();
var logger = new MockLogger();
var isInMultiLive = true;
var eventId = Guid.NewGuid();
var eventData = new EventData();
var processor = new MarketDataProcessor(settingService, eventNotificationService, logger, isInMultiLive, eventId, eventData);
var markets = new List<Market>
new Market { Name = "Market 1", MarketType = new MarketType { ShortNamePattern = "Pattern1" }, SpecifierValues = new Dictionary<string, string>() { { "spec1", "value1" } } },
new Market { Name = "Market 2", MarketType = new MarketType { ShortNamePattern = "Pattern2" }, SpecifierValues = new Dictionary<string, string>() { { "spec2", "value2" } } }
await processor.SendSignalRMarketsInternalAsync(markets);
Console.WriteLine("Markets processed.");
public class MockSettingService : ISettingService
public async Task<SignalRMessageSetting> GetSignalRMessageSettingAsync()
return await Task.FromResult(new SignalRMessageSetting { GenerateShortName = true, EnableMarketsSyncStateSlim = true });
public class MockEventNotificationService : IEventNotificationService
public async Task SendMarketsAsync(IEnumerable<Market> markets, Guid eventId, bool enableMarketsSyncStateSlim)
Console.WriteLine($"Sending {markets.Count()} markets for event {eventId}. Slim state: {enableMarketsSyncStateSlim}");
foreach(var m in markets)
Console.WriteLine($"Market: Name = {m.Name}, ShortName = {m.ShortName}");
await Task.CompletedTask;
public class MockLogger : ILogger
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
Console.WriteLine($"{logLevel}: {formatter(state, exception)}");
public bool IsEnabled(LogLevel logLevel)
public IDisposable BeginScope<TState>(TState state)
public void LogError(Exception ex, string message, params object?[] args)
Console.WriteLine($"ERROR: {message} - {ex.Message} - {string.Join(", ",args)}");
public void LogInformation(string? message, params object?[] args)
Console.WriteLine($"INFO: {message} - {string.Join(", ",args)}");