Base solution for your next web application
Open Closed

Plugin Example With CustomData context. #12364


User avatar
0
mittera created

Is there an example plugin that includes adding a new data context and services?

I can get services to work if the data context is not in the plugin, but i would like the data context to be int eh plugin as well.


4 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @mittera

    Unfortunately we don't have such a sample. Do you want a totally separate DbContext which belongs to PlugIn project ?

  • User Avatar
    0
    mittera created

    Yes i want to have a plugin that provides a service that uses a separate (existing) database to store it's information.

    I can for see multiple plugins like this for my application and want it to be a plugin where the base connection string resolver doesn't need to know about it.

    I can get it working if i add a reference and add the context to the connection string resolver...

    But that is the apart i am trying to avoid by using a plugin.

    How can i have a plugin with a separate database context?

    I currently have three DB contexts in my application.

    1. ABP Base Tables = AppDBContext

    2. Host Tables = HostDbContext

    3. Tenant Tables = TenantDbContext

    -- New Plugin Context
    4) Plugin Tables = MetadataDbContext

    Using the code below works, but want the plugin code in the plugin...

    When commenting out the metadata context from the connection string resolver it fails as the connection string is not initialized.

    I am manually registering my context in the plugin, and at that time I am setting the connection string.

    But when the app service code hits the context there is no connection string...

    I feel i am close, but something is missing, any help would be appreciated!

        public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
        {
            if (args.ContainsKey("ConnectionString"))
            {
                return args["ConnectionString"].ToString();
            }    
            
            if (args.ContainsKey("DbContextConcreteType"))
            {
                #region Host Database
                if (args["DbContextConcreteType"] as Type == typeof(HostDbContext) || args["DbContextConcreteType"] as Type == typeof(BaseAppDbContext))
                {
                    return base.GetNameOrConnectionString(args);
                }
                #endregion
    
                #region Metadata Database
                if (args["DbContextConcreteType"] as Type == typeof(MetadataDbContext))
                {
                    return System.Configuration.ConfigurationManager.ConnectionStrings["Metadata"].ConnectionString;
                }
                #endregion
            }
    
            #region Tenant Database
            int? tenantId = _currentUnitOfWorkProvider.Current.GetTenantId();
    
            if (tenantId != null)
            {
                var tenantCacheItem = _tenantCache.Get(tenantId.Value);
    
                if (tenantCacheItem.ConnectionString.IsNullOrEmpty())
                {
                    return _appConfiguration[$"ConnectionStrings:Default"];
                }
    
                return tenantCacheItem.ConnectionString;
            }
            #endregion
    
            #region Default Database
            return base.GetNameOrConnectionString(args);
            #endregion
        }
    
  • User Avatar
    0
    mittera created

    In the end it was a problem with the DbContext registration.

    In addtion to setting the connection string like the host and tenant database, i also had to register the component afterwards in my preinitalize

            Configuration.Modules.AbpEfCore().AddDbContext<MyDbContext>(options =>
            {
                if (options.ExistingConnection != null)
                {
                    MyDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
                }
                else
                {
                    MyDbContextConfigurer.Configure(options.DbContextOptions, GetMyDbContextConnectionString());
                }
            });
    
            // Add this here to fix it. 
            IocManager.IocContainer.Register(
                Castle.MicroKernel.Registration.Component.For<MyDbContext>()
                    .UsingFactoryMethod(() =>
                    {
                        var options = new DbContextOptionsBuilder<MyDbContext>()
                            .UseSqlServer(GetMyDbContextConnectionString()) 
                            .Options;
    
                        return new MyDbContext(options);
                    })
                    .LifestyleTransient()
            );
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @mittera

    Thank you for sharing the solution :)