Stove
Domain Driven Design oriented application framework, meets CRUD needs
Install / Use
/learn @stoveproject/StoveREADME
Stove
<img src="https://raw.githubusercontent.com/osoykan/Stove/master/stove.png" alt="alt text" width="100" height="100">
|Package|Status|
|:------|:-----:|
|Stove||
|Stove.Entityframework|
|
|Stove.EntityframeworkCore|
|
|Stove.Hangfire|
|
|Stove.NLog|
|
|Stove.Serilog|
|
|Stove.Mapster|
|
|Stove.Redis|
|
|Stove.Dapper|
|
|Stove.RabbitMQ|
|
|Stove.NHibernate|
|
|Stove.RavenDB|
|
|Stove.Couchbase|
|
Stove is an application framework that wraps and abstracts your needs for easy use. Built with strongly adopted dependency injection principles.
IoC
- Autofac
- Conventional Registration Mechanism with Autofac.Extras.IocManager
Use-Case & Transaction approach
- AsyncLocal Unit Of Work pattern
Adopted principles
- Domain Driven Design
- Persistence agnosticism with IRepository<T>
- EventBus for DDD use cases
Persistence Support
- EntityFramework
- EntityFramework Core
- NHibernate
Transactional structure
|Tool|Supports Multiple Database/Session Control inside one UOW| |:------|:-----:| |EntityFramework| :white_check_mark: | |EntityFrameworkCore| :white_check_mark: | |NHibernate| :white_check_mark: | |Dapper| :white_check_mark: |
Notes
-
To work with Dapper, you must use EF & EF Core or NHibernate as primary ORM choice. Dapper shares their transactions to execute its sqls inside of one Unit Of Work scope.
-
Dapper-EntityFramework, Dapper-NHibernate or Dapper-EntityFrameworkCore works under same transaction and unit of work scope, if any exception appears in domain whole transaction will be rollback, including Dapper's insert/deletes or EF's or NH's.
-
Stove.Dapper supports Dynamic Filters to filter automatically and default ISoftDelete or other user defined filters.
-
NHibernate supports multiple database in one UOW scope.
Nhibernate Multiple Database
Let's assume that we have two entities which are inherited from Entity<int>. If we want to work with multiple database with NHibernate we have to tell to Stove that which entities belong to which database or session. To achive that Stove has to know your database distinction. Basically StoveSessionContext does that.
StoveSessionContext
public class PrimaryStoveSessionContext : StoveSessionContext
{
public IStoveSessionSet<Product> Products { get; set; }
}
public class SecondaryStoveSessionContext : StoveSessionContext
{
public IStoveSessionSet<Category> Categories { get; set; }
}
Registration:
builder
.UseStoveNHibernate(nhConfiguration =>
{
nhConfiguration.AddFluentConfigurationFor<PrimaryStoveSessionContext>(() =>
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(true, true, false, _connection, Console.Out));
});
nhConfiguration.AddFluentConfigurationFor<SecondaryStoveSessionContext>(() =>
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(true, true, false, _connection, Console.Out));
});
return nhConfiguration;
})
After this definition, we have to define which SessionContext uses which connection string for connect to database and creating session factory.
[DependsOn(
typeof(StoveNHibernateBootstrapper)
)]
public class StoveNHibernateTestBootstrapper : StoveBootstrapper
{
public override void PreStart()
{
StoveConfiguration.DefaultNameOrConnectionString = "data source=:memory:";
StoveConfiguration.TypedConnectionStrings.Add(typeof(PrimaryStoveSessionContext),StoveConfiguration.DefaultNameOrConnectionString);
StoveConfiguration.TypedConnectionStrings.Add(typeof(SecondaryStoveSessionContext),StoveConfiguration.DefaultNameOrConnectionString);
DapperExtensions.DapperExtensions.SqlDialect = new SqliteDialect();
DapperExtensions.DapperExtensions.SetMappingAssemblies(new List<Assembly> { Assembly.GetExecutingAssembly() });
}
}
As you see connection strings are same but they are inside of different StoveSessionContexts. If these entities are inside of same database but you want to treat as different bounded contexts to them, you can choose this kind of approach for your sessions. Otherwise entities can sit together in one SessionContext.
Usage is always same and persistence agnostic:
using (IUnitOfWorkCompleteHandle uow = The<IUnitOfWorkManager>().Begin())
{
The<IDapperRepository<Product>>().GetAll().Count().ShouldBe(1);
The<IRepository<Product>>().GetAll().Count().ShouldBe(1);
uow.Complete();
}
Document Databases
- RavenDB -> IRepository<T>
- Couchbase -> IRepository<T>
Queue Mechanism
- RabbitMQ support
Background Jobs
- HangFire support
Caching
- Redis support
Others
- A lot of extensions
- Strictly SOLID
Composition Root
IRootResolver resolver = IocBuilder.New
.UseAutofacContainerBuilder()
.UseStove<StoveDemoBootstrapper>(autoUnitOfWorkInterceptionEnabled: true)
.UseStoveEntityFramework()
.UseStoveDapper()
.UseStoveMapster()
.UseStoveDefaultEventBus()
.UseStoveDbContextEfTransactionStrategy()
.UseStoveTypedConnectionStringResolver()
.UseStoveNLog()
.UseStoveBackgroundJobs()
.UseStoveRedisCaching()
.UseStoveRabbitMQ(configuration =>
{
configuration.HostAddress = "rabbitmq://localhost/";
configuration.Username = "admin";
configuration.Password = "admin";
configuration.QueueName = "Default";
return configuration;
})
.UseStoveHangfire(configuration =>
{
configuration.GlobalConfiguration
.UseSqlServerStorage("Default")
.UseNLogLogProvider();
return configuration;
})
.RegisterServices(r => r.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()))
.CreateResolver();
var someDomainService = resolver.Resolve<SomeDomainService>();
someDomainService.DoSomeStuff();
Related Skills
diffs
344.1kUse the diffs tool to produce real, shareable diffs (viewer URL, file artifact, or both) instead of manual edit summaries.
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
2.0kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
HappyColorBlend
HappyColorBlendVibe Project Guidelines Project Overview HappyColorBlendVibe is a Figma plugin for color palette generation with advanced tint/shade blending capabilities. It allows designers to
