一个基于 netstandard2.1 开发的简单易用的快速开发框架,遵循领域驱动设计(DDD)规范约束,提供实现事件驱动、事件回溯、响应式等特性的基础设施。让开发者享受到正真意义的面向对象设计模式来带的美感。
Polly、FluentValidation、Metrics
- Auditing (审核日志)
- Caching (缓存 Memory Distributed)
- Dapper
- Data (DataFilter)
- Elasticsearch
- EntityFrameworkCore
- EventBus
- EventStores (ES)
- Hangfire
- Mediator
- MongoDB
- MultiTenancy (多租用户)
- RabbitMQ
各日常工具类集合
- EncryptUtils
- JsonUtils
- 领域驱动设计 (DDD)
- 事件驱动架构 (EDA)
- 事件回溯 (ES)
- 最终一致性 (Eventually Consistent)
- 框架中每个组件都有基础实现,最简单时只需一个核心类库就能跑起来
- 遵循端口与适配器模式,框架组件适配多种第三方组件实现,可从单体架构到面向服务架构按需扩展
- 领域驱动设计(Domain Driven Design (Layers and Domain Model Pattern)
- 命令查询职责分离(CQRS:Command Query Responsibility Segregation)
- 领域通知 (Domain Notification)
- 领域驱动 (Domain Events)
- 事件驱动架构 (EDA)
- 事件回溯 (Event Sourcing)
- 最终一致性 (Eventually Consistent)
- 工作单元模式 (Unit of Work )
- 泛型仓储 (Repository and Generic Repository)
- 尽量使用.NET Standard和官方提供的类库,第三方类库设计成组件利用DI来按需组合。
PM> Install-Package LinFx
- Visual Studio 15.3+
- .NET Core SDK 2.2+
public void ConfigureServices(IServiceCollection services)
{
services.AddLinFx()
.AddDistributedRedisCache(options =>
{
options.Configuration = configuration.GetConnectionString("ReidsConnection");
})
.AddMongoDBContext(options =>
{
options.Name = "default";
options.Configuration = configuration.GetConnectionString("MongoConnection");
})
.AddElasticsearch(options =>
{
options.DefaultIndex = "default";
options.Host = "http://10.0.1.112:9200";
});
}
using LinFx.Extensions.EventBus.Abstractions;
using LinFx.Test.Extensions.EventBus.Events;
using LinFx.Utils;
using LinFx.Extensions.EventBus.RabbitMQ;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Xunit;
using LinFx.Test.Extensions.EventBus.EventHandling;
using System.Collections.Generic;
using System;
namespace LinFx.Test.Extensions.EventBus
{
public class EventBusRabbitMQTest
{
private readonly IEventBus _eventBus;
public EventBusRabbitMQTest()
{
var services = new ServiceCollection();
services.AddLinFx()
.AddEventBus(options =>
{
options.Durable = true;
options.BrokerName = "tc_cloud_event_bus";
options.QueueName = "tc_cloud_process_queue";
options.ConfigureEventBus = (fx, builder) => builder.UseRabbitMQ(fx, x =>
{
x.Host = "14.21.34.85";
x.UserName = "admin";
x.Password = "admin.123456";
});
});
//services
services.AddTransient<OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
//services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>();
var applicationServices = services.BuildServiceProvider();
//ConfigureEventBus
_eventBus = applicationServices.GetRequiredService<IEventBus>();
_eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>();
//eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>();
}
[Fact]
public async Task Should_Call_Handler_On_Event_With_Correct_SourceAsync()
{
var orderId = Guid.NewGuid().GetHashCode() & ushort.MaxValue;
var evt = new OrderStatusChangedToAwaitingValidationIntegrationEvent(orderId, new List<OrderStockItem>
{
});
await _eventBus.PublishAsync(evt);
//for (int i = 0; i < 2; i++)
//{
// await _eventBus.PublishAsync(new ClientCreateIntergrationEvent
// {
// ClientId = IDUtils.CreateNewId().ToString(),
// ClientSecrets = new[] { "191d437f0cc3463b85669f2b570cdc21" },
// AllowedGrantTypes = new[] { "client_credentials" },
// AllowedScopes = new[] { "api3.device" }
// });
//}
}
}
}
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace LinFx.Test.Caching
{
public class RedisCacheTest
{
IDistributedCache _cache;
public RedisCacheTest()
{
var services = new ServiceCollection();
services.AddLinFx()
.AddDistributedRedisCache(options =>
{
options.Configuration = "10.0.1.112:6379,password=redis";
options.InstanceName = "linfx_test:";
});
var container = services.BuildServiceProvider();
_cache = container.GetService<IDistributedCache>();
}
[Fact]
public void GetMissingKeyReturnsNull()
{
string key = "non-existent-key";
var result = _cache.Get(key);
Assert.Null(result);
}
[Fact]
public void SetAndGetReturnsObject()
{
var value = new byte[1];
string key = "myKey";
_cache.Set(key, value);
var result = _cache.Get(key);
Assert.Equal(value, result);
}
[Fact]
public void SetAndGetWorksWithCaseSensitiveKeys()
{
var value = new byte[1];
string key1 = "myKey";
string key2 = "Mykey";
_cache.Set(key1, value);
var result = _cache.Get(key1);
Assert.Equal(value, result);
result = _cache.Get(key2);
Assert.Null(result);
}
}
}
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace LinFx.Test.Caching
{
public class MemoryCacheTest
{
[Fact]
public void MemoryCacheGetAndSetTests()
{
var services = new ServiceCollection();
services.AddLinFx()
.AddDistributedMemoryCache();
var container = services.BuildServiceProvider();
var _cache = container.GetService<IMemoryCache>();
var expected = 100;
_cache.Set("key1", expected);
var actual = _cache.Get("key1");
Assert.Equal(expected, actual);
}
}
}