OrderNumberGenerator
Documentație pentru serviciul OrderNumberGenerator
1. Descriere Generală
OrderNumberGenerator
este un serviciu server-side care generează numere unice de comandă pentru cererile de servicii. Serviciul combină ID-ul serviciului, timestamp-ul curent și un număr aleatoriu pentru a crea identificatori unici și cronologici.
Caracteristici principale:
- Generare numere unice de comandă
- Încorporare timestamp pentru sortare cronologică
- Component aleatoriu pentru unicitate
- Format predictibil și consistent
- Utilizare RandomNumberGenerator
criptografic sigur
2. Configurare și Înregistrare
// Program.cs sau Startup.cs (server-side)
builder.Services.AddScoped<IOrderNumberGenerator, OrderNumberGenerator>();
// În modulul Server.ServicesSetup
public static IServiceCollection AddServerServices(this IServiceCollection services)
{
services.AddScoped<IOrderNumberGenerator, OrderNumberGenerator>();
return services;
}
3. Interfață
public interface IOrderNumberGenerator
{
string Generate(string serviceId);
}
4. Metodă Disponibilă
Generate
Generează un număr unic de comandă bazat pe ID-ul serviciului.
Parametri:
- serviceId
(string) - Identificatorul serviciului pentru care se generează numărul
Returnează:
- string
- Număr de comandă în format: {serviceId}{yyMMddHHmmss}{randomNumber}
Format număr generat: - Prefix: ID-ul serviciului (ex: "SR001") - Timestamp: An(2)+Lună+Zi+Oră+Minut+Secundă (12 caractere) - Sufix: Număr aleatoriu între 100-999 (3 caractere)
5. Exemple de Utilizare
Generare număr comandă simplu
public class ServiceRequestController : ControllerBase
{
private readonly IOrderNumberGenerator _orderNumberGenerator;
public ServiceRequestController(IOrderNumberGenerator orderNumberGenerator)
{
_orderNumberGenerator = orderNumberGenerator;
}
[HttpPost("create")]
public IActionResult CreateServiceRequest(ServiceRequestDto request)
{
// Generare număr comandă
var orderNumber = _orderNumberGenerator.Generate(request.ServiceId);
// Exemplu rezultat: "SR001240630143025487"
// Unde: SR001 = serviceId
// 240630 = 2024-06-30
// 143025 = 14:30:25
// 487 = număr aleatoriu
var serviceRequest = new ServiceRequest
{
OrderNumber = orderNumber,
ServiceId = request.ServiceId,
CreatedAt = DateTime.Now
// alte proprietăți...
};
_repository.Add(serviceRequest);
return Ok(new { orderNumber });
}
}
Generare pentru diferite servicii
public class OrderService
{
private readonly IOrderNumberGenerator _generator;
public OrderService(IOrderNumberGenerator generator)
{
_generator = generator;
}
public void GenerateOrdersExample()
{
// Apostilă
var apostillaOrder = _generator.Generate("APOST");
// Rezultat: "APOST240630143025123"
// Certificat
var certificateOrder = _generator.Generate("CERT");
// Rezultat: "CERT240630143025456"
// Traducere
var translationOrder = _generator.Generate("TRAD");
// Rezultat: "TRAD240630143025789"
// Serviciu personalizat
var customOrder = _generator.Generate("CUSTOM-001");
// Rezultat: "CUSTOM-001240630143025234"
}
}
Batch generation cu garantare unicitate
public class BatchOrderService
{
private readonly IOrderNumberGenerator _generator;
private readonly ILogger<BatchOrderService> _logger;
public async Task<List<string>> GenerateBatchOrders(
string serviceId,
int count)
{
var orders = new HashSet<string>();
var attempts = 0;
var maxAttempts = count * 10; // Protecție împotriva buclei infinite
while (orders.Count < count && attempts < maxAttempts)
{
var orderNumber = _generator.Generate(serviceId);
if (orders.Add(orderNumber))
{
_logger.LogInformation(
"Generated order number: {OrderNumber}",
orderNumber);
}
else
{
// Foarte puțin probabil datorită componentei aleatorii
_logger.LogWarning(
"Duplicate order number detected: {OrderNumber}",
orderNumber);
}
attempts++;
// Delay minim pentru a evita coliziuni de timestamp
if (orders.Count < count)
{
await Task.Delay(1);
}
}
return orders.ToList();
}
}
6. Integrare cu alte servicii
Cu serviciul de cereri
public class ServiceRequestService
{
private readonly IOrderNumberGenerator _orderGenerator;
private readonly IServiceRequestRepository _repository;
private readonly INotificationService _notificationService;
public ServiceRequestService(
IOrderNumberGenerator orderGenerator,
IServiceRequestRepository repository,
INotificationService notificationService)
{
_orderGenerator = orderGenerator;
_repository = repository;
_notificationService = notificationService;
}
public async Task<ServiceRequestResult> CreateRequest(
CreateServiceRequestDto dto)
{
// Generare număr comandă
var orderNumber = _orderGenerator.Generate(dto.ServiceId);
var request = new ServiceRequest
{
OrderNumber = orderNumber,
ServiceId = dto.ServiceId,
UserId = dto.UserId,
Status = ServiceRequestStatus.New,
CreatedAt = DateTime.UtcNow,
Data = dto.Data
};
await _repository.AddAsync(request);
// Notificare cu numărul de comandă
await _notificationService.SendAsync(new Notification
{
UserId = dto.UserId,
Subject = "Cerere înregistrată",
Message = $"Cererea dvs. a fost înregistrată cu numărul: {orderNumber}"
});
return new ServiceRequestResult
{
Success = true,
OrderNumber = orderNumber,
RequestId = request.Id
};
}
}
Cu audit și tracking
public class AuditableOrderService
{
private readonly IOrderNumberGenerator _generator;
private readonly IAuditService _auditService;
public async Task<string> GenerateAuditedOrder(
string serviceId,
string userId,
Dictionary<string, object> metadata = null)
{
var orderNumber = _generator.Generate(serviceId);
// Înregistrare audit
await _auditService.LogAsync(new AuditEntry
{
Action = "OrderGenerated",
EntityType = "ServiceRequest",
EntityId = orderNumber,
UserId = userId,
Timestamp = DateTime.UtcNow,
Details = new
{
ServiceId = serviceId,
OrderNumber = orderNumber,
Metadata = metadata
}
});
return orderNumber;
}
}
7. Parsare și validare numere generate
public class OrderNumberParser
{
public OrderNumberInfo Parse(string orderNumber)
{
if (string.IsNullOrEmpty(orderNumber) || orderNumber.Length < 15)
{
throw new ArgumentException("Invalid order number format");
}
// Extrage componentele
var timestampStart = orderNumber.Length - 15; // 12 timestamp + 3 random
var serviceId = orderNumber.Substring(0, timestampStart);
var timestamp = orderNumber.Substring(timestampStart, 12);
var randomPart = orderNumber.Substring(orderNumber.Length - 3);
// Parsare timestamp
var year = 2000 + int.Parse(timestamp.Substring(0, 2));
var month = int.Parse(timestamp.Substring(2, 2));
var day = int.Parse(timestamp.Substring(4, 2));
var hour = int.Parse(timestamp.Substring(6, 2));
var minute = int.Parse(timestamp.Substring(8, 2));
var second = int.Parse(timestamp.Substring(10, 2));
var dateTime = new DateTime(year, month, day, hour, minute, second);
return new OrderNumberInfo
{
ServiceId = serviceId,
GeneratedAt = dateTime,
RandomComponent = randomPart,
FullOrderNumber = orderNumber
};
}
}
public class OrderNumberInfo
{
public string ServiceId { get; set; }
public DateTime GeneratedAt { get; set; }
public string RandomComponent { get; set; }
public string FullOrderNumber { get; set; }
}
8. Implementare personalizată
public class CustomOrderNumberGenerator : IOrderNumberGenerator
{
private readonly IConfiguration _configuration;
private readonly ISystemClock _clock;
public CustomOrderNumberGenerator(
IConfiguration configuration,
ISystemClock clock)
{
_configuration = configuration;
_clock = clock;
}
public string Generate(string serviceId)
{
var prefix = _configuration["OrderNumber:Prefix"] ?? "";
var separator = _configuration["OrderNumber:Separator"] ?? "-";
var includeMilliseconds = _configuration.GetValue<bool>("OrderNumber:IncludeMilliseconds");
var now = _clock.UtcNow;
var timestamp = includeMilliseconds
? now.ToString("yyMMddHHmmssfff")
: now.ToString("yyMMddHHmmss");
var random = GenerateSecureRandom();
return $"{prefix}{serviceId}{separator}{timestamp}{separator}{random}";
}
private string GenerateSecureRandom()
{
// Folosește 4 cifre pentru mai multă unicitate
return RandomNumberGenerator.GetInt32(1000, 9999).ToString();
}
}
9. Best Practices
- Unicitate: Deși generatorul include o componentă aleatorie, pentru aplicații critice considerați verificarea unicității în baza de date
- Timezone: Utilizați UTC pentru aplicații internaționale
- Format consistent: Păstrați același format pentru toate serviciile pentru a facilita parsarea
- Stocare: Indexați câmpul orderNumber în baza de date pentru căutări rapide
- Validare: Implementați validare pentru a detecta numere de comandă invalide sau modificate
10. Testing
[TestClass]
public class OrderNumberGeneratorTests
{
private readonly IOrderNumberGenerator _generator = new OrderNumberGenerator();
[TestMethod]
public void Generate_ReturnsCorrectFormat()
{
// Arrange
var serviceId = "TEST";
// Act
var result = _generator.Generate(serviceId);
// Assert
Assert.IsTrue(result.StartsWith(serviceId));
Assert.AreEqual(serviceId.Length + 15, result.Length);
// Verificare componentă numerică
var numericPart = result.Substring(serviceId.Length);
Assert.IsTrue(long.TryParse(numericPart, out _));
}
[TestMethod]
public void Generate_ProducesUniqueNumbers()
{
// Arrange
var serviceId = "TEST";
var numbers = new HashSet<string>();
// Act
for (int i = 0; i < 100; i++)
{
var number = _generator.Generate(serviceId);
numbers.Add(number);
Thread.Sleep(1); // Asigură timestamp diferit
}
// Assert
Assert.AreEqual(100, numbers.Count);
}
}
11. Concluzie
OrderNumberGenerator
oferă o soluție simplă și eficientă pentru generarea de numere unice de comandă în aplicațiile FOD. Cu format predictibil care include informații despre timp și serviciu, facilitează atât identificarea unică cât și sortarea cronologică a cererilor. Componenta aleatorie criptografic sigură asigură unicitate chiar și pentru cereri generate în același moment.