Base solution for your next web application

Activities of "michael.pear"

I've created issue #3481 in Github for this:

https://github.com/aspnetzero/aspnet-zero-core/issues/3481

At the time I posted, I did not have a ServiceCollectionRegistrar in my test module. I added one that mimics the one provided with the AspnetZero project, and removed the flag I had added to skip the Resolve<ChatUserStateWatcher>, and it works now.

Is there someplace that explains what adding this does in the dependency injection process? I'd like to better understand the dependency injection system in Aspnetzero.

Although I've not how to find the source of the dependency injection that is causing the error, I was able to satisfy the dependency by adding the component being requested in my test case with:

            var inMemorySqlite = new SqliteConnection("Data Source=:memory:");
            inMemorySqlite.Open();
            var options = new DbContextOptionsBuilder<NexusAppsDbContext>()
                .UseSqlite(inMemorySqlite)
                .Options;

             LocalIocManager.IocContainer.Register(
                Component
                .For<DbContextOptions<NexusAppsDbContext>>()
                .Instance(options)
                .IsDefault()
                .Named("OverridingDbContextOptions")
                .LifestyleSingleton()
                );

<br> I'm looking at ways to avoid bringing in the entire ".Application" module, which seems to create the requirement for initializing the database context I do not need for my targeted tests. That sounds like another question, so I'm marking this question as answered.

I sent a link to a folder with my project to [email protected]. Please confirm that you have access.

I am still interested in general approaches to finding dependency injection errors. Given the large number of classes in the dependency injection container, trial and error approaches are not feasible. I can see in the debugger that the LocalIocManager.IocContainer provides debugging views, and I can locate the component NexusAppsDbContext that is listed in the original error message. However, it doesn't tell me what triggers the resolution of the dependency that fails. I see mention of "diagnostic logging" in Castle Windsor which the Abp dependency injection is based on. How is that turned on? I would expect that to show me the information needed and give me an idea of how I can avoid the unnecessary attempted instantiation of NexusAppsDbContext that appears to be causing the problem.

Yes, I do for normal operation. I duplicated the configuration configuration code for the AZN project DB Context. But for the test cases I set "SkipDbContextRegistration" to true so that neither context is registered in the Core module, and I handle that in the TestBase class.

In my TestModule class:

        public TrainingManagerTestModule(NexusAppsEntityFrameworkCoreModule dbModule)
        {
            //This keeps core module from setting setting up db context. 
            //Will do that within this class.
            dbModule.SkipDbContextRegistration = true;
        }

In my TestBase class: <br>

 public TrainingManagerTestBase() : base()
        {


            if (_dbContext == null)
            {
                var builder = new DbContextOptionsBuilder<TrainingManagerDbContext>();
                builder.UseSqlServer(connectionString);
                _dbContext = new TrainingManagerDbContext(builder.Options);
                _dbContext.Database.EnsureCreated(); //Make sure database schema is created
                //Check to see if the data is seeded already
                var countTrainees = _dbContext.Trainees.Count();
                if (countTrainees >0 )
                {
                    IsSeeded = true;
                } else
                {
                    IsSeeded = false; //Indicate that data seeding is needed
                }


            }
        }

I did reduce my test case, and found that the error actually happens when the service is called. Here is the minimal test class that causes failure. If the call to the service is removed, there is no failure.  It would be nice to see where the IOC resolver is called that is resulting in the error. <br>

    public class TraineeAppService_Tests : TrainingManagerTestBase
    {
        private ITraineeAppService _traineeAppService;
        private TrainingManagerDbContext _trainingSchemaDb;
        private void InitializeDatabase()
        {
            _trainingSchemaDb = GetContext();
 
        }

        [Fact]
        public async Task GetTrainees_FromService()
        {
            InitializeDatabase();
            _traineeAppService = LocalIocManager.Resolve<ITraineeAppService>();
            var traineesAll = await _traineeAppService.GetTrainees(new NexusApps.Dto.PagedAndFilteredInputDto { Filter = String.Empty });
        }
    }

Test Base Class in Step 5

Subsitute for or whatever you ended up using for your Module file and Test base class. <br>

namespace <YourProjectName>
{
    public class <YourProjectName>Base: <YourProjectName>Base<<YourProjectName>Module>
    {
        string connectionString = "YourConnectionString ";

private YourDbContext _dbContext = null;
        public Boolean IsSeeded { get; set; }
        public <YourProjectName>Base() : base()
        {
            if (_dbContext == null)
            {
                var builder = new DbContextOptionsBuilder<YourDbContext>();
                builder.UseSqlServer(connectionString);
                _dbContext = new YourrDbContext(builder.Options);
                _dbContext.Database.EnsureCreated(); //Make sure database schema is created
                //Check to see if the data is seeded already
                var count = _dbContext.<SomeEntityThatWouldIndicateSeedingAlreadyDone>.Count();
                if (count >0 )
                {
                    IsSeeded = true;
                } else
                {
                    IsSeeded = false; //Indicate that data seeding is needed
                }
            }
        }
        public TrainingManagerDbContext GetContext()
        {
            //Check for seeding, and load data if not
            if (!IsSeeded)
            {

//Alternative to external data loader is to build in the seeding operation directly here
                using (var loader = LocalIocManager.ResolveAsDisposable<YourDataLoader>())
                {
                    loader.Object.CreateDbContext(connectionString);
                    loader.Object.LoadData(@"data\SeedData.json");
                }
                IsSeeded = true;
            }
            //Make sure _dbContext is not disposed during seeding operation!
            return _dbContext;
        }
    }
    public abstract class <YourProjectName>Base<T> : AbpIntegratedTestBase<T> where T : AbpModule
    {
        protected <YourProjectName>Base()
        {

        }
    }

Module class from Step 3:

I replaced my project name with "&lt;YourProjectName>" for your test project. Also, the data loading module reference can be left out if you will seed data directly in your test base class.

namespace <YourProjectName>
{
    [DependsOn(
        typeof(<DataLoadingModuleIfYouHaveOne>), //This is a module with data loading utilities
        typeof(NexusAppsEntityFrameworkCoreModule),
        typeof(AbpTestBaseModule))]
    public class <YourProjectName>Module : AbpModule
    {
        public <YourProjectName>Module(<AspNetZeroProject>EntityFrameworkCoreModule dbModule)
        {
            //This keeps core module from setting setting up db context. 
            //Will do that within this class.
            dbModule.SkipDbContextRegistration = true;
        }
        public override void PreInitialize()
        {
            var configuration = GetConfiguration();
            //Use as means to communicate configinfo
            LocalConfiguration = configuration;
            //May not be needed.
            Configuration.Modules.AbpAutoMapper().UseStaticMapper = false;
            Configuration.ReplaceService<IAppConfigurationAccessor, <YourProjectName>ConfigurationAccessor>();
            Configuration.Modules.AspNetZero().LicenseCode = configuration["AbpZeroLicenseCode"];
        }

        public IConfigurationRoot LocalConfiguration { get; set; }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(<YourProjectName>Module).GetAssembly());
        }

        private static IConfigurationRoot GetConfiguration()
        {
            return AppConfigurations.Get(Directory.GetCurrentDirectory(), addUserSecrets: false);
        }
    }
}

I recently did this in order to allow for using my DB Context with MSSQLocalDb rather than SQLLite or an InMemory database, due to some of the limitations of those. I also had the objective of keeping the project as simple as possible, without all the cpmplexities that come along with the AspNetZero test. I found that modeling it after the ".GraphQL.Tests" was an easier starting point. ( is your project name) Here are the steps I followed: <br>

  1. Created separate DbContext in .EntityFrameWorkCore project, which except for modifications to EntityFrameworkCoreModule.cs to initialize the context.
  2. Create a new, empty project to use for your tests. (suggest in the tests asp-netcore/tests folder). (Will use name below.
  3. Add a Module.cs by copying and modifying .GraphQL.Tests Module.cs Change the DependsOn list to reference EntityFrameworkCoreModule and AbpTestBaseModule. I also added a dependency to my module to a utilities module where I have a dataloader and test date for the database. [I'll post a copy of my module file in a subsequent message rather than describe the details]
  4. Add a custom configuration accessor, so you can access an appsettings.json. I copied and used the "TestAppConfigurationAccessor" class in ".Test.Base. This step may not be needed...I originally intended to use it for a connection string, but ended up hardcoding in my test base class.
  5. Create a TestBase class. This will create the context, create the schema if necessary, and seed the data. Because I am using a persistent SQLServer instance, then I had to allow for seeding data only if the database was empty. Also, I assume that migrations are not automatically done, so I would have to delete the database on any schema changes, which I've not allowed for in the base module.  I'll post a skeleton of this in a subsequent message.
  6. Create a teste case class, and derive the class from your test base class in step 5. Add a [Fact] annotated method, and try accessing the context which was created in your test base class.
  7. At this point, you should be able to run your test and access your separate DB context.

Confirmed that the order of the mapping in the "CreateMap" method written in CustomDtoMapper.cs by the Rad Power Tools has the Dto and Entity reversed, so either the order of the mapping needs to be changed to CreateMap<Entity,Dto> or add ".ReverseMap()". Hoping this can be fixed in the Power Tools quickly

I am seeing this problem using the Rad Power Tools 2.0.2.1 with a new V7.1.0 AspNetZero project. I can enter new entity through the generated interface with no problem, but an Automapper exception is thrown when attempting to edit the entity. The problem appears to be with the generated "CreateOrEdit" Dto. Here is exception (without full stacktrace) showing in log:

ERROR 2019-07-26 11:55:26,310 [121  ] Mvc.ExceptionHandling.AbpExceptionFilter - Missing type map configuration or unsupported mapping.

Mapping types:
Trainee -> CreateOrEditTraineeDto
NexusApps.TrainingManager.Trainee -> NexusApps.TrainingManager.Dtos.CreateOrEditTraineeDto
AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

Mapping types:
Trainee -> CreateOrEditTraineeDto
NexusApps.TrainingManager.Trainee -> NexusApps.TrainingManager.Dtos.CreateOrEditTraineeDto
Showing 11 to 20 of 21 entries