Foundatio.Xunit 10.7.1

前缀已保留
dotnet add package Foundatio.Xunit --version 10.7.1                
NuGet\Install-Package Foundatio.Xunit -Version 10.7.1                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用 NuGet 模块的 Install-Package 版本。
<PackageReference Include="Foundatio.Xunit" Version="10.7.1" />                
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件中以引用软件包。
paket add Foundatio.Xunit --version 10.7.1                
#r "nuget: Foundatio.Xunit, 10.7.1"                
#r 指令可用于 F# Interactive 和 Polyglot Notebooks。将此内容复制到交互式工具或脚本的源代码中以引用软件包。
// Install Foundatio.Xunit as a Cake Addin
#addin nuget:?package=Foundatio.Xunit&version=10.7.1

// Install Foundatio.Xunit as a Cake Tool
#tool nuget:?package=Foundatio.Xunit&version=10.7.1                

FoundatioFoundatio

Build status NuGet Version feedz.io Discord

构建松散连接的分布式应用程序的插件式基础块。

包含 Redis、Azure、AWS、RabbitMQ、Kafka 以及内存(用于开发)中的实现。

为什么选择 Foundatio?

在构建几个大型云应用时,我们发现缺乏优秀解决方案(这并非说没有解决方案)来构建可扩展的分布式应用程序,同时保持开发体验简单。以下是我们构建和使用 Foundatio 的几个例子:

  • 希望针对抽象接口进行构建,以便轻松更换实现。
  • 希望这些块对依赖注入友好。
  • 缓存:我们最初使用开源的 Redis 缓存客户端,但后来它变成了一个具有高许可费用的商业产品。不仅如此,而且没有内存实现,所以每个开发人员都需要设置和配置 Redis。
  • 消息总线:我们最初考虑过NServiceBus(一款优秀的产品),但是它的许可费用很高(他们也必须盈利),而且对开源不友好。我们还研究过MassTransit(另一款优秀的产品),但当时发现Azure的支持不足,并且本地设置很麻烦(对于内存存储)。我们想要一个简单易用、本地或云端都能工作的消息总线。
  • 存储:我们找不到任何现有的项目能够解耦并支持内存、文件存储或Azure Blob存储。

总结来说,如果您希望在应用程序可扩展的同时无需忍受开发和测试的痛苦,请使用Foundatio!

实现方式

入门(开发)

您可以通过NuGet包管理器安装Foundatio。如果您需要帮助,请提出问题或加入我们的Discord聊天室。如果您有任何疑问,我们随时都在这里为您解答!

本节仅用于开发目的!如果您尝试使用Foundatio库,请从NuGet获取。

  1. 您需要安装Visual Studio Code
  2. 打开Foundatio.sln Visual Studio解决方案文件。

使用Foundatio

以下各节仅展示了Foundatio功能的一小部分。我们建议您查看源代码以获取更多信息。如果您有任何疑问或需要帮助,请告诉我们!

缓存

缓存允许您以闪电般的速度存储和访问数据,从而节约创建或获取数据的昂贵操作。我们提供了四种不同的缓存实现,它们都源自于ICacheClient接口

  1. InMemoryCacheClient:一个内存缓存客户端实现。这种缓存实现仅在进程生存期内有效。值得注意的是,内存缓存客户端具有通过MaxItems属性缓存最后X个项的能力。我们使用它来在Exceptionless中仅保留最后250个解析的geoip结果
  2. HybridCacheClient:这种缓存实现同时使用ICacheClientInMemoryCacheClient,并通过IMessageBus在每个进程之间保持缓存同步。这可以带来巨大的性能提升,因为如果项存在于本地缓存中,您将节省序列化操作和远程缓存调用。
  3. RedisCacheClient:Redis缓存客户端实现。
  4. RedisHybridCacheClient:一种混合缓存客户端实现,使用RedisCacheClient作为ICacheClient,并使用RedisMessageBus作为IMessageBus
  5. ScopedCacheClient:该缓存实现接受一个ICacheClient实例和一个字符串scope。该作用域会被添加到每个缓存键的前面。这使得对所有缓存键进行作用域划分并轻松删除变得更加简单。
示例
using Foundatio.Caching;

ICacheClient cache = new InMemoryCacheClient();
await cache.SetAsync("test", 1);
var value = await cache.GetAsync<int>("test");

队列

队列提供先入先出(FIFO)的消息投递。我们提供了四种不同的队列实现,它们都继承自IQueue接口

  1. InMemoryQueue:一种内存队列实现。此队列实现仅对进程的有效生命周期有效。
  2. RedisQueue:一种Redis队列实现。
  3. AzureServiceBusQueue:一种Azure Service Bus队列实现。
  4. AzureStorageQueue:一种Azure Storage队列实现。
  5. SQSQueue:一种AWS SQS实现。
示例
using Foundatio.Queues;

IQueue<SimpleWorkItem> queue = new InMemoryQueue<SimpleWorkItem>();

await queue.EnqueueAsync(new SimpleWorkItem {
    Data = "Hello"
});

var workItem = await queue.DequeueAsync();

锁确保资源在任何给定时间只被一个消费者访问。我们提供两种基于ILockProvider接口的锁定实现。

  1. CacheLockProvider:一种使用缓存进行进程间通信的锁定实现。
  2. ThrottlingLockProvider:一种只允许一定数量的锁通过的锁定实现。你可以用它来限制对某些外部服务的API调用,它会跨所有请求该锁的进程进行限制。
  3. ScopedLockProvider:这种锁定实现接受一个ILockProvider实例和一个字符串scope。作用域会被添加到每个锁定键的前面。这使得对所有锁定进行作用域划分并轻松释放变得极其简单。

值得注意的是,所有锁提供者都接受一个ICacheClient。这允许你确保你的代码可以跨机器正确锁定。

示例
using Foundatio.Lock;

ILockProvider locker = new CacheLockProvider(new InMemoryCacheClient(), new InMemoryMessageBus());
var testLock = await locker.AcquireAsync("test");
// ...
await testLock.ReleaseAsync();

ILockProvider throttledLocker = new ThrottlingLockProvider(new InMemoryCacheClient(), 1, TimeSpan.FromMinutes(1));
var throttledLock = await throttledLocker.AcquireAsync("test");
// ...
await throttledLock.ReleaseAsync();

消息传递

允许你在应用中发布和订阅消息流。我们提供四种基于IMessageBus接口的消息总线实现。

  1. InMemoryMessageBus:一种内存消息总线实现。此消息总线实现仅对进程的有效生命周期有效。
  2. RedisMessageBus:一种Redis消息总线实现。
  3. RabbitMQMessageBus:一种RabbitMQ实现。
  4. KafkaMessageBus:一种Kafka实现。
  5. AzureServiceBusMessageBus:一种Azure Service Bus实现。
示例
using Foundatio.Messaging;

IMessageBus messageBus = new InMemoryMessageBus();
await messageBus.SubscribeAsync<SimpleMessageA>(msg => {
  // Got message
});

await messageBus.PublishAsync(new SimpleMessageA { Data = "Hello" });

作业

允许您运行持久运行的过程(在进程内或进程外),无需担心其被提前终止。根据您的用例,我们提供了三种定义工作方式的途径。

  1. 工作:所有工作都必须从IJob接口继承。我们还提供了一个可以从之继承的JobBase基类,它提供了Job上下文和日志记录功能。然后您可以通过在工作实例上调用RunAsync()或在JobRunner上创建实例并调用其中一个Run方法来运行工作。JobRunner可以用来方便地将工作作为Azure Web Jobs运行。
示例
using Foundatio.Jobs;

public class HelloWorldJob : JobBase {
  public int RunCount { get; set; }

  protected override Task<JobResult> RunInternalAsync(JobContext context) {
     RunCount++;
     return Task.FromResult(JobResult.Success);
  }
}
var job = new HelloWorldJob();
await job.RunAsync(); // job.RunCount = 1;
await job.RunContinuousAsync(iterationLimit: 2); // job.RunCount = 3;
await job.RunContinuousAsync(cancellationToken: new CancellationTokenSource(10).Token); // job.RunCount > 10;
  1. 队列处理器工作:队列处理器工作非常适合与来自队列数据的工作配合使用。队列处理器工作必须从QueueJobBase<T>继承。然后您可以直接在工作实例上调用RunAsync()或将其传递给JobRunner。JobRunner可以用来方便地将工作作为Azure Web Jobs运行。
示例
using Foundatio.Jobs;

public class HelloWorldQueueJob : QueueJobBase<HelloWorldQueueItem> {
  public int RunCount { get; set; }

  public HelloWorldQueueJob(IQueue<HelloWorldQueueItem> queue) : base(queue) {}

  protected override Task<JobResult> ProcessQueueEntryAsync(QueueEntryContext<HelloWorldQueueItem> context) {
     RunCount++;

     return Task.FromResult(JobResult.Success);
  }
}

public class HelloWorldQueueItem {
  public string Message { get; set; }
}
 // Register the queue for HelloWorldQueueItem.
container.AddSingleton<IQueue<HelloWorldQueueItem>>(s => new InMemoryQueue<HelloWorldQueueItem>());

// To trigger the job we need to queue the HelloWorldWorkItem message.
// This assumes that we injected an instance of IQueue<HelloWorldWorkItem> queue

IJob job = new HelloWorldQueueJob();
await job.RunAsync(); // job.RunCount = 0; The RunCount wasn't incremented because we didn't enqueue any data.

await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await job.RunAsync(); // job.RunCount = 1;

await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await job.RunUntilEmptyAsync(); // job.RunCount = 3;
  1. 工作项工作:工作项工作将在工作池中与其他工作项工作一起运行。此类工作非常适合那些不太经常发生但应包含在作业中的事情(例如:删除具有许多子项的实体)。它在您在消息总线上发布消息时将被触发。此类工作必须从WorkItemHandlerBase继承。然后您可以通过JobRunner来运行所有共享工作项。JobRunner可以用来方便地将工作作为Azure Web Jobs运行。
示例
using System.Threading.Tasks;
using Foundatio.Jobs;

public class HelloWorldWorkItemHandler : WorkItemHandlerBase {
  public override async Task HandleItemAsync(WorkItemContext ctx) {
    var workItem = ctx.GetData<HelloWorldWorkItem>();

    // We can report the progress over the message bus easily.
    // To receive these messages just inject IMessageSubscriber
    // and Subscribe to messages of type WorkItemStatus
    await ctx.ReportProgressAsync(0, "Starting Hello World Job");
    await Task.Delay(TimeSpan.FromSeconds(2.5));
    await ctx.ReportProgressAsync(50, "Reading value");
    await Task.Delay(TimeSpan.FromSeconds(.5));
    await ctx.ReportProgressAsync(70, "Reading value");
    await Task.Delay(TimeSpan.FromSeconds(.5));
    await ctx.ReportProgressAsync(90, "Reading value.");
    await Task.Delay(TimeSpan.FromSeconds(.5));

    await ctx.ReportProgressAsync(100, workItem.Message);
  }
}

public class HelloWorldWorkItem {
  public string Message { get; set; }
}
// Register the shared job.
var handlers = new WorkItemHandlers();
handlers.Register<HelloWorldWorkItem, HelloWorldWorkItemHandler>();

// Register the handlers with dependency injection.
container.AddSingleton(handlers);

// Register the queue for WorkItemData.
container.AddSingleton<IQueue<WorkItemData>>(s => new InMemoryQueue<WorkItemData>());

// The job runner will automatically look for and run all registered WorkItemHandlers.
new JobRunner(container.GetRequiredService<WorkItemJob>(), instanceCount: 2).RunInBackground();
 // To trigger the job we need to queue the HelloWorldWorkItem message.
 // This assumes that we injected an instance of IQueue<WorkItemData> queue

 // NOTE: You may have noticed that HelloWorldWorkItem doesn't derive from WorkItemData.
 // Foundatio has an extension method that takes the model you post and serializes it to the
 // WorkItemData.Data property.
 await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });

文件存储

我们提供不同的文件存储实现,它们都从IFileStorage接口继承。

  1. InMemoryFileStorage:一个内存文件实现。此文件存储实现仅对进程的生命周期有效。
  2. FolderFileStorage:一个使用硬盘进行存储的文件存储实现。
  3. AzureFileStorage:一个Azure Blob存储实现。
  4. S3FileStorage:一个AWS S3文件存储实现。
  5. RedisFileStorage:一个Redis文件存储实现。
  6. MinioFileStorage:一个Minio文件存储实现。
  7. AliyunFileStorage:一个阿里云文件存储实现。
  8. RedisFileStorage:一个Redis文件存储实现。

我们建议使用所有IFileStorage实现作为单例。

示例
using Foundatio.Storage;

IFileStorage storage = new InMemoryFileStorage();
await storage.SaveFileAsync("test.txt", "test");
string content = await storage.GetFileContentsAsync("test.txt")

度量

我们提供了从IMetricsClient接口继承的五个实现。

  1. InMemoryMetricsClient:一个内存指标实现。
  2. RedisMetricsClient:Redis度量实现。
  3. StatsDMetricsClient:statsd度量实现。
  4. MetricsNETClient:Metrics.NET实现。
  5. AppMetricsClient:AppMetrics实现。
  6. CloudWatchMetricsClient:AWS CloudWatch实现。

我们建议使用所有IMetricsClient实现作为单例。

示例
IMetricsClient metrics = new InMemoryMetricsClient();
metrics.Counter("c1");
metrics.Gauge("g1", 2.534);
metrics.Timer("t1", 50788);

示例应用程序

我们有幻灯片示例应用程序,展示了如何使用Foundatio。

感谢所有做出贡献的人

contributors

产品 兼容的以及额外计算的目标框架版本。
.NET net5.0 已计算。 net5.0-windows 已计算。 net6.0 已计算。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
.NET Core netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。
.NET Standard netstandard2.0 兼容。 netstandard2.1 已计算。
.NET Framework net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。
MonoAndroid monoandroid 已计算。
MonoMac monomac 已计算。
MonoTouch monotouch 已计算。
Tizen tizen40 已计算。 tizen60 已计算。
Xamarin.iOS xamarinios 已计算。
Xamarin.Mac xamarinmac 已计算。
Xamarin.TVOS xamarintvos 已计算。
Xamarin.WatchOS xamarinwatchos 已计算。
兼容的目标框架
包含的目标框架(在包中)
了解更多关于 目标框架.NET Standard 的信息。

NuGet 包 (1)

显示 1 个依赖于 Foundatio.Xunit 的顶级 NuGet 包

下载
Foundatio.TestHarness

构建分布式应用的插件式基础块。

GitHub 仓库 (2)

显示 2 个依赖于 Foundatio.Xunit 的最受欢迎的 GitHub 仓库

仓库 星标
exceptionless/Exceptionless
Exceptionless 应用
exceptionless/Exceptionless.DateTimeExtensions
DateTimeRange、工作日和多种 DateTime、DateTimeOffset、TimeSpan 扩展方法
版本 下载 最后更新
10.7.1 6,184 3/27/2024
10.7.0 4,591 1/5/2024
10.6.1 8,219 6/23/2023
10.6.0 12,037 1/1/2023
10.5.0 9,704 5/18/2022
10.4.0 3,368 3/7/2022
10.3.1 1,438 1/20/2022
10.3.0 808 1/20/2022
10.2.5 1,057 12/7/2021
10.2.4 1,141 12/3/2021
10.2.3 658 11/22/2021
10.2.2 2,923 9/23/2021
10.2.1 2,414 7/19/2021
10.2.0 846 7/8/2021
10.1.4 918 6/16/2021
10.1.3 1,538 4/23/2021
10.1.2 669 4/23/2021
10.1.1 1,320 4/15/2021
10.1.0 713 4/13/2021
10.0.2 2,056 1/20/2021
10.0.1 2,438 11/2/2020
10.0.0 1,684 9/16/2020
10.0.0-beta9 1,193 8/25/2020
10.0.0-beta8 845 8/3/2020
10.0.0-beta7 722 7/29/2020
10.0.0-beta6 1,091 7/7/2020
10.0.0-beta5 958 6/20/2020
10.0.0-beta3 743 6/14/2020
10.0.0-beta2 819 6/6/2020
10.0.0-beta10 786 9/15/2020