### Example Service Using IRepository Source: https://context7.com/luxoft/bssframework/llms.txt Demonstrates how to use `IRepositoryFactory` to create repositories for domain objects. Shows examples of creating repositories with and without security rules, and performing basic CRUD operations. ```csharp public class ExampleService( IRepositoryFactory employeeFactory, IRepositoryFactory buFactory) { // No security check (admin context) private readonly IRepository adminRepo = employeeFactory.Create(); // Only rows the current user is allowed to VIEW private readonly IRepository viewRepo = buFactory.Create(SecurityRule.View); public async Task<(List, List)> LoadPairAsync(CancellationToken ct = default) { var employees = await adminRepo.GetQueryable().GenericToHashSetAsync(ct); var businessUnits = await viewRepo.GetQueryable().GenericToHashSetAsync(ct); return (employees.ToList(), businessUnits.ToList()); } public async Task SaveNewEmployee(CancellationToken ct = default) { var employee = new Employee { Login = "luxoft\jdoe", Email = "jdoe@luxoft.com" }; await adminRepo.InsertAsync(employee, Guid.NewGuid(), ct); } public async Task UpdateEmployee(Employee employee, CancellationToken ct = default) { employee.Email = "updated@luxoft.com"; await adminRepo.SaveAsync(employee, ct); } public async Task DeleteEmployee(Employee employee, CancellationToken ct = default) { await adminRepo.RemoveAsync(employee, ct); } } ``` -------------------------------- ### Xunit Integration Test Setup Source: https://github.com/luxoft/bssframework/blob/main/docs/integrationtests.md Implement IAutomationCoreInitialization and configure the test framework for xUnit. Use [BssTheory] instead of xUnit's [Theory] to leverage test initialization and cleanup features. ```csharp [assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass)] [assembly: TestFramework("Bss.Testing.Xunit.TestFramework", "Bss.Testing.Xunit")] public class EnvironmentInitializer : AutomationCoreFrameworkInitializer { public override IServiceCollection ConfigureFramework(IServiceCollection services) => services .AddSingleton() .AddSingleton() .AddSingleton( new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", false) .AddEnvironmentVariables($"{nameof(SampleSystem)}_" ) .Build()); public override IServiceProvider ConfigureTestEnvironment(IServiceCollection services, IConfiguration configuration) => services .AddApplication(configuration, new HostingEnvironment { EnvironmentName = Environments.Development }) .AddIntegrationTestServices( options => { options.IntegrationTestUserName = TestConstants.Principals.Admin.Name; }) .BuildServiceProvider(); } ``` -------------------------------- ### Integration Testing Assembly Setup (xUnit) Source: https://context7.com/luxoft/bssframework/llms.txt Configures xUnit test framework behavior at the assembly level, including collection behavior and specifying the test framework. This setup is required for AutomationCoreFramework integration tests. ```csharp // Assembly-level setup (xUnit): [assembly: CollectionBehavior(CollectionBehavior.CollectionPerClass)] [assembly: TestFramework("Bss.Testing.Xunit.TestFramework", "Bss.Testing.Xunit")] ``` -------------------------------- ### Code Generation for BSS Framework Artifacts Source: https://context7.com/luxoft/bssframework/llms.txt Examples of running code generators for BLL factories, DTOs, NHibernate mappings, and REST controllers. Includes a CI gate to check for up-to-date generated files. ```csharp // SampleSystem.CodeGenerate project: run to regenerate all artefacts. public class ServerGenerators : GeneratorsBase { [Fact] public void GenerateBLLCore() => this.GenerateBLLCoreFiles(new BLLCoreGeneratorConfiguration(this.Environment)); [Fact] public void GenerateDTO() => this.GenerateServerDTOFiles(new ServerDTOGeneratorConfiguration(this.Environment)); [Fact] public void GenerateDAL() => this.GenerateDALFiles(new DALGeneratorConfiguration(this.Environment)); [Fact] public void GenerateWebApi() => this.GenerateMainServiceFiles(new MainServiceGeneratorConfiguration(this.Environment)); } // Check generated files are up-to-date (CI gate): public class GenerationTests { [Fact] public void GeneratedFilesAreUpToDate() { // Runs all generators in-memory and compares to committed output. // Fails the build if the domain model changed but generation was not run. ServerGenerators.CheckAllGeneratedFilesAreActual(); } } ``` -------------------------------- ### Register SMTP Notification Service Source: https://context7.com/luxoft/bssframework/llms.txt Registers the SMTP notification service in the Dependency Injection container. In non-production environments, this setup activates email redirection to a test address and rewrites receiver addresses. ```csharp services.AddSmtpNotification(configuration, isProd: false); ``` -------------------------------- ### Register Core Application Services Source: https://context7.com/luxoft/bssframework/llms.txt Use `AddGenericApplicationServices` to wire up core DI services. Optional configurations for named locks and DAL event listeners are also shown. ```csharp services.AddGenericApplicationServices(); // Optional: named locks services.AddNamedLocks(setup => { setup.Add(); }); // Optional: DAL event listeners services.AddListeners(setup => { setup.Add(); }); ``` -------------------------------- ### Authorization: Managing Principals, Roles, and Permissions Source: https://context7.com/luxoft/bssframework/llms.txt Demonstrates creating principals with permissions via a REST API facade, delegating permissions to other principals, and removing permissions. Handles potential exceptions like ObjectByIdNotFoundException. ```csharp var authController = GetAuthControllerEvaluator(); var roleIdentity = authController .Evaluate(c => c.GetSimpleBusinessRoleByName("HR_Manager")) .Identity; var principalStrict = new PrincipalStrictDTO { Name = "luxoft\jdoe", Permissions = [new PermissionStrictDTO { Role = roleIdentity }] }; var principalIdentity = authController.Evaluate(c => c.SavePrincipal(principalStrict)); ``` ```csharp var delegateModel = new ChangePermissionDelegatesModelStrictDTO { DelegateFromPermission = permissionIdentity, Items = { new DelegateToItemModelStrictDTO { Principal = delegateePrincipalIdentity, Permission = new PermissionStrictDTO { Role = roleIdentity } } } }; authController.Evaluate(c => c.ChangeDelegatePermissions(delegateModel)); ``` ```csharp authController.Evaluate(c => c.RemovePermission(permissionIdentity)); // Throws ObjectByIdNotFoundException if already removed. ``` -------------------------------- ### SampleSystemBLLContext Definition Source: https://context7.com/luxoft/bssframework/llms.txt Defines the SampleSystemBLLContext, inheriting from SecurityBLLBaseContext. It exposes strongly-typed BLL factories via the Logics property and includes various dependencies for BLL operations. ```csharp public partial class SampleSystemBLLContext( IServiceProvider serviceProvider, IEventOperationSender operationSender, IAccessDeniedExceptionService accessDeniedExceptionService, IHierarchicalObjectExpanderFactory hierarchicalObjectExpanderFactory, ITrackingService trackingService, ISelectOperationParser selectOperationParser, ISampleSystemValidator validator, IRootSecurityService securityService, ISampleSystemBLLFactoryContainer logics, IAuthorizationBLLContext authorization, IConfigurationBLLContext configuration, ISecurityAccessorResolver securityAccessorResolver, ICurrentUserSource currentEmployeeSource) : SecurityBLLBaseContext(...) { public override ISampleSystemBLLFactoryContainer Logics { get; } = logics; public IValidator Validator { get; } = validator; } ``` -------------------------------- ### AutomationCoreFramework Environment Initializer Source: https://context7.com/luxoft/bssframework/llms.txt Initializes the test environment for AutomationCoreFramework by configuring services, including the test database generator and application services. It also sets up the hosting environment for development. ```csharp public class EnvironmentInitializer : AutomationCoreFrameworkInitializer { public override IServiceCollection ConfigureFramework(IServiceCollection services) => services .AddSingleton() .AddSingleton() .AddSingleton( new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", false) .AddEnvironmentVariables("SampleSystem_") .Build()); public override IServiceProvider ConfigureTestEnvironment( IServiceCollection services, IConfiguration configuration) => services .AddApplication(configuration, new HostingEnvironment { EnvironmentName = Environments.Development }) .AddIntegrationTestServices(o => { o.IntegrationTestUserName = "admin"; }) .BuildServiceProvider(); } ``` -------------------------------- ### Add SMTP Notification in Startup Source: https://context7.com/luxoft/bssframework/llms.txt Configures the application to use SMTP notifications by calling `AddSmtpNotification`. The `isProd` parameter should be set based on the current environment to enable or disable email redirection. ```csharp services.AddSmtpNotification(configuration, isProd: Environment.IsProduction()); ``` -------------------------------- ### Integration Test Configuration in appsettings.json Source: https://context7.com/luxoft/bssframework/llms.txt Defines settings for integration tests, including system name, test run mode, local database usage, test run server folder, and connection strings for the main database. ```json { "SystemName": "SampleSystem", "TestRunMode": "DefaultRunModeOnEmptyDatabase", "UseLocalDb": true, "TestRunServerRootFolder": "C:\\Temp\\TestRun", "ConnectionStrings": { "Main": "Server=(localdb)\\MSSQLLocalDB;Database=SampleSystem_Test;Trusted_Connection=True;" } } ``` -------------------------------- ### SMTP Notification Pipeline Overview Source: https://context7.com/luxoft/bssframework/llms.txt Illustrates the sequence of components involved in sending an email notification, from initial message generation to the final SMTP sending and optional logging. ```text // The pipeline: // IMessageSender → NotificationMessageSender // → IMailMessageModifier[] (HtmlMarker, SubjectCleaner, RedirectToSupport, [RedirectToTest]) // → IMessageSender → SmtpMessageSender // → ISentNotificationLogger? (optional audit log) ``` -------------------------------- ### TestRunMode Configuration Options Source: https://context7.com/luxoft/bssframework/llms.txt Enum options for controlling the database lifecycle during test runs. Useful for debugging and rapid iteration. ```csharp // TestRunMode enum controls the database lifecycle for each test run: // // DefaultRunModeOnEmptyDatabase (default): // - Fresh DB generated before tests; deleted after. // // RestoreDatabaseUsingAttach: // - Reuses existing detached MDF/LDF files if present; preserves them after. // - Useful for debugging long-running test data seeds. // // GenerateTestDataOnExistingDatabase: // - Runs against a pre-existing database with no generation or deletion. // - Use for rapid iteration against a shared dev database. // In appsettings.json: { "TestRunMode": "RestoreDatabaseUsingAttach", "TestsParallelize": true // enables randomised DB name for parallel safety } ``` -------------------------------- ### Integration Test with TestBase Source: https://context7.com/luxoft/bssframework/llms.txt Demonstrates using TestBase for integration tests, including data saving, API calls, and assertions. ```csharp public class EmployeeTests : TestBase { [Fact] public void AddNewEmployee_CheckEmployeeSaved() { var controller = this.MainWebApi.Employee; var identity = this.DataHelper.SaveEmployee(Guid.NewGuid()); var employees = controller.Evaluate(c => c.GetSimpleEmployees()); Assert.Contains(employees, e => e.Id == identity.Id); } [Fact] public void GetEmployeeByOData_FilterByPin_ReturnsCorrectSubset() { var qCtrl = this.GetControllerEvaluator(); foreach (var pin in new[] { 123, 456 }) { var id = this.DataHelper.SaveEmployee(Guid.NewGuid()); var emp = this.MainWebApi.Employee.Evaluate(c => c.GetSimpleEmployee(id)); emp.Pin = pin; this.MainWebApi.Employee.Evaluate(c => c.SaveEmployee(emp.ToStrict())); } var result = qCtrl.Evaluate( c => c.GetSimpleEmployeesByODataQueryString("$top=30&$filter=substringof('23',Pin)")); var pins = result.Items.Select(x => x.Pin).ToArray(); Assert.Contains(123, pins); Assert.DoesNotContain(456, pins); } [Fact] public void ChangeEmployee_ProcessModifications_ContainsNotification() { var employeeId = this.DataHelper.SaveEmployee(Guid.NewGuid()); var version = this.MainWebApi.Employee.Evaluate(c => c.GetSimpleEmployee(employeeId)).Version; this.ClearNotifications(); this.MainWebApi.Employee.Evaluate( c => c.UpdateEmployee(new EmployeeUpdateDTO { Id = employeeId.Id, Interphone = Maybe.Return("1234"), Version = version })); this.GetConfigurationControllerEvaluator() .WithImpersonate("integration-bus") .Evaluate(c => c.ProcessModifications(1000)); var notifications = this.GetNotifications(); Assert.Single( notifications, n => n.Message.Message.Contains("Hi there!!!") && n.TechnicalInformation.ContextObjectId == employeeId.Id); } [Fact] public void DirectBLLQuery_FilterByAge_ExcludesNulls() { this.DataHelper.SaveEmployee(Guid.NewGuid(), age: 10); var result = this.Evaluate( DBSessionMode.Read, ctx => ctx.Logics.Employee .GetUnsecureQueryable() .Where(q => q.Age == 10) .ToList()); Assert.Single(result); Assert.All(result, e => Assert.Equal(10, e.Age)); } } ``` -------------------------------- ### Validation Framework: Attribute-Based and Custom Rules Source: https://context7.com/luxoft/bssframework/llms.txt Illustrates how to define validation rules using attributes on domain types and extend the validation map with custom validators. Validation is automatically triggered on BLL Save calls. ```csharp public class Country : PersistentDomainObjectBase { [RequiredValidator] [MaxLengthValidator(3)] [EnglishAlphabetValidator] public virtual string Code { get; set; } [RequiredValidator] public virtual string Name { get; set; } } ``` ```csharp public partial class SampleSystemValidationMap { protected override IEnumerable> GetEmployee_ExternalIdValidators() { yield return new EmployeeExternalIdValidator(); // custom logic } } ``` ```csharp public class EmployeeExternalIdValidator : PropertyValidator { public override ValidationResult Validate(PropertyValidationContext ctx) { if (ctx.Value <= 0) return ValidationResult.CreateError(ctx, "ExternalId must be positive"); return ValidationResult.Success; } } ``` ```csharp bllContext.Logics.Employee.Save(employee); // throws AggregateValidationException on failure ``` -------------------------------- ### Execute Async with Read Session Source: https://context7.com/luxoft/bssframework/llms.txt Executes an asynchronous operation using a read-only database session. No specific user credentials are required. ```csharp public async Task> GetActiveAsync() => await evaluator.EvaluateAsync( DBSessionMode.Read, ctx => Task.FromResult( ctx.Logics.Employee.GetUnsecureQueryable() .Where(e => e.Active) .ToList())); ``` -------------------------------- ### Execute Async with Write Session and User Credentials Source: https://context7.com/luxoft/bssframework/llms.txt Performs an asynchronous operation requiring a writable database session and specific user credentials. The operation modifies employee email domains and returns the count of modified employees. ```csharp public async Task BulkUpdateEmailDomainAsync(string oldDomain, string newDomain) { await evaluator.EvaluateAsync( DBSessionMode.Write, new UserCredential("integration-bus"), async ctx => { var employees = ctx.Logics.Employee .GetUnsecureQueryable() .Where(e => e.Email.EndsWith(oldDomain)) .ToList(); employees.ForEach(e => e.Email = e.Email.Replace(oldDomain, newDomain)); ctx.Logics.Employee.Save(employees); return employees.Count; // returned value type is inferred }); } ``` -------------------------------- ### SMTP Notification Configuration in appsettings.json Source: https://context7.com/luxoft/bssframework/llms.txt Configures SMTP server details, including host, port, SSL settings, username, and password. Also includes settings for rewriting email receivers in non-production environments. ```json { "SmtpSettings": { "Host": "smtp.luxoft.com", "Port": 587, "EnableSsl": true, "UserName": "svc-notifications@luxoft.com", "Password": "***" }, "RewriteReceiversSettings": { "TestAddress": "dev-team@luxoft.com", "Rules": [] } } ``` -------------------------------- ### BLL Registration Resolution Source: https://context7.com/luxoft/bssframework/llms.txt Details the components resolved and registered by AddBLLSystem, including ISampleSystemValidator, ISampleSystemBLLFactoryContainer, ISampleSystemBLLContext, and IFetchRuleExpander. ```csharp // The call resolves and registers: // ISampleSystemValidator → SampleSystemValidator // ISampleSystemBLLFactoryContainer → SampleSystemBLLFactoryContainer // ISampleSystemBLLContext → SampleSystemBLLContext (scoped) // IFetchRuleExpander → SampleSystemFetchRuleExpander ``` -------------------------------- ### MediatR Handler Usage of BLL Factory Source: https://context7.com/luxoft/bssframework/llms.txt Demonstrates how a MediatR handler uses an IEmployeeBLLFactory to obtain a security-filtered BLL instance for retrieving active employees. ```csharp // Usage in a MediatR handler: public class GetEmployeesHandler(IEmployeeBLLFactory employeeBllFactory) : IRequestHandler { // Factory.Create(rule) returns a security-filtered BLL instance private readonly IEmployeeBLL bll = employeeBllFactory.Create(SecurityRule.View); public async Task Handle(GetEmployeesQuery _, CancellationToken ct) { var employees = bll.GetUnsecureQueryable() .Where(e => e.Active) .ToList(); return employees.Select(e => new GetEmployeesResponse(e.Id, e.NameEng.FullName)) .ToArray(); } } ``` -------------------------------- ### Execute Synchronously with Read Session Source: https://context7.com/luxoft/bssframework/llms.txt A synchronous convenience method to count all active employees using a read-only database session. ```csharp public int CountAll() => evaluator.Evaluate( DBSessionMode.Read, ctx => ctx.Logics.Employee.GetUnsecureQueryable().Count()); ``` -------------------------------- ### Define Employee Update Subscription Source: https://context7.com/luxoft/bssframework/llms.txt Defines a subscription for employee updates, specifying the change type, sender, recipients, and a Razor template for the email body. Ensure the Razor template class implements the Execute method. ```csharp public class EmployeeUpdateSubscription : Subscription { public override DomainObjectChangeType DomainObjectChangeType { get; } = DomainObjectChangeType.Update; public override MailAddress Sender { get; } = new("SampleSystem@luxoft.com", "SampleSystem"); public override bool InlineAttachments { get; } = false; public override IEnumerable> GetTo( IServiceProvider _, DomainObjectVersions versions) { yield return new("hr-team@luxoft.com", versions); } public override IEnumerable> GetCopyTo( IServiceProvider _, DomainObjectVersions versions) { yield return new("compliance@luxoft.com", versions); } } ``` -------------------------------- ### Razor Message Template for Employee Updates Source: https://context7.com/luxoft/bssframework/llms.txt Implements a Razor template for email messages related to employee updates. This partial class requires the `Execute` method to be implemented for rendering the email body. ```csharp public partial class _Employee_Update_MessageTemplate_cshtml : RazorTemplate { public override string Subject => $"Employee {Current?.NameEng?.FullName} was updated"; protected override void Execute() { WriteLiteral("

Hi there!!!

Employee "); Write(Current?.NameEng?.FullName); WriteLiteral(" was modified.

"); } } ``` -------------------------------- ### BLL System Registration Source: https://context7.com/luxoft/bssframework/llms.txt Registers the BLL system with the service collection, specifying the BLL context interface and implementation. This enables auto-discovery of validation maps, validators, factory containers, and fetch-rule expanders. ```csharp // ServiceEnvironment / Startup.cs services.AddBLLSystem(); ``` -------------------------------- ### Security Attributes for Domain Object Access Control Source: https://context7.com/luxoft/bssframework/llms.txt Applies security attributes to domain types and properties to control BLL operations based on security rules. Supports whole-class and property-level restrictions, as well as dependency security. ```csharp // Whole-class security rules: [ViewDomainObject(typeof(SampleSystemSecurityOperation), nameof(SampleSystemSecurityOperation.EmployeeView))] [EditDomainObject(typeof(SampleSystemSecurityOperation), nameof(SampleSystemSecurityOperation.EmployeeEdit))] public partial class Employee { /* ... */ } ``` ```csharp // Property-level restriction: [ViewDomainObject(SecurityRule.View)] public virtual string SensitiveData { get; set; } ``` ```csharp // Dependency security (access inherited from parent): [DependencySecurityAttribute(typeof(Employee))] public partial class EmployeeCellPhone { /* ... */ } ``` -------------------------------- ### Domain Object Attributes for Security and DTO Roles Source: https://context7.com/luxoft/bssframework/llms.txt Defines attributes on a domain type to enforce database uniqueness, control DTO projections for view access, and manage insert/update operations. Also specifies custom serialization modes for properties. ```csharp [UniqueGroup(UseDbEvaluation = true)] [BLLViewRole(Max = MainDTOType.FullDTO)] [BLLSaveRole(SaveType = BLLSaveType.Both)] [BLLIntegrationSaveRole] public partial class Employee : AuditPersistentDomainObjectBase, ISecurityContext { [MaxLength(50)] public virtual string Email { get; set; } [MaxLength(30)] [UniqueElement] public virtual string Login { get; set; } [CustomSerialization(CustomSerializationMode.ReadOnly)] public virtual DateTime? HireDate { get; set; } [CustomSerialization(CustomSerializationMode.Ignore, DTORole.Event | DTORole.Integration)] public virtual string PersonalCellPhone { get; set; } [PropertyValidationMode(true)] public virtual DateTime ValidateVirtualProp { get; set; } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.