From 5d1c1bfb0872e343b2ecd4d65e6e4961dca56dda Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Sep 2019 13:52:47 +0800 Subject: [PATCH 01/76] Architectural refactoring --- CAP.sln | 7 + .../Controllers/ValuesController.cs | 12 +- samples/Sample.RabbitMQ.MySql/Program.cs | 1 + .../Properties/launchSettings.json | 2 +- samples/Sample.RabbitMQ.MySql/Startup.cs | 5 +- .../Sample.RabbitMQ.MySql/appsettings.json | 2 +- .../CAP.AzureServiceBusOptionsExtension.cs | 2 +- .../BatchCommandDispatcher.cs | 0 .../CAP.DashboardMiddleware.cs | 0 .../CAP.DashboardOptions.cs | 0 .../CAP.DashboardOptionsExtensions.cs | 0 .../CombinedResourceDispatcher.cs | 0 .../CommandDispatcher.cs | 0 .../Content/css/bootstrap.min.css | 0 .../Content/css/cap.css | 0 .../Content/css/jsonview.min.css | 0 .../Content/css/rickshaw.min.css | 0 .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin .../fonts/glyphicons-halflings-regular.woff2 | Bin .../Content/js/bootstrap.min.js | 0 .../Content/js/cap.js | 0 .../Content/js/d3.layout.min.js | 0 .../Content/js/d3.min.js | 0 .../Content/js/jquery-2.1.4.min.js | 0 .../Content/js/jsonview.min.js | 0 .../Content/js/moment-with-locales.min.js | 0 .../Content/js/moment.min.js | 0 .../Content/js/rickshaw.min.js | 0 .../Content/resx/Strings.Designer.cs | 2 +- .../Content/resx/Strings.resx | 0 .../Content/resx/Strings.zh.resx | 0 .../DashboardContext.cs | 0 .../DashboardMetric.cs | 0 .../DashboardMetrics.cs | 0 .../DashboardRequest.cs | 0 .../DashboardResponse.cs | 0 .../DashboardRoutes.cs | 0 .../DotNetCore.CAP.Dashboard.csproj | 125 ++++++ .../EmbeddedResourceDispatcher.cs | 0 .../GatewayProxy/DownstreamUrl.cs | 0 .../GatewayProxy/GatewayProxyMiddleware.cs | 0 .../GatewayProxy/IRequestMapper.Default.cs | 0 .../GatewayProxy/IRequestMapper.cs | 0 .../Requester/HttpClientBuilder.cs | 0 .../Requester/HttpClientHttpRequester.cs | 0 .../GatewayProxy/Requester/IHttpClient.cs | 0 .../Requester/IHttpClientBuilder.cs | 0 .../Requester/IHttpClientCache.cs | 0 .../GatewayProxy/Requester/IHttpRequester.cs | 0 .../Requester/MemoryHttpClientCache.cs | 0 .../HtmlHelper.cs | 2 +- .../IDashboardAuthorizationFilter.cs | 0 .../IDashboardDispatcher.cs | 0 .../IMonitoringApi.cs | 2 +- .../JsonDispatcher.cs | 0 .../JsonStats.cs | 0 .../LocalRequestsOnlyAuthorizationFilter.cs | 0 .../MenuItem.cs | 0 .../MessageHistoryRenderer.cs | 0 .../MessagesSidebarMenu.cs | 0 .../Metric.cs | 0 .../Monitoring/MessageDto.cs | 0 .../Monitoring/MessageQueryDto.cs | 2 +- .../Monitoring/ServerDto.cs | 0 .../Monitoring/StatisticsDto.cs | 0 .../NavigationMenu.cs | 0 .../NonEscapedString.cs | 0 .../Pager.cs | 0 .../Pages/BlockMetric.cs | 0 .../Pages/Breadcrumbs.cs | 0 .../Pages/HomePage.cs | 0 .../Pages/HomePage.cshtml | 2 +- .../Pages/HomePage.generated.cs | 6 +- .../Pages/InlineMetric.cs | 0 .../Pages/LayoutPage.cs | 0 .../Pages/LayoutPage.cshtml | 0 .../Pages/LayoutPage.generated.cs | 0 .../Pages/NodePage.cs | 0 .../Pages/NodePage.cshtml | 0 .../Pages/NodePage.generated.cs | 0 .../Pages/PublishedPage.cs | 0 .../Pages/PublishedPage.cshtml | 2 +- .../Pages/PublishedPage.generated.cs | 5 +- .../Pages/ReceivedPage.cs | 0 .../Pages/ReceivedPage.cshtml | 2 +- .../Pages/ReceivedPage.generated.cs | 5 +- .../Pages/SidebarMenu.cs | 0 .../Pages/SubscriberPage.cshtml | 0 .../Pages/SubscriberPage.generated.cs | 0 .../Pages/_BlockMetric.cshtml | 0 .../Pages/_BlockMetric.generated.cs | 0 .../Pages/_Breadcrumbs.cshtml | 0 .../Pages/_Breadcrumbs.generated.cs | 0 .../Pages/_InlineMetric.cshtml | 0 .../Pages/_InlineMetric.generated.cs | 0 .../Pages/_Navigation.cshtml | 0 .../Pages/_Navigation.generated.cs | 0 .../Pages/_Paginator.cs | 0 .../Pages/_Paginator.cshtml | 0 .../Pages/_Paginator.generated.cs | 0 .../Pages/_PerPageSelector.cs | 0 .../Pages/_PerPageSelector.cshtml | 0 .../Pages/_PerPageSelector.generated.cs | 0 .../Pages/_SidebarMenu.cshtml | 0 .../Pages/_SidebarMenu.generated.cs | 0 .../RazorPage.cs | 0 .../RazorPageDispatcher.cs | 0 .../RouteCollection.cs | 0 .../RouteCollectionExtensions.cs | 0 .../TimelineCounter.cs | 0 .../UrlHelper.cs | 0 .../ICapPublisher.InMemory.cs | 2 +- .../IMonitoringApi.InMemory.cs | 2 +- .../IStorageConnection.InMemory.cs | 2 +- .../IStorageTransaction.InMemory.cs | 2 +- .../CAP.KafkaCapOptionsExtension.cs | 2 +- .../ICapPublisher.MongoDB.cs | 2 +- .../IMonitoringApi.MongoDB.cs | 2 +- .../IStorageConnection.MongoDB.cs | 2 +- .../IStorageTransaction.MongoDB.cs | 2 +- src/DotNetCore.CAP.MongoDB/StorageMessage.cs | 2 +- .../CAP.MySqlCapOptionsExtension.cs | 8 +- .../ICapPublisher.MySql.cs | 66 --- .../ICapTransaction.MySql.cs | 1 - .../ICollectProcessor.MySql.cs | 61 --- .../IMonitoringApi.MySql.cs | 425 ++++++++++-------- src/DotNetCore.CAP.MySql/IStorage.MySql.cs | 62 +-- .../IStorageConnection.MySql.cs | 116 ----- .../IStorageTransaction.MySql.cs | 63 --- src/DotNetCore.CAP.MySql/MySqlDataStorage.cs | 215 +++++++++ .../ICapPublisher.PostgreSql.cs | 2 +- .../IMonitoringApi.PostgreSql.cs | 2 +- .../IStorageConnection.PostgreSql.cs | 2 +- .../IStorageTransaction.PostgreSql.cs | 2 +- .../CAP.RabbitMQCapOptionsExtension.cs | 4 +- .../IPublishMessageSender.RabbitMQ.cs | 35 +- .../RabbitMQConsumerClient.cs | 22 +- .../Diagnostics/DiagnosticObserver.cs | 2 +- .../DiagnosticProcessorObserver.cs | 2 +- .../ICapPublisher.SqlServer.cs | 2 +- .../ICapTransaction.SqlServer.cs | 2 +- .../IMonitoringApi.SqlServer.cs | 2 +- .../IStorageConnection.SqlServer.cs | 2 +- .../IStorageTransaction.SqlServer.cs | 2 +- .../Abstractions/CapPublisher.cs | 117 +++++ .../Abstractions/CapPublisherBase.cs | 128 ------ .../Abstractions/IContentSerializer.cs | 2 +- .../CAP.AppBuilderExtensions.cs | 60 ++- src/DotNetCore.CAP/CAP.Options.cs | 5 +- .../CAP.ServiceCollectionExtensions.cs | 7 +- .../DiagnosticListenerExtensions.cs | 283 ++++++------ .../Diagnostics/EventData.Broker.Consume.cs | 16 +- .../EventData.Broker.ConsumeEnd.cs | 7 +- .../EventData.Broker.ConsumeError.cs | 17 +- .../Diagnostics/EventData.Broker.Publish.cs | 5 +- .../EventData.Broker.PublishEnd.cs | 6 +- .../EventData.Broker.PublishError.cs | 6 +- .../Diagnostics/EventData.Broker.cs | 14 +- .../Diagnostics/EventData.SubscriberInvoke.cs | 5 +- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 104 +---- src/DotNetCore.CAP/IBootstrapper.Default.cs | 5 +- src/DotNetCore.CAP/ICallbackPublisher.cs | 2 +- src/DotNetCore.CAP/ICapPublisher.cs | 6 +- src/DotNetCore.CAP/ICapTransaction.Base.cs | 9 +- src/DotNetCore.CAP/IConsumerClient.cs | 3 +- .../IConsumerRegister.Default.cs | 115 ++--- src/DotNetCore.CAP/IDispatcher.cs | 7 +- src/DotNetCore.CAP/IPublishExecutor.cs | 21 - .../IPublishMessageSender.Base.cs | 198 -------- src/DotNetCore.CAP/IPublishMessageSender.cs | 13 - src/DotNetCore.CAP/IStorage.cs | 30 -- src/DotNetCore.CAP/IStorageConnection.cs | 6 +- src/DotNetCore.CAP/IStorageTransaction.cs | 22 - .../ISubscribeExecutor.Default.cs | 86 ++-- src/DotNetCore.CAP/ISubscriberExecutor.cs | 4 +- .../Infrastructure/StatusName.cs | 20 +- .../Internal/ConsumerContext.cs | 5 +- .../Internal/ConsumerInvokerFactory.cs | 14 +- .../ICallbackMessageSender.Default.cs | 71 --- .../Internal/IConsumerInvoker.Default.cs | 60 +-- .../Internal/IMessagePacker.Default.cs | 2 +- .../Internal/IMessageSender.Default.cs | 184 ++++++++ ...backMessageSender.cs => IMessageSender.cs} | 5 +- .../Internal/LoggerExtensions.cs | 8 +- src/DotNetCore.CAP/MessageContext.cs | 33 -- .../{Models => Messages}/CapMessageDto.cs | 3 +- src/DotNetCore.CAP/Messages/Headers.cs | 30 ++ src/DotNetCore.CAP/Messages/Message.cs | 56 +++ .../{Models => Messages}/MessageType.cs | 2 +- .../Messages/TransportMessage.cs | 32 ++ .../Models/CapReceivedMessage.cs | 56 --- .../Persistence/CapPublishedMessage.cs | 25 ++ .../CapReceivedMessage.cs} | 12 +- .../Persistence/IDashboardQuerying.cs | 26 ++ .../Persistence/IDataStorage.cs | 52 +++ .../Persistence/IStorageInitializer.cs | 14 + .../Persistence/MediumMessage.cs | 18 + .../Processor/ICollectProcessor.cs | 9 - .../Processor/IDispatcher.Default.cs | 22 +- .../Processor/IProcessingServer.Cap.cs | 2 +- .../Processor/IProcessor.Collector.cs | 60 +++ .../Processor/IProcessor.NeedRetry.cs | 18 +- .../Processor/States/IState.Failed.cs | 25 -- .../Processor/States/IState.Scheduled.cs | 25 -- .../Processor/States/IState.Succeeded.cs | 35 -- src/DotNetCore.CAP/Processor/States/IState.cs | 19 - .../Processor/States/IStateChanger.Default.cs | 45 -- .../States/IStateChanger.Extensions.cs | 31 -- .../Processor/States/IStateChanger.cs | 14 - .../Serialization/ISerializer.cs | 18 + .../Serialization/StringSerializer.cs | 27 ++ src/DotNetCore.CAP/Transport/ITransport.cs | 12 + .../MongoDBMonitoringApiTest.cs | 2 +- .../MongoDBStorageConnectionTest.cs | 2 +- .../MySqlStorageConnectionTest.cs | 2 +- .../PostgreSqlStorageConnectionTest.cs | 2 +- .../SqlServerStorageConnectionTest.cs | 2 +- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 9 +- .../CallbackMessageSenderTest.cs | 2 +- .../ConsumerInvokerTest.cs | 2 +- .../JsonContentSerializerTest.cs | 2 +- .../Processor/StateChangerTest.cs | 2 +- test/DotNetCore.CAP.Test/Sample.cs | 1 - 226 files changed, 1777 insertions(+), 1956 deletions(-) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/BatchCommandDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/CAP.DashboardMiddleware.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/CAP.DashboardOptions.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/CAP.DashboardOptionsExtensions.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/CombinedResourceDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/CommandDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/css/bootstrap.min.css (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/css/cap.css (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/css/jsonview.min.css (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/css/rickshaw.min.css (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/fonts/glyphicons-halflings-regular.eot (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/fonts/glyphicons-halflings-regular.svg (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/fonts/glyphicons-halflings-regular.ttf (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/fonts/glyphicons-halflings-regular.woff (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/fonts/glyphicons-halflings-regular.woff2 (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/bootstrap.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/cap.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/d3.layout.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/d3.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/jquery-2.1.4.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/jsonview.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/moment-with-locales.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/moment.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/js/rickshaw.min.js (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/resx/Strings.Designer.cs (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/resx/Strings.resx (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Content/resx/Strings.zh.resx (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardContext.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardMetric.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardMetrics.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardRequest.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardResponse.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/DashboardRoutes.cs (100%) create mode 100644 src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/EmbeddedResourceDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/DownstreamUrl.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/GatewayProxyMiddleware.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/IRequestMapper.Default.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/IRequestMapper.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/HttpClientBuilder.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/HttpClientHttpRequester.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/IHttpClient.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/IHttpClientBuilder.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/IHttpClientCache.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/IHttpRequester.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/GatewayProxy/Requester/MemoryHttpClientCache.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/HtmlHelper.cs (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/IDashboardAuthorizationFilter.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/IDashboardDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/IMonitoringApi.cs (95%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/JsonDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/JsonStats.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/LocalRequestsOnlyAuthorizationFilter.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/MenuItem.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/MessageHistoryRenderer.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/MessagesSidebarMenu.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Metric.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Monitoring/MessageDto.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Monitoring/MessageQueryDto.cs (94%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Monitoring/ServerDto.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Monitoring/StatisticsDto.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/NavigationMenu.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/NonEscapedString.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pager.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/BlockMetric.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/Breadcrumbs.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/HomePage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/HomePage.cshtml (98%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/HomePage.generated.cs (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/InlineMetric.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/LayoutPage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/LayoutPage.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/LayoutPage.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/NodePage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/NodePage.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/NodePage.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/PublishedPage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/PublishedPage.cshtml (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/PublishedPage.generated.cs (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/ReceivedPage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/ReceivedPage.cshtml (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/ReceivedPage.generated.cs (99%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/SidebarMenu.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/SubscriberPage.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/SubscriberPage.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_BlockMetric.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_BlockMetric.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Breadcrumbs.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Breadcrumbs.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_InlineMetric.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_InlineMetric.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Navigation.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Navigation.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Paginator.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Paginator.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_Paginator.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_PerPageSelector.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_PerPageSelector.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_PerPageSelector.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_SidebarMenu.cshtml (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/Pages/_SidebarMenu.generated.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/RazorPage.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/RazorPageDispatcher.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/RouteCollection.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/RouteCollectionExtensions.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/TimelineCounter.cs (100%) rename src/{DotNetCore.CAP/Dashboard => DotNetCore.CAP.Dashboard}/UrlHelper.cs (100%) delete mode 100644 src/DotNetCore.CAP.MySql/ICapPublisher.MySql.cs delete mode 100644 src/DotNetCore.CAP.MySql/ICollectProcessor.MySql.cs delete mode 100644 src/DotNetCore.CAP.MySql/IStorageConnection.MySql.cs delete mode 100644 src/DotNetCore.CAP.MySql/IStorageTransaction.MySql.cs create mode 100644 src/DotNetCore.CAP.MySql/MySqlDataStorage.cs create mode 100644 src/DotNetCore.CAP/Abstractions/CapPublisher.cs delete mode 100644 src/DotNetCore.CAP/Abstractions/CapPublisherBase.cs delete mode 100644 src/DotNetCore.CAP/IPublishExecutor.cs delete mode 100644 src/DotNetCore.CAP/IPublishMessageSender.Base.cs delete mode 100644 src/DotNetCore.CAP/IPublishMessageSender.cs delete mode 100644 src/DotNetCore.CAP/IStorage.cs delete mode 100644 src/DotNetCore.CAP/IStorageTransaction.cs delete mode 100644 src/DotNetCore.CAP/Internal/ICallbackMessageSender.Default.cs create mode 100644 src/DotNetCore.CAP/Internal/IMessageSender.Default.cs rename src/DotNetCore.CAP/Internal/{ICallbackMessageSender.cs => IMessageSender.cs} (64%) delete mode 100644 src/DotNetCore.CAP/MessageContext.cs rename src/DotNetCore.CAP/{Models => Messages}/CapMessageDto.cs (91%) create mode 100644 src/DotNetCore.CAP/Messages/Headers.cs create mode 100644 src/DotNetCore.CAP/Messages/Message.cs rename src/DotNetCore.CAP/{Models => Messages}/MessageType.cs (87%) create mode 100644 src/DotNetCore.CAP/Messages/TransportMessage.cs delete mode 100644 src/DotNetCore.CAP/Models/CapReceivedMessage.cs create mode 100644 src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs rename src/DotNetCore.CAP/{Models/CapPublishedMessage.cs => Persistence/CapReceivedMessage.cs} (68%) create mode 100644 src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs create mode 100644 src/DotNetCore.CAP/Persistence/IDataStorage.cs create mode 100644 src/DotNetCore.CAP/Persistence/IStorageInitializer.cs create mode 100644 src/DotNetCore.CAP/Persistence/MediumMessage.cs delete mode 100644 src/DotNetCore.CAP/Processor/ICollectProcessor.cs create mode 100644 src/DotNetCore.CAP/Processor/IProcessor.Collector.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IState.Failed.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IState.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs delete mode 100644 src/DotNetCore.CAP/Processor/States/IStateChanger.cs create mode 100644 src/DotNetCore.CAP/Serialization/ISerializer.cs create mode 100644 src/DotNetCore.CAP/Serialization/StringSerializer.cs create mode 100644 src/DotNetCore.CAP/Transport/ITransport.cs diff --git a/CAP.sln b/CAP.sln index 21c804b..f9bcb17 100644 --- a/CAP.sln +++ b/CAP.sln @@ -68,6 +68,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.InMemoryStor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.AzureServiceBus.InMemory", "samples\Sample.AzureServiceBus.InMemory\Sample.AzureServiceBus.InMemory.csproj", "{1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCore.CAP.Dashboard", "src\DotNetCore.CAP.Dashboard\DotNetCore.CAP.Dashboard.csproj", "{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -142,6 +144,10 @@ Global {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Release|Any CPU.Build.0 = Release|Any CPU + {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -165,6 +171,7 @@ Global {63B2A464-FBEA-42FB-8EFA-98AFA39FC920} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {58B6E829-C6C8-457C-9DD0-C600650254DF} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8} = {3A6B6931-A123-477A-9469-8B468B5385AF} + {56FB261C-67AF-4715-9A46-4FA4FAB91B2C} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2E70565D-94CF-40B4-BFE1-AC18D5F736AB} diff --git a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs index a9c2c96..578e201 100644 --- a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs @@ -36,10 +36,10 @@ namespace Sample.RabbitMQ.MySql.Controllers //your business code connection.Execute("insert into test(name) values('test')", transaction: (IDbTransaction)transaction.DbTransaction); - for (int i = 0; i < 5; i++) - { - _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); - } + //for (int i = 0; i < 5; i++) + //{ + _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); + //} transaction.Commit(); } @@ -68,10 +68,10 @@ namespace Sample.RabbitMQ.MySql.Controllers } [NonAction] - [CapSubscribe("#.rabbitmq.mysql")] + [CapSubscribe("sample.rabbitmq.mysql")] public void Subscriber(DateTime time) { - Console.WriteLine($@"{DateTime.Now}, Subscriber invoked, Sent time:{time}"); + //Console.WriteLine($@"{DateTime.Now}, Subscriber invoked, Sent time:{time}"); } } } diff --git a/samples/Sample.RabbitMQ.MySql/Program.cs b/samples/Sample.RabbitMQ.MySql/Program.cs index d8e6083..80d0fe6 100644 --- a/samples/Sample.RabbitMQ.MySql/Program.cs +++ b/samples/Sample.RabbitMQ.MySql/Program.cs @@ -13,6 +13,7 @@ namespace Sample.RabbitMQ.MySql public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() + .UseUrls("http://*:15173") .Build(); } } diff --git a/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json b/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json index 369b41c..c0a90d4 100644 --- a/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json +++ b/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json @@ -21,7 +21,7 @@ "launchBrowser": true, "launchUrl": "cap", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Production" }, "applicationUrl": "http://localhost:57173/" } diff --git a/samples/Sample.RabbitMQ.MySql/Startup.cs b/samples/Sample.RabbitMQ.MySql/Startup.cs index b9f16e7..cf6b8f8 100644 --- a/samples/Sample.RabbitMQ.MySql/Startup.cs +++ b/samples/Sample.RabbitMQ.MySql/Startup.cs @@ -15,12 +15,13 @@ namespace Sample.RabbitMQ.MySql services.AddCap(x => { x.UseEntityFramework(); - x.UseRabbitMQ("localhost"); + x.UseRabbitMQ("192.168.2.120"); x.UseDashboard(); x.FailedRetryCount = 5; x.FailedThresholdCallback = (type, name, content) => { - Console.WriteLine($@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {name}, message body: {content}"); + Console.WriteLine( + $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {name}, message body: {content}"); }; }); diff --git a/samples/Sample.RabbitMQ.MySql/appsettings.json b/samples/Sample.RabbitMQ.MySql/appsettings.json index 20aa907..50fe9a3 100644 --- a/samples/Sample.RabbitMQ.MySql/appsettings.json +++ b/samples/Sample.RabbitMQ.MySql/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Debug" + "Default": "Error" } } } diff --git a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs index 395c0f0..1a2feac 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs @@ -24,7 +24,7 @@ namespace DotNetCore.CAP services.Configure(_configure); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); } } diff --git a/src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs b/src/DotNetCore.CAP.Dashboard/BatchCommandDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/BatchCommandDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/CAP.DashboardMiddleware.cs b/src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/CAP.DashboardMiddleware.cs rename to src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs diff --git a/src/DotNetCore.CAP/Dashboard/CAP.DashboardOptions.cs b/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptions.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/CAP.DashboardOptions.cs rename to src/DotNetCore.CAP.Dashboard/CAP.DashboardOptions.cs diff --git a/src/DotNetCore.CAP/Dashboard/CAP.DashboardOptionsExtensions.cs b/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/CAP.DashboardOptionsExtensions.cs rename to src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs diff --git a/src/DotNetCore.CAP/Dashboard/CombinedResourceDispatcher.cs b/src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/CombinedResourceDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/CommandDispatcher.cs b/src/DotNetCore.CAP.Dashboard/CommandDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/CommandDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/CommandDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/Content/css/bootstrap.min.css b/src/DotNetCore.CAP.Dashboard/Content/css/bootstrap.min.css similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/css/bootstrap.min.css rename to src/DotNetCore.CAP.Dashboard/Content/css/bootstrap.min.css diff --git a/src/DotNetCore.CAP/Dashboard/Content/css/cap.css b/src/DotNetCore.CAP.Dashboard/Content/css/cap.css similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/css/cap.css rename to src/DotNetCore.CAP.Dashboard/Content/css/cap.css diff --git a/src/DotNetCore.CAP/Dashboard/Content/css/jsonview.min.css b/src/DotNetCore.CAP.Dashboard/Content/css/jsonview.min.css similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/css/jsonview.min.css rename to src/DotNetCore.CAP.Dashboard/Content/css/jsonview.min.css diff --git a/src/DotNetCore.CAP/Dashboard/Content/css/rickshaw.min.css b/src/DotNetCore.CAP.Dashboard/Content/css/rickshaw.min.css similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/css/rickshaw.min.css rename to src/DotNetCore.CAP.Dashboard/Content/css/rickshaw.min.css diff --git a/src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.eot b/src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.eot rename to src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.eot diff --git a/src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.svg b/src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.svg rename to src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.svg diff --git a/src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.ttf b/src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.ttf rename to src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.ttf diff --git a/src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.woff b/src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.woff rename to src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.woff diff --git a/src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.woff2 b/src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.woff2 similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/fonts/glyphicons-halflings-regular.woff2 rename to src/DotNetCore.CAP.Dashboard/Content/fonts/glyphicons-halflings-regular.woff2 diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/bootstrap.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/bootstrap.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/bootstrap.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/bootstrap.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/cap.js b/src/DotNetCore.CAP.Dashboard/Content/js/cap.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/cap.js rename to src/DotNetCore.CAP.Dashboard/Content/js/cap.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/d3.layout.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/d3.layout.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/d3.layout.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/d3.layout.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/d3.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/d3.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/d3.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/d3.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/jquery-2.1.4.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/jquery-2.1.4.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/jquery-2.1.4.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/jquery-2.1.4.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/jsonview.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/jsonview.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/jsonview.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/jsonview.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/moment-with-locales.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/moment-with-locales.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/moment-with-locales.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/moment-with-locales.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/moment.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/moment.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/moment.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/moment.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/js/rickshaw.min.js b/src/DotNetCore.CAP.Dashboard/Content/js/rickshaw.min.js similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/js/rickshaw.min.js rename to src/DotNetCore.CAP.Dashboard/Content/js/rickshaw.min.js diff --git a/src/DotNetCore.CAP/Dashboard/Content/resx/Strings.Designer.cs b/src/DotNetCore.CAP.Dashboard/Content/resx/Strings.Designer.cs similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Content/resx/Strings.Designer.cs rename to src/DotNetCore.CAP.Dashboard/Content/resx/Strings.Designer.cs index 4f911c2..38eb369 100644 --- a/src/DotNetCore.CAP/Dashboard/Content/resx/Strings.Designer.cs +++ b/src/DotNetCore.CAP.Dashboard/Content/resx/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace DotNetCore.CAP.Dashboard.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Strings { diff --git a/src/DotNetCore.CAP/Dashboard/Content/resx/Strings.resx b/src/DotNetCore.CAP.Dashboard/Content/resx/Strings.resx similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/resx/Strings.resx rename to src/DotNetCore.CAP.Dashboard/Content/resx/Strings.resx diff --git a/src/DotNetCore.CAP/Dashboard/Content/resx/Strings.zh.resx b/src/DotNetCore.CAP.Dashboard/Content/resx/Strings.zh.resx similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Content/resx/Strings.zh.resx rename to src/DotNetCore.CAP.Dashboard/Content/resx/Strings.zh.resx diff --git a/src/DotNetCore.CAP/Dashboard/DashboardContext.cs b/src/DotNetCore.CAP.Dashboard/DashboardContext.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardContext.cs rename to src/DotNetCore.CAP.Dashboard/DashboardContext.cs diff --git a/src/DotNetCore.CAP/Dashboard/DashboardMetric.cs b/src/DotNetCore.CAP.Dashboard/DashboardMetric.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardMetric.cs rename to src/DotNetCore.CAP.Dashboard/DashboardMetric.cs diff --git a/src/DotNetCore.CAP/Dashboard/DashboardMetrics.cs b/src/DotNetCore.CAP.Dashboard/DashboardMetrics.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardMetrics.cs rename to src/DotNetCore.CAP.Dashboard/DashboardMetrics.cs diff --git a/src/DotNetCore.CAP/Dashboard/DashboardRequest.cs b/src/DotNetCore.CAP.Dashboard/DashboardRequest.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardRequest.cs rename to src/DotNetCore.CAP.Dashboard/DashboardRequest.cs diff --git a/src/DotNetCore.CAP/Dashboard/DashboardResponse.cs b/src/DotNetCore.CAP.Dashboard/DashboardResponse.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardResponse.cs rename to src/DotNetCore.CAP.Dashboard/DashboardResponse.cs diff --git a/src/DotNetCore.CAP/Dashboard/DashboardRoutes.cs b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/DashboardRoutes.cs rename to src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs diff --git a/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj b/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj new file mode 100644 index 0000000..1d40d14 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj @@ -0,0 +1,125 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Strings.resx + + + _SidebarMenu.cshtml + + + _SidebarMenu.cshtml + + + ReceivedPage.cshtml + + + ReceivedPage.cshtml + + + _BlockMetric.cshtml + + + _BlockMetric.cshtml + + + _Breadcrumbs.cshtml + + + _Breadcrumbs.cshtml + + + _Paginator.cshtml + + + _Paginator.cshtml + + + _PerPageSelector.cshtml + + + _PerPageSelector.cshtml + + + PublishedPage.cshtml + + + PublishedPage.cshtml + + + LayoutPage.cshtml + + + LayoutPage.cshtml + + + _InlineMetric.cshtml + + + _InlineMetric.cshtml + + + _Navigation.cshtml + + + HomePage.cshtml + + + HomePage.cshtml + + + SubscriberPage.cshtml + + + NodePage.cshtml + + + + + + DotNetCore.CAP.Dashboard.Resources + Strings.Designer.cs + PublicResXFileCodeGenerator + + + + + + PublicResXFileCodeGenerator + DotNetCore.CAP.Dashboard.Resources + Strings.Designer.cs + + + + diff --git a/src/DotNetCore.CAP/Dashboard/EmbeddedResourceDispatcher.cs b/src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/EmbeddedResourceDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/DownstreamUrl.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/DownstreamUrl.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/DownstreamUrl.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/DownstreamUrl.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/GatewayProxyMiddleware.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/GatewayProxyMiddleware.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.Default.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.Default.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.Default.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.Default.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/IRequestMapper.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/HttpClientBuilder.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientBuilder.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/HttpClientBuilder.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientBuilder.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/HttpClientHttpRequester.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientHttpRequester.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/HttpClientHttpRequester.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/HttpClientHttpRequester.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClient.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClient.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClient.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClient.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClientBuilder.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientBuilder.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClientBuilder.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientBuilder.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClientCache.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientCache.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpClientCache.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpClientCache.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpRequester.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpRequester.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/IHttpRequester.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/IHttpRequester.cs diff --git a/src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/MemoryHttpClientCache.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/MemoryHttpClientCache.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/GatewayProxy/Requester/MemoryHttpClientCache.cs rename to src/DotNetCore.CAP.Dashboard/GatewayProxy/Requester/MemoryHttpClientCache.cs diff --git a/src/DotNetCore.CAP/Dashboard/HtmlHelper.cs b/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs similarity index 99% rename from src/DotNetCore.CAP/Dashboard/HtmlHelper.cs rename to src/DotNetCore.CAP.Dashboard/HtmlHelper.cs index dad4664..6b896a7 100644 --- a/src/DotNetCore.CAP/Dashboard/HtmlHelper.cs +++ b/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs @@ -11,7 +11,7 @@ using System.Text.RegularExpressions; using DotNetCore.CAP.Dashboard.Pages; using DotNetCore.CAP.Dashboard.Resources; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Internal; namespace DotNetCore.CAP.Dashboard diff --git a/src/DotNetCore.CAP/Dashboard/IDashboardAuthorizationFilter.cs b/src/DotNetCore.CAP.Dashboard/IDashboardAuthorizationFilter.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/IDashboardAuthorizationFilter.cs rename to src/DotNetCore.CAP.Dashboard/IDashboardAuthorizationFilter.cs diff --git a/src/DotNetCore.CAP/Dashboard/IDashboardDispatcher.cs b/src/DotNetCore.CAP.Dashboard/IDashboardDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/IDashboardDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/IDashboardDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/IMonitoringApi.cs b/src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs similarity index 95% rename from src/DotNetCore.CAP/Dashboard/IMonitoringApi.cs rename to src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs index e5ecd71..bc8505e 100644 --- a/src/DotNetCore.CAP/Dashboard/IMonitoringApi.cs +++ b/src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Dashboard { diff --git a/src/DotNetCore.CAP/Dashboard/JsonDispatcher.cs b/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/JsonDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/JsonStats.cs b/src/DotNetCore.CAP.Dashboard/JsonStats.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/JsonStats.cs rename to src/DotNetCore.CAP.Dashboard/JsonStats.cs diff --git a/src/DotNetCore.CAP/Dashboard/LocalRequestsOnlyAuthorizationFilter.cs b/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/LocalRequestsOnlyAuthorizationFilter.cs rename to src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs diff --git a/src/DotNetCore.CAP/Dashboard/MenuItem.cs b/src/DotNetCore.CAP.Dashboard/MenuItem.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/MenuItem.cs rename to src/DotNetCore.CAP.Dashboard/MenuItem.cs diff --git a/src/DotNetCore.CAP/Dashboard/MessageHistoryRenderer.cs b/src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/MessageHistoryRenderer.cs rename to src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs diff --git a/src/DotNetCore.CAP/Dashboard/MessagesSidebarMenu.cs b/src/DotNetCore.CAP.Dashboard/MessagesSidebarMenu.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/MessagesSidebarMenu.cs rename to src/DotNetCore.CAP.Dashboard/MessagesSidebarMenu.cs diff --git a/src/DotNetCore.CAP/Dashboard/Metric.cs b/src/DotNetCore.CAP.Dashboard/Metric.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Metric.cs rename to src/DotNetCore.CAP.Dashboard/Metric.cs diff --git a/src/DotNetCore.CAP/Dashboard/Monitoring/MessageDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Monitoring/MessageDto.cs rename to src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs diff --git a/src/DotNetCore.CAP/Dashboard/Monitoring/MessageQueryDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs similarity index 94% rename from src/DotNetCore.CAP/Dashboard/Monitoring/MessageQueryDto.cs rename to src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs index 02da29b..61c4706 100644 --- a/src/DotNetCore.CAP/Dashboard/Monitoring/MessageQueryDto.cs +++ b/src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Dashboard.Monitoring { diff --git a/src/DotNetCore.CAP/Dashboard/Monitoring/ServerDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Monitoring/ServerDto.cs rename to src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs diff --git a/src/DotNetCore.CAP/Dashboard/Monitoring/StatisticsDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Monitoring/StatisticsDto.cs rename to src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs diff --git a/src/DotNetCore.CAP/Dashboard/NavigationMenu.cs b/src/DotNetCore.CAP.Dashboard/NavigationMenu.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/NavigationMenu.cs rename to src/DotNetCore.CAP.Dashboard/NavigationMenu.cs diff --git a/src/DotNetCore.CAP/Dashboard/NonEscapedString.cs b/src/DotNetCore.CAP.Dashboard/NonEscapedString.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/NonEscapedString.cs rename to src/DotNetCore.CAP.Dashboard/NonEscapedString.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pager.cs b/src/DotNetCore.CAP.Dashboard/Pager.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pager.cs rename to src/DotNetCore.CAP.Dashboard/Pager.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/BlockMetric.cs b/src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/BlockMetric.cs rename to src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/Breadcrumbs.cs b/src/DotNetCore.CAP.Dashboard/Pages/Breadcrumbs.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/Breadcrumbs.cs rename to src/DotNetCore.CAP.Dashboard/Pages/Breadcrumbs.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/HomePage.cs b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/HomePage.cs rename to src/DotNetCore.CAP.Dashboard/Pages/HomePage.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/HomePage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.cshtml similarity index 98% rename from src/DotNetCore.CAP/Dashboard/Pages/HomePage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/HomePage.cshtml index a416980..91b840d 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/HomePage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.cshtml @@ -1,7 +1,7 @@ @* Generator: Template TypeVisibility: Internal GeneratePrettyNames: True *@ @using DotNetCore.CAP.Dashboard.Pages @using DotNetCore.CAP.Dashboard.Resources -@using DotNetCore.CAP.Models +@using DotNetCore.CAP.Messages @using Newtonsoft.Json @inherits DotNetCore.CAP.Dashboard.RazorPage @{ diff --git a/src/DotNetCore.CAP/Dashboard/Pages/HomePage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Pages/HomePage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs index d9b3137..12947d4 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/HomePage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs @@ -1,4 +1,6 @@ -#pragma warning disable 1591 +using DotNetCore.CAP.Messages; + +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -45,8 +47,6 @@ namespace DotNetCore.CAP.Dashboard.Pages #line hidden #line 4 "..\..\HomePage.cshtml" - using DotNetCore.CAP.Models; - #line default #line hidden diff --git a/src/DotNetCore.CAP/Dashboard/Pages/InlineMetric.cs b/src/DotNetCore.CAP.Dashboard/Pages/InlineMetric.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/InlineMetric.cs rename to src/DotNetCore.CAP.Dashboard/Pages/InlineMetric.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cs b/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cs rename to src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/NodePage.cs b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/NodePage.cs rename to src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/NodePage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/NodePage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/NodePage.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/NodePage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/NodePage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cs b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cs rename to src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml index 2d76089..d4313db 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml @@ -4,7 +4,7 @@ @using DotNetCore.CAP.Dashboard.Monitoring @using DotNetCore.CAP.Dashboard.Pages @using DotNetCore.CAP.Dashboard.Resources -@using DotNetCore.CAP.Models +@using DotNetCore.CAP.Messages @inherits DotNetCore.CAP.Dashboard.RazorPage @{ Layout = new LayoutPage(Strings.PublishedMessagesPage_Title); diff --git a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs index 4d8a578..250c6c8 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/PublishedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs @@ -1,4 +1,6 @@ -#pragma warning disable 1591 +using DotNetCore.CAP.Messages; + +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -46,7 +48,6 @@ namespace DotNetCore.CAP.Dashboard.Pages #line hidden #line 3 "..\..\PublishedPage.cshtml" - using DotNetCore.CAP.Models; #line default #line hidden diff --git a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cs b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cs rename to src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml index 5b92167..fb179cf 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml @@ -4,7 +4,7 @@ @using DotNetCore.CAP.Dashboard.Monitoring @using DotNetCore.CAP.Dashboard.Pages @using DotNetCore.CAP.Dashboard.Resources -@using DotNetCore.CAP.Models +@using DotNetCore.CAP.Messages @inherits DotNetCore.CAP.Dashboard.RazorPage @{ Layout = new LayoutPage(Strings.ReceivedMessagesPage_Title); diff --git a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs similarity index 99% rename from src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs index 7b78863..17365c7 100644 --- a/src/DotNetCore.CAP/Dashboard/Pages/ReceivedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs @@ -1,4 +1,6 @@ -#pragma warning disable 1591 +using DotNetCore.CAP.Messages; + +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -46,7 +48,6 @@ namespace DotNetCore.CAP.Dashboard.Pages #line hidden #line 3 "..\..\ReceivedPage.cshtml" - using DotNetCore.CAP.Models; #line default #line hidden diff --git a/src/DotNetCore.CAP/Dashboard/Pages/SidebarMenu.cs b/src/DotNetCore.CAP.Dashboard/Pages/SidebarMenu.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/SidebarMenu.cs rename to src/DotNetCore.CAP.Dashboard/Pages/SidebarMenu.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/SubscriberPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/SubscriberPage.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/SubscriberPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/SubscriberPage.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_BlockMetric.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_BlockMetric.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_BlockMetric.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_BlockMetric.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Breadcrumbs.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Breadcrumbs.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Breadcrumbs.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Breadcrumbs.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_InlineMetric.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_InlineMetric.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_InlineMetric.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_InlineMetric.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Navigation.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Navigation.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_Navigation.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Navigation.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Navigation.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Paginator.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Paginator.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_Paginator.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Paginator.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Paginator.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_Paginator.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_Paginator.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_Paginator.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.cs b/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_PerPageSelector.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_SidebarMenu.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.cshtml similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_SidebarMenu.cshtml rename to src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.cshtml diff --git a/src/DotNetCore.CAP/Dashboard/Pages/_SidebarMenu.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/Pages/_SidebarMenu.generated.cs rename to src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs diff --git a/src/DotNetCore.CAP/Dashboard/RazorPage.cs b/src/DotNetCore.CAP.Dashboard/RazorPage.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/RazorPage.cs rename to src/DotNetCore.CAP.Dashboard/RazorPage.cs diff --git a/src/DotNetCore.CAP/Dashboard/RazorPageDispatcher.cs b/src/DotNetCore.CAP.Dashboard/RazorPageDispatcher.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/RazorPageDispatcher.cs rename to src/DotNetCore.CAP.Dashboard/RazorPageDispatcher.cs diff --git a/src/DotNetCore.CAP/Dashboard/RouteCollection.cs b/src/DotNetCore.CAP.Dashboard/RouteCollection.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/RouteCollection.cs rename to src/DotNetCore.CAP.Dashboard/RouteCollection.cs diff --git a/src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs b/src/DotNetCore.CAP.Dashboard/RouteCollectionExtensions.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs rename to src/DotNetCore.CAP.Dashboard/RouteCollectionExtensions.cs diff --git a/src/DotNetCore.CAP/Dashboard/TimelineCounter.cs b/src/DotNetCore.CAP.Dashboard/TimelineCounter.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/TimelineCounter.cs rename to src/DotNetCore.CAP.Dashboard/TimelineCounter.cs diff --git a/src/DotNetCore.CAP/Dashboard/UrlHelper.cs b/src/DotNetCore.CAP.Dashboard/UrlHelper.cs similarity index 100% rename from src/DotNetCore.CAP/Dashboard/UrlHelper.cs rename to src/DotNetCore.CAP.Dashboard/UrlHelper.cs diff --git a/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs index 12e9f8c..6cb759c 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs @@ -5,7 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.InMemoryStorage diff --git a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs index d96b976..7454435 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs @@ -7,7 +7,7 @@ using System.Linq; using DotNetCore.CAP.Dashboard; using DotNetCore.CAP.Dashboard.Monitoring; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.InMemoryStorage { diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs index 3783ddb..22364b0 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.InMemoryStorage diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs index 40bf28f..a63d8a5 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.InMemoryStorage { diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs index 55902e7..6699eb0 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs @@ -24,7 +24,7 @@ namespace DotNetCore.CAP services.Configure(_configure); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); } diff --git a/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs index f74696c..62e2a3e 100644 --- a/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs @@ -5,7 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using MongoDB.Driver; diff --git a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs index 6bf0a26..3b022f2 100644 --- a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using DotNetCore.CAP.Dashboard; using DotNetCore.CAP.Dashboard.Monitoring; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; diff --git a/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs index 387e4c7..772ecb1 100644 --- a/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using MongoDB.Driver; diff --git a/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs index 1cbeff8..992aa8f 100644 --- a/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs @@ -3,7 +3,7 @@ using System; using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using MongoDB.Driver; namespace DotNetCore.CAP.MongoDB diff --git a/src/DotNetCore.CAP.MongoDB/StorageMessage.cs b/src/DotNetCore.CAP.MongoDB/StorageMessage.cs index b5abafa..ac253be 100644 --- a/src/DotNetCore.CAP.MongoDB/StorageMessage.cs +++ b/src/DotNetCore.CAP.MongoDB/StorageMessage.cs @@ -1,4 +1,4 @@ -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.MongoDB { diff --git a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs index d9c7569..76aa126 100644 --- a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs @@ -3,7 +3,6 @@ using System; using DotNetCore.CAP.MySql; -using DotNetCore.CAP.Processor; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -22,12 +21,7 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(provider => (MySqlPublisher)provider.GetService()); - services.AddSingleton(); - + //services.AddSingleton(); services.AddTransient(); //Add MySqlOptions diff --git a/src/DotNetCore.CAP.MySql/ICapPublisher.MySql.cs b/src/DotNetCore.CAP.MySql/ICapPublisher.MySql.cs deleted file mode 100644 index ae67245..0000000 --- a/src/DotNetCore.CAP.MySql/ICapPublisher.MySql.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using MySql.Data.MySqlClient; - -namespace DotNetCore.CAP.MySql -{ - public class MySqlPublisher : CapPublisherBase, ICallbackPublisher - { - private readonly MySqlOptions _options; - - public MySqlPublisher(IServiceProvider provider) : base(provider) - { - _options = provider.GetService>().Value; - } - - public async Task PublishCallbackAsync(CapPublishedMessage message) - { - await PublishAsyncInternal(message); - } - - protected override async Task ExecuteAsync(CapPublishedMessage message, - ICapTransaction transaction = null, - CancellationToken cancel = default(CancellationToken)) - { - if (transaction == null) - { - using (var connection = new MySqlConnection(_options.ConnectionString)) - { - await connection.ExecuteAsync(PrepareSql(), message); - return; - } - } - - var dbTrans = transaction.DbTransaction as IDbTransaction; - if (dbTrans == null && transaction.DbTransaction is IDbContextTransaction dbContextTrans) - { - dbTrans = dbContextTrans.GetDbTransaction(); - } - - var conn = dbTrans?.Connection; - await conn.ExecuteAsync(PrepareSql(), message, dbTrans); - } - - #region private methods - - private string PrepareSql() - { - return - $"INSERT INTO `{_options.TableNamePrefix}.published` (`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`)" + - $"VALUES(@Id,'{_options.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - } - - #endregion private methods - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs index 605b4cd..77f7919 100644 --- a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs +++ b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs @@ -3,7 +3,6 @@ using System.Data; using System.Diagnostics; -using System.Threading; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; diff --git a/src/DotNetCore.CAP.MySql/ICollectProcessor.MySql.cs b/src/DotNetCore.CAP.MySql/ICollectProcessor.MySql.cs deleted file mode 100644 index 55955c7..0000000 --- a/src/DotNetCore.CAP.MySql/ICollectProcessor.MySql.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Processor; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using MySql.Data.MySqlClient; - -namespace DotNetCore.CAP.MySql -{ - internal class MySqlCollectProcessor : ICollectProcessor - { - private const int MaxBatch = 1000; - private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); - private readonly ILogger _logger; - private readonly MySqlOptions _options; - private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); - - public MySqlCollectProcessor(ILogger logger, IOptions mysqlOptions) - { - _logger = logger; - _options = mysqlOptions.Value; - } - - public async Task ProcessAsync(ProcessingContext context) - { - var tables = new[] - { - $"{_options.TableNamePrefix}.published", - $"{_options.TableNamePrefix}.received" - }; - - foreach (var table in tables) - { - _logger.LogDebug($"Collecting expired data from table [{table}]."); - - int removedCount; - do - { - using (var connection = new MySqlConnection(_options.ConnectionString)) - { - removedCount = await connection.ExecuteAsync( - $@"DELETE FROM `{table}` WHERE ExpiresAt < @now limit @count;", - new { now = DateTime.Now, count = MaxBatch }); - } - - if (removedCount != 0) - { - await context.WaitAsync(_delay); - context.ThrowIfStopping(); - } - } while (removedCount != 0); - } - - await context.WaitAsync(_waitingInterval); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs index 7cd4135..ff5e491 100644 --- a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs @@ -1,194 +1,231 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using Dapper; -using DotNetCore.CAP.Dashboard; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.MySql -{ - internal class MySqlMonitoringApi : IMonitoringApi - { - private readonly string _prefix; - private readonly MySqlStorage _storage; - - public MySqlMonitoringApi(IStorage storage, IOptions options) - { - _storage = storage as MySqlStorage ?? throw new ArgumentNullException(nameof(storage)); - _prefix = options.Value.TableNamePrefix ?? throw new ArgumentNullException(nameof(options)); - } - - public StatisticsDto GetStatistics() - { - var sql = string.Format(@" -set transaction isolation level read committed; -select count(Id) from `{0}.published` where StatusName = N'Succeeded'; -select count(Id) from `{0}.received` where StatusName = N'Succeeded'; -select count(Id) from `{0}.published` where StatusName = N'Failed'; -select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); - - var statistics = UseConnection(connection => - { - var stats = new StatisticsDto(); - using (var multi = connection.QueryMultiple(sql)) - { - stats.PublishedSucceeded = multi.ReadSingle(); - stats.ReceivedSucceeded = multi.ReadSingle(); - - stats.PublishedFailed = multi.ReadSingle(); - stats.ReceivedFailed = multi.ReadSingle(); - } - - return stats; - }); - return statistics; - } - - public IDictionary HourlyFailedJobs(MessageType type) - { - var tableName = type == MessageType.Publish ? "published" : "received"; - return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Failed)); - } - - public IDictionary HourlySucceededJobs(MessageType type) - { - var tableName = type == MessageType.Publish ? "published" : "received"; - return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Succeeded)); - } - - public IList Messages(MessageQueryDto queryDto) - { - var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; - var where = string.Empty; - if (!string.IsNullOrEmpty(queryDto.StatusName)) - { - where += " and StatusName=@StatusName"; - } - - if (!string.IsNullOrEmpty(queryDto.Name)) - { - where += " and Name=@Name"; - } - - if (!string.IsNullOrEmpty(queryDto.Group)) - { - where += " and `Group`=@Group"; - } - - if (!string.IsNullOrEmpty(queryDto.Content)) - { - where += " and Content like '%@Content%'"; - } - - var sqlQuery = - $"select * from `{_prefix}.{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; - - return UseConnection(conn => conn.Query(sqlQuery, new - { - queryDto.StatusName, - queryDto.Group, - queryDto.Name, - queryDto.Content, - Offset = queryDto.CurrentPage * queryDto.PageSize, - Limit = queryDto.PageSize - }).ToList()); - } - - public int PublishedFailedCount() - { - return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Failed)); - } - - public int PublishedSucceededCount() - { - return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Succeeded)); - } - - public int ReceivedFailedCount() - { - return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Failed)); - } - - public int ReceivedSucceededCount() - { - return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Succeeded)); - } - - private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) - { - var sqlQuery = $"select count(Id) from `{_prefix}.{tableName}` where StatusName = @state"; - - var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); - return count; - } - - private T UseConnection(Func action) - { - return _storage.UseConnection(action); - } - - private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, - string statusName) - { - var endDate = DateTime.Now; - var dates = new List(); - for (var i = 0; i < 24; i++) - { - dates.Add(endDate); - endDate = endDate.AddHours(-1); - } - - var keyMaps = dates.ToDictionary(x => x.ToString("yyyy-MM-dd-HH"), x => x); - - return GetTimelineStats(connection, tableName, statusName, keyMaps); - } - - private Dictionary GetTimelineStats( - IDbConnection connection, - string tableName, - string statusName, - IDictionary keyMaps) - { - var sqlQuery = - $@" -select aggr.* from ( - select date_format(`Added`,'%Y-%m-%d-%H') as `Key`, - count(id) `Count` - from `{_prefix}.{tableName}` - where StatusName = @statusName - group by date_format(`Added`,'%Y-%m-%d-%H') -) aggr where `Key` in @keys;"; - - var valuesMap = connection.Query( - sqlQuery, - new { keys = keyMaps.Keys, statusName }) - .ToDictionary(x => x.Key, x => x.Count); - - foreach (var key in keyMaps.Keys) - { - if (!valuesMap.ContainsKey(key)) - { - valuesMap.Add(key, 0); - } - } - - var result = new Dictionary(); - for (var i = 0; i < keyMaps.Count; i++) - { - var value = valuesMap[keyMaps.ElementAt(i).Key]; - result.Add(keyMaps.ElementAt(i).Value, value); - } - - return result; - } - } -} \ No newline at end of file +//// Copyright (c) .NET Core Community. All rights reserved. +//// Licensed under the MIT License. See License.txt in the project root for license information. + +//using System; +//using System.Collections.Generic; +//using System.Data; +//using System.Linq; +//using Dapper; +//using DotNetCore.CAP.Dashboard; +//using DotNetCore.CAP.Dashboard.Monitoring; +//using DotNetCore.CAP.Infrastructure; +//using DotNetCore.CAP.Messages; +//using Microsoft.Extensions.Options; +//using MySql.Data.MySqlClient; + +//namespace DotNetCore.CAP.MySql +//{ +// internal class MySqlMonitoringApi : IMonitoringApi +// { +// private readonly IDbConnection _existingConnection = null; +// private readonly string _prefix; +// private readonly string _connectionString; + +// public MySqlMonitoringApi(IOptions options) +// { +// _prefix = options.Value.TableNamePrefix ?? throw new ArgumentNullException(nameof(options)); +// _connectionString = options.Value.ConnectionString; +// } + +// public StatisticsDto GetStatistics() +// { +// var sql = string.Format(@" +//set transaction isolation level read committed; +//select count(Id) from `{0}.published` where StatusName = N'Succeeded'; +//select count(Id) from `{0}.received` where StatusName = N'Succeeded'; +//select count(Id) from `{0}.published` where StatusName = N'Failed'; +//select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); + +// var statistics = UseConnection(connection => +// { +// var stats = new StatisticsDto(); +// using (var multi = connection.QueryMultiple(sql)) +// { +// stats.PublishedSucceeded = multi.ReadSingle(); +// stats.ReceivedSucceeded = multi.ReadSingle(); + +// stats.PublishedFailed = multi.ReadSingle(); +// stats.ReceivedFailed = multi.ReadSingle(); +// } + +// return stats; +// }); +// return statistics; +// } + +// public IDictionary HourlyFailedJobs(MessageType type) +// { +// var tableName = type == MessageType.Publish ? "published" : "received"; +// return UseConnection(connection => +// GetHourlyTimelineStats(connection, tableName, StatusName.Failed)); +// } + +// public IDictionary HourlySucceededJobs(MessageType type) +// { +// var tableName = type == MessageType.Publish ? "published" : "received"; +// return UseConnection(connection => +// GetHourlyTimelineStats(connection, tableName, StatusName.Succeeded)); +// } + +// public IList Messages(MessageQueryDto queryDto) +// { +// var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; +// var where = string.Empty; +// if (!string.IsNullOrEmpty(queryDto.StatusName)) +// { +// where += " and StatusName=@StatusName"; +// } + +// if (!string.IsNullOrEmpty(queryDto.Name)) +// { +// where += " and Name=@Name"; +// } + +// if (!string.IsNullOrEmpty(queryDto.Group)) +// { +// where += " and `Group`=@Group"; +// } + +// if (!string.IsNullOrEmpty(queryDto.Content)) +// { +// where += " and Content like '%@Content%'"; +// } + +// var sqlQuery = +// $"select * from `{_prefix}.{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; + +// return UseConnection(conn => conn.Query(sqlQuery, new +// { +// queryDto.StatusName, +// queryDto.Group, +// queryDto.Name, +// queryDto.Content, +// Offset = queryDto.CurrentPage * queryDto.PageSize, +// Limit = queryDto.PageSize +// }).ToList()); +// } + +// public int PublishedFailedCount() +// { +// return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Failed)); +// } + +// public int PublishedSucceededCount() +// { +// return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Succeeded)); +// } + +// public int ReceivedFailedCount() +// { +// return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Failed)); +// } + +// public int ReceivedSucceededCount() +// { +// return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Succeeded)); +// } + +// private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) +// { +// var sqlQuery = $"select count(Id) from `{_prefix}.{tableName}` where StatusName = @state"; + +// var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); +// return count; +// } + +// private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, +// string statusName) +// { +// var endDate = DateTime.Now; +// var dates = new List(); +// for (var i = 0; i < 24; i++) +// { +// dates.Add(endDate); +// endDate = endDate.AddHours(-1); +// } + +// var keyMaps = dates.ToDictionary(x => x.ToString("yyyy-MM-dd-HH"), x => x); + +// return GetTimelineStats(connection, tableName, statusName, keyMaps); +// } + +// private Dictionary GetTimelineStats( +// IDbConnection connection, +// string tableName, +// string statusName, +// IDictionary keyMaps) +// { +// var sqlQuery = +// $@" +//select aggr.* from ( +// select date_format(`Added`,'%Y-%m-%d-%H') as `Key`, +// count(id) `Count` +// from `{_prefix}.{tableName}` +// where StatusName = @statusName +// group by date_format(`Added`,'%Y-%m-%d-%H') +//) aggr where `Key` in @keys;"; + +// var valuesMap = connection.Query( +// sqlQuery, +// new { keys = keyMaps.Keys, statusName }) +// .ToDictionary(x => x.Key, x => x.Count); + +// foreach (var key in keyMaps.Keys) +// { +// if (!valuesMap.ContainsKey(key)) +// { +// valuesMap.Add(key, 0); +// } +// } + +// var result = new Dictionary(); +// for (var i = 0; i < keyMaps.Count; i++) +// { +// var value = valuesMap[keyMaps.ElementAt(i).Key]; +// result.Add(keyMaps.ElementAt(i).Value, value); +// } + +// return result; +// } + +// private T UseConnection(Func func) +// { +// IDbConnection connection = null; + +// try +// { +// connection = CreateAndOpenConnection(); +// return func(connection); +// } +// finally +// { +// ReleaseConnection(connection); +// } +// } + +// private IDbConnection CreateAndOpenConnection() +// { +// var connection = _existingConnection ?? new MySqlConnection(_connectionString); + +// if (connection.State == ConnectionState.Closed) +// { +// connection.Open(); +// } + +// return connection; +// } + +// private bool IsExistingConnection(IDbConnection connection) +// { +// return connection != null && ReferenceEquals(connection, _existingConnection); +// } + +// private void ReleaseConnection(IDbConnection connection) +// { +// if (connection != null && !IsExistingConnection(connection)) +// { +// connection.Dispose(); +// } +// } +// } +//} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/IStorage.MySql.cs b/src/DotNetCore.CAP.MySql/IStorage.MySql.cs index 5be40b8..be84cc9 100644 --- a/src/DotNetCore.CAP.MySql/IStorage.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IStorage.MySql.cs @@ -1,43 +1,38 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; -using System.Data; using System.Threading; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Dashboard; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MySql.Data.MySqlClient; namespace DotNetCore.CAP.MySql { - public class MySqlStorage : IStorage + public class MySqlStorageInitializer : IStorageInitializer { - private readonly IOptions _capOptions; private readonly IOptions _options; - private readonly IDbConnection _existingConnection = null; private readonly ILogger _logger; - public MySqlStorage( - ILogger logger, + public MySqlStorageInitializer( + ILogger logger, IOptions options, IOptions capOptions) { _options = options; - _capOptions = capOptions; _logger = logger; } - public IStorageConnection GetConnection() + public string GetPublishedTableName() { - return new MySqlStorageConnection(_options, _capOptions); + return $"{_options.Value.TableNamePrefix}.published"; } - public IMonitoringApi GetMonitoringApi() + public string GetReceivedTableName() { - return new MySqlMonitoringApi(this, _options); + return $"{_options.Value.TableNamePrefix}.received"; } public async Task InitializeAsync(CancellationToken cancellationToken) @@ -56,6 +51,7 @@ namespace DotNetCore.CAP.MySql _logger.LogDebug("Ensuring all create database tables script are applied."); } + protected virtual string CreateDbTablesScript(string prefix) { var batchSql = @@ -87,45 +83,5 @@ CREATE TABLE IF NOT EXISTS `{prefix}.published` ( "; return batchSql; } - - internal T UseConnection(Func func) - { - IDbConnection connection = null; - - try - { - connection = CreateAndOpenConnection(); - return func(connection); - } - finally - { - ReleaseConnection(connection); - } - } - - internal IDbConnection CreateAndOpenConnection() - { - var connection = _existingConnection ?? new MySqlConnection(_options.Value.ConnectionString); - - if (connection.State == ConnectionState.Closed) - { - connection.Open(); - } - - return connection; - } - - internal bool IsExistingConnection(IDbConnection connection) - { - return connection != null && ReferenceEquals(connection, _existingConnection); - } - - internal void ReleaseConnection(IDbConnection connection) - { - if (connection != null && !IsExistingConnection(connection)) - { - connection.Dispose(); - } - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/IStorageConnection.MySql.cs b/src/DotNetCore.CAP.MySql/IStorageConnection.MySql.cs deleted file mode 100644 index 5f300bb..0000000 --- a/src/DotNetCore.CAP.MySql/IStorageConnection.MySql.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.Options; -using MySql.Data.MySqlClient; - -namespace DotNetCore.CAP.MySql -{ - public class MySqlStorageConnection : IStorageConnection - { - private readonly CapOptions _capOptions; - private readonly IOptions _options; - private readonly string _prefix; - - public MySqlStorageConnection(IOptions options, IOptions capOptions) - { - _options = options; - _capOptions = capOptions.Value; - _prefix = options.Value.TableNamePrefix; - } - - public MySqlOptions Options => _options.Value; - - public IStorageTransaction CreateTransaction() - { - return new MySqlStorageTransaction(this); - } - - public async Task GetPublishedMessageAsync(long id) - { - var sql = $@"SELECT * FROM `{_prefix}.published` WHERE `Id`={id};"; - - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetPublishedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT * FROM `{_prefix}.published` WHERE `Retries`<{_capOptions.FailedRetryCount} AND `Version`='{_capOptions.Version}' AND `Added`<'{fourMinsAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; - - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public void StoreReceivedMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = $@" -INSERT INTO `{_prefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) -VALUES(@Id,'{_capOptions.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - connection.Execute(sql, message); - } - } - - public async Task GetReceivedMessageAsync(long id) - { - var sql = $@"SELECT * FROM `{_prefix}.received` WHERE Id={id};"; - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetReceivedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT * FROM `{_prefix}.received` WHERE `Retries`<{_capOptions.FailedRetryCount} AND `Version`='{_capOptions.Version}' AND `Added`<'{fourMinsAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public bool ChangePublishedState(long messageId, string state) - { - var sql = - $"UPDATE `{_prefix}.published` SET `Retries`=`Retries`+1,`ExpiresAt`=NULL,`StatusName` = '{state}' WHERE `Id`={messageId}"; - - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - - public bool ChangeReceivedState(long messageId, string state) - { - var sql = - $"UPDATE `{_prefix}.received` SET `Retries`=`Retries`+1,`ExpiresAt`=NULL,`StatusName` = '{state}' WHERE `Id`={messageId}"; - - using (var connection = new MySqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/IStorageTransaction.MySql.cs b/src/DotNetCore.CAP.MySql/IStorageTransaction.MySql.cs deleted file mode 100644 index 44b77ab..0000000 --- a/src/DotNetCore.CAP.MySql/IStorageTransaction.MySql.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Models; -using MySql.Data.MySqlClient; - -namespace DotNetCore.CAP.MySql -{ - public class MySqlStorageTransaction : IStorageTransaction - { - private readonly IDbConnection _dbConnection; - - private readonly string _prefix; - - public MySqlStorageTransaction(MySqlStorageConnection connection) - { - var options = connection.Options; - _prefix = options.TableNamePrefix; - - _dbConnection = new MySqlConnection(options.ConnectionString); - } - - public void UpdateMessage(CapPublishedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $"UPDATE `{_prefix}.published` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; - _dbConnection.Execute(sql, message); - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $"UPDATE `{_prefix}.received` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; - _dbConnection.Execute(sql, message); - } - - public Task CommitAsync() - { - _dbConnection.Close(); - _dbConnection.Dispose(); - return Task.CompletedTask; - } - - public void Dispose() - { - _dbConnection.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs new file mode 100644 index 0000000..05f02aa --- /dev/null +++ b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Options; +using MySql.Data.MySqlClient; + +namespace DotNetCore.CAP.MySql +{ + public class MySqlDataStorage : IDataStorage + { + private readonly IOptions _options; + private readonly IOptions _capOptions; + + public MySqlDataStorage(IOptions options, IOptions capOptions) + { + _options = options; + _capOptions = capOptions; + } + + public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) + { + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + var sql = $"UPDATE `{_options.Value.TableNamePrefix}.published` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + Retries = message.Retries, + ExpiresAt = message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + } + + public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) + { + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + var sql = $"UPDATE `{_options.Value.TableNamePrefix}.received` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + Retries = message.Retries, + ExpiresAt = message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + } + + public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default) + { + var sql = $"INSERT INTO `{_options.Value.TableNamePrefix}.published`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var message = new MediumMessage() + { + DbId = content.GetId(), + Origin = content, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + var po = new + { + Id = message.DbId, + Name = name, + Content = StringSerializer.Serialize(message.Origin), + Retries = message.Retries, + Added = message.Added, + ExpiresAt = message.ExpiresAt, + StatusName = StatusName.Scheduled + }; + + if (dbTransaction == null) + { + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + await connection.ExecuteAsync(sql, po); + } + } + else + { + var dbTrans = dbTransaction as IDbTransaction; + if (dbTrans == null && dbTransaction is IDbContextTransaction dbContextTrans) + { + dbTrans = dbContextTrans.GetDbTransaction(); + } + + var conn = dbTrans?.Connection; + await conn.ExecuteAsync(sql, po, dbTrans); + } + + return message; + } + + public async Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default) + { + var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var message = new MediumMessage() + { + DbId = SnowflakeId.Default().NextId().ToString(), + Origin = content, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + var po = new + { + Id = message.DbId, + Group = group, + Name = name, + Content = StringSerializer.Serialize(message.Origin), + Retries = message.Retries, + Added = message.Added, + ExpiresAt = message.ExpiresAt, + StatusName = StatusName.Scheduled + }; + + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + await connection.ExecuteAsync(sql, po); + } + return message; + } + + public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default) + { + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + return await connection.ExecuteAsync( + $@"DELETE FROM `{table}` WHERE ExpiresAt < @timeout limit @batchCount;", + new { timeout, batchCount }); + } + } + + public async Task> GetPublishedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = $"SELECT * FROM `{_options.Value.TableNamePrefix}.published` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; + + var result = new List(); + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage() + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + } + return result; + } + + public async Task> GetReceivedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = + $"SELECT * FROM `{_options.Value.TableNamePrefix}.received` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; + + var result = new List(); + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage() + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + } + return result; + } + + //public Task GetPublishedMessageAsync(long id) + //{ + // var sql = $@"SELECT * FROM `{_prefix}.published` WHERE `Id`={id};"; + + // using (var connection = new MySqlConnection(Options.ConnectionString)) + // { + // return await connection.QueryFirstOrDefaultAsync(sql); + // } + //} + + //public Task GetReceivedMessageAsync(long id) + //{ + // var sql = + // $@"SELECT * FROM `{_prefix}.received` WHERE Id={id};"; + // using (var connection = new MySqlConnection(Options.ConnectionString)) + // { + // return await connection.QueryFirstOrDefaultAsync(sql); + // } + //} + } +} diff --git a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs index 9c34b65..2631f7f 100644 --- a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs index 9760188..a2c3bcb 100644 --- a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs @@ -9,7 +9,7 @@ using Dapper; using DotNetCore.CAP.Dashboard; using DotNetCore.CAP.Dashboard.Monitoring; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.PostgreSql diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs index afb3296..f2c0b5a 100644 --- a/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using Npgsql; diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs index 28d75d8..44750eb 100644 --- a/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs @@ -5,7 +5,7 @@ using System; using System.Data; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Npgsql; namespace DotNetCore.CAP.PostgreSql diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index ac1455a..4ed02f7 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.RabbitMQ; using Microsoft.Extensions.DependencyInjection; @@ -24,8 +25,7 @@ namespace DotNetCore.CAP services.Configure(_configure); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs b/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs index ac4f2b9..2cb7efe 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs +++ b/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs @@ -2,53 +2,50 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Text; +using System.Linq; using System.Threading.Tasks; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Processor.States; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using RabbitMQ.Client; using RabbitMQ.Client.Framing; namespace DotNetCore.CAP.RabbitMQ { - internal sealed class RabbitMQPublishMessageSender : BasePublishMessageSender + internal sealed class RabbitMQMessageSender : ITransport { private readonly IConnectionChannelPool _connectionChannelPool; private readonly ILogger _logger; private readonly string _exchange; - public RabbitMQPublishMessageSender( - ILogger logger, - IOptions options, - IStorageConnection connection, - IConnectionChannelPool connectionChannelPool, - IStateChanger stateChanger) - : base(logger, options, connection, stateChanger) + public RabbitMQMessageSender( + ILogger logger, + IConnectionChannelPool connectionChannelPool) { _logger = logger; _connectionChannelPool = connectionChannelPool; _exchange = _connectionChannelPool.Exchange; } - protected override string ServersAddress => _connectionChannelPool.HostAddress; + public string Address => _connectionChannelPool.HostAddress; - public override Task PublishAsync(string keyName, string content) + public Task SendAsync(TransportMessage message) { var channel = _connectionChannelPool.Rent(); try { - var body = Encoding.UTF8.GetBytes(content); - var props = new BasicProperties() + var props = new BasicProperties { - DeliveryMode = 2 + DeliveryMode = 2, + Headers = message.Headers.ToDictionary(x => x.Key, x => (object)x.Value) }; channel.ExchangeDeclare(_exchange, RabbitMQOptions.ExchangeType, true); - channel.BasicPublish(_exchange, keyName, props, body); - _logger.LogDebug($"RabbitMQ topic message [{keyName}] has been published. Body: {content}"); + channel.BasicPublish(_exchange, message.GetName(), props, message.Body); + + _logger.LogDebug($"RabbitMQ topic message [{message.GetName()}] has been published."); return Task.FromResult(OperateResult.Success); } @@ -71,6 +68,6 @@ namespace DotNetCore.CAP.RabbitMQ channel.Dispose(); } } - } + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 430ac20..94bf2cd 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -3,11 +3,13 @@ using System; using System.Collections.Generic; -using System.Text; +using System.Linq; using System.Threading; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using RabbitMQ.Client; using RabbitMQ.Client.Events; +using Headers = DotNetCore.CAP.Messages.Headers; namespace DotNetCore.CAP.RabbitMQ { @@ -34,7 +36,7 @@ namespace DotNetCore.CAP.RabbitMQ _exchangeName = connectionChannelPool.Exchange; } - public event EventHandler OnMessageReceived; + public event EventHandler OnMessageReceived; public event EventHandler OnLog; @@ -125,7 +127,7 @@ namespace DotNetCore.CAP.RabbitMQ { _connectionLock.Release(); } - } + } private void OnConsumerConsumerCancelled(object sender, ConsumerEventArgs e) { @@ -160,12 +162,13 @@ namespace DotNetCore.CAP.RabbitMQ private void OnConsumerReceived(object sender, BasicDeliverEventArgs e) { _deliveryTag = e.DeliveryTag; - var message = new MessageContext - { - Group = _queueName, - Name = e.RoutingKey, - Content = Encoding.UTF8.GetString(e.Body) - }; + + var header = e.BasicProperties.Headers + .ToDictionary(x => x.Key, x => x.Value.ToString()); + header.Add(Headers.Group, _queueName); + + var message = new TransportMessage(header, e.Body); + OnMessageReceived?.Invoke(sender, message); } @@ -176,6 +179,7 @@ namespace DotNetCore.CAP.RabbitMQ LogType = MqLogType.ConsumerShutdown, Reason = e.ReplyText }; + OnLog?.Invoke(sender, args); } diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs index 2f466fd..46d1b55 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs @@ -6,7 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Data.SqlClient; using System.Reflection; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.SqlServer.Diagnostics { diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs index 658f088..2e952a2 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.SqlServer.Diagnostics { diff --git a/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs index 7df28cf..59461eb 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs index c321801..006676b 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using DotNetCore.CAP.SqlServer.Diagnostics; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs index d5498f2..a353c51 100644 --- a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs @@ -9,7 +9,7 @@ using Dapper; using DotNetCore.CAP.Dashboard; using DotNetCore.CAP.Dashboard.Monitoring; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.SqlServer diff --git a/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs index 72978a1..3ec78ed 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs @@ -7,7 +7,7 @@ using System.Data.SqlClient; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.SqlServer diff --git a/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs index d4d38f0..33fcce7 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs @@ -6,7 +6,7 @@ using System.Data; using System.Data.SqlClient; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.SqlServer { diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs new file mode 100644 index 0000000..976ea8a --- /dev/null +++ b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs @@ -0,0 +1,117 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Diagnostics; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.Abstractions +{ + public class CapPublisher : ICapPublisher + { + private readonly IDispatcher _dispatcher; + private readonly IDataStorage _storage; + + // ReSharper disable once InconsistentNaming + protected static readonly DiagnosticListener s_diagnosticListener = + new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + + protected CapPublisher(IServiceProvider service) + { + ServiceProvider = service; + _dispatcher = service.GetRequiredService(); + _storage = service.GetRequiredService(); + Transaction = new AsyncLocal(); + } + + public IServiceProvider ServiceProvider { get; } + + public AsyncLocal Transaction { get; } + + public async Task PublishAsync(string name, T value, + IDictionary optionHeaders, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + + if (optionHeaders == null) + { + optionHeaders = new Dictionary(); + } + + var messageId = SnowflakeId.Default().NextId().ToString(); + optionHeaders.Add(Headers.MessageId, messageId); + if (!optionHeaders.ContainsKey(Headers.CorrelationId)) + { + optionHeaders.Add(Headers.CorrelationId, messageId); + optionHeaders.Add(Headers.CorrelationSequence, 0.ToString()); + } + optionHeaders.Add(Headers.MessageName, name); + optionHeaders.Add(Headers.Type, typeof(T).ToString()); + optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); + + var message = new Message(optionHeaders, value); + + var operationId = default(Guid); + try + { + operationId = s_diagnosticListener.WritePublishMessageStoreBefore(message); + + if (Transaction.Value?.DbTransaction == null) + { + var mediumMessage = await _storage.StoreMessageAsync(name, message, cancellationToken: cancellationToken); + + s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); + + _dispatcher.EnqueueToPublish(mediumMessage); + } + else + { + var transaction = (CapTransactionBase)Transaction.Value; + + var mediumMessage = await _storage.StoreMessageAsync(name, message, transaction, cancellationToken); + + s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); + + transaction.AddToSent(mediumMessage); + + if (transaction.AutoCommit) + { + transaction.Commit(); + } + } + } + catch (Exception e) + { + s_diagnosticListener.WritePublishMessageStoreError(operationId, message, e); + throw; + } + } + + public void Publish(string name, T value, string callbackName = null) + { + PublishAsync(name, value, callbackName).GetAwaiter().GetResult(); + } + + public Task PublishAsync(string name, T value, string callbackName = null, + CancellationToken cancellationToken = default) + { + var header = new Dictionary + { + {Headers.CallbackName, callbackName} + }; + + return PublishAsync(name, value, header, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisherBase.cs b/src/DotNetCore.CAP/Abstractions/CapPublisherBase.cs deleted file mode 100644 index 90665fd..0000000 --- a/src/DotNetCore.CAP/Abstractions/CapPublisherBase.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP.Abstractions -{ - public abstract class CapPublisherBase : ICapPublisher - { - private readonly IMessagePacker _msgPacker; - private readonly IContentSerializer _serializer; - private readonly IDispatcher _dispatcher; - - // ReSharper disable once InconsistentNaming - protected static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - - protected CapPublisherBase(IServiceProvider service) - { - ServiceProvider = service; - _dispatcher = service.GetRequiredService(); - _msgPacker = service.GetRequiredService(); - _serializer = service.GetRequiredService(); - Transaction = new AsyncLocal(); - } - - public IServiceProvider ServiceProvider { get; } - - public AsyncLocal Transaction { get; } - - public void Publish(string name, T contentObj, string callbackName = null) - { - var message = new CapPublishedMessage - { - Id = SnowflakeId.Default().NextId(), - Name = name, - Content = Serialize(contentObj, callbackName), - StatusName = StatusName.Scheduled - }; - - PublishAsyncInternal(message).GetAwaiter().GetResult(); - } - - public async Task PublishAsync(string name, T contentObj, string callbackName = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - var message = new CapPublishedMessage - { - Id = SnowflakeId.Default().NextId(), - Name = name, - Content = Serialize(contentObj, callbackName), - StatusName = StatusName.Scheduled - }; - - await PublishAsyncInternal(message); - } - - protected async Task PublishAsyncInternal(CapPublishedMessage message) - { - var operationId = default(Guid); - - try - { - operationId = s_diagnosticListener.WritePublishMessageStoreBefore(message); - - if (Transaction.Value?.DbTransaction == null) - { - await ExecuteAsync(message); - - s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); - - _dispatcher.EnqueueToPublish(message); - } - else - { - var transaction = (CapTransactionBase)Transaction.Value; - - await ExecuteAsync(message, transaction); - - s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); - - transaction.AddToSent(message); - if (transaction.AutoCommit) - { - transaction.Commit(); - } - } - } - catch (Exception e) - { - s_diagnosticListener.WritePublishMessageStoreError(operationId, message, e); - - throw; - } - } - - protected abstract Task ExecuteAsync(CapPublishedMessage message, - ICapTransaction transaction = null, - CancellationToken cancel = default(CancellationToken)); - - protected virtual string Serialize(T obj, string callbackName = null) - { - string content; - if (obj != null) - { - content = Helper.IsComplexType(obj.GetType()) - ? _serializer.Serialize(obj) - : obj.ToString(); - } - else - { - content = string.Empty; - } - var message = new CapMessageDto(content) - { - CallbackName = callbackName - }; - return _msgPacker.Pack(message); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs b/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs index 108f975..d225dd3 100644 --- a/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs +++ b/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Abstractions { diff --git a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs b/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs index 7d15d0b..035d295 100644 --- a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs +++ b/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs @@ -3,8 +3,6 @@ using System; using DotNetCore.CAP; -using DotNetCore.CAP.Dashboard.GatewayProxy; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -20,29 +18,29 @@ namespace Microsoft.AspNetCore.Builder /// /// The instance this method extends. /// The instance this method extends. - public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } + //public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) + //{ + // if (app == null) + // { + // throw new ArgumentNullException(nameof(app)); + // } - CheckRequirement(app); + // CheckRequirement(app); - var provider = app.ApplicationServices; + // var provider = app.ApplicationServices; - if (provider.GetService() != null) - { - if (provider.GetService() != null) - { - app.UseMiddleware(); - } + // if (provider.GetService() != null) + // { + // if (provider.GetService() != null) + // { + // app.UseMiddleware(); + // } - app.UseMiddleware(); - } + // app.UseMiddleware(); + // } - return app; - } + // return app; + //} private static void CheckRequirement(IApplicationBuilder app) { @@ -69,16 +67,16 @@ namespace Microsoft.AspNetCore.Builder } } - sealed class CapStartupFilter : IStartupFilter - { - public Action Configure(Action next) - { - return app => - { - app.UseCapDashboard(); + //sealed class CapStartupFilter : IStartupFilter + //{ + // public Action Configure(Action next) + // { + // return app => + // { + // app.UseCapDashboard(); - next(app); - }; - } - } + // next(app); + // }; + // } + //} } \ No newline at end of file diff --git a/src/DotNetCore.CAP/CAP.Options.cs b/src/DotNetCore.CAP/CAP.Options.cs index 13a3af4..ea178d1 100644 --- a/src/DotNetCore.CAP/CAP.Options.cs +++ b/src/DotNetCore.CAP/CAP.Options.cs @@ -4,7 +4,8 @@ using System; using System.Collections.Generic; using System.Reflection; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; + // ReSharper disable InconsistentNaming namespace DotNetCore.CAP @@ -52,7 +53,7 @@ namespace DotNetCore.CAP /// /// We’ll invoke this call-back with message type,name,content when retry failed (send or executed) messages equals times. /// - public Action FailedThresholdCallback { get; set; } + public Action FailedThresholdCallback { get; set; } /// /// The number of message retries, the retry will stop when the threshold is reached. diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index c28743d..f349455 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -6,7 +6,6 @@ using DotNetCore.CAP; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Processor; -using DotNetCore.CAP.Processor.States; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -44,7 +43,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); + //services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -53,13 +52,13 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); - services.TryAddSingleton(); //Queue's message processor services.TryAddSingleton(); services.TryAddSingleton(); //Sender and Executors + services.AddSingleton(); services.TryAddSingleton(); // Warning: IPublishMessageSender need to inject at extension project. services.TryAddSingleton(); @@ -74,7 +73,7 @@ namespace Microsoft.Extensions.DependencyInjection services.Configure(setupAction); //Startup and Hosted - services.AddTransient(); + //services.AddTransient(); services.AddHostedService(); return new CapBuilder(services); diff --git a/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs b/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs index da0cc0c..0016a4d 100644 --- a/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs +++ b/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs @@ -4,8 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { @@ -18,28 +17,28 @@ namespace DotNetCore.CAP.Diagnostics private const string CapPrefix = "DotNetCore.CAP."; - public const string CapBeforePublishMessageStore = CapPrefix + nameof(WritePublishMessageStoreBefore); - public const string CapAfterPublishMessageStore = CapPrefix + nameof(WritePublishMessageStoreAfter); - public const string CapErrorPublishMessageStore = CapPrefix + nameof(WritePublishMessageStoreError); + public const string CapBeforePublishMessageStore = CapPrefix + "WritePublishMessageStoreBefore"; + public const string CapAfterPublishMessageStore = CapPrefix + "WritePublishMessageStoreAfter"; + public const string CapErrorPublishMessageStore = CapPrefix + "WritePublishMessageStoreError"; - public const string CapBeforePublish = CapPrefix + nameof(WritePublishBefore); - public const string CapAfterPublish = CapPrefix + nameof(WritePublishAfter); - public const string CapErrorPublish = CapPrefix + nameof(WritePublishError); + public const string CapBeforePublish = CapPrefix + "WritePublishBefore"; + public const string CapAfterPublish = CapPrefix + "WritePublishAfter"; + public const string CapErrorPublish = CapPrefix + "WritePublishError"; - public const string CapBeforeConsume = CapPrefix + nameof(WriteConsumeBefore); - public const string CapAfterConsume = CapPrefix + nameof(WriteConsumeAfter); - public const string CapErrorConsume = CapPrefix + nameof(WriteConsumeError); + public const string CapBeforeConsume = CapPrefix + "WriteConsumeBefore"; + public const string CapAfterConsume = CapPrefix + "WriteConsumeAfter"; + public const string CapErrorConsume = CapPrefix + "WriteConsumeError"; - public const string CapBeforeSubscriberInvoke = CapPrefix + nameof(WriteSubscriberInvokeBefore); - public const string CapAfterSubscriberInvoke = CapPrefix + nameof(WriteSubscriberInvokeAfter); - public const string CapErrorSubscriberInvoke = CapPrefix + nameof(WriteSubscriberInvokeError); + public const string CapBeforeSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeBefore"; + public const string CapAfterSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeAfter"; + public const string CapErrorSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeError"; //============================================================================ //==================== Before publish store message ==================== //============================================================================ public static Guid WritePublishMessageStoreBefore(this DiagnosticListener @this, - CapPublishedMessage message, + Message message, [CallerMemberName] string operation = "") { if (@this.IsEnabled(CapBeforePublishMessageStore)) @@ -50,8 +49,7 @@ namespace DotNetCore.CAP.Diagnostics { OperationId = operationId, Operation = operation, - MessageName = message.Name, - MessageContent = message.Content + Message = message }); return operationId; @@ -62,7 +60,7 @@ namespace DotNetCore.CAP.Diagnostics public static void WritePublishMessageStoreAfter(this DiagnosticListener @this, Guid operationId, - CapPublishedMessage message, + Message message, [CallerMemberName] string operation = "") { if (@this.IsEnabled(CapAfterPublishMessageStore)) @@ -71,9 +69,7 @@ namespace DotNetCore.CAP.Diagnostics { OperationId = operationId, Operation = operation, - MessageId = message.Id, - MessageName = message.Name, - MessageContent = message.Content, + Message = message, Timestamp = Stopwatch.GetTimestamp() }); } @@ -81,7 +77,7 @@ namespace DotNetCore.CAP.Diagnostics public static void WritePublishMessageStoreError(this DiagnosticListener @this, Guid operationId, - CapPublishedMessage message, + Message message, Exception ex, [CallerMemberName] string operation = "") { @@ -91,8 +87,7 @@ namespace DotNetCore.CAP.Diagnostics { OperationId = operationId, Operation = operation, - MessageName = message.Name, - MessageContent = message.Content, + Message = message, Exception = ex, Timestamp = Stopwatch.GetTimestamp() }); @@ -100,135 +95,135 @@ namespace DotNetCore.CAP.Diagnostics } - //============================================================================ - //==================== Publish ==================== - //============================================================================ - public static void WritePublishBefore(this DiagnosticListener @this, BrokerPublishEventData eventData) - { - if (@this.IsEnabled(CapBeforePublish)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapBeforePublish, eventData); - } - } - - public static void WritePublishAfter(this DiagnosticListener @this, BrokerPublishEndEventData eventData) - { - if (@this.IsEnabled(CapAfterPublish)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapAfterPublish, eventData); - } - } - - public static void WritePublishError(this DiagnosticListener @this, BrokerPublishErrorEventData eventData) - { - if (@this.IsEnabled(CapErrorPublish)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapErrorPublish, eventData); - } - } + ////============================================================================ + ////==================== Publish ==================== + ////============================================================================ + //public static void WritePublishBefore(this DiagnosticListener @this, BrokerPublishEventData eventData) + //{ + // if (@this.IsEnabled(CapBeforePublish)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapBeforePublish, eventData); + // } + //} + + //public static void WritePublishAfter(this DiagnosticListener @this, BrokerPublishEndEventData eventData) + //{ + // if (@this.IsEnabled(CapAfterPublish)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapAfterPublish, eventData); + // } + //} + + //public static void WritePublishError(this DiagnosticListener @this, BrokerPublishErrorEventData eventData) + //{ + // if (@this.IsEnabled(CapErrorPublish)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapErrorPublish, eventData); + // } + //} //============================================================================ //==================== Consume ==================== //============================================================================ - public static Guid WriteConsumeBefore(this DiagnosticListener @this, BrokerConsumeEventData eventData) - { - if (@this.IsEnabled(CapBeforeConsume)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapBeforeConsume, eventData); - } - - return Guid.Empty; - } - - public static void WriteConsumeAfter(this DiagnosticListener @this, BrokerConsumeEndEventData eventData) - { - if (@this.IsEnabled(CapAfterConsume)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapAfterConsume, eventData); - } - } - - public static void WriteConsumeError(this DiagnosticListener @this, BrokerConsumeErrorEventData eventData) - { - if (@this.IsEnabled(CapErrorConsume)) - { - eventData.Headers = new TracingHeaders(); - @this.Write(CapErrorConsume, eventData); - } - } + //public static Guid WriteConsumeBefore(this DiagnosticListener @this, BrokerConsumeEventData eventData) + //{ + // if (@this.IsEnabled(CapBeforeConsume)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapBeforeConsume, eventData); + // } + + // return Guid.Empty; + //} + + //public static void WriteConsumeAfter(this DiagnosticListener @this, BrokerConsumeEndEventData eventData) + //{ + // if (@this.IsEnabled(CapAfterConsume)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapAfterConsume, eventData); + // } + //} + + //public static void WriteConsumeError(this DiagnosticListener @this, BrokerConsumeErrorEventData eventData) + //{ + // if (@this.IsEnabled(CapErrorConsume)) + // { + // eventData.Headers = new TracingHeaders(); + // @this.Write(CapErrorConsume, eventData); + // } + //} //============================================================================ //==================== SubscriberInvoke ==================== //============================================================================ - public static Guid WriteSubscriberInvokeBefore(this DiagnosticListener @this, - ConsumerContext context, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapBeforeSubscriberInvoke)) - { - var operationId = Guid.NewGuid(); - - var methodName = context.ConsumerDescriptor.MethodInfo.Name; - var subscribeName = context.ConsumerDescriptor.Attribute.Name; - var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - var parameterValues = context.DeliverMessage.Content; - - @this.Write(CapBeforeSubscriberInvoke, new SubscriberInvokeEventData(operationId, operation, methodName, - subscribeName, - subscribeGroup, parameterValues, DateTimeOffset.UtcNow)); - - return operationId; - } - - return Guid.Empty; - } - - public static void WriteSubscriberInvokeAfter(this DiagnosticListener @this, - Guid operationId, - ConsumerContext context, - DateTimeOffset startTime, - TimeSpan duration, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapAfterSubscriberInvoke)) - { - var methodName = context.ConsumerDescriptor.MethodInfo.Name; - var subscribeName = context.ConsumerDescriptor.Attribute.Name; - var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - var parameterValues = context.DeliverMessage.Content; - - @this.Write(CapAfterSubscriberInvoke, new SubscriberInvokeEndEventData(operationId, operation, methodName, - subscribeName, - subscribeGroup, parameterValues, startTime, duration)); - } - } - - public static void WriteSubscriberInvokeError(this DiagnosticListener @this, - Guid operationId, - ConsumerContext context, - Exception ex, - DateTimeOffset startTime, - TimeSpan duration, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapErrorSubscriberInvoke)) - { - var methodName = context.ConsumerDescriptor.MethodInfo.Name; - var subscribeName = context.ConsumerDescriptor.Attribute.Name; - var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - var parameterValues = context.DeliverMessage.Content; - - @this.Write(CapErrorSubscriberInvoke, new SubscriberInvokeErrorEventData(operationId, operation, methodName, - subscribeName, - subscribeGroup, parameterValues, ex, startTime, duration)); - } - } + //public static Guid WriteSubscriberInvokeBefore(this DiagnosticListener @this, + // ConsumerContext context, + // [CallerMemberName] string operation = "") + //{ + // if (@this.IsEnabled(CapBeforeSubscriberInvoke)) + // { + // var operationId = Guid.NewGuid(); + + // var methodName = context.ConsumerDescriptor.MethodInfo.Name; + // var subscribeName = context.ConsumerDescriptor.Attribute.Name; + // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; + // var values = context.DeliverMessage.Value; + + // @this.Write(CapBeforeSubscriberInvoke, new SubscriberInvokeEventData(operationId, operation, methodName, + // subscribeName, + // subscribeGroup, parameterValues, DateTimeOffset.UtcNow)); + + // return operationId; + // } + + // return Guid.Empty; + //} + + //public static void WriteSubscriberInvokeAfter(this DiagnosticListener @this, + // Guid operationId, + // ConsumerContext context, + // DateTimeOffset startTime, + // TimeSpan duration, + // [CallerMemberName] string operation = "") + //{ + // if (@this.IsEnabled(CapAfterSubscriberInvoke)) + // { + // var methodName = context.ConsumerDescriptor.MethodInfo.Name; + // var subscribeName = context.ConsumerDescriptor.Attribute.Name; + // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; + // var values = context.DeliverMessage.Value; + + // @this.Write(CapAfterSubscriberInvoke, new SubscriberInvokeEndEventData(operationId, operation, methodName, + // subscribeName, + // subscribeGroup, parameterValues, startTime, duration)); + // } + //} + + //public static void WriteSubscriberInvokeError(this DiagnosticListener @this, + // Guid operationId, + // ConsumerContext context, + // Exception ex, + // DateTimeOffset startTime, + // TimeSpan duration, + // [CallerMemberName] string operation = "") + //{ + // if (@this.IsEnabled(CapErrorSubscriberInvoke)) + // { + // var methodName = context.ConsumerDescriptor.MethodInfo.Name; + // var subscribeName = context.ConsumerDescriptor.Attribute.Name; + // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; + // var parameterValues = context.DeliverMessage.Content; + + // @this.Write(CapErrorSubscriberInvoke, new SubscriberInvokeErrorEventData(operationId, operation, methodName, + // subscribeName, + // subscribeGroup, parameterValues, ex, startTime, duration)); + // } + //} } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs index b24b01a..177dcf2 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs @@ -2,18 +2,26 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { - public class BrokerConsumeEventData : BrokerEventData + public class BrokerConsumeEventData { - public BrokerConsumeEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, string brokerTopicBody, DateTimeOffset startTime) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody) + public BrokerConsumeEventData(Guid operationId,string brokerAddress, TransportMessage message, DateTimeOffset startTime) { + OperationId = operationId; StartTime = startTime; + BrokerAddress = brokerAddress; + Message = message; } + public Guid OperationId { get; set; } + + public string BrokerAddress { get; set; } + + public TransportMessage Message { get; set; } + public DateTimeOffset StartTime { get; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs index 013eace..135998c 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs @@ -2,15 +2,14 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { public class BrokerConsumeEndEventData : BrokerConsumeEventData { - public BrokerConsumeEndEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, - string brokerTopicBody, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody, startTime) + public BrokerConsumeEndEventData(Guid operationId, string operation, string brokerAddress, TransportMessage message, DateTimeOffset startTime, TimeSpan duration) + : base(operationId, brokerAddress, message, startTime) { Duration = duration; } diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs index 36af350..f6c17b4 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs @@ -2,19 +2,26 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { - public class BrokerConsumeErrorEventData : BrokerConsumeEndEventData, IErrorEventData + public class BrokerConsumeErrorEventData : IErrorEventData { - public BrokerConsumeErrorEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, string brokerTopicBody, Exception exception, DateTimeOffset startTime, - TimeSpan duration) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody, startTime, duration) + public BrokerConsumeErrorEventData(Guid operationId, string brokerAddress, TransportMessage message, Exception exception) { + OperationId = operationId; + BrokerAddress = brokerAddress; + Message = message; Exception = exception; } + public Guid OperationId { get; set; } + + public string BrokerAddress { get; } + + public TransportMessage Message { get; } + public Exception Exception { get; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs index 320f956..56b43e9 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs @@ -2,14 +2,15 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { public class BrokerPublishEventData : BrokerEventData { public BrokerPublishEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, string brokerTopicBody, DateTimeOffset startTime) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody) + Message message , DateTimeOffset startTime) + : base(operationId, operation, brokerAddress, message) { StartTime = startTime; } diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs index bc3d0cb..6286dfc 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs @@ -2,15 +2,15 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { public class BrokerPublishEndEventData : BrokerPublishEventData { public BrokerPublishEndEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, - string brokerTopicBody, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody, startTime) + Message message, DateTimeOffset startTime, TimeSpan duration) + : base(operationId, operation, brokerAddress, message, startTime) { Duration = duration; } diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs index ec44e3b..fbf561a 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs @@ -2,15 +2,15 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { public class BrokerPublishErrorEventData : BrokerPublishEndEventData, IErrorEventData { public BrokerPublishErrorEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, string brokerTopicBody, Exception exception, DateTimeOffset startTime, - TimeSpan duration) - : base(operationId, operation, brokerAddress, brokerTopicName, brokerTopicBody, startTime, duration) + Message message, Exception exception, DateTimeOffset startTime, TimeSpan duration) + : base(operationId, operation, brokerAddress, message, startTime, duration) { Exception = exception; } diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs index 2db1794..77a41b1 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs @@ -2,26 +2,22 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Diagnostics { public class BrokerEventData : EventData { - public BrokerEventData(Guid operationId, string operation, string brokerAddress, - string brokerTopicName, string brokerTopicBody) + public BrokerEventData(Guid operationId, string operation, string brokerAddress, Message message) : base(operationId, operation) { BrokerAddress = brokerAddress; - BrokerTopicName = brokerTopicName; - BrokerTopicBody = brokerTopicBody; - } - public TracingHeaders Headers { get; set; } + Message = message; + } public string BrokerAddress { get; set; } - public string BrokerTopicBody { get; set; } - - public string BrokerTopicName { get; set; } + public Message Message { get; set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs b/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs index 2302eec..f3c5cb0 100644 --- a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs +++ b/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs @@ -12,14 +12,13 @@ namespace DotNetCore.CAP.Diagnostics string methodName, string subscribeName, string subscribeGroup, - string parameterValues, + object values, DateTimeOffset startTime) : base(operationId, operation) { MethodName = methodName; SubscribeName = subscribeName; SubscribeGroup = subscribeGroup; - ParameterValues = parameterValues; StartTime = startTime; } @@ -31,6 +30,6 @@ namespace DotNetCore.CAP.Diagnostics public string SubscribeGroup { get; set; } - public string ParameterValues { get; set; } + public string Values { get; set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index 892d42d..61a59bd 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -9,27 +9,6 @@ 1701;1702;1705;CS1591 - - - - - - - - - - - - - - - - - - - - - @@ -37,88 +16,7 @@ - - - - True - True - Strings.resx - - - _SidebarMenu.cshtml - - - _SidebarMenu.cshtml - - - ReceivedPage.cshtml - - - ReceivedPage.cshtml - - - _BlockMetric.cshtml - - - _BlockMetric.cshtml - - - _Breadcrumbs.cshtml - - - _Breadcrumbs.cshtml - - - _Paginator.cshtml - - - _Paginator.cshtml - - - _PerPageSelector.cshtml - - - _PerPageSelector.cshtml - - - PublishedPage.cshtml - - - PublishedPage.cshtml - - - LayoutPage.cshtml - - - LayoutPage.cshtml - - - _InlineMetric.cshtml - - - _InlineMetric.cshtml - - - _Navigation.cshtml - - - HomePage.cshtml - - - HomePage.cshtml - - - SubscriberPage.cshtml - - - NodePage.cshtml - - - - PublicResXFileCodeGenerator - DotNetCore.CAP.Dashboard.Resources - Strings.Designer.cs - + \ No newline at end of file diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/IBootstrapper.Default.cs index 87a56c0..f580efa 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/IBootstrapper.Default.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -19,7 +20,7 @@ namespace DotNetCore.CAP public DefaultBootstrapper( ILogger logger, - IStorage storage, + IStorageInitializer storage, IEnumerable processors) { _logger = logger; @@ -27,7 +28,7 @@ namespace DotNetCore.CAP Processors = processors; } - private IStorage Storage { get; } + private IStorageInitializer Storage { get; } private IEnumerable Processors { get; } diff --git a/src/DotNetCore.CAP/ICallbackPublisher.cs b/src/DotNetCore.CAP/ICallbackPublisher.cs index e92e6c9..01d8920 100644 --- a/src/DotNetCore.CAP/ICallbackPublisher.cs +++ b/src/DotNetCore.CAP/ICallbackPublisher.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP { diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index dacfb42..e6f5ef2 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -26,7 +27,10 @@ namespace DotNetCore.CAP /// message body content, that will be serialized of json. /// callback subscriber name /// - Task PublishAsync(string name, T contentObj, string callbackName = null, CancellationToken cancellationToken = default(CancellationToken)); + Task PublishAsync(string name, T contentObj, string callbackName = null, CancellationToken cancellationToken = default); + + + Task PublishAsync(string name, T contentObj, IDictionary optionHeaders, CancellationToken cancellationToken = default); /// /// Publish an object message. diff --git a/src/DotNetCore.CAP/ICapTransaction.Base.cs b/src/DotNetCore.CAP/ICapTransaction.Base.cs index 2ad69b0..6f5c623 100644 --- a/src/DotNetCore.CAP/ICapTransaction.Base.cs +++ b/src/DotNetCore.CAP/ICapTransaction.Base.cs @@ -1,5 +1,5 @@ using System.Collections.Concurrent; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP { @@ -7,19 +7,19 @@ namespace DotNetCore.CAP { private readonly IDispatcher _dispatcher; - private readonly ConcurrentQueue _bufferList; + private readonly ConcurrentQueue _bufferList; protected CapTransactionBase(IDispatcher dispatcher) { _dispatcher = dispatcher; - _bufferList = new ConcurrentQueue(); + _bufferList = new ConcurrentQueue(); } public bool AutoCommit { get; set; } public object DbTransaction { get; set; } - protected internal virtual void AddToSent(CapPublishedMessage msg) + protected internal virtual void AddToSent(MediumMessage msg) { _bufferList.Enqueue(msg); } @@ -29,6 +29,7 @@ namespace DotNetCore.CAP while (!_bufferList.IsEmpty) { _bufferList.TryDequeue(out var message); + _dispatcher.EnqueueToPublish(message); } } diff --git a/src/DotNetCore.CAP/IConsumerClient.cs b/src/DotNetCore.CAP/IConsumerClient.cs index 150bc4c..b918fc8 100644 --- a/src/DotNetCore.CAP/IConsumerClient.cs +++ b/src/DotNetCore.CAP/IConsumerClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Threading; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP { @@ -36,7 +37,7 @@ namespace DotNetCore.CAP /// void Reject(); - event EventHandler OnMessageReceived; + event EventHandler OnMessageReceived; event EventHandler OnLog; } diff --git a/src/DotNetCore.CAP/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/IConsumerRegister.Default.cs index 22bf989..5e86511 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/IConsumerRegister.Default.cs @@ -7,9 +7,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -17,9 +18,10 @@ namespace DotNetCore.CAP { internal class ConsumerRegister : IConsumerRegister { - private readonly IStorageConnection _connection; private readonly IConsumerClientFactory _consumerClientFactory; private readonly IDispatcher _dispatcher; + private readonly ISerializer _serializer; + private readonly IDataStorage _storage; private readonly ILogger _logger; private readonly TimeSpan _pollingDelay = TimeSpan.FromSeconds(1); private readonly CapOptions _options; @@ -40,7 +42,8 @@ namespace DotNetCore.CAP IOptions options, IConsumerClientFactory consumerClientFactory, IDispatcher dispatcher, - IStorageConnection connection, + ISerializer serializer, + IDataStorage storage, ILogger logger, MethodMatcherCache selector) { @@ -49,7 +52,8 @@ namespace DotNetCore.CAP _logger = logger; _consumerClientFactory = consumerClientFactory; _dispatcher = dispatcher; - _connection = connection; + _serializer = serializer; + _storage = storage; _cts = new CancellationTokenSource(); } @@ -144,34 +148,28 @@ namespace DotNetCore.CAP private void RegisterMessageProcessor(IConsumerClient client) { - client.OnMessageReceived += (sender, messageContext) => + client.OnMessageReceived += async (sender, messageContext) => { _cts.Token.ThrowIfCancellationRequested(); - - var startTime = DateTimeOffset.UtcNow; - var stopwatch = Stopwatch.StartNew(); - - var tracingResult = TracingBefore(messageContext.Name, messageContext.Content); - var operationId = tracingResult.Item1; - var messageBody = tracingResult.Item2; - - var receivedMessage = new CapReceivedMessage(messageContext) - { - Id = SnowflakeId.Default().NextId(), - StatusName = StatusName.Scheduled, - Content = messageBody - }; - + Guid? operationId = null; try { - StoreMessage(receivedMessage); + operationId = TracingBefore(messageContext); + + var startTime = DateTimeOffset.UtcNow; + var stopwatch = Stopwatch.StartNew(); + + var message = await _serializer.DeserializeAsync(messageContext); + var mediumMessage = await _storage.StoreMessageAsync(message.GetName(), message.GetGroup(), message); client.Commit(); - TracingAfter(operationId, receivedMessage.Name, receivedMessage.Content, startTime, - stopwatch.Elapsed); + if (operationId != null) + { + TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); + } - _dispatcher.EnqueueToExecute(receivedMessage); + _dispatcher.EnqueueToExecute(mediumMessage); } catch (Exception e) { @@ -179,8 +177,10 @@ namespace DotNetCore.CAP client.Reject(); - TracingError(operationId, receivedMessage.Name, receivedMessage.Content, e, startTime, - stopwatch.Elapsed); + if (operationId != null) + { + TracingError(operationId.Value, messageContext, e); + } } }; @@ -217,56 +217,39 @@ namespace DotNetCore.CAP } } - private void StoreMessage(CapReceivedMessage receivedMessage) + private Guid? TracingBefore(TransportMessage message) { - _connection.StoreReceivedMessage(receivedMessage); - } - - private (Guid, string) TracingBefore(string topic, string values) - { - _logger.LogDebug("CAP received topic message:" + topic); + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapBeforeConsume)) + { + var operationId = Guid.NewGuid(); - Guid operationId = Guid.NewGuid(); + var eventData = new BrokerConsumeEventData(operationId, _serverAddress, message, DateTimeOffset.UtcNow); - var eventData = new BrokerConsumeEventData( - operationId, "", - _serverAddress, - topic, - values, - DateTimeOffset.UtcNow); + s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapBeforeConsume, eventData); - s_diagnosticListener.WriteConsumeBefore(eventData); + return operationId; + } - return (operationId, eventData.BrokerTopicBody); + return null; } - private void TracingAfter(Guid operationId, string topic, string values, DateTimeOffset startTime, TimeSpan du) + private void TracingAfter(Guid operationId, Message message, DateTimeOffset startTime, TimeSpan du) { - var eventData = new BrokerConsumeEndEventData( - operationId, - "", - _serverAddress, - topic, - values, - startTime, - du); - - s_diagnosticListener.WriteConsumeAfter(eventData); + //if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterConsume)) + //{ + // var eventData = new BrokerConsumeEndEventData(operationId, "", _serverAddress, message, startTime, du); + + // s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapAfterConsume, eventData); + //} } - private void TracingError(Guid operationId, string topic, string values, Exception ex, DateTimeOffset startTime, TimeSpan du) + private void TracingError(Guid operationId, TransportMessage message, Exception ex) { - var eventData = new BrokerConsumeErrorEventData( - operationId, - "", - _serverAddress, - topic, - values, - ex, - startTime, - du); - - s_diagnosticListener.WriteConsumeError(eventData); + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapErrorConsume)) + { + var eventData = new BrokerConsumeErrorEventData(operationId, _serverAddress, message, ex); + s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapErrorConsume, eventData); + } } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IDispatcher.cs b/src/DotNetCore.CAP/IDispatcher.cs index e8553ea..c56a582 100644 --- a/src/DotNetCore.CAP/IDispatcher.cs +++ b/src/DotNetCore.CAP/IDispatcher.cs @@ -1,14 +1,15 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP { public interface IDispatcher { - void EnqueueToPublish(CapPublishedMessage message); + void EnqueueToPublish(MediumMessage message); - void EnqueueToExecute(CapReceivedMessage message); + void EnqueueToExecute(MediumMessage message); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IPublishExecutor.cs b/src/DotNetCore.CAP/IPublishExecutor.cs deleted file mode 100644 index 3997273..0000000 --- a/src/DotNetCore.CAP/IPublishExecutor.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace DotNetCore.CAP -{ - /// - /// publish message excutor. The excutor sends the message to the message queue - /// - public interface IPublishExecutor - { - /// - /// publish message to message queue. - /// - /// The message topic name. - /// The message content. - /// - Task PublishAsync(string keyName, string content); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IPublishMessageSender.Base.cs b/src/DotNetCore.CAP/IPublishMessageSender.Base.cs deleted file mode 100644 index 873929f..0000000 --- a/src/DotNetCore.CAP/IPublishMessageSender.Base.cs +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; -using DotNetCore.CAP.Processor; -using DotNetCore.CAP.Processor.States; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP -{ - public abstract class BasePublishMessageSender : IPublishMessageSender, IPublishExecutor - { - private readonly IStorageConnection _connection; - private readonly ILogger _logger; - private readonly CapOptions _options; - private readonly IStateChanger _stateChanger; - - protected abstract string ServersAddress { get; } - - // diagnostics listener - // ReSharper disable once InconsistentNaming - protected static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - - protected BasePublishMessageSender( - ILogger logger, - IOptions options, - IStorageConnection connection, - IStateChanger stateChanger) - { - _options = options.Value; - _connection = connection; - _stateChanger = stateChanger; - _logger = logger; - } - - public abstract Task PublishAsync(string keyName, string content); - - public async Task SendAsync(CapPublishedMessage message) - { - bool retry; - OperateResult result; - do - { - var executedResult = await SendWithoutRetryAsync(message); - result = executedResult.Item2; - if (result == OperateResult.Success) - { - return result; - } - retry = executedResult.Item1; - } while (retry); - - return result; - } - - private async Task<(bool, OperateResult)> SendWithoutRetryAsync(CapPublishedMessage message) - { - var startTime = DateTimeOffset.UtcNow; - var stopwatch = Stopwatch.StartNew(); - - var tracingResult = TracingBefore(message.Name, message.Content); - var operationId = tracingResult.Item1; - - var sendValues = tracingResult.Item2 != null - ? Helper.AddTracingHeaderProperty(message.Content, tracingResult.Item2) - : message.Content; - - var result = await PublishAsync(message.Name, sendValues); - - stopwatch.Stop(); - if (result.Succeeded) - { - await SetSuccessfulState(message); - - TracingAfter(operationId, message.Name, sendValues, startTime, stopwatch.Elapsed); - - return (false, OperateResult.Success); - } - else - { - TracingError(operationId, message, result, startTime, stopwatch.Elapsed); - - var needRetry = await SetFailedState(message, result.Exception); - return (needRetry, OperateResult.Failed(result.Exception)); - } - } - - - private Task SetSuccessfulState(CapPublishedMessage message) - { - var succeededState = new SucceededState(_options.SucceedMessageExpiredAfter); - return _stateChanger.ChangeStateAsync(message, succeededState, _connection); - } - - private async Task SetFailedState(CapPublishedMessage message, Exception ex) - { - AddErrorReasonToContent(message, ex); - - var needRetry = UpdateMessageForRetry(message); - - await _stateChanger.ChangeStateAsync(message, new FailedState(), _connection); - - return needRetry; - } - - private static void AddErrorReasonToContent(CapPublishedMessage message, Exception exception) - { - message.Content = Helper.AddExceptionProperty(message.Content, exception); - } - - private bool UpdateMessageForRetry(CapPublishedMessage message) - { - var retryBehavior = RetryBehavior.DefaultRetry; - - var retries = ++message.Retries; - message.ExpiresAt = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); - - var retryCount = Math.Min(_options.FailedRetryCount, retryBehavior.RetryCount); - if (retries >= retryCount) - { - if (retries == _options.FailedRetryCount) - { - try - { - _options.FailedThresholdCallback?.Invoke(MessageType.Subscribe, message.Name, message.Content); - - _logger.SenderAfterThreshold(message.Id, _options.FailedRetryCount); - } - catch (Exception ex) - { - _logger.ExecutedThresholdCallbackFailed(ex); - } - } - return false; - } - - _logger.SenderRetrying(message.Id, retries); - - return true; - } - - private (Guid, TracingHeaders) TracingBefore(string topic, string values) - { - Guid operationId = Guid.NewGuid(); - - var eventData = new BrokerPublishEventData( - operationId, "", - ServersAddress, topic, - values, - DateTimeOffset.UtcNow); - - s_diagnosticListener.WritePublishBefore(eventData); - - return (operationId, eventData.Headers); //if not enabled diagnostics ,the header will be null - } - - private void TracingAfter(Guid operationId, string topic, string values, DateTimeOffset startTime, TimeSpan du) - { - var eventData = new BrokerPublishEndEventData( - operationId, - "", - ServersAddress, - topic, - values, - startTime, - du); - - s_diagnosticListener.WritePublishAfter(eventData); - } - - private void TracingError(Guid operationId, CapPublishedMessage message, OperateResult result, DateTimeOffset startTime, TimeSpan du) - { - var ex = new PublisherSentFailedException(result.ToString(), result.Exception); - - _logger.MessagePublishException(message.Id, result.ToString(), ex); - - var eventData = new BrokerPublishErrorEventData( - operationId, - "", - ServersAddress, - message.Name, - message.Content, - ex, - startTime, - du); - - s_diagnosticListener.WritePublishError(eventData); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IPublishMessageSender.cs b/src/DotNetCore.CAP/IPublishMessageSender.cs deleted file mode 100644 index c99afd8..0000000 --- a/src/DotNetCore.CAP/IPublishMessageSender.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP -{ - public interface IPublishMessageSender - { - Task SendAsync(CapPublishedMessage message); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorage.cs b/src/DotNetCore.CAP/IStorage.cs deleted file mode 100644 index a31b351..0000000 --- a/src/DotNetCore.CAP/IStorage.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Dashboard; - -namespace DotNetCore.CAP -{ - /// - /// Represents a persisted storage. - /// - public interface IStorage - { - /// - /// Initializes the storage. For example, making sure a database is created and migrations are applied. - /// - Task InitializeAsync(CancellationToken cancellationToken); - - /// - /// Provider the dashboard metric api. - /// - IMonitoringApi GetMonitoringApi(); - - /// - /// Storage connection of database operate. - /// - IStorageConnection GetConnection(); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs index ba9b413..5ce8d9e 100644 --- a/src/DotNetCore.CAP/IStorageConnection.cs +++ b/src/DotNetCore.CAP/IStorageConnection.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP { @@ -44,10 +44,6 @@ namespace DotNetCore.CAP /// Task> GetReceivedMessagesOfNeedRetry(); - /// - /// Creates and returns an . - /// - IStorageTransaction CreateTransaction(); /// /// Change specified message's state of published message diff --git a/src/DotNetCore.CAP/IStorageTransaction.cs b/src/DotNetCore.CAP/IStorageTransaction.cs deleted file mode 100644 index 7ee5185..0000000 --- a/src/DotNetCore.CAP/IStorageTransaction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP -{ - /// - /// A transactional database storage operation. - /// Update message state of the message table with transactional. - /// - public interface IStorageTransaction : IDisposable - { - void UpdateMessage(CapPublishedMessage message); - - void UpdateMessage(CapReceivedMessage message); - - Task CommitAsync(); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs index 19ecbc9..2694098 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs @@ -2,15 +2,16 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Processor; -using DotNetCore.CAP.Processor.States; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -18,10 +19,9 @@ namespace DotNetCore.CAP { internal class DefaultSubscriberExecutor : ISubscriberExecutor { - private readonly ICallbackMessageSender _callbackMessageSender; - private readonly IStorageConnection _connection; + private readonly ICapPublisher _sender; + private readonly IDataStorage _dataStorage; private readonly ILogger _logger; - private readonly IStateChanger _stateChanger; private readonly CapOptions _options; private readonly MethodMatcherCache _selector; @@ -34,16 +34,14 @@ namespace DotNetCore.CAP ILogger logger, IOptions options, IConsumerInvokerFactory consumerInvokerFactory, - ICallbackMessageSender callbackMessageSender, - IStateChanger stateChanger, - IStorageConnection connection, + ICapPublisher sender, + IDataStorage dataStorage, MethodMatcherCache selector) { _selector = selector; - _callbackMessageSender = callbackMessageSender; + _sender = sender; _options = options.Value; - _stateChanger = stateChanger; - _connection = connection; + _dataStorage = dataStorage; _logger = logger; Invoker = consumerInvokerFactory.CreateInvoker(); @@ -51,7 +49,7 @@ namespace DotNetCore.CAP private IConsumerInvoker Invoker { get; } - public async Task ExecuteAsync(CapReceivedMessage message, CancellationToken cancellationToken) + public async Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken) { bool retry; OperateResult result; @@ -69,13 +67,7 @@ namespace DotNetCore.CAP return result; } - /// - /// Execute message consumption once. - /// - /// the message received of - /// - /// Item1 is need still retry, Item2 is executed result. - private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(CapReceivedMessage message, CancellationToken cancellationToken) + private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(MediumMessage message, CancellationToken cancellationToken) { if (message == null) { @@ -100,35 +92,36 @@ namespace DotNetCore.CAP } catch (Exception ex) { - _logger.LogError(ex, $"An exception occurred while executing the subscription method. Topic:{message.Name}, Id:{message.Id}"); + _logger.LogError(ex, $"An exception occurred while executing the subscription method. Topic:{message.Origin.GetName()}, Id:{message.DbId}"); return (await SetFailedState(message, ex), OperateResult.Failed(ex)); } } - private Task SetSuccessfulState(CapReceivedMessage message) + private Task SetSuccessfulState(MediumMessage message) { - var succeededState = new SucceededState(_options.SucceedMessageExpiredAfter); - return _stateChanger.ChangeStateAsync(message, succeededState, _connection); + message.ExpiresAt = DateTime.Now.AddSeconds(_options.SucceedMessageExpiredAfter); + return _dataStorage.ChangeReceiveStateAsync(message, StatusName.Succeeded); } - private async Task SetFailedState(CapReceivedMessage message, Exception ex) + private async Task SetFailedState(MediumMessage message, Exception ex) { if (ex is SubscriberNotFoundException) { message.Retries = _options.FailedRetryCount; // not retry if SubscriberNotFoundException } - AddErrorReasonToContent(message, ex); + //TODO: Add exception to content + // AddErrorReasonToContent(message, ex); var needRetry = UpdateMessageForRetry(message); - await _stateChanger.ChangeStateAsync(message, new FailedState(), _connection); + await _dataStorage.ChangeReceiveStateAsync(message, StatusName.Failed); return needRetry; } - private bool UpdateMessageForRetry(CapReceivedMessage message) + private bool UpdateMessageForRetry(MediumMessage message) { var retryBehavior = RetryBehavior.DefaultRetry; @@ -142,9 +135,9 @@ namespace DotNetCore.CAP { try { - _options.FailedThresholdCallback?.Invoke(MessageType.Subscribe, message.Name, message.Content); + _options.FailedThresholdCallback?.Invoke(MessageType.Subscribe, message.Origin); - _logger.ConsumerExecutedAfterThreshold(message.Id, _options.FailedRetryCount); + _logger.ConsumerExecutedAfterThreshold(message.DbId, _options.FailedRetryCount); } catch (Exception ex) { @@ -154,22 +147,24 @@ namespace DotNetCore.CAP return false; } - _logger.ConsumerExecutionRetrying(message.Id, retries); + _logger.ConsumerExecutionRetrying(message.DbId, retries); return true; } - private static void AddErrorReasonToContent(CapReceivedMessage message, Exception exception) - { - message.Content = Helper.AddExceptionProperty(message.Content, exception); - } + //private static void AddErrorReasonToContent(CapReceivedMessage message, Exception exception) + //{ + // message.Content = Helper.AddExceptionProperty(message.Content, exception); + //} - private async Task InvokeConsumerMethodAsync(CapReceivedMessage receivedMessage, CancellationToken cancellationToken) + private async Task InvokeConsumerMethodAsync(MediumMessage message, CancellationToken cancellationToken) { - if (!_selector.TryGetTopicExecutor(receivedMessage.Name, receivedMessage.Group, + if (!_selector.TryGetTopicExecutor( + message.Origin.GetName(), + message.Origin.GetGroup(), out var executor)) { - var error = $"Message can not be found subscriber. {receivedMessage} \r\n see: https://github.com/dotnetcore/CAP/issues/63"; + var error = $"Message can not be found subscriber. {message} \r\n see: https://github.com/dotnetcore/CAP/issues/63"; throw new SubscriberNotFoundException(error); } @@ -177,20 +172,25 @@ namespace DotNetCore.CAP var stopwatch = Stopwatch.StartNew(); var operationId = Guid.Empty; - var consumerContext = new ConsumerContext(executor, receivedMessage.ToMessageContext()); + var consumerContext = new ConsumerContext(executor, message.Origin); try { - operationId = s_diagnosticListener.WriteSubscriberInvokeBefore(consumerContext); + // operationId = s_diagnosticListener.WriteSubscriberInvokeBefore(consumerContext); var ret = await Invoker.InvokeAsync(consumerContext, cancellationToken); - s_diagnosticListener.WriteSubscriberInvokeAfter(operationId, consumerContext, startTime, - stopwatch.Elapsed); + // s_diagnosticListener.WriteSubscriberInvokeAfter(operationId, consumerContext, startTime,stopwatch.Elapsed); if (!string.IsNullOrEmpty(ret.CallbackName)) { - await _callbackMessageSender.SendAsync(ret.MessageId, ret.CallbackName, ret.Result); + var header = new Dictionary() + { + [Headers.CorrelationId] = message.Origin.GetId(), + [Headers.CorrelationSequence] = (message.Origin.GetCorrelationSequence() + 1).ToString() + }; + + await _sender.PublishAsync(ret.CallbackName, ret.Result, header, cancellationToken); } } catch (OperationCanceledException) @@ -199,7 +199,7 @@ namespace DotNetCore.CAP } catch (Exception ex) { - s_diagnosticListener.WriteSubscriberInvokeError(operationId, consumerContext, ex, startTime, stopwatch.Elapsed); + // s_diagnosticListener.WriteSubscriberInvokeError(operationId, consumerContext, ex, startTime, stopwatch.Elapsed); throw new SubscriberExecutionFailedException(ex.Message, ex); } diff --git a/src/DotNetCore.CAP/ISubscriberExecutor.cs b/src/DotNetCore.CAP/ISubscriberExecutor.cs index daeb60f..559bee0 100644 --- a/src/DotNetCore.CAP/ISubscriberExecutor.cs +++ b/src/DotNetCore.CAP/ISubscriberExecutor.cs @@ -3,7 +3,7 @@ using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP { @@ -12,6 +12,6 @@ namespace DotNetCore.CAP /// public interface ISubscriberExecutor { - Task ExecuteAsync(CapReceivedMessage message, CancellationToken cancellationToken = default); + Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/StatusName.cs b/src/DotNetCore.CAP/Infrastructure/StatusName.cs index f8c5142..018e28d 100644 --- a/src/DotNetCore.CAP/Infrastructure/StatusName.cs +++ b/src/DotNetCore.CAP/Infrastructure/StatusName.cs @@ -6,22 +6,10 @@ namespace DotNetCore.CAP.Infrastructure /// /// The message status name. /// - public struct StatusName + public enum StatusName { - public const string Scheduled = nameof(Scheduled); - public const string Succeeded = nameof(Succeeded); - public const string Failed = nameof(Failed); - - public static string Standardized(string input) - { - foreach (var item in typeof(StatusName).GetFields()) - { - if (item.Name.ToLower() == input.ToLower()) - { - return item.Name; - } - } - return string.Empty; - } + Failed = -1, + Scheduled, + Succeeded } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ConsumerContext.cs b/src/DotNetCore.CAP/Internal/ConsumerContext.cs index 49762ed..574c011 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerContext.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerContext.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Internal { @@ -15,7 +16,7 @@ namespace DotNetCore.CAP.Internal /// /// consumer method descriptor. /// received message. - public ConsumerContext(ConsumerExecutorDescriptor descriptor, MessageContext message) + public ConsumerContext(ConsumerExecutorDescriptor descriptor, Message message) { ConsumerDescriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor)); DeliverMessage = message ?? throw new ArgumentNullException(nameof(message)); @@ -29,6 +30,6 @@ namespace DotNetCore.CAP.Internal /// /// consumer received message. /// - public MessageContext DeliverMessage { get; } + public Message DeliverMessage { get; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index 90633dc..1feeb6a 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -10,25 +10,25 @@ namespace DotNetCore.CAP.Internal internal class ConsumerInvokerFactory : IConsumerInvokerFactory { private readonly ILoggerFactory _loggerFactory; - private readonly IMessagePacker _messagePacker; - private readonly IModelBinderFactory _modelBinderFactory; + //private readonly IMessagePacker _messagePacker; + //private readonly IModelBinderFactory _modelBinderFactory; private readonly IServiceProvider _serviceProvider; public ConsumerInvokerFactory( ILoggerFactory loggerFactory, - IMessagePacker messagePacker, - IModelBinderFactory modelBinderFactory, + //IMessagePacker messagePacker, + //IModelBinderFactory modelBinderFactory, IServiceProvider serviceProvider) { _loggerFactory = loggerFactory; - _messagePacker = messagePacker; - _modelBinderFactory = modelBinderFactory; + //_messagePacker = messagePacker; + //_modelBinderFactory = modelBinderFactory; _serviceProvider = serviceProvider; } public IConsumerInvoker CreateInvoker() { - return new DefaultConsumerInvoker(_loggerFactory, _serviceProvider, _messagePacker, _modelBinderFactory); + return new DefaultConsumerInvoker(_loggerFactory, _serviceProvider); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ICallbackMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/ICallbackMessageSender.Default.cs deleted file mode 100644 index 2114eed..0000000 --- a/src/DotNetCore.CAP/Internal/ICallbackMessageSender.Default.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.Internal -{ - internal class CallbackMessageSender : ICallbackMessageSender - { - private readonly IContentSerializer _contentSerializer; - private readonly ILogger _logger; - private readonly IMessagePacker _messagePacker; - private readonly IServiceProvider _serviceProvider; - - public CallbackMessageSender( - ILogger logger, - IServiceProvider serviceProvider, - IContentSerializer contentSerializer, - IMessagePacker messagePacker) - { - _logger = logger; - _serviceProvider = serviceProvider; - _contentSerializer = contentSerializer; - _messagePacker = messagePacker; - } - - public async Task SendAsync(string messageId, string topicName, object bodyObj) - { - string body; - if (bodyObj != null && Helper.IsComplexType(bodyObj.GetType())) - { - body = _contentSerializer.Serialize(bodyObj); - } - else - { - body = bodyObj?.ToString(); - } - - _logger.LogDebug($"Callback message will publishing, name:{topicName},content:{body}"); - - var callbackMessage = new CapMessageDto - { - Id = messageId, - Content = body - }; - - var content = _messagePacker.Pack(callbackMessage); - - var publishedMessage = new CapPublishedMessage - { - Id = SnowflakeId.Default().NextId(), - Name = topicName, - Content = content, - StatusName = StatusName.Scheduled - }; - - using (var scope = _serviceProvider.CreateScope()) - { - var provider = scope.ServiceProvider; - var callbackPublisher = provider.GetService(); - await callbackPublisher.PublishCallbackAsync(publishedMessage); - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs index 4392cd0..62af0a7 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs @@ -5,7 +5,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Internal; using Microsoft.Extensions.Logging; @@ -15,18 +15,19 @@ namespace DotNetCore.CAP.Internal internal class DefaultConsumerInvoker : IConsumerInvoker { private readonly ILogger _logger; - private readonly IMessagePacker _messagePacker; - private readonly IModelBinderFactory _modelBinderFactory; + //private readonly IMessagePacker _messagePacker; + //private readonly IModelBinderFactory _modelBinderFactory; private readonly IServiceProvider _serviceProvider; public DefaultConsumerInvoker(ILoggerFactory loggerFactory, - IServiceProvider serviceProvider, - IMessagePacker messagePacker, - IModelBinderFactory modelBinderFactory) + IServiceProvider serviceProvider + //IMessagePacker messagePacker, + //IModelBinderFactory modelBinderFactory + ) { - _modelBinderFactory = modelBinderFactory; + //_modelBinderFactory = modelBinderFactory; _serviceProvider = serviceProvider; - _messagePacker = messagePacker; + //_messagePacker = messagePacker; _logger = loggerFactory.CreateLogger(); } @@ -58,20 +59,21 @@ namespace DotNetCore.CAP.Internal obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType); } - var jsonContent = context.DeliverMessage.Content; - var message = _messagePacker.UnPack(jsonContent); + //var jsonContent = context.DeliverMessage.Content; + //var message = _messagePacker.UnPack(jsonContent); + var message = context.DeliverMessage; object resultObj; if (executor.MethodParameters.Length > 0) { - resultObj = await ExecuteWithParameterAsync(executor, obj, message.Content); + resultObj = await ExecuteWithParameterAsync(executor, obj, message.Value); } else { resultObj = await ExecuteAsync(executor, obj); } - return new ConsumerExecutedResult(resultObj, message.Id, message.CallbackName); + return new ConsumerExecutedResult(resultObj, message.GetId(), message.GetCallbackName()); } } @@ -85,31 +87,35 @@ namespace DotNetCore.CAP.Internal return executor.Execute(@class); } - private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, - object @class, string parameterString) + private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class, object parameter) { var firstParameter = executor.MethodParameters[0]; try { - var binder = _modelBinderFactory.CreateBinder(firstParameter); - var bindResult = await binder.BindModelAsync(parameterString); - if (bindResult.IsSuccess) + if (executor.IsMethodAsync) { - if (executor.IsMethodAsync) - { - return await executor.ExecuteAsync(@class, bindResult.Model); - } - - return executor.Execute(@class, bindResult.Model); + return await executor.ExecuteAsync(@class, parameter); } - throw new MethodBindException( - $"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameterString} "); + return executor.Execute(@class, parameter); + //var binder = _modelBinderFactory.CreateBinder(firstParameter); + //var bindResult = await binder.BindModelAsync(parameter); + //if (bindResult.IsSuccess) + //{ + // if (executor.IsMethodAsync) + // { + // return await executor.ExecuteAsync(@class, bindResult.Model); + // } + + // return executor.Execute(@class, bindResult.Model); + //} + + //throw new MethodBindException( + // $"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameter} "); } catch (FormatException ex) { - _logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameterString, - ex); + //_logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameter, ex); return null; } } diff --git a/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs b/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs index 6de5ac8..ce06429 100644 --- a/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Internal { diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs new file mode 100644 index 0000000..364b4b5 --- /dev/null +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -0,0 +1,184 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using DotNetCore.CAP.Diagnostics; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Serialization; +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.Internal +{ + internal class MessageSender : IMessageSender + { + private readonly IDataStorage _dataStorage; + private readonly ISerializer _serializer; + private readonly ITransport _transport; + private readonly ILogger _logger; + private readonly IOptions _options; + + // ReSharper disable once InconsistentNaming + protected static readonly DiagnosticListener s_diagnosticListener = + new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + + protected MessageSender( + ILogger logger, + IOptions options, + IDataStorage dataStorage, + ISerializer serializer, + ITransport transport) + { + _options = options; + _dataStorage = dataStorage; + _serializer = serializer; + _transport = transport; + _logger = logger; + } + + public async Task SendAsync(MediumMessage message) + { + bool retry; + OperateResult result; + do + { + var executedResult = await SendWithoutRetryAsync(message); + result = executedResult.Item2; + if (result == OperateResult.Success) + { + return result; + } + retry = executedResult.Item1; + } while (retry); + + return result; + } + + private async Task<(bool, OperateResult)> SendWithoutRetryAsync(MediumMessage message) + { + var startTime = DateTimeOffset.UtcNow; + var stopwatch = Stopwatch.StartNew(); + + var operationId = TracingBefore(message.Origin); + + var transportMsg = await _serializer.SerializeAsync(message.Origin); + var result = await _transport.SendAsync(transportMsg); + + stopwatch.Stop(); + if (result.Succeeded) + { + await SetSuccessfulState(message); + + if (operationId != null) + { + TracingAfter(operationId.Value, message.Origin, startTime, stopwatch.Elapsed); + } + + return (false, OperateResult.Success); + } + else + { + if (operationId != null) + { + TracingError(operationId.Value, message.Origin, result, startTime, stopwatch.Elapsed); + } + + var needRetry = await SetFailedState(message, result.Exception); + + return (needRetry, OperateResult.Failed(result.Exception)); + } + } + + private async Task SetSuccessfulState(MediumMessage message) + { + message.ExpiresAt = DateTime.Now.AddSeconds(_options.Value.SucceedMessageExpiredAfter); + await _dataStorage.ChangePublishStateAsync(message, StatusName.Succeeded); + } + + private async Task SetFailedState(MediumMessage message, Exception ex) + { + //TODO: Add exception to content + + var needRetry = UpdateMessageForRetry(message); + + await _dataStorage.ChangePublishStateAsync(message, StatusName.Failed); + + return needRetry; + } + + private bool UpdateMessageForRetry(MediumMessage message) + { + var retryBehavior = RetryBehavior.DefaultRetry; + + var retries = ++message.Retries; + message.ExpiresAt = message.Added.AddSeconds(retryBehavior.RetryIn(retries)); + + var retryCount = Math.Min(_options.Value.FailedRetryCount, retryBehavior.RetryCount); + if (retries >= retryCount) + { + if (retries == _options.Value.FailedRetryCount) + { + try + { + _options.Value.FailedThresholdCallback?.Invoke(MessageType.Publish, message.Origin); + + _logger.SenderAfterThreshold(message.DbId, _options.Value.FailedRetryCount); + } + catch (Exception ex) + { + _logger.ExecutedThresholdCallbackFailed(ex); + } + } + return false; + } + + _logger.SenderRetrying(message.DbId, retries); + + return true; + } + + private Guid? TracingBefore(Message message) + { + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapBeforePublish)) + { + var operationId = Guid.NewGuid(); + + var eventData = new BrokerPublishEventData(operationId, "",_transport.Address, message,DateTimeOffset.UtcNow); + + s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapBeforePublish, eventData); + + return operationId; + } + + return null; + } + + private void TracingAfter(Guid operationId, Message message, DateTimeOffset startTime, TimeSpan du) + { + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterPublish)) + { + var eventData = new BrokerPublishEndEventData(operationId, "", _transport.Address, message, startTime, du); + + s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapAfterPublish, eventData); + } + } + + private void TracingError(Guid operationId, Message message, OperateResult result, DateTimeOffset startTime, TimeSpan du) + { + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterPublish)) + { + var ex = new PublisherSentFailedException(result.ToString(), result.Exception); + var eventData = new BrokerPublishErrorEventData(operationId, "", _transport.Address, + message, ex, startTime, du); + + s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapErrorPublish, eventData); + } + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ICallbackMessageSender.cs b/src/DotNetCore.CAP/Internal/IMessageSender.cs similarity index 64% rename from src/DotNetCore.CAP/Internal/ICallbackMessageSender.cs rename to src/DotNetCore.CAP/Internal/IMessageSender.cs index b66cf9b..de0143a 100644 --- a/src/DotNetCore.CAP/Internal/ICallbackMessageSender.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.cs @@ -2,11 +2,12 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Threading.Tasks; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP.Internal { - internal interface ICallbackMessageSender + public interface IMessageSender { - Task SendAsync(string messageId, string topicName, object bodyObj); + Task SendAsync(MediumMessage message); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs index 5d7046f..f44cb17 100644 --- a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs @@ -10,12 +10,12 @@ namespace DotNetCore.CAP [SuppressMessage("ReSharper", "InconsistentNaming")] internal static class LoggerExtensions { - public static void ConsumerExecutedAfterThreshold(this ILogger logger, long messageId, int retries) + public static void ConsumerExecutedAfterThreshold(this ILogger logger, string messageId, int retries) { logger.LogWarning($"The Subscriber of the message({messageId}) still fails after {retries}th executions and we will stop retrying."); } - public static void SenderAfterThreshold(this ILogger logger, long messageId, int retries) + public static void SenderAfterThreshold(this ILogger logger, string messageId, int retries) { logger.LogWarning($"The Publisher of the message({messageId}) still fails after {retries}th sends and we will stop retrying."); } @@ -25,12 +25,12 @@ namespace DotNetCore.CAP logger.LogWarning(ex, "FailedThresholdCallback action raised an exception:" + ex.Message); } - public static void ConsumerExecutionRetrying(this ILogger logger, long messageId, int retries) + public static void ConsumerExecutionRetrying(this ILogger logger, string messageId, int retries) { logger.LogWarning($"The {retries}th retrying consume a message failed. message id: {messageId}"); } - public static void SenderRetrying(this ILogger logger, long messageId, int retries) + public static void SenderRetrying(this ILogger logger, string messageId, int retries) { logger.LogWarning($"The {retries}th retrying send a message failed. message id: {messageId} "); } diff --git a/src/DotNetCore.CAP/MessageContext.cs b/src/DotNetCore.CAP/MessageContext.cs deleted file mode 100644 index 17ae8ba..0000000 --- a/src/DotNetCore.CAP/MessageContext.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Collections.Generic; - -namespace DotNetCore.CAP -{ - /// - /// Message context - /// - public class MessageContext - { - /// - /// Gets or sets the message group. - /// - public string Group { get; set; } - - /// - /// Message name. - /// - public string Name { get; set; } - - /// - /// Message content - /// - public string Content { get; set; } - - public override string ToString() - { - return $"Group:{Group}, Name:{Name}, Content:{Content}"; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Models/CapMessageDto.cs b/src/DotNetCore.CAP/Messages/CapMessageDto.cs similarity index 91% rename from src/DotNetCore.CAP/Models/CapMessageDto.cs rename to src/DotNetCore.CAP/Messages/CapMessageDto.cs index c79fb97..8f2fdf2 100644 --- a/src/DotNetCore.CAP/Models/CapMessageDto.cs +++ b/src/DotNetCore.CAP/Messages/CapMessageDto.cs @@ -4,7 +4,7 @@ using System; using DotNetCore.CAP.Infrastructure; -namespace DotNetCore.CAP.Models +namespace DotNetCore.CAP.Messages { public abstract class CapMessage { @@ -36,6 +36,5 @@ namespace DotNetCore.CAP.Models public override string Content { get; set; } - public override string CallbackName { get; set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Messages/Headers.cs b/src/DotNetCore.CAP/Messages/Headers.cs new file mode 100644 index 0000000..8aad623 --- /dev/null +++ b/src/DotNetCore.CAP/Messages/Headers.cs @@ -0,0 +1,30 @@ +namespace DotNetCore.CAP.Messages +{ + public static class Headers + { + /// + /// Id of the message. Either set the ID explicitly when sending a message, or Rebus will assign one to the message. + /// + public const string MessageId = "cap-msg-id"; + + public const string MessageName = "cap-msg-name"; + + public const string CorrelationId = "cap-corr-id"; + + public const string CorrelationSequence = "cap-corr-seq"; + + /// + /// Message value .NET type + /// + public const string Type = "cap-msg-type"; + + public const string CallbackName = "cap-callback-name"; + + public const string Group = "cap-msg-group"; + + public const string SentTime = "cap-senttime"; + + public const string ContentType = "cap-content-type"; + + } +} diff --git a/src/DotNetCore.CAP/Messages/Message.cs b/src/DotNetCore.CAP/Messages/Message.cs new file mode 100644 index 0000000..9fdd778 --- /dev/null +++ b/src/DotNetCore.CAP/Messages/Message.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; + +namespace DotNetCore.CAP.Messages +{ + public class Message + { + public Message(IDictionary headers, object value) + { + Headers = headers ?? throw new ArgumentNullException(nameof(headers)); + Value = value ?? throw new ArgumentNullException(nameof(value)); + } + + public IDictionary Headers { get; } + + public object Value { get; } + } + + public static class MessageExtensions + { + public static string GetId(this Message message) + { + message.Headers.TryGetValue(Headers.MessageId, out var value); + return value; + } + + public static string GetName(this Message message) + { + message.Headers.TryGetValue(Headers.MessageName, out var value); + return value; + } + + public static string GetCallbackName(this Message message) + { + message.Headers.TryGetValue(Headers.CallbackName, out var value); + return value; + } + + public static string GetGroup(this Message message) + { + message.Headers.TryGetValue(Headers.Group, out var value); + return value; + } + + public static int GetCorrelationSequence(this Message message) + { + if (message.Headers.TryGetValue(Headers.CorrelationSequence, out var value)) + { + return int.Parse(value); + } + + return 0; + } + } + +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Models/MessageType.cs b/src/DotNetCore.CAP/Messages/MessageType.cs similarity index 87% rename from src/DotNetCore.CAP/Models/MessageType.cs rename to src/DotNetCore.CAP/Messages/MessageType.cs index 141040e..46ded20 100644 --- a/src/DotNetCore.CAP/Models/MessageType.cs +++ b/src/DotNetCore.CAP/Messages/MessageType.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -namespace DotNetCore.CAP.Models +namespace DotNetCore.CAP.Messages { public enum MessageType { diff --git a/src/DotNetCore.CAP/Messages/TransportMessage.cs b/src/DotNetCore.CAP/Messages/TransportMessage.cs new file mode 100644 index 0000000..b360ea9 --- /dev/null +++ b/src/DotNetCore.CAP/Messages/TransportMessage.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace DotNetCore.CAP.Messages +{ + /// + /// Message content field + /// + public class TransportMessage + { + public TransportMessage(Dictionary headers, byte[] body) + { + Headers = headers ?? throw new ArgumentNullException(nameof(headers)); + Body = body ?? throw new ArgumentNullException(nameof(body)); + } + + /// + /// Gets the headers of this message + /// + public Dictionary Headers { get; } + + /// + /// Gets the body object of this message + /// + public byte[] Body { get; } + + public string GetName() + { + return Headers.TryGetValue(Messages.Headers.MessageName, out var value) ? value : null; + } + } +} diff --git a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs b/src/DotNetCore.CAP/Models/CapReceivedMessage.cs deleted file mode 100644 index 3e2dbf6..0000000 --- a/src/DotNetCore.CAP/Models/CapReceivedMessage.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Models -{ - public class CapReceivedMessage - { - /// - /// Initializes a new instance of . - /// - public CapReceivedMessage() - { - Added = DateTime.Now; - } - - public CapReceivedMessage(MessageContext message) : this() - { - Group = message.Group; - Name = message.Name; - Content = message.Content; - } - - public long Id { get; set; } - - public string Group { get; set; } - - public string Name { get; set; } - - public string Content { get; set; } - - public DateTime Added { get; set; } - - public DateTime? ExpiresAt { get; set; } - - public int Retries { get; set; } - - public string StatusName { get; set; } - - public MessageContext ToMessageContext() - { - return new MessageContext - { - Group = Group, - Name = Name, - Content = Content - }; - } - - public override string ToString() - { - return "name:" + Name + ", group:" + Group + ", content:" + Content; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs b/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs new file mode 100644 index 0000000..8d68ed1 --- /dev/null +++ b/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; + +namespace DotNetCore.CAP.Messages +{ + public class CapPublishedMessage + { + public CapPublishedMessage() + { + Added = DateTime.Now; + } + + public Message Message { get; set; } + + public DateTime Added { get; set; } + + public DateTime? ExpiresAt { get; set; } + + public int Retries { get; set; } + + public string StatusName { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Models/CapPublishedMessage.cs b/src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs similarity index 68% rename from src/DotNetCore.CAP/Models/CapPublishedMessage.cs rename to src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs index 955063d..1e29561 100644 --- a/src/DotNetCore.CAP/Models/CapPublishedMessage.cs +++ b/src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs @@ -3,20 +3,22 @@ using System; -namespace DotNetCore.CAP.Models +namespace DotNetCore.CAP.Messages { - public class CapPublishedMessage + public class CapReceivedMessage { /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - public CapPublishedMessage() + public CapReceivedMessage() { Added = DateTime.Now; } public long Id { get; set; } + public string Group { get; set; } + public string Name { get; set; } public string Content { get; set; } @@ -31,7 +33,7 @@ namespace DotNetCore.CAP.Models public override string ToString() { - return "name:" + Name + ", content:" + Content; + return "name:" + Name + ", group:" + Group + ", content:" + Content; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs b/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs new file mode 100644 index 0000000..384a1f2 --- /dev/null +++ b/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs @@ -0,0 +1,26 @@ +//using System; +//using System.Collections.Generic; +//using DotNetCore.CAP.Dashboard.Monitoring; +//using DotNetCore.CAP.Messages; + +//namespace DotNetCore.CAP.Persistence +//{ +// public interface IDashboardQuerying +// { +// StatisticsDto GetStatistics(); + +// IList Messages(MessageQueryDto queryDto); + +// int PublishedFailedCount(); + +// int PublishedSucceededCount(); + +// int ReceivedFailedCount(); + +// int ReceivedSucceededCount(); + +// IDictionary HourlySucceededJobs(MessageType type); + +// IDictionary HourlyFailedJobs(MessageType type); +// } +//} diff --git a/src/DotNetCore.CAP/Persistence/IDataStorage.cs b/src/DotNetCore.CAP/Persistence/IDataStorage.cs new file mode 100644 index 0000000..ab18dca --- /dev/null +++ b/src/DotNetCore.CAP/Persistence/IDataStorage.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Persistence +{ + public interface IDataStorage + { + Task ChangePublishStateAsync(MediumMessage message, StatusName state); + + Task ChangeReceiveStateAsync(MediumMessage message, StatusName state); + + Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default); + + Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default); + + Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default); + + Task> GetPublishedMessagesOfNeedRetry(); + + Task> GetReceivedMessagesOfNeedRetry(); + + //Task GetPublishedMessageAsync(long id); + //Task GetReceivedMessageAsync(long id); + + //public void UpdateMessage(CapPublishedMessage message) + //{ + // if (message == null) + // { + // throw new ArgumentNullException(nameof(message)); + // } + + // var sql = + // $"UPDATE `{_prefix}.published` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + // _dbConnection.Execute(sql, message); + //} + + //public void UpdateMessage(CapReceivedMessage message) + //{ + // if (message == null) + // { + // throw new ArgumentNullException(nameof(message)); + // } + + // var sql = $"UPDATE `{_prefix}.received` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + // _dbConnection.Execute(sql, message); + //} + } +} diff --git a/src/DotNetCore.CAP/Persistence/IStorageInitializer.cs b/src/DotNetCore.CAP/Persistence/IStorageInitializer.cs new file mode 100644 index 0000000..141652d --- /dev/null +++ b/src/DotNetCore.CAP/Persistence/IStorageInitializer.cs @@ -0,0 +1,14 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace DotNetCore.CAP.Persistence +{ + public interface IStorageInitializer + { + Task InitializeAsync(CancellationToken cancellationToken); + + string GetPublishedTableName(); + + string GetReceivedTableName(); + } +} diff --git a/src/DotNetCore.CAP/Persistence/MediumMessage.cs b/src/DotNetCore.CAP/Persistence/MediumMessage.cs new file mode 100644 index 0000000..638f27d --- /dev/null +++ b/src/DotNetCore.CAP/Persistence/MediumMessage.cs @@ -0,0 +1,18 @@ +using System; +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Persistence +{ + public class MediumMessage + { + public string DbId { get; set; } + + public Message Origin { get; set; } + + public DateTime Added { get; set; } + + public DateTime? ExpiresAt { get; set; } + + public int Retries { get; set; } + } +} diff --git a/src/DotNetCore.CAP/Processor/ICollectProcessor.cs b/src/DotNetCore.CAP/Processor/ICollectProcessor.cs deleted file mode 100644 index 9fd2625..0000000 --- a/src/DotNetCore.CAP/Processor/ICollectProcessor.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.Processor -{ - public interface ICollectProcessor : IProcessor - { - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index b310bc9..60b7f17 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -5,7 +5,8 @@ using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Processor @@ -13,19 +14,18 @@ namespace DotNetCore.CAP.Processor public class Dispatcher : IDispatcher, IDisposable { private readonly CancellationTokenSource _cts = new CancellationTokenSource(); + private readonly IMessageSender _sender; private readonly ISubscriberExecutor _executor; private readonly ILogger _logger; - private readonly BlockingCollection _publishedMessageQueue = - new BlockingCollection(new ConcurrentQueue()); + private readonly BlockingCollection _publishedMessageQueue = + new BlockingCollection(new ConcurrentQueue()); - private readonly BlockingCollection _receivedMessageQueue = - new BlockingCollection(new ConcurrentQueue()); - - private readonly IPublishMessageSender _sender; + private readonly BlockingCollection _receivedMessageQueue = + new BlockingCollection(new ConcurrentQueue()); public Dispatcher(ILogger logger, - IPublishMessageSender sender, + IMessageSender sender, ISubscriberExecutor executor) { _logger = logger; @@ -36,12 +36,12 @@ namespace DotNetCore.CAP.Processor Task.Factory.StartNew(Processing, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } - public void EnqueueToPublish(CapPublishedMessage message) + public void EnqueueToPublish(MediumMessage message) { _publishedMessageQueue.Add(message); } - public void EnqueueToExecute(CapReceivedMessage message) + public void EnqueueToExecute(MediumMessage message) { _receivedMessageQueue.Add(message); } @@ -67,7 +67,7 @@ namespace DotNetCore.CAP.Processor } catch (Exception ex) { - _logger.LogError(ex, $"An exception occurred when sending a message to the MQ. Topic:{message.Name}, Id:{message.Id}"); + _logger.LogError(ex, $"An exception occurred when sending a message to the MQ. Id:{message.DbId}"); } }); } diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index bb29d2b..e00128b 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -95,7 +95,7 @@ namespace DotNetCore.CAP.Processor { _provider.GetRequiredService(), _provider.GetRequiredService(), - _provider.GetRequiredService() + _provider.GetRequiredService() }; return returnedProcessors.ToArray(); diff --git a/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs b/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs new file mode 100644 index 0000000..c055109 --- /dev/null +++ b/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Persistence; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Processor +{ + public class CollectorProcessor : IProcessor + { + private readonly ILogger _logger; + private readonly IStorageInitializer _initializer; + private readonly IDataStorage _storage; + + private const int ItemBatch = 1000; + private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); + private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); + + public CollectorProcessor( + ILogger logger, + IStorageInitializer initializer, + IDataStorage storage) + { + _logger = logger; + _initializer = initializer; + _storage = storage; + } + + public async Task ProcessAsync(ProcessingContext context) + { + var tables = new[] + { + _initializer.GetPublishedTableName(), + _initializer.GetReceivedTableName() + }; + + foreach (var table in tables) + { + _logger.LogDebug($"Collecting expired data from table [{table}]."); + + int deletedCount; + var time = DateTime.Now; + do + { + deletedCount = await _storage.DeleteExpiresAsync(table, time, ItemBatch, context.CancellationToken); + + if (deletedCount != 0) + { + await context.WaitAsync(_delay); + context.ThrowIfStopping(); + } + } while (deletedCount != 0); + } + + await context.WaitAsync(_waitingInterval); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs index a7e92b3..b900e80 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -15,7 +17,7 @@ namespace DotNetCore.CAP.Processor { private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); private readonly ILogger _logger; - private readonly IPublishMessageSender _publishMessageSender; + private readonly IMessageSender _messageSender; private readonly ISubscriberExecutor _subscriberExecutor; private readonly TimeSpan _waitingInterval; @@ -23,11 +25,11 @@ namespace DotNetCore.CAP.Processor IOptions options, ILogger logger, ISubscriberExecutor subscriberExecutor, - IPublishMessageSender publishMessageSender) + IMessageSender messageSender) { _logger = logger; _subscriberExecutor = subscriberExecutor; - _publishMessageSender = publishMessageSender; + _messageSender = messageSender; _waitingInterval = TimeSpan.FromSeconds(options.Value.FailedRetryInterval); } @@ -38,14 +40,14 @@ namespace DotNetCore.CAP.Processor throw new ArgumentNullException(nameof(context)); } - var connection = context.Provider.GetRequiredService(); + var storage = context.Provider.GetRequiredService(); - await Task.WhenAll(ProcessPublishedAsync(connection, context), ProcessReceivedAsync(connection, context)); + await Task.WhenAll(ProcessPublishedAsync(storage, context), ProcessReceivedAsync(storage, context)); await context.WaitAsync(_waitingInterval); } - private async Task ProcessPublishedAsync(IStorageConnection connection, ProcessingContext context) + private async Task ProcessPublishedAsync(IDataStorage connection, ProcessingContext context) { context.ThrowIfStopping(); @@ -53,13 +55,13 @@ namespace DotNetCore.CAP.Processor foreach (var message in messages) { - await _publishMessageSender.SendAsync(message); + await _messageSender.SendAsync(message); await context.WaitAsync(_delay); } } - private async Task ProcessReceivedAsync(IStorageConnection connection, ProcessingContext context) + private async Task ProcessReceivedAsync(IDataStorage connection, ProcessingContext context) { context.ThrowIfStopping(); diff --git a/src/DotNetCore.CAP/Processor/States/IState.Failed.cs b/src/DotNetCore.CAP/Processor/States/IState.Failed.cs deleted file mode 100644 index 4fb34b6..0000000 --- a/src/DotNetCore.CAP/Processor/States/IState.Failed.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public class FailedState : IState - { - public const string StateName = "Failed"; - - public TimeSpan? ExpiresAfter => TimeSpan.FromDays(15); - - public string Name => StateName; - - public void Apply(CapPublishedMessage message, IStorageTransaction transaction) - { - } - - public void Apply(CapReceivedMessage message, IStorageTransaction transaction) - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs b/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs deleted file mode 100644 index b5cd805..0000000 --- a/src/DotNetCore.CAP/Processor/States/IState.Scheduled.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public class ScheduledState : IState - { - public const string StateName = "Scheduled"; - - public TimeSpan? ExpiresAfter => null; - - public string Name => StateName; - - public void Apply(CapPublishedMessage message, IStorageTransaction transaction) - { - } - - public void Apply(CapReceivedMessage message, IStorageTransaction transaction) - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs b/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs deleted file mode 100644 index 3c0d16d..0000000 --- a/src/DotNetCore.CAP/Processor/States/IState.Succeeded.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public class SucceededState : IState - { - public const string StateName = "Succeeded"; - - public SucceededState() - { - ExpiresAfter = TimeSpan.FromHours(1); - } - - public SucceededState(int expireAfterSeconds) - { - ExpiresAfter = TimeSpan.FromSeconds(expireAfterSeconds); - } - - public TimeSpan? ExpiresAfter { get; } - - public string Name => StateName; - - public void Apply(CapPublishedMessage message, IStorageTransaction transaction) - { - } - - public void Apply(CapReceivedMessage message, IStorageTransaction transaction) - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IState.cs b/src/DotNetCore.CAP/Processor/States/IState.cs deleted file mode 100644 index f1b8417..0000000 --- a/src/DotNetCore.CAP/Processor/States/IState.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public interface IState - { - TimeSpan? ExpiresAfter { get; } - - string Name { get; } - - void Apply(CapPublishedMessage message, IStorageTransaction transaction); - - void Apply(CapReceivedMessage message, IStorageTransaction transaction); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs deleted file mode 100644 index 436dcb6..0000000 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.Default.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public class StateChanger : IStateChanger - { - public void ChangeState(CapPublishedMessage message, IState state, IStorageTransaction transaction) - { - var now = DateTime.Now; - if (state.ExpiresAfter != null) - { - message.ExpiresAt = now.Add(state.ExpiresAfter.Value); - } - else - { - message.ExpiresAt = null; - } - - message.StatusName = state.Name; - state.Apply(message, transaction); - transaction.UpdateMessage(message); - } - - public void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction) - { - var now = DateTime.Now; - if (state.ExpiresAfter != null) - { - message.ExpiresAt = now.Add(state.ExpiresAfter.Value); - } - else - { - message.ExpiresAt = null; - } - - message.StatusName = state.Name; - state.Apply(message, transaction); - transaction.UpdateMessage(message); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs deleted file mode 100644 index b0e1e75..0000000 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.Extensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public static class StateChangerExtensions - { - public static async Task ChangeStateAsync( - this IStateChanger @this, CapPublishedMessage message, IState state, IStorageConnection connection) - { - using (var transaction = connection.CreateTransaction()) - { - @this.ChangeState(message, state, transaction); - await transaction.CommitAsync(); - } - } - - public static async Task ChangeStateAsync( - this IStateChanger @this, CapReceivedMessage message, IState state, IStorageConnection connection) - { - using (var transaction = connection.CreateTransaction()) - { - @this.ChangeState(message, state, transaction); - await transaction.CommitAsync(); - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/States/IStateChanger.cs b/src/DotNetCore.CAP/Processor/States/IStateChanger.cs deleted file mode 100644 index c15e23a..0000000 --- a/src/DotNetCore.CAP/Processor/States/IStateChanger.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using DotNetCore.CAP.Models; - -namespace DotNetCore.CAP.Processor.States -{ - public interface IStateChanger - { - void ChangeState(CapPublishedMessage message, IState state, IStorageTransaction transaction); - - void ChangeState(CapReceivedMessage message, IState state, IStorageTransaction transaction); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.cs b/src/DotNetCore.CAP/Serialization/ISerializer.cs new file mode 100644 index 0000000..75d05d5 --- /dev/null +++ b/src/DotNetCore.CAP/Serialization/ISerializer.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Serialization +{ + public interface ISerializer + { + /// + /// Serializes the given into a + /// + Task SerializeAsync(Message message); + + /// + /// Deserializes the given back into a + /// + Task DeserializeAsync(TransportMessage transportMessage); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Serialization/StringSerializer.cs b/src/DotNetCore.CAP/Serialization/StringSerializer.cs new file mode 100644 index 0000000..42ba12a --- /dev/null +++ b/src/DotNetCore.CAP/Serialization/StringSerializer.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using DotNetCore.CAP.Messages; +using Newtonsoft.Json; + +namespace DotNetCore.CAP.Serialization +{ + public class StringSerializer + { + public static string Serialize(Message message) + { + return JsonConvert.SerializeObject(message); + } + + public static Message DeSerialize(string json) + { + try + { + return JsonConvert.DeserializeObject(json); + } + catch (Exception exception) + { + throw new SerializationException($"Could not deserialize JSON text '{json}'", exception); + } + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Transport/ITransport.cs b/src/DotNetCore.CAP/Transport/ITransport.cs new file mode 100644 index 0000000..7c9e2e0 --- /dev/null +++ b/src/DotNetCore.CAP/Transport/ITransport.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Transport +{ + public interface ITransport + { + string Address { get; } + + Task SendAsync(TransportMessage message); + } +} diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs index 57e2fd6..58a6969 100644 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs +++ b/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs @@ -2,7 +2,7 @@ using System; using System.Linq; using DotNetCore.CAP.Dashboard.Monitoring; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using FluentAssertions; using Xunit; diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs index 4034192..37537f9 100644 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs @@ -1,6 +1,6 @@ using System; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; diff --git a/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs b/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs index 042a6d8..82cfdcd 100644 --- a/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using Xunit; diff --git a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs b/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs index a068161..323f16d 100644 --- a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; using Xunit; diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs index 0df9649..b019a18 100644 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Xunit; namespace DotNetCore.CAP.SqlServer.Test diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index 402ef1a..f661ff2 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -1,8 +1,9 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Xunit; @@ -130,6 +131,12 @@ namespace DotNetCore.CAP.Test throw new NotImplementedException(); } + public Task PublishAsync(string name, T contentObj, IDictionary optionHeaders = null, + CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + public void Publish(string name, T contentObj, string callbackName = null) { throw new NotImplementedException(); diff --git a/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs b/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs index 6aa9a44..0509cd3 100644 --- a/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs +++ b/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs index fbee4ed..6da7c41 100644 --- a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs @@ -3,7 +3,7 @@ using System.Reflection; using System.Threading.Tasks; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; diff --git a/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs b/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs index 86bbfc3..fa7541e 100644 --- a/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs +++ b/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs @@ -1,6 +1,6 @@ using System; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using Newtonsoft.Json; using Xunit; diff --git a/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs b/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs index 26cb8ee..b6905e4 100644 --- a/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs +++ b/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs @@ -1,6 +1,6 @@ using System; using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Models; +using DotNetCore.CAP.Messages; using DotNetCore.CAP.Processor.States; using Moq; using Xunit; diff --git a/test/DotNetCore.CAP.Test/Sample.cs b/test/DotNetCore.CAP.Test/Sample.cs index fa4ea26..c4e1623 100644 --- a/test/DotNetCore.CAP.Test/Sample.cs +++ b/test/DotNetCore.CAP.Test/Sample.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using DotNetCore.CAP.Models; using Newtonsoft.Json; using Xunit; From 3845698f2cbc4829b9a9bb84f087db25051e42d4 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 26 Sep 2019 09:48:36 +0800 Subject: [PATCH 02/76] Add new memory serializer --- .../Serialization/ISerializer.Memory.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs b/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs new file mode 100644 index 0000000..4b1e050 --- /dev/null +++ b/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs @@ -0,0 +1,32 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; +using System.Runtime.Serialization.Formatters.Binary; + +namespace DotNetCore.CAP.Serialization +{ + public class MemorySerializer : ISerializer + { + public Task SerializeAsync(Message message) + { + var bf = new BinaryFormatter(); + using (var ms = new MemoryStream()) + { + bf.Serialize(ms, message.Value); + return Task.FromResult(new TransportMessage(message.Headers, ms.ToArray())); + } + } + + public async Task DeserializeAsync(TransportMessage transportMessage) + { + using (var memStream = new MemoryStream()) + { + var binForm = new BinaryFormatter(); + await memStream.WriteAsync(transportMessage.Body, 0, transportMessage.Body.Length); + memStream.Seek(0, SeekOrigin.Begin); + var obj = binForm.Deserialize(memStream); + return new Message(transportMessage.Headers, obj); + } + } + } +} From 556cb5a0a59083f81b3e4d96615176bc4ba8566b Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 26 Sep 2019 09:49:25 +0800 Subject: [PATCH 03/76] code refactor --- CAP.sln | 1 + samples/Sample.RabbitMQ.MySql/AppDbContext.cs | 2 +- samples/Sample.RabbitMQ.MySql/Startup.cs | 7 ++++--- src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs | 3 ++- src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs | 8 +++++--- src/DotNetCore.CAP/Internal/IMessageSender.Default.cs | 2 +- src/DotNetCore.CAP/Messages/TransportMessage.cs | 4 ++-- 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CAP.sln b/CAP.sln index f9bcb17..66c3488 100644 --- a/CAP.sln +++ b/CAP.sln @@ -108,6 +108,7 @@ Global {80A84F62-1558-427B-BA74-B47AA8A665B5}.Release|Any CPU.ActiveCfg = Release|Any CPU {80A84F62-1558-427B-BA74-B47AA8A665B5}.Release|Any CPU.Build.0 = Release|Any CPU {9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Debug|Any CPU.Build.0 = Debug|Any CPU {9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Release|Any CPU.ActiveCfg = Release|Any CPU {9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873}.Release|Any CPU.Build.0 = Release|Any CPU {82C403AB-ED68-4084-9A1D-11334F9F08F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/samples/Sample.RabbitMQ.MySql/AppDbContext.cs b/samples/Sample.RabbitMQ.MySql/AppDbContext.cs index ce3535d..346209e 100644 --- a/samples/Sample.RabbitMQ.MySql/AppDbContext.cs +++ b/samples/Sample.RabbitMQ.MySql/AppDbContext.cs @@ -11,7 +11,7 @@ namespace Sample.RabbitMQ.MySql public class AppDbContext : DbContext { - public const string ConnectionString = "Server=localhost;Database=testcap;UserId=root;Password=123123;"; + public const string ConnectionString = "Server=192.168.2.120;Database=captest;UserId=root;Password=123123;"; public DbSet Persons { get; set; } diff --git a/samples/Sample.RabbitMQ.MySql/Startup.cs b/samples/Sample.RabbitMQ.MySql/Startup.cs index cf6b8f8..f402deb 100644 --- a/samples/Sample.RabbitMQ.MySql/Startup.cs +++ b/samples/Sample.RabbitMQ.MySql/Startup.cs @@ -1,4 +1,5 @@ using System; +using DotNetCore.CAP.Messages; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -16,12 +17,12 @@ namespace Sample.RabbitMQ.MySql { x.UseEntityFramework(); x.UseRabbitMQ("192.168.2.120"); - x.UseDashboard(); + //x.UseDashboard(); x.FailedRetryCount = 5; - x.FailedThresholdCallback = (type, name, content) => + x.FailedThresholdCallback = (type, msg) => { Console.WriteLine( - $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {name}, message body: {content}"); + $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {msg.GetName()}"); }; }); diff --git a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs index 76aa126..7e3a380 100644 --- a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs @@ -3,6 +3,7 @@ using System; using DotNetCore.CAP.MySql; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -21,7 +22,7 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); - //services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); //Add MySqlOptions diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index f349455..43afd25 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -6,8 +6,7 @@ using DotNetCore.CAP; using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Processor; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; +using DotNetCore.CAP.Serialization; using Microsoft.Extensions.DependencyInjection.Extensions; // ReSharper disable once CheckNamespace @@ -58,8 +57,11 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); //Sender and Executors - services.AddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); + + services.TryAddSingleton(); + // Warning: IPublishMessageSender need to inject at extension project. services.TryAddSingleton(); diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs index 364b4b5..33ee272 100644 --- a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -29,7 +29,7 @@ namespace DotNetCore.CAP.Internal new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); protected MessageSender( - ILogger logger, + ILogger logger, IOptions options, IDataStorage dataStorage, ISerializer serializer, diff --git a/src/DotNetCore.CAP/Messages/TransportMessage.cs b/src/DotNetCore.CAP/Messages/TransportMessage.cs index b360ea9..93e32bd 100644 --- a/src/DotNetCore.CAP/Messages/TransportMessage.cs +++ b/src/DotNetCore.CAP/Messages/TransportMessage.cs @@ -8,7 +8,7 @@ namespace DotNetCore.CAP.Messages /// public class TransportMessage { - public TransportMessage(Dictionary headers, byte[] body) + public TransportMessage(IDictionary headers, byte[] body) { Headers = headers ?? throw new ArgumentNullException(nameof(headers)); Body = body ?? throw new ArgumentNullException(nameof(body)); @@ -17,7 +17,7 @@ namespace DotNetCore.CAP.Messages /// /// Gets the headers of this message /// - public Dictionary Headers { get; } + public IDictionary Headers { get; } /// /// Gets the body object of this message From 5b3f5c2c873014f2a95e12b052401bab74d9385e Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 22 Oct 2019 15:30:54 +0800 Subject: [PATCH 04/76] Add service inject --- src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs | 2 ++ src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs index 7e3a380..ffffd0e 100644 --- a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs @@ -22,6 +22,8 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index 4ed02f7..169835f 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -4,6 +4,7 @@ using System; using DotNetCore.CAP.Internal; using DotNetCore.CAP.RabbitMQ; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -23,6 +24,7 @@ namespace DotNetCore.CAP services.AddSingleton(); services.Configure(_configure); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); From aba3ba9e9e63b8e01c30b646ec72e9207fa11946 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 23 Oct 2019 17:38:19 +0800 Subject: [PATCH 05/76] update to publish --- src/DotNetCore.CAP/Abstractions/CapPublisher.cs | 2 +- src/DotNetCore.CAP/Internal/IMessageSender.Default.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs index 976ea8a..1e018f6 100644 --- a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs +++ b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs @@ -23,7 +23,7 @@ namespace DotNetCore.CAP.Abstractions protected static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - protected CapPublisher(IServiceProvider service) + public CapPublisher(IServiceProvider service) { ServiceProvider = service; _dispatcher = service.GetRequiredService(); diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs index 33ee272..b014b89 100644 --- a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -28,7 +28,7 @@ namespace DotNetCore.CAP.Internal protected static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - protected MessageSender( + public MessageSender( ILogger logger, IOptions options, IDataStorage dataStorage, From 71e3e1d4ad44c3f899532beef80ef33d7afc5d30 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 23 Oct 2019 17:38:32 +0800 Subject: [PATCH 06/76] Fix message consumer bugs --- .../Controllers/ValuesController.cs | 2 +- src/DotNetCore.CAP.MySql/MySqlDataStorage.cs | 9 +++++---- .../RabbitMQConsumerClient.cs | 12 +++++++---- .../CAP.ServiceCollectionExtensions.cs | 3 +++ .../IConsumerRegister.Default.cs | 1 + .../ISubscribeExecutor.Default.cs | 20 +++++++++---------- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs index 578e201..4e7bfb3 100644 --- a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs @@ -71,7 +71,7 @@ namespace Sample.RabbitMQ.MySql.Controllers [CapSubscribe("sample.rabbitmq.mysql")] public void Subscriber(DateTime time) { - //Console.WriteLine($@"{DateTime.Now}, Subscriber invoked, Sent time:{time}"); + Console.WriteLine($@"{DateTime.Now}, Subscriber invoked, Sent time:{time}"); } } } diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs index 05f02aa..3b640de 100644 --- a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs +++ b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs @@ -103,7 +103,7 @@ namespace DotNetCore.CAP.MySql return message; } - public async Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default) + public Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default) { var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; @@ -125,14 +125,15 @@ namespace DotNetCore.CAP.MySql Retries = message.Retries, Added = message.Added, ExpiresAt = message.ExpiresAt, - StatusName = StatusName.Scheduled + StatusName = nameof(StatusName.Scheduled) }; using (var connection = new MySqlConnection(_options.Value.ConnectionString)) { - await connection.ExecuteAsync(sql, po); + connection.Execute(sql, po); } - return message; + + return Task.FromResult(message); } public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default) diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index 94bf2cd..db13dac 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading; using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; @@ -163,11 +164,14 @@ namespace DotNetCore.CAP.RabbitMQ { _deliveryTag = e.DeliveryTag; - var header = e.BasicProperties.Headers - .ToDictionary(x => x.Key, x => x.Value.ToString()); - header.Add(Headers.Group, _queueName); + var headers = new Dictionary(); + foreach (var header in e.BasicProperties.Headers) + { + headers.Add(header.Key, header.Value == null ? null : Encoding.UTF8.GetString((byte[])header.Value)); + } + headers.Add(Headers.Group, _queueName); - var message = new TransportMessage(header, e.Body); + var message = new TransportMessage(headers, e.Body); OnMessageReceived?.Invoke(sender, message); } diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 43afd25..29e5e18 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -36,6 +36,8 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); + services.TryAddSingleton(); + //Serializer and model binder services.TryAddSingleton(); services.TryAddSingleton(); @@ -55,6 +57,7 @@ namespace Microsoft.Extensions.DependencyInjection //Queue's message processor services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); //Sender and Executors services.TryAddSingleton(); diff --git a/src/DotNetCore.CAP/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/IConsumerRegister.Default.cs index 5e86511..da3e363 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/IConsumerRegister.Default.cs @@ -160,6 +160,7 @@ namespace DotNetCore.CAP var stopwatch = Stopwatch.StartNew(); var message = await _serializer.DeserializeAsync(messageContext); + var mediumMessage = await _storage.StoreMessageAsync(message.GetName(), message.GetGroup(), message); client.Commit(); diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs index 2694098..4e6c0cc 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs @@ -14,14 +14,15 @@ using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Processor; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP { internal class DefaultSubscriberExecutor : ISubscriberExecutor { - private readonly ICapPublisher _sender; private readonly IDataStorage _dataStorage; private readonly ILogger _logger; + private readonly IServiceProvider _provider; private readonly CapOptions _options; private readonly MethodMatcherCache _selector; @@ -33,18 +34,17 @@ namespace DotNetCore.CAP public DefaultSubscriberExecutor( ILogger logger, IOptions options, - IConsumerInvokerFactory consumerInvokerFactory, - ICapPublisher sender, - IDataStorage dataStorage, + IServiceProvider provider, MethodMatcherCache selector) { _selector = selector; - _sender = sender; - _options = options.Value; - _dataStorage = dataStorage; - _logger = logger; - Invoker = consumerInvokerFactory.CreateInvoker(); + _provider = provider; + _logger = logger; + _options = options.Value; + + _dataStorage = _provider.GetService(); + Invoker = _provider.GetService().CreateInvoker(); } private IConsumerInvoker Invoker { get; } @@ -190,7 +190,7 @@ namespace DotNetCore.CAP [Headers.CorrelationSequence] = (message.Origin.GetCorrelationSequence() + 1).ToString() }; - await _sender.PublishAsync(ret.CallbackName, ret.Result, header, cancellationToken); + await _provider.GetService().PublishAsync(ret.CallbackName, ret.Result, header, cancellationToken); } } catch (OperationCanceledException) From 673bd335d4c22e939a5947bba1e818a8bfcb301f Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 24 Oct 2019 12:03:35 +0800 Subject: [PATCH 07/76] upgrade to netcoreapp3.0 --- samples/Sample.RabbitMQ.MySql/AppDbContext.cs | 15 +++++++++++++++ .../Controllers/ValuesController.cs | 11 ++++++++--- samples/Sample.RabbitMQ.MySql/Program.cs | 17 +++++++++-------- .../Properties/launchSettings.json | 15 ++++++++------- .../Sample.RabbitMQ.MySql.csproj | 7 +++---- samples/Sample.RabbitMQ.MySql/Startup.cs | 12 +++++++----- 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/samples/Sample.RabbitMQ.MySql/AppDbContext.cs b/samples/Sample.RabbitMQ.MySql/AppDbContext.cs index 346209e..e5b22e5 100644 --- a/samples/Sample.RabbitMQ.MySql/AppDbContext.cs +++ b/samples/Sample.RabbitMQ.MySql/AppDbContext.cs @@ -7,8 +7,23 @@ namespace Sample.RabbitMQ.MySql public int Id { get; set; } public string Name { get; set; } + + public override string ToString() + { + return $"Name:{Name}, Id:{Id}"; + } } + public class Person2 + { + public int Id { get; set; } + public string Name { get; set; } + + public override string ToString() + { + return $"Name:{Name}, Id:{Id}"; + } + } public class AppDbContext : DbContext { public const string ConnectionString = "Server=192.168.2.120;Database=captest;UserId=root;Password=123123;"; diff --git a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs index 4e7bfb3..b8c920f 100644 --- a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Data; using System.Threading.Tasks; using Dapper; @@ -21,7 +22,11 @@ namespace Sample.RabbitMQ.MySql.Controllers [Route("~/without/transaction")] public async Task WithoutTransaction() { - await _capBus.PublishAsync("sample.rabbitmq.mysql", DateTime.Now); + await _capBus.PublishAsync("sample.rabbitmq.mysql", new Person() + { + Id = 123, + Name = "Bar" + }); return Ok(); } @@ -69,9 +74,9 @@ namespace Sample.RabbitMQ.MySql.Controllers [NonAction] [CapSubscribe("sample.rabbitmq.mysql")] - public void Subscriber(DateTime time) + public void Subscriber(Person2 p) { - Console.WriteLine($@"{DateTime.Now}, Subscriber invoked, Sent time:{time}"); + Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); } } } diff --git a/samples/Sample.RabbitMQ.MySql/Program.cs b/samples/Sample.RabbitMQ.MySql/Program.cs index 80d0fe6..07a0ced 100644 --- a/samples/Sample.RabbitMQ.MySql/Program.cs +++ b/samples/Sample.RabbitMQ.MySql/Program.cs @@ -1,5 +1,5 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; namespace Sample.RabbitMQ.MySql { @@ -7,13 +7,14 @@ namespace Sample.RabbitMQ.MySql { public static void Main(string[] args) { - BuildWebHost(args).Run(); + CreateHostBuilder(args).Build().Run(); } - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .UseUrls("http://*:15173") - .Build(); + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } diff --git a/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json b/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json index c0a90d4..0898ae3 100644 --- a/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json +++ b/samples/Sample.RabbitMQ.MySql/Properties/launchSettings.json @@ -1,10 +1,11 @@ -{ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:57171/", - "sslPort": 0 + "applicationUrl": "http://localhost:49558", + "sslPort": 44332 } }, "profiles": { @@ -20,10 +21,10 @@ "commandName": "Project", "launchBrowser": true, "launchUrl": "cap", + "applicationUrl": "http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Production" - }, - "applicationUrl": "http://localhost:57173/" + "ASPNETCORE_ENVIRONMENT": "Development" + } } } -} \ No newline at end of file +} diff --git a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj index 5e3b6b5..8756e56 100644 --- a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj +++ b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj @@ -1,13 +1,12 @@  - netcoreapp2.2 + netcoreapp3.0 - - - + + diff --git a/samples/Sample.RabbitMQ.MySql/Startup.cs b/samples/Sample.RabbitMQ.MySql/Startup.cs index f402deb..f29e53f 100644 --- a/samples/Sample.RabbitMQ.MySql/Startup.cs +++ b/samples/Sample.RabbitMQ.MySql/Startup.cs @@ -1,9 +1,7 @@ using System; using DotNetCore.CAP.Messages; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; namespace Sample.RabbitMQ.MySql { @@ -26,12 +24,16 @@ namespace Sample.RabbitMQ.MySql }; }); - services.AddMvc(); + services.AddControllers(); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + public void Configure(IApplicationBuilder app) { - app.UseMvc(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); } } } From 96c646a778c6438d966d52a8b5547a99e8def7bd Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 24 Oct 2019 12:04:04 +0800 Subject: [PATCH 08/76] remove discoverys code --- .../NodeDiscovery/CAP.DiscoveryOptions.cs | 38 ------- .../CAP.DiscoveryOptionsExtensions.cs | 60 ---------- .../IDiscoveryProviderFactory.Default.cs | 28 ----- .../IDiscoveryProviderFactory.cs | 10 -- .../INodeDiscoveryProvider.Consul.cs | 107 ------------------ .../NodeDiscovery/INodeDiscoveryProvider.cs | 15 --- .../NodeDiscovery/IProcessingServer.Consul.cs | 35 ------ src/DotNetCore.CAP/NodeDiscovery/Node.cs | 18 --- 8 files changed, 311 deletions(-) delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptions.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.Default.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.Consul.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/IProcessingServer.Consul.cs delete mode 100644 src/DotNetCore.CAP/NodeDiscovery/Node.cs diff --git a/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptions.cs b/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptions.cs deleted file mode 100644 index fb79054..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptions.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP -{ - public class DiscoveryOptions - { - public const string DefaultDiscoveryServerHost = "localhost"; - public const int DefaultDiscoveryServerPort = 8500; - - public const string DefaultCurrentNodeHostName = "localhost"; - public const int DefaultCurrentNodePort = 5000; - - public const string DefaultMatchPath = "/cap"; - - public DiscoveryOptions() - { - DiscoveryServerHostName = DefaultDiscoveryServerHost; - DiscoveryServerPort = DefaultDiscoveryServerPort; - - CurrentNodeHostName = DefaultCurrentNodeHostName; - CurrentNodePort = DefaultCurrentNodePort; - - MatchPath = DefaultMatchPath; - } - - public string DiscoveryServerHostName { get; set; } - public int DiscoveryServerPort { get; set; } - - public string CurrentNodeHostName { get; set; } - public int CurrentNodePort { get; set; } - - public string NodeId { get; set; } - public string NodeName { get; set; } - - public string MatchPath { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs b/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs deleted file mode 100644 index 8617520..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP; -using DotNetCore.CAP.NodeDiscovery; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP -{ - internal sealed class DiscoveryOptionsExtension : ICapOptionsExtension - { - private readonly Action _options; - - public DiscoveryOptionsExtension(Action option) - { - _options = option; - } - - public void AddServices(IServiceCollection services) - { - var discoveryOptions = new DiscoveryOptions(); - - _options?.Invoke(discoveryOptions); - services.AddSingleton(discoveryOptions); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(x => - { - var configOptions = x.GetService(); - var factory = x.GetService(); - return factory.Create(configOptions); - }); - } - } -} - -namespace Microsoft.Extensions.DependencyInjection -{ - public static class CapDiscoveryOptionsExtensions - { - public static CapOptions UseDiscovery(this CapOptions capOptions) - { - return capOptions.UseDiscovery(opt => { }); - } - - public static CapOptions UseDiscovery(this CapOptions capOptions, Action options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - capOptions.RegisterExtension(new DiscoveryOptionsExtension(options)); - - return capOptions; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.Default.cs b/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.Default.cs deleted file mode 100644 index 5627282..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.Default.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.NodeDiscovery -{ - internal class DiscoveryProviderFactory : IDiscoveryProviderFactory - { - private readonly ILoggerFactory _loggerFactory; - - public DiscoveryProviderFactory(ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } - - public INodeDiscoveryProvider Create(DiscoveryOptions options) - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - - return new ConsulNodeDiscoveryProvider(_loggerFactory, options); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.cs b/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.cs deleted file mode 100644 index 22dcee9..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/IDiscoveryProviderFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.NodeDiscovery -{ - internal interface IDiscoveryProviderFactory - { - INodeDiscoveryProvider Create(DiscoveryOptions options); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.Consul.cs b/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.Consul.cs deleted file mode 100644 index 1e52eb3..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.Consul.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Consul; -using DotNetCore.CAP.Internal; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.NodeDiscovery -{ - public class ConsulNodeDiscoveryProvider : INodeDiscoveryProvider, IDisposable - { - private readonly ILogger _logger; - private readonly DiscoveryOptions _options; - private ConsulClient _consul; - - public ConsulNodeDiscoveryProvider(ILoggerFactory logger, DiscoveryOptions options) - { - _logger = logger.CreateLogger(); - _options = options; - - InitClient(); - } - - public void Dispose() - { - _consul.Dispose(); - } - - public async Task> GetNodes() - { - try - { - var nodes = new List(); - var services = await _consul.Catalog.Services(); - foreach (var service in services.Response) - { - var serviceInfo = await _consul.Catalog.Service(service.Key); - var node = serviceInfo.Response.SkipWhile(x => !x.ServiceTags.Contains("CAP")) - .Select(info => new Node - { - Id = info.ServiceID, - Name = info.ServiceName, - Address = info.ServiceAddress, - Port = info.ServicePort, - Tags = string.Join(", ", info.ServiceTags) - }).ToList(); - - nodes.AddRange(node); - } - - CapCache.Global.AddOrUpdate("cap.nodes.count", nodes.Count, TimeSpan.FromSeconds(60), true); - - return nodes; - } - catch (Exception ex) - { - CapCache.Global.AddOrUpdate("cap.nodes.count", 0, TimeSpan.FromSeconds(20)); - - _logger.LogError( - $"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}"); - return null; - } - } - - public Task RegisterNode() - { - try - { - return _consul.Agent.ServiceRegister(new AgentServiceRegistration - { - ID = _options.NodeId, - Name = _options.NodeName, - Address = _options.CurrentNodeHostName, - Port = _options.CurrentNodePort, - Tags = new[] {"CAP", "Client", "Dashboard"}, - Check = new AgentServiceCheck - { - DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30), - Interval = TimeSpan.FromSeconds(10), - Status = HealthStatus.Passing, - HTTP = - $"http://{_options.CurrentNodeHostName}:{_options.CurrentNodePort}{_options.MatchPath}/health" - } - }); - } - catch (Exception ex) - { - _logger.LogError( - $"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}"); - return null; - } - } - - private void InitClient() - { - _consul = new ConsulClient(config => - { - config.WaitTime = TimeSpan.FromSeconds(5); - config.Address = new Uri($"http://{_options.DiscoveryServerHostName}:{_options.DiscoveryServerPort}"); - }); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.cs b/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.cs deleted file mode 100644 index 960fbc4..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/INodeDiscoveryProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace DotNetCore.CAP.NodeDiscovery -{ - public interface INodeDiscoveryProvider - { - Task> GetNodes(); - - Task RegisterNode(); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/IProcessingServer.Consul.cs b/src/DotNetCore.CAP/NodeDiscovery/IProcessingServer.Consul.cs deleted file mode 100644 index af3b065..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/IProcessingServer.Consul.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.NodeDiscovery -{ - internal class ConsulProcessingNodeServer : IProcessingServer - { - private readonly DiscoveryOptions _dashboardOptions; - private readonly IDiscoveryProviderFactory _discoveryProviderFactory; - - public ConsulProcessingNodeServer( - DiscoveryOptions dashboardOptions, - IDiscoveryProviderFactory discoveryProviderFactory) - { - _dashboardOptions = dashboardOptions; - _discoveryProviderFactory = discoveryProviderFactory; - } - - public void Start() - { - var discoveryProvider = _discoveryProviderFactory.Create(_dashboardOptions); - - discoveryProvider.RegisterNode(); - } - - public void Pulse() - { - //ignore - } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/NodeDiscovery/Node.cs b/src/DotNetCore.CAP/NodeDiscovery/Node.cs deleted file mode 100644 index ea077f7..0000000 --- a/src/DotNetCore.CAP/NodeDiscovery/Node.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.NodeDiscovery -{ - public class Node - { - public string Id { get; set; } - - public string Name { get; set; } - - public string Address { get; set; } - - public int Port { get; set; } - - public string Tags { get; set; } - } -} \ No newline at end of file From 0e70d7dec18f6351601f873ec0c7997502cd1dd6 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 24 Oct 2019 12:04:24 +0800 Subject: [PATCH 09/76] remove unused files --- .../Abstractions/IContentSerializer.cs | 66 ---------- .../CAP.AppBuilderExtensions.cs | 82 ------------ .../Internal/IContentSerializer.Json.cs | 27 ---- .../Internal/IMessagePacker.Default.cs | 28 ---- .../Internal/IModelBinder.ComplexType.cs | 39 ------ .../Internal/IModelBinder.SimpleType.cs | 85 ------------ .../Internal/MethodBindException.cs | 23 ---- .../Internal/ModelBinderFactory.cs | 124 ------------------ src/DotNetCore.CAP/Messages/CapMessageDto.cs | 40 ------ .../Serialization/ISerializer.Memory.cs | 32 ----- 10 files changed, 546 deletions(-) delete mode 100644 src/DotNetCore.CAP/Abstractions/IContentSerializer.cs delete mode 100644 src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs delete mode 100644 src/DotNetCore.CAP/Internal/IContentSerializer.Json.cs delete mode 100644 src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs delete mode 100644 src/DotNetCore.CAP/Internal/IModelBinder.ComplexType.cs delete mode 100644 src/DotNetCore.CAP/Internal/IModelBinder.SimpleType.cs delete mode 100644 src/DotNetCore.CAP/Internal/MethodBindException.cs delete mode 100644 src/DotNetCore.CAP/Internal/ModelBinderFactory.cs delete mode 100644 src/DotNetCore.CAP/Messages/CapMessageDto.cs delete mode 100644 src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs diff --git a/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs b/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs deleted file mode 100644 index d225dd3..0000000 --- a/src/DotNetCore.CAP/Abstractions/IContentSerializer.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Abstractions -{ - /// - /// Message content serializer. - /// - /// By default, CAP will use Json as a serializer, and you can customize this interface to achieve serialization of - /// other methods. - /// - /// - public interface IContentSerializer - { - /// - /// Serializes the specified object to a string. - /// - /// The type of the value being serialized. - /// The object to serialize. - /// A string representation of the object. - string Serialize(T value); - - /// - /// Deserializes the string to the specified .NET type. - /// - /// The type of the object to deserialize to. - /// The content string to deserialize. - /// The deserialized object from the string. - T DeSerialize(string value); - - /// - /// Deserializes the string to the specified .NET type. - /// - /// The string to deserialize. - /// The type of the object to deserialize to. - /// The deserialized object from the string. - object DeSerialize(string value, Type type); - } - - /// - /// CAP message content wapper. - /// You can customize the message body filed name of the wrapper or add fields that you interested. - /// - /// - /// We use the wrapper to provide some additional information for the message content,which is important for CAP。 - /// Typically, we may need to customize the field display name of the message, - /// which includes interacting with other message components, which can be adapted in this manner - /// - public interface IMessagePacker - { - /// - /// Package a message object - /// - /// The obj message to be packed. - string Pack(CapMessage obj); - - /// - /// Unpack a message strings to object. - /// - /// The string of packed message. - CapMessage UnPack(string packingMessage); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs b/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs deleted file mode 100644 index 035d295..0000000 --- a/src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP; -using Microsoft.Extensions.DependencyInjection; - -// ReSharper disable once CheckNamespace -namespace Microsoft.AspNetCore.Builder -{ - /// - /// app extensions for - /// - internal static class AppBuilderExtensions - { - /// - /// Enables cap for the current application - /// - /// The instance this method extends. - /// The instance this method extends. - //public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) - //{ - // if (app == null) - // { - // throw new ArgumentNullException(nameof(app)); - // } - - // CheckRequirement(app); - - // var provider = app.ApplicationServices; - - // if (provider.GetService() != null) - // { - // if (provider.GetService() != null) - // { - // app.UseMiddleware(); - // } - - // app.UseMiddleware(); - // } - - // return app; - //} - - private static void CheckRequirement(IApplicationBuilder app) - { - var marker = app.ApplicationServices.GetService(); - if (marker == null) - { - throw new InvalidOperationException( - "AddCap() must be called on the service collection. eg: services.AddCap(...)"); - } - - var messageQueueMarker = app.ApplicationServices.GetService(); - if (messageQueueMarker == null) - { - throw new InvalidOperationException( - "You must be config used message queue provider at AddCap() options! eg: services.AddCap(options=>{ options.UseKafka(...) })"); - } - - var databaseMarker = app.ApplicationServices.GetService(); - if (databaseMarker == null) - { - throw new InvalidOperationException( - "You must be config used database provider at AddCap() options! eg: services.AddCap(options=>{ options.UseSqlServer(...) })"); - } - } - } - - //sealed class CapStartupFilter : IStartupFilter - //{ - // public Action Configure(Action next) - // { - // return app => - // { - // app.UseCapDashboard(); - - // next(app); - // }; - // } - //} -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IContentSerializer.Json.cs b/src/DotNetCore.CAP/Internal/IContentSerializer.Json.cs deleted file mode 100644 index 408b82c..0000000 --- a/src/DotNetCore.CAP/Internal/IContentSerializer.Json.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Infrastructure; - -namespace DotNetCore.CAP.Internal -{ - internal class JsonContentSerializer : IContentSerializer - { - public T DeSerialize(string messageObjStr) - { - return Helper.FromJson(messageObjStr); - } - - public object DeSerialize(string content, Type type) - { - return Helper.FromJson(content, type); - } - - public string Serialize(T messageObj) - { - return Helper.ToJson(messageObj); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs b/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs deleted file mode 100644 index ce06429..0000000 --- a/src/DotNetCore.CAP/Internal/IMessagePacker.Default.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Internal -{ - internal class DefaultMessagePacker : IMessagePacker - { - private readonly IContentSerializer _serializer; - - public DefaultMessagePacker(IContentSerializer serializer) - { - _serializer = serializer; - } - - public string Pack(CapMessage obj) - { - return _serializer.Serialize(obj); - } - - public CapMessage UnPack(string packingMessage) - { - return _serializer.DeSerialize(packingMessage); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IModelBinder.ComplexType.cs b/src/DotNetCore.CAP/Internal/IModelBinder.ComplexType.cs deleted file mode 100644 index 79cf4c3..0000000 --- a/src/DotNetCore.CAP/Internal/IModelBinder.ComplexType.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Reflection; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Abstractions.ModelBinding; - -namespace DotNetCore.CAP.Internal -{ - internal class ComplexTypeModelBinder : IModelBinder - { - private readonly ParameterInfo _parameterInfo; - private readonly IContentSerializer _serializer; - - public ComplexTypeModelBinder(ParameterInfo parameterInfo, IContentSerializer contentSerializer) - { - _parameterInfo = parameterInfo; - _serializer = contentSerializer; - } - - public Task BindModelAsync(string content) - { - try - { - var type = _parameterInfo.ParameterType; - - var value = _serializer.DeSerialize(content, type); - - return Task.FromResult(ModelBindingResult.Success(value)); - } - catch (Exception) - { - return Task.FromResult(ModelBindingResult.Failed()); - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IModelBinder.SimpleType.cs b/src/DotNetCore.CAP/Internal/IModelBinder.SimpleType.cs deleted file mode 100644 index 3761891..0000000 --- a/src/DotNetCore.CAP/Internal/IModelBinder.SimpleType.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.ComponentModel; -using System.Globalization; -using System.Reflection; -using System.Runtime.ExceptionServices; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions.ModelBinding; - -namespace DotNetCore.CAP.Internal -{ - internal class SimpleTypeModelBinder : IModelBinder - { - private readonly ParameterInfo _parameterInfo; - private readonly TypeConverter _typeConverter; - - public SimpleTypeModelBinder(ParameterInfo parameterInfo) - { - _parameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo)); - _typeConverter = TypeDescriptor.GetConverter(parameterInfo.ParameterType); - } - - public Task BindModelAsync(string content) - { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - var parameterType = _parameterInfo.ParameterType; - - try - { - object model; - if (parameterType == typeof(string)) - { - if (string.IsNullOrWhiteSpace(content)) - { - model = null; - } - else - { - model = content; - } - } - else if (string.IsNullOrWhiteSpace(content)) - { - model = null; - } - else - { - model = _typeConverter.ConvertFrom( - null, - CultureInfo.CurrentCulture, - content); - } - - if (model == null && !IsReferenceOrNullableType(parameterType)) - { - return Task.FromResult(ModelBindingResult.Failed()); - } - - return Task.FromResult(ModelBindingResult.Success(model)); - } - catch (Exception exception) - { - var isFormatException = exception is FormatException; - if (!isFormatException && exception.InnerException != null) - { - exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException; - } - - throw; - } - } - - private bool IsReferenceOrNullableType(Type type) - { - var isNullableValueType = Nullable.GetUnderlyingType(type) != null; - return !type.GetTypeInfo().IsValueType || isNullableValueType; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/MethodBindException.cs b/src/DotNetCore.CAP/Internal/MethodBindException.cs deleted file mode 100644 index 1d6c0bc..0000000 --- a/src/DotNetCore.CAP/Internal/MethodBindException.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Internal -{ - [Serializable] - public class MethodBindException : Exception - { - public MethodBindException() - { - } - - public MethodBindException(string message) : base(message) - { - } - - public MethodBindException(string message, Exception inner) : base(message, inner) - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ModelBinderFactory.cs b/src/DotNetCore.CAP/Internal/ModelBinderFactory.cs deleted file mode 100644 index d8f0291..0000000 --- a/src/DotNetCore.CAP/Internal/ModelBinderFactory.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Concurrent; -using System.Reflection; -using System.Runtime.CompilerServices; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Abstractions.ModelBinding; -using DotNetCore.CAP.Infrastructure; - -namespace DotNetCore.CAP.Internal -{ - /// - /// A factory for instances. - /// - internal class ModelBinderFactory : IModelBinderFactory - { - private readonly ConcurrentDictionary _cache; - private readonly IContentSerializer _serializer; - - public ModelBinderFactory(IContentSerializer contentSerializer) - { - _serializer = contentSerializer; - _cache = new ConcurrentDictionary(); - } - - public IModelBinder CreateBinder(ParameterInfo parameter) - { - if (parameter == null) - { - throw new ArgumentNullException(nameof(parameter)); - } - - object token = parameter; - - var binder = CreateBinderCoreCached(parameter, token); - if (binder == null) - { - throw new InvalidOperationException("Format Could Not Create IModelBinder"); - } - - return binder; - } - - private IModelBinder CreateBinderCoreCached(ParameterInfo parameterInfo, object token) - { - if (TryGetCachedBinder(parameterInfo, token, out var binder)) - { - return binder; - } - - if (!Helper.IsComplexType(parameterInfo.ParameterType)) - { - binder = new SimpleTypeModelBinder(parameterInfo); - } - else - { - binder = new ComplexTypeModelBinder(parameterInfo, _serializer); - } - - AddToCache(parameterInfo, token, binder); - - return binder; - } - - private void AddToCache(ParameterInfo info, object cacheToken, IModelBinder binder) - { - if (cacheToken == null) - { - return; - } - - _cache.TryAdd(new Key(info, cacheToken), binder); - } - - private bool TryGetCachedBinder(ParameterInfo info, object cacheToken, out IModelBinder binder) - { - if (cacheToken == null) - { - binder = null; - return false; - } - - return _cache.TryGetValue(new Key(info, cacheToken), out binder); - } - - private struct Key : IEquatable - { - private readonly ParameterInfo _metadata; - private readonly object _token; - - public Key(ParameterInfo metadata, object token) - { - _metadata = metadata; - _token = token; - } - - public bool Equals(Key other) - { - return _metadata.Equals(other._metadata) && ReferenceEquals(_token, other._token); - } - - public override bool Equals(object obj) - { - var other = obj as Key?; - return other.HasValue && Equals(other.Value); - } - - public override int GetHashCode() - { - var hash = new HashCodeCombiner(); - hash.Add(_metadata); - hash.Add(RuntimeHelpers.GetHashCode(_token)); - return hash; - } - - public override string ToString() - { - return $"{_token} (Property: '{_metadata.Name}' Type: '{_metadata.ParameterType.Name}')"; - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Messages/CapMessageDto.cs b/src/DotNetCore.CAP/Messages/CapMessageDto.cs deleted file mode 100644 index 8f2fdf2..0000000 --- a/src/DotNetCore.CAP/Messages/CapMessageDto.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Infrastructure; - -namespace DotNetCore.CAP.Messages -{ - public abstract class CapMessage - { - public virtual string Id { get; set; } - - public virtual DateTime Timestamp { get; set; } - - public virtual string Content { get; set; } - - public virtual string CallbackName { get; set; } - } - - public sealed class CapMessageDto : CapMessage - { - public CapMessageDto() - { - Id = ObjectId.GenerateNewStringId(); - Timestamp = DateTime.Now; - } - - public CapMessageDto(string content) : this() - { - Content = content; - } - - public override string Id { get; set; } - - public override DateTime Timestamp { get; set; } - - public override string Content { get; set; } - - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs b/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs deleted file mode 100644 index 4b1e050..0000000 --- a/src/DotNetCore.CAP/Serialization/ISerializer.Memory.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.IO; -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; -using System.Runtime.Serialization.Formatters.Binary; - -namespace DotNetCore.CAP.Serialization -{ - public class MemorySerializer : ISerializer - { - public Task SerializeAsync(Message message) - { - var bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, message.Value); - return Task.FromResult(new TransportMessage(message.Headers, ms.ToArray())); - } - } - - public async Task DeserializeAsync(TransportMessage transportMessage) - { - using (var memStream = new MemoryStream()) - { - var binForm = new BinaryFormatter(); - await memStream.WriteAsync(transportMessage.Body, 0, transportMessage.Body.Length); - memStream.Seek(0, SeekOrigin.Begin); - var obj = binForm.Deserialize(memStream); - return new Message(transportMessage.Headers, obj); - } - } - } -} From b1bd53bf1c925fa1306d5408fef325ed19f99d8d Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 24 Oct 2019 18:29:07 +0800 Subject: [PATCH 10/76] Code refactor --- .../Abstractions/CapPublisher.cs | 2 +- src/DotNetCore.CAP/CAP.Builder.cs | 20 --- .../CAP.ServiceCollectionExtensions.cs | 13 +- src/DotNetCore.CAP/CAP.SubscribeAttribute.cs | 7 + src/DotNetCore.CAP/Cap.Header.cs | 13 ++ .../ConsumerExecutorDescriptor.cs | 13 ++ src/DotNetCore.CAP/DotNetCore.CAP.csproj | 14 +- .../IConsumerRegister.Default.cs | 25 +++- .../IConsumerServiceSelector.Default.cs | 16 ++- src/DotNetCore.CAP/IDispatcher.cs | 3 +- .../ISubscribeExecutor.Default.cs | 44 ++++--- src/DotNetCore.CAP/ISubscriberExecutor.cs | 2 + src/DotNetCore.CAP/Infrastructure/Helper.cs | 121 ------------------ .../Internal/ConsumerInvokerFactory.cs | 1 + .../Internal/IConsumerInvoker.Default.cs | 61 +++------ src/DotNetCore.CAP/Messages/Headers.cs | 3 - .../Messages/TransportMessage.cs | 5 + .../Processor/IDispatcher.Default.cs | 10 +- .../Serialization/ISerializer.JsonUtf8.cs | 25 ++++ .../Serialization/ISerializer.cs | 6 +- .../Serialization/StringSerializer.cs | 17 +-- .../SubscriberNotFoundException.cs | 9 -- 22 files changed, 159 insertions(+), 271 deletions(-) create mode 100644 src/DotNetCore.CAP/Cap.Header.cs create mode 100644 src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs index 1e018f6..25c9927 100644 --- a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs +++ b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs @@ -57,7 +57,7 @@ namespace DotNetCore.CAP.Abstractions optionHeaders.Add(Headers.CorrelationSequence, 0.ToString()); } optionHeaders.Add(Headers.MessageName, name); - optionHeaders.Add(Headers.Type, typeof(T).ToString()); + optionHeaders.Add(Headers.Type, typeof(T).AssemblyQualifiedName); optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); var message = new Message(optionHeaders, value); diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index 8b9889f..c737b8a 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -53,26 +53,6 @@ namespace DotNetCore.CAP return AddScoped(typeof(ICapPublisher), typeof(T)); } - /// - /// Add a custom content serializer - /// - /// The type of the service. - public CapBuilder AddContentSerializer() - where T : class, IContentSerializer - { - return AddSingleton(typeof(IContentSerializer), typeof(T)); - } - - /// - /// Add a custom message wapper - /// - /// The type of the service. - public CapBuilder AddMessagePacker() - where T : class, IMessagePacker - { - return AddSingleton(typeof(IMessagePacker), typeof(T)); - } - /// /// Adds a scoped service of the type specified in serviceType with an implementation /// diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 29e5e18..2275439 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -38,19 +38,13 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); - //Serializer and model binder - services.TryAddSingleton(); - services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); - - //services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); - //Processors services.TryAddSingleton(); + //Processors services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -63,7 +57,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); // Warning: IPublishMessageSender need to inject at extension project. services.TryAddSingleton(); @@ -77,8 +71,7 @@ namespace Microsoft.Extensions.DependencyInjection } services.Configure(setupAction); - //Startup and Hosted - //services.AddTransient(); + //Startup and Hosted services.AddHostedService(); return new CapBuilder(services); diff --git a/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs b/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs index bd3e1e5..fda43e2 100644 --- a/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs +++ b/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using DotNetCore.CAP.Abstractions; // ReSharper disable once CheckNamespace @@ -22,4 +23,10 @@ namespace DotNetCore.CAP return Name; } } + + [AttributeUsage(AttributeTargets.Parameter)] + public class FromCapAttribute : Attribute + { + + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Cap.Header.cs b/src/DotNetCore.CAP/Cap.Header.cs new file mode 100644 index 0000000..657f5cc --- /dev/null +++ b/src/DotNetCore.CAP/Cap.Header.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace DotNetCore.CAP +{ + public class CapHeader : ReadOnlyDictionary + { + public CapHeader(IDictionary dictionary) : base(dictionary) + { + + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs b/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs index 8b33a55..6a7795a 100644 --- a/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs +++ b/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; +using System.Collections.Generic; using System.Reflection; using DotNetCore.CAP.Abstractions; @@ -18,5 +20,16 @@ namespace DotNetCore.CAP public TypeInfo ImplTypeInfo { get; set; } public TopicAttribute Attribute { get; set; } + + public IList Parameters { get; set; } + } + + public class ParameterDescriptor + { + public string Name { get; set; } + + public Type ParameterType { get; set; } + + public bool IsFromCap { get; set; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index 61a59bd..b3667f3 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -10,13 +10,11 @@ - - - - - - - - + + + + + + \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/IConsumerRegister.Default.cs index da3e363..ecfb31c 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/IConsumerRegister.Default.cs @@ -148,20 +148,31 @@ namespace DotNetCore.CAP private void RegisterMessageProcessor(IConsumerClient client) { - client.OnMessageReceived += async (sender, messageContext) => + client.OnMessageReceived += async (sender, transportMessage) => { _cts.Token.ThrowIfCancellationRequested(); Guid? operationId = null; try { - operationId = TracingBefore(messageContext); + operationId = TracingBefore(transportMessage); var startTime = DateTimeOffset.UtcNow; var stopwatch = Stopwatch.StartNew(); - var message = await _serializer.DeserializeAsync(messageContext); + var name = transportMessage.GetName(); + var group = transportMessage.GetGroup(); - var mediumMessage = await _storage.StoreMessageAsync(message.GetName(), message.GetGroup(), message); + if (!_selector.TryGetTopicExecutor(name, group, out var executor)) + { + var error = $"Message can not be found subscriber. Name:{name}, Group:{group}. {Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; + throw new SubscriberNotFoundException(error); + } + + var type = executor.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType; + + var message = await _serializer.DeserializeAsync(transportMessage, type); + + var mediumMessage = await _storage.StoreMessageAsync(name, group, message); client.Commit(); @@ -170,17 +181,17 @@ namespace DotNetCore.CAP TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); } - _dispatcher.EnqueueToExecute(mediumMessage); + _dispatcher.EnqueueToExecute(mediumMessage, executor); } catch (Exception e) { - _logger.LogError(e, "An exception occurred when store received message. Message:'{0}'.", messageContext); + _logger.LogError(e, "An exception occurred when store received message. Message:'{0}'.", transportMessage); client.Reject(); if (operationId != null) { - TracingError(operationId.Value, messageContext, e); + TracingError(operationId.Value, transportMessage, e); } } }; diff --git a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs index f9a030d..4039bf6 100644 --- a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs @@ -134,7 +134,15 @@ namespace DotNetCore.CAP attr.Group = attr.Group + "." + _capOptions.Version; } - yield return InitDescriptor(attr, method, typeInfo, serviceTypeInfo); + var parameters = method.GetParameters() + .Select(parameter => new ParameterDescriptor + { + Name = parameter.Name, + ParameterType = parameter.ParameterType, + IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any() + }).ToList(); + + yield return InitDescriptor(attr, method, typeInfo, serviceTypeInfo, parameters); } } } @@ -143,14 +151,16 @@ namespace DotNetCore.CAP TopicAttribute attr, MethodInfo methodInfo, TypeInfo implType, - TypeInfo serviceTypeInfo) + TypeInfo serviceTypeInfo, + IList parameters) { var descriptor = new ConsumerExecutorDescriptor { Attribute = attr, MethodInfo = methodInfo, ImplTypeInfo = implType, - ServiceTypeInfo = serviceTypeInfo + ServiceTypeInfo = serviceTypeInfo, + Parameters = parameters }; return descriptor; diff --git a/src/DotNetCore.CAP/IDispatcher.cs b/src/DotNetCore.CAP/IDispatcher.cs index c56a582..bc47c02 100644 --- a/src/DotNetCore.CAP/IDispatcher.cs +++ b/src/DotNetCore.CAP/IDispatcher.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP @@ -10,6 +9,6 @@ namespace DotNetCore.CAP { void EnqueueToPublish(MediumMessage message); - void EnqueueToExecute(MediumMessage message); + void EnqueueToExecute(MediumMessage message, ConsumerExecutorDescriptor descriptor); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs index 4e6c0cc..8b2625e 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs @@ -24,7 +24,6 @@ namespace DotNetCore.CAP private readonly ILogger _logger; private readonly IServiceProvider _provider; private readonly CapOptions _options; - private readonly MethodMatcherCache _selector; // diagnostics listener // ReSharper disable once InconsistentNaming @@ -34,28 +33,40 @@ namespace DotNetCore.CAP public DefaultSubscriberExecutor( ILogger logger, IOptions options, - IServiceProvider provider, - MethodMatcherCache selector) + IServiceProvider provider) { - _selector = selector; - _provider = provider; _logger = logger; _options = options.Value; - + _dataStorage = _provider.GetService(); Invoker = _provider.GetService().CreateInvoker(); } private IConsumerInvoker Invoker { get; } - public async Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken) + public Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken) + { + var selector = _provider.GetService(); + if (!selector.TryGetTopicExecutor(message.Origin.GetName(), message.Origin.GetGroup(), out var executor)) + { + var error = $"Message (Name:{message.Origin.GetName()},Group:{message.Origin.GetGroup()}) can not be found subscriber." + + $"{Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; + _logger.LogError(error); + + return Task.FromResult(OperateResult.Failed(new SubscriberNotFoundException(error))); + } + + return ExecuteAsync(message, executor, cancellationToken); + } + + public async Task ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) { bool retry; OperateResult result; do { - var executedResult = await ExecuteWithoutRetryAsync(message, cancellationToken); + var executedResult = await ExecuteWithoutRetryAsync(message, descriptor, cancellationToken); result = executedResult.Item2; if (result == OperateResult.Success) { @@ -67,7 +78,7 @@ namespace DotNetCore.CAP return result; } - private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(MediumMessage message, CancellationToken cancellationToken) + private async Task<(bool, OperateResult)> ExecuteWithoutRetryAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) { if (message == null) { @@ -80,7 +91,7 @@ namespace DotNetCore.CAP { var sp = Stopwatch.StartNew(); - await InvokeConsumerMethodAsync(message, cancellationToken); + await InvokeConsumerMethodAsync(message, descriptor, cancellationToken); sp.Stop(); @@ -157,22 +168,13 @@ namespace DotNetCore.CAP // message.Content = Helper.AddExceptionProperty(message.Content, exception); //} - private async Task InvokeConsumerMethodAsync(MediumMessage message, CancellationToken cancellationToken) + private async Task InvokeConsumerMethodAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) { - if (!_selector.TryGetTopicExecutor( - message.Origin.GetName(), - message.Origin.GetGroup(), - out var executor)) - { - var error = $"Message can not be found subscriber. {message} \r\n see: https://github.com/dotnetcore/CAP/issues/63"; - throw new SubscriberNotFoundException(error); - } - var startTime = DateTimeOffset.UtcNow; var stopwatch = Stopwatch.StartNew(); var operationId = Guid.Empty; - var consumerContext = new ConsumerContext(executor, message.Origin); + var consumerContext = new ConsumerContext(descriptor, message.Origin); try { diff --git a/src/DotNetCore.CAP/ISubscriberExecutor.cs b/src/DotNetCore.CAP/ISubscriberExecutor.cs index 559bee0..b60d5f0 100644 --- a/src/DotNetCore.CAP/ISubscriberExecutor.cs +++ b/src/DotNetCore.CAP/ISubscriberExecutor.cs @@ -13,5 +13,7 @@ namespace DotNetCore.CAP public interface ISubscriberExecutor { Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken = default); + + Task ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Infrastructure/Helper.cs b/src/DotNetCore.CAP/Infrastructure/Helper.cs index 1fe4e39..4acc33f 100644 --- a/src/DotNetCore.CAP/Infrastructure/Helper.cs +++ b/src/DotNetCore.CAP/Infrastructure/Helper.cs @@ -2,63 +2,13 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.ComponentModel; using System.Reflection; -using DotNetCore.CAP.Diagnostics; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace DotNetCore.CAP.Infrastructure { public static class Helper { - private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); - private static JsonSerializerSettings _serializerSettings; - - public static void SetSerializerSettings(JsonSerializerSettings setting) - { - _serializerSettings = setting; - } - - public static string ToJson(object value) - { - return value != null - ? JsonConvert.SerializeObject(value, _serializerSettings) - : null; - } - - public static T FromJson(string value) - { - return value != null - ? JsonConvert.DeserializeObject(value, _serializerSettings) - : default(T); - } - - public static object FromJson(string value, Type type) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return value != null - ? JsonConvert.DeserializeObject(value, type, _serializerSettings) - : null; - } - - public static long ToTimestamp(DateTime value) - { - var elapsedTime = value - Epoch; - return (long)elapsedTime.TotalSeconds; - } - - - public static DateTime FromTimestamp(long value) - { - return Epoch.AddSeconds(value); - } - public static bool IsController(TypeInfo typeInfo) { if (!typeInfo.IsClass) @@ -85,40 +35,6 @@ namespace DotNetCore.CAP.Infrastructure return !CanConvertFromString(type); } - public static string AddExceptionProperty(string json, Exception exception) - { - var jObject = ToJObject(exception); - return AddJsonProperty(json, "ExceptionMessage", jObject); - } - - public static string AddTracingHeaderProperty(string json, TracingHeaders headers) - { - var jObject = ToJObject(headers); - return AddJsonProperty(json, nameof(TracingHeaders), jObject); - } - - public static bool TryExtractTracingHeaders(string json, out TracingHeaders headers, out string removedHeadersJson) - { - var jObj = JObject.Parse(json); - var jToken = jObj[nameof(TracingHeaders)]; - if (jToken != null) - { - headers = new TracingHeaders(); - foreach (var item in jToken.ToObject>()) - { - headers.Add(item.Key, item.Value); - } - - jObj.Remove(nameof(TracingHeaders)); - removedHeadersJson = jObj.ToString(); - return true; - } - - headers = null; - removedHeadersJson = null; - return false; - } - public static bool IsInnerIP(string ipAddress) { bool isInnerIp; @@ -138,7 +54,6 @@ namespace DotNetCore.CAP.Infrastructure isInnerIp = IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd); return isInnerIp; } - private static long GetIpNum(string ipAddress) { var ip = ipAddress.Split('.'); @@ -174,41 +89,5 @@ namespace DotNetCore.CAP.Infrastructure type == typeof(TimeSpan) || type == typeof(Uri); } - - private static JObject ToJObject(Exception exception) - { - return JObject.FromObject(new - { - exception.Source, - exception.Message, - InnerMessage = exception.InnerException?.Message - }); - } - - private static JObject ToJObject(TracingHeaders headers) - { - var jobj = new JObject(); - foreach (var keyValuePair in headers) - { - jobj[keyValuePair.Key] = keyValuePair.Value; - } - return jobj; - } - - private static string AddJsonProperty(string json, string propertyName, JObject propertyValue) - { - var jObj = JObject.Parse(json); - - if (jObj.TryGetValue(propertyName, out var _)) - { - jObj[propertyName] = propertyValue; - } - else - { - jObj.Add(new JProperty(propertyName, propertyValue)); - } - - return jObj.ToString(Formatting.None); - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index 1feeb6a..cb7247a 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -11,6 +11,7 @@ namespace DotNetCore.CAP.Internal { private readonly ILoggerFactory _loggerFactory; //private readonly IMessagePacker _messagePacker; + // //private readonly IModelBinderFactory _modelBinderFactory; private readonly IServiceProvider _serviceProvider; diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs index 62af0a7..577468d 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs @@ -59,65 +59,34 @@ namespace DotNetCore.CAP.Internal obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType); } - //var jsonContent = context.DeliverMessage.Content; - //var message = _messagePacker.UnPack(jsonContent); - var message = context.DeliverMessage; - object resultObj; - if (executor.MethodParameters.Length > 0) - { - resultObj = await ExecuteWithParameterAsync(executor, obj, message.Value); - } - else + var parameterDescriptors = context.ConsumerDescriptor.Parameters; + var executeParameters = new object[parameterDescriptors.Count]; + for (var i = 0; i < parameterDescriptors.Count; i++) { - resultObj = await ExecuteAsync(executor, obj); + if (parameterDescriptors[i].IsFromCap) + { + executeParameters[i] = new CapHeader(message.Headers); + } + else + { + executeParameters[i] = message.Value; + } } + var resultObj = await ExecuteWithParameterAsync(executor, obj, executeParameters); return new ConsumerExecutedResult(resultObj, message.GetId(), message.GetCallbackName()); } } - private async Task ExecuteAsync(ObjectMethodExecutor executor, object @class) + private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class, object[] parameter) { if (executor.IsMethodAsync) { - return await executor.ExecuteAsync(@class); + return await executor.ExecuteAsync(@class, parameter); } - return executor.Execute(@class); - } - - private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class, object parameter) - { - var firstParameter = executor.MethodParameters[0]; - try - { - if (executor.IsMethodAsync) - { - return await executor.ExecuteAsync(@class, parameter); - } - - return executor.Execute(@class, parameter); - //var binder = _modelBinderFactory.CreateBinder(firstParameter); - //var bindResult = await binder.BindModelAsync(parameter); - //if (bindResult.IsSuccess) - //{ - // if (executor.IsMethodAsync) - // { - // return await executor.ExecuteAsync(@class, bindResult.Model); - // } - - // return executor.Execute(@class, bindResult.Model); - //} - - //throw new MethodBindException( - // $"Parameters:{firstParameter.Name} bind failed! ParameterString is: {parameter} "); - } - catch (FormatException ex) - { - //_logger.ModelBinderFormattingException(executor.MethodInfo?.Name, firstParameter.Name, parameter, ex); - return null; - } + return executor.Execute(@class, parameter); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Messages/Headers.cs b/src/DotNetCore.CAP/Messages/Headers.cs index 8aad623..f953bd4 100644 --- a/src/DotNetCore.CAP/Messages/Headers.cs +++ b/src/DotNetCore.CAP/Messages/Headers.cs @@ -23,8 +23,5 @@ public const string Group = "cap-msg-group"; public const string SentTime = "cap-senttime"; - - public const string ContentType = "cap-content-type"; - } } diff --git a/src/DotNetCore.CAP/Messages/TransportMessage.cs b/src/DotNetCore.CAP/Messages/TransportMessage.cs index 93e32bd..7183bb4 100644 --- a/src/DotNetCore.CAP/Messages/TransportMessage.cs +++ b/src/DotNetCore.CAP/Messages/TransportMessage.cs @@ -28,5 +28,10 @@ namespace DotNetCore.CAP.Messages { return Headers.TryGetValue(Messages.Headers.MessageName, out var value) ? value : null; } + + public string GetGroup() + { + return Headers.TryGetValue(Messages.Headers.Group, out var value) ? value : null; + } } } diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 60b7f17..7f1fb8c 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -21,8 +21,8 @@ namespace DotNetCore.CAP.Processor private readonly BlockingCollection _publishedMessageQueue = new BlockingCollection(new ConcurrentQueue()); - private readonly BlockingCollection _receivedMessageQueue = - new BlockingCollection(new ConcurrentQueue()); + private readonly BlockingCollection<(MediumMessage, ConsumerExecutorDescriptor)> _receivedMessageQueue = + new BlockingCollection<(MediumMessage, ConsumerExecutorDescriptor)>(new ConcurrentQueue<(MediumMessage, ConsumerExecutorDescriptor)>()); public Dispatcher(ILogger logger, IMessageSender sender, @@ -41,9 +41,9 @@ namespace DotNetCore.CAP.Processor _publishedMessageQueue.Add(message); } - public void EnqueueToExecute(MediumMessage message) + public void EnqueueToExecute(MediumMessage message, ConsumerExecutorDescriptor descriptor) { - _receivedMessageQueue.Add(message); + _receivedMessageQueue.Add((message, descriptor)); } public void Dispose() @@ -85,7 +85,7 @@ namespace DotNetCore.CAP.Processor { foreach (var message in _receivedMessageQueue.GetConsumingEnumerable(_cts.Token)) { - _executor.ExecuteAsync(message, _cts.Token); + _executor.ExecuteAsync(message.Item1, message.Item2, _cts.Token); } } catch (OperationCanceledException) diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs new file mode 100644 index 0000000..5362342 --- /dev/null +++ b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; +using System.Text.Json; + +namespace DotNetCore.CAP.Serialization +{ + public class JsonUtf8Serializer : ISerializer + { + public Task SerializeAsync(Message message) + { + return Task.FromResult(new TransportMessage(message.Headers, JsonSerializer.SerializeToUtf8Bytes(message.Value))); + } + + public Task DeserializeAsync(TransportMessage transportMessage, Type valueType) + { + if (valueType == null) + { + return Task.FromResult(new Message(transportMessage.Headers, null)); + } + + return Task.FromResult(new Message(transportMessage.Headers, JsonSerializer.Deserialize(transportMessage.Body, valueType))); + } + } +} diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.cs b/src/DotNetCore.CAP/Serialization/ISerializer.cs index 75d05d5..c38d064 100644 --- a/src/DotNetCore.CAP/Serialization/ISerializer.cs +++ b/src/DotNetCore.CAP/Serialization/ISerializer.cs @@ -1,5 +1,7 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using DotNetCore.CAP.Messages; +using JetBrains.Annotations; namespace DotNetCore.CAP.Serialization { @@ -13,6 +15,6 @@ namespace DotNetCore.CAP.Serialization /// /// Deserializes the given back into a /// - Task DeserializeAsync(TransportMessage transportMessage); + Task DeserializeAsync(TransportMessage transportMessage, [CanBeNull] Type valueType); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Serialization/StringSerializer.cs b/src/DotNetCore.CAP/Serialization/StringSerializer.cs index 42ba12a..8e89111 100644 --- a/src/DotNetCore.CAP/Serialization/StringSerializer.cs +++ b/src/DotNetCore.CAP/Serialization/StringSerializer.cs @@ -1,7 +1,5 @@ -using System; -using System.Runtime.Serialization; -using DotNetCore.CAP.Messages; -using Newtonsoft.Json; +using DotNetCore.CAP.Messages; +using System.Text.Json; namespace DotNetCore.CAP.Serialization { @@ -9,19 +7,12 @@ namespace DotNetCore.CAP.Serialization { public static string Serialize(Message message) { - return JsonConvert.SerializeObject(message); + return JsonSerializer.Serialize(message); } public static Message DeSerialize(string json) { - try - { - return JsonConvert.DeserializeObject(json); - } - catch (Exception exception) - { - throw new SerializationException($"Could not deserialize JSON text '{json}'", exception); - } + return JsonSerializer.Deserialize(json); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/SubscriberNotFoundException.cs b/src/DotNetCore.CAP/SubscriberNotFoundException.cs index 6e5738f..b312159 100644 --- a/src/DotNetCore.CAP/SubscriberNotFoundException.cs +++ b/src/DotNetCore.CAP/SubscriberNotFoundException.cs @@ -7,17 +7,8 @@ namespace DotNetCore.CAP { public class SubscriberNotFoundException : Exception { - public SubscriberNotFoundException() - { - } - public SubscriberNotFoundException(string message) : base(message) { } - - public SubscriberNotFoundException(string message, Exception inner) : - base(message, inner) - { - } } } \ No newline at end of file From e5175a6cebc1c4161a035f08327bc22b2f954568 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 25 Oct 2019 15:24:37 +0800 Subject: [PATCH 11/76] code cleanup --- src/DotNetCore.CAP.MySql/MySqlDataStorage.cs | 2 +- .../Abstractions/CapPublisher.cs | 2 +- ...SubscribeAttribute.cs => CAP.Attribute.cs} | 13 +++- src/DotNetCore.CAP/Cap.Header.cs | 13 ---- src/DotNetCore.CAP/ICallbackPublisher.cs | 19 ------ .../IConsumerServiceSelector.Default.cs | 2 +- src/DotNetCore.CAP/IStorageConnection.cs | 62 ------------------- .../ISubscribeExecutor.Default.cs | 1 - .../{Infrastructure => Internal}/Helper.cs | 2 +- .../Internal/IMessageSender.Default.cs | 1 - .../{Infrastructure => Internal}/ObjectId.cs | 2 +- .../SnowflakeId.cs | 2 +- .../StatusName.cs | 2 +- .../WaitHandleEx.cs | 2 +- .../Persistence/CapPublishedMessage.cs | 25 -------- .../Persistence/CapReceivedMessage.cs | 39 ------------ .../Persistence/IDashboardQuerying.cs | 26 -------- .../Persistence/IDataStorage.cs | 28 +-------- 18 files changed, 19 insertions(+), 224 deletions(-) rename src/DotNetCore.CAP/{CAP.SubscribeAttribute.cs => CAP.Attribute.cs} (71%) delete mode 100644 src/DotNetCore.CAP/Cap.Header.cs delete mode 100644 src/DotNetCore.CAP/ICallbackPublisher.cs delete mode 100644 src/DotNetCore.CAP/IStorageConnection.cs rename src/DotNetCore.CAP/{Infrastructure => Internal}/Helper.cs (98%) rename src/DotNetCore.CAP/{Infrastructure => Internal}/ObjectId.cs (99%) rename src/DotNetCore.CAP/{Infrastructure => Internal}/SnowflakeId.cs (98%) rename src/DotNetCore.CAP/{Infrastructure => Internal}/StatusName.cs (88%) rename src/DotNetCore.CAP/{Infrastructure => Internal}/WaitHandleEx.cs (96%) delete mode 100644 src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs delete mode 100644 src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs delete mode 100644 src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs index 3b640de..96aff83 100644 --- a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs +++ b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs @@ -4,7 +4,7 @@ using System.Data; using System.Threading; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Serialization; diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs index 25c9927..13df6a9 100644 --- a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs +++ b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs @@ -7,7 +7,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; diff --git a/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs b/src/DotNetCore.CAP/CAP.Attribute.cs similarity index 71% rename from src/DotNetCore.CAP/CAP.SubscribeAttribute.cs rename to src/DotNetCore.CAP/CAP.Attribute.cs index fda43e2..242bc47 100644 --- a/src/DotNetCore.CAP/CAP.SubscribeAttribute.cs +++ b/src/DotNetCore.CAP/CAP.Attribute.cs @@ -2,14 +2,13 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using DotNetCore.CAP.Abstractions; // ReSharper disable once CheckNamespace namespace DotNetCore.CAP { - /// - /// An attribute for subscribe event bus message. - /// public class CapSubscribeAttribute : TopicAttribute { public CapSubscribeAttribute(string name) @@ -29,4 +28,12 @@ namespace DotNetCore.CAP { } + + public class CapHeader : ReadOnlyDictionary + { + public CapHeader(IDictionary dictionary) : base(dictionary) + { + + } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Cap.Header.cs b/src/DotNetCore.CAP/Cap.Header.cs deleted file mode 100644 index 657f5cc..0000000 --- a/src/DotNetCore.CAP/Cap.Header.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace DotNetCore.CAP -{ - public class CapHeader : ReadOnlyDictionary - { - public CapHeader(IDictionary dictionary) : base(dictionary) - { - - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICallbackPublisher.cs b/src/DotNetCore.CAP/ICallbackPublisher.cs deleted file mode 100644 index 01d8920..0000000 --- a/src/DotNetCore.CAP/ICallbackPublisher.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP -{ - /// - /// A callback that is sent to Producer after a successful consumer execution - /// - public interface ICallbackPublisher - { - /// - /// Publish a callback message - /// - Task PublishCallbackAsync(CapPublishedMessage obj); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs index 4039bf6..e7b9a56 100644 --- a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs @@ -7,9 +7,9 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Infrastructure; using Microsoft.Extensions.DependencyInjection; using System.Collections.Concurrent; +using DotNetCore.CAP.Internal; using Microsoft.Extensions.Options; namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/IStorageConnection.cs b/src/DotNetCore.CAP/IStorageConnection.cs deleted file mode 100644 index 5ce8d9e..0000000 --- a/src/DotNetCore.CAP/IStorageConnection.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP -{ - /// - /// Represents a connection to the storage. - /// - public interface IStorageConnection - { - //Sent messages - - /// - /// Returns the message with the given id. - /// - /// The message's id. - Task GetPublishedMessageAsync(long id); - - /// - /// Returns executed failed messages. - /// - Task> GetPublishedMessagesOfNeedRetry(); - - // Received messages - - /// - /// Stores the message. - /// - /// The message to store. - void StoreReceivedMessage(CapReceivedMessage message); - - /// - /// Returns the message with the given id. - /// - /// The message's id. - Task GetReceivedMessageAsync(long id); - - /// - /// Returns executed failed message. - /// - Task> GetReceivedMessagesOfNeedRetry(); - - - /// - /// Change specified message's state of published message - /// - /// Message id - /// State name - bool ChangePublishedState(long messageId, string state); - - /// - /// Change specified message's state of received message - /// - /// Message id - /// State name - bool ChangeReceivedState(long messageId, string state); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs index 8b2625e..8d2dacd 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; diff --git a/src/DotNetCore.CAP/Infrastructure/Helper.cs b/src/DotNetCore.CAP/Internal/Helper.cs similarity index 98% rename from src/DotNetCore.CAP/Infrastructure/Helper.cs rename to src/DotNetCore.CAP/Internal/Helper.cs index 4acc33f..a1084e2 100644 --- a/src/DotNetCore.CAP/Infrastructure/Helper.cs +++ b/src/DotNetCore.CAP/Internal/Helper.cs @@ -5,7 +5,7 @@ using System; using System.ComponentModel; using System.Reflection; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { public static class Helper { diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs index b014b89..8cf6f5b 100644 --- a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Processor; diff --git a/src/DotNetCore.CAP/Infrastructure/ObjectId.cs b/src/DotNetCore.CAP/Internal/ObjectId.cs similarity index 99% rename from src/DotNetCore.CAP/Infrastructure/ObjectId.cs rename to src/DotNetCore.CAP/Internal/ObjectId.cs index 8d84a6f..3dab571 100644 --- a/src/DotNetCore.CAP/Infrastructure/ObjectId.cs +++ b/src/DotNetCore.CAP/Internal/ObjectId.cs @@ -9,7 +9,7 @@ using System.Security.Cryptography; using System.Text; using System.Threading; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { /// /// Represents an ObjectId diff --git a/src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs b/src/DotNetCore.CAP/Internal/SnowflakeId.cs similarity index 98% rename from src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs rename to src/DotNetCore.CAP/Internal/SnowflakeId.cs index 339d254..b1670e3 100644 --- a/src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs +++ b/src/DotNetCore.CAP/Internal/SnowflakeId.cs @@ -3,7 +3,7 @@ using System; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { public class SnowflakeId { diff --git a/src/DotNetCore.CAP/Infrastructure/StatusName.cs b/src/DotNetCore.CAP/Internal/StatusName.cs similarity index 88% rename from src/DotNetCore.CAP/Infrastructure/StatusName.cs rename to src/DotNetCore.CAP/Internal/StatusName.cs index 018e28d..d4463de 100644 --- a/src/DotNetCore.CAP/Infrastructure/StatusName.cs +++ b/src/DotNetCore.CAP/Internal/StatusName.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { /// /// The message status name. diff --git a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs b/src/DotNetCore.CAP/Internal/WaitHandleEx.cs similarity index 96% rename from src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs rename to src/DotNetCore.CAP/Internal/WaitHandleEx.cs index 14ed410..e5f5ba2 100644 --- a/src/DotNetCore.CAP/Infrastructure/WaitHandleEx.cs +++ b/src/DotNetCore.CAP/Internal/WaitHandleEx.cs @@ -5,7 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; -namespace DotNetCore.CAP.Infrastructure +namespace DotNetCore.CAP.Internal { public static class WaitHandleEx { diff --git a/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs b/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs deleted file mode 100644 index 8d68ed1..0000000 --- a/src/DotNetCore.CAP/Persistence/CapPublishedMessage.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Messages -{ - public class CapPublishedMessage - { - public CapPublishedMessage() - { - Added = DateTime.Now; - } - - public Message Message { get; set; } - - public DateTime Added { get; set; } - - public DateTime? ExpiresAt { get; set; } - - public int Retries { get; set; } - - public string StatusName { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs b/src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs deleted file mode 100644 index 1e29561..0000000 --- a/src/DotNetCore.CAP/Persistence/CapReceivedMessage.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Messages -{ - public class CapReceivedMessage - { - /// - /// Initializes a new instance of . - /// - public CapReceivedMessage() - { - Added = DateTime.Now; - } - - public long Id { get; set; } - - public string Group { get; set; } - - public string Name { get; set; } - - public string Content { get; set; } - - public DateTime Added { get; set; } - - public DateTime? ExpiresAt { get; set; } - - public int Retries { get; set; } - - public string StatusName { get; set; } - - public override string ToString() - { - return "name:" + Name + ", group:" + Group + ", content:" + Content; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs b/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs deleted file mode 100644 index 384a1f2..0000000 --- a/src/DotNetCore.CAP/Persistence/IDashboardQuerying.cs +++ /dev/null @@ -1,26 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using DotNetCore.CAP.Dashboard.Monitoring; -//using DotNetCore.CAP.Messages; - -//namespace DotNetCore.CAP.Persistence -//{ -// public interface IDashboardQuerying -// { -// StatisticsDto GetStatistics(); - -// IList Messages(MessageQueryDto queryDto); - -// int PublishedFailedCount(); - -// int PublishedSucceededCount(); - -// int ReceivedFailedCount(); - -// int ReceivedSucceededCount(); - -// IDictionary HourlySucceededJobs(MessageType type); - -// IDictionary HourlyFailedJobs(MessageType type); -// } -//} diff --git a/src/DotNetCore.CAP/Persistence/IDataStorage.cs b/src/DotNetCore.CAP/Persistence/IDataStorage.cs index ab18dca..41255c2 100644 --- a/src/DotNetCore.CAP/Persistence/IDataStorage.cs +++ b/src/DotNetCore.CAP/Persistence/IDataStorage.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Persistence @@ -22,31 +22,5 @@ namespace DotNetCore.CAP.Persistence Task> GetPublishedMessagesOfNeedRetry(); Task> GetReceivedMessagesOfNeedRetry(); - - //Task GetPublishedMessageAsync(long id); - //Task GetReceivedMessageAsync(long id); - - //public void UpdateMessage(CapPublishedMessage message) - //{ - // if (message == null) - // { - // throw new ArgumentNullException(nameof(message)); - // } - - // var sql = - // $"UPDATE `{_prefix}.published` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; - // _dbConnection.Execute(sql, message); - //} - - //public void UpdateMessage(CapReceivedMessage message) - //{ - // if (message == null) - // { - // throw new ArgumentNullException(nameof(message)); - // } - - // var sql = $"UPDATE `{_prefix}.received` SET `Retries` = @Retries,`Content`= @Content,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; - // _dbConnection.Execute(sql, message); - //} } } From 6aef9ad47ef01a449034de9d6bb3c043860bfe54 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 31 Oct 2019 16:41:39 +0800 Subject: [PATCH 12/76] remove unused file --- .../IMonitoringApi.MySql.cs | 231 ------------------ 1 file changed, 231 deletions(-) delete mode 100644 src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs deleted file mode 100644 index ff5e491..0000000 --- a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs +++ /dev/null @@ -1,231 +0,0 @@ -//// Copyright (c) .NET Core Community. All rights reserved. -//// Licensed under the MIT License. See License.txt in the project root for license information. - -//using System; -//using System.Collections.Generic; -//using System.Data; -//using System.Linq; -//using Dapper; -//using DotNetCore.CAP.Dashboard; -//using DotNetCore.CAP.Dashboard.Monitoring; -//using DotNetCore.CAP.Infrastructure; -//using DotNetCore.CAP.Messages; -//using Microsoft.Extensions.Options; -//using MySql.Data.MySqlClient; - -//namespace DotNetCore.CAP.MySql -//{ -// internal class MySqlMonitoringApi : IMonitoringApi -// { -// private readonly IDbConnection _existingConnection = null; -// private readonly string _prefix; -// private readonly string _connectionString; - -// public MySqlMonitoringApi(IOptions options) -// { -// _prefix = options.Value.TableNamePrefix ?? throw new ArgumentNullException(nameof(options)); -// _connectionString = options.Value.ConnectionString; -// } - -// public StatisticsDto GetStatistics() -// { -// var sql = string.Format(@" -//set transaction isolation level read committed; -//select count(Id) from `{0}.published` where StatusName = N'Succeeded'; -//select count(Id) from `{0}.received` where StatusName = N'Succeeded'; -//select count(Id) from `{0}.published` where StatusName = N'Failed'; -//select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); - -// var statistics = UseConnection(connection => -// { -// var stats = new StatisticsDto(); -// using (var multi = connection.QueryMultiple(sql)) -// { -// stats.PublishedSucceeded = multi.ReadSingle(); -// stats.ReceivedSucceeded = multi.ReadSingle(); - -// stats.PublishedFailed = multi.ReadSingle(); -// stats.ReceivedFailed = multi.ReadSingle(); -// } - -// return stats; -// }); -// return statistics; -// } - -// public IDictionary HourlyFailedJobs(MessageType type) -// { -// var tableName = type == MessageType.Publish ? "published" : "received"; -// return UseConnection(connection => -// GetHourlyTimelineStats(connection, tableName, StatusName.Failed)); -// } - -// public IDictionary HourlySucceededJobs(MessageType type) -// { -// var tableName = type == MessageType.Publish ? "published" : "received"; -// return UseConnection(connection => -// GetHourlyTimelineStats(connection, tableName, StatusName.Succeeded)); -// } - -// public IList Messages(MessageQueryDto queryDto) -// { -// var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; -// var where = string.Empty; -// if (!string.IsNullOrEmpty(queryDto.StatusName)) -// { -// where += " and StatusName=@StatusName"; -// } - -// if (!string.IsNullOrEmpty(queryDto.Name)) -// { -// where += " and Name=@Name"; -// } - -// if (!string.IsNullOrEmpty(queryDto.Group)) -// { -// where += " and `Group`=@Group"; -// } - -// if (!string.IsNullOrEmpty(queryDto.Content)) -// { -// where += " and Content like '%@Content%'"; -// } - -// var sqlQuery = -// $"select * from `{_prefix}.{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; - -// return UseConnection(conn => conn.Query(sqlQuery, new -// { -// queryDto.StatusName, -// queryDto.Group, -// queryDto.Name, -// queryDto.Content, -// Offset = queryDto.CurrentPage * queryDto.PageSize, -// Limit = queryDto.PageSize -// }).ToList()); -// } - -// public int PublishedFailedCount() -// { -// return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Failed)); -// } - -// public int PublishedSucceededCount() -// { -// return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Succeeded)); -// } - -// public int ReceivedFailedCount() -// { -// return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Failed)); -// } - -// public int ReceivedSucceededCount() -// { -// return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Succeeded)); -// } - -// private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) -// { -// var sqlQuery = $"select count(Id) from `{_prefix}.{tableName}` where StatusName = @state"; - -// var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); -// return count; -// } - -// private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, -// string statusName) -// { -// var endDate = DateTime.Now; -// var dates = new List(); -// for (var i = 0; i < 24; i++) -// { -// dates.Add(endDate); -// endDate = endDate.AddHours(-1); -// } - -// var keyMaps = dates.ToDictionary(x => x.ToString("yyyy-MM-dd-HH"), x => x); - -// return GetTimelineStats(connection, tableName, statusName, keyMaps); -// } - -// private Dictionary GetTimelineStats( -// IDbConnection connection, -// string tableName, -// string statusName, -// IDictionary keyMaps) -// { -// var sqlQuery = -// $@" -//select aggr.* from ( -// select date_format(`Added`,'%Y-%m-%d-%H') as `Key`, -// count(id) `Count` -// from `{_prefix}.{tableName}` -// where StatusName = @statusName -// group by date_format(`Added`,'%Y-%m-%d-%H') -//) aggr where `Key` in @keys;"; - -// var valuesMap = connection.Query( -// sqlQuery, -// new { keys = keyMaps.Keys, statusName }) -// .ToDictionary(x => x.Key, x => x.Count); - -// foreach (var key in keyMaps.Keys) -// { -// if (!valuesMap.ContainsKey(key)) -// { -// valuesMap.Add(key, 0); -// } -// } - -// var result = new Dictionary(); -// for (var i = 0; i < keyMaps.Count; i++) -// { -// var value = valuesMap[keyMaps.ElementAt(i).Key]; -// result.Add(keyMaps.ElementAt(i).Value, value); -// } - -// return result; -// } - -// private T UseConnection(Func func) -// { -// IDbConnection connection = null; - -// try -// { -// connection = CreateAndOpenConnection(); -// return func(connection); -// } -// finally -// { -// ReleaseConnection(connection); -// } -// } - -// private IDbConnection CreateAndOpenConnection() -// { -// var connection = _existingConnection ?? new MySqlConnection(_connectionString); - -// if (connection.State == ConnectionState.Closed) -// { -// connection.Open(); -// } - -// return connection; -// } - -// private bool IsExistingConnection(IDbConnection connection) -// { -// return connection != null && ReferenceEquals(connection, _existingConnection); -// } - -// private void ReleaseConnection(IDbConnection connection) -// { -// if (connection != null && !IsExistingConnection(connection)) -// { -// connection.Dispose(); -// } -// } -// } -//} \ No newline at end of file From c99869fc3d345cd10a2dde226b88c1accaa679b3 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 31 Oct 2019 16:42:06 +0800 Subject: [PATCH 13/76] upgrade nuget and upgrade framework to netstandard 2.1 --- src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj b/src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj index 1babd81..8616c68 100644 --- a/src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj +++ b/src/DotNetCore.CAP.MySql/DotNetCore.CAP.MySql.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.1 DotNetCore.CAP.MySql $(PackageTags);MySQL @@ -12,10 +12,10 @@ - - - - + + + + From ce06c23c46763b1efa54ec41530912635faad2c5 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 31 Oct 2019 16:42:44 +0800 Subject: [PATCH 14/76] add async support for CAPTransaction --- .../ICapTransaction.MySql.cs | 33 +++++++++++++++++++ .../IDbContextTransaction.CAP.cs | 22 +++++++++++-- src/DotNetCore.CAP/ICapTransaction.Base.cs | 6 ++++ src/DotNetCore.CAP/ICapTransaction.cs | 6 ++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs index 77f7919..fac7430 100644 --- a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs +++ b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs @@ -3,6 +3,8 @@ using System.Data; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; @@ -33,6 +35,22 @@ namespace DotNetCore.CAP Flush(); } + public override async Task CommitAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + switch (DbTransaction) + { + case IDbTransaction dbTransaction: + dbTransaction.Commit(); + break; + case IDbContextTransaction dbContextTransaction: + await dbContextTransaction.CommitAsync(cancellationToken); + break; + } + Flush(); + } + public override void Rollback() { Debug.Assert(DbTransaction != null); @@ -48,6 +66,21 @@ namespace DotNetCore.CAP } } + public override async Task RollbackAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + switch (DbTransaction) + { + case IDbTransaction dbTransaction: + dbTransaction.Rollback(); + break; + case IDbContextTransaction dbContextTransaction: + await dbContextTransaction.RollbackAsync(cancellationToken); + break; + } + } + public override void Dispose() { (DbTransaction as IDbTransaction)?.Dispose(); diff --git a/src/DotNetCore.CAP.MySql/IDbContextTransaction.CAP.cs b/src/DotNetCore.CAP.MySql/IDbContextTransaction.CAP.cs index 0f2354a..85a36b2 100644 --- a/src/DotNetCore.CAP.MySql/IDbContextTransaction.CAP.cs +++ b/src/DotNetCore.CAP.MySql/IDbContextTransaction.CAP.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; using DotNetCore.CAP; // ReSharper disable once CheckNamespace @@ -15,10 +17,12 @@ namespace Microsoft.EntityFrameworkCore.Storage public CapEFDbTransaction(ICapTransaction transaction) { _transaction = transaction; - var dbContextTransaction = (IDbContextTransaction) _transaction.DbTransaction; + var dbContextTransaction = (IDbContextTransaction)_transaction.DbTransaction; TransactionId = dbContextTransaction.TransactionId; } + public Guid TransactionId { get; } + public void Dispose() { _transaction.Dispose(); @@ -29,11 +33,25 @@ namespace Microsoft.EntityFrameworkCore.Storage _transaction.Commit(); } + public Task CommitAsync(CancellationToken cancellationToken = default) + { + return _transaction.CommitAsync(cancellationToken); + } + public void Rollback() { _transaction.Rollback(); } - public Guid TransactionId { get; } + public Task RollbackAsync(CancellationToken cancellationToken = default) + { + return _transaction.CommitAsync(cancellationToken); + } + + public ValueTask DisposeAsync() + { + Dispose(); + return new ValueTask(); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/ICapTransaction.Base.cs b/src/DotNetCore.CAP/ICapTransaction.Base.cs index 6f5c623..1df1af2 100644 --- a/src/DotNetCore.CAP/ICapTransaction.Base.cs +++ b/src/DotNetCore.CAP/ICapTransaction.Base.cs @@ -1,4 +1,6 @@ using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP @@ -36,8 +38,12 @@ namespace DotNetCore.CAP public abstract void Commit(); + public abstract Task CommitAsync(CancellationToken cancellationToken = default); + public abstract void Rollback(); + public abstract Task RollbackAsync(CancellationToken cancellationToken = default); + public abstract void Dispose(); } } diff --git a/src/DotNetCore.CAP/ICapTransaction.cs b/src/DotNetCore.CAP/ICapTransaction.cs index f73865d..3892ed1 100644 --- a/src/DotNetCore.CAP/ICapTransaction.cs +++ b/src/DotNetCore.CAP/ICapTransaction.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; namespace DotNetCore.CAP { @@ -25,9 +27,13 @@ namespace DotNetCore.CAP /// void Commit(); + Task CommitAsync(CancellationToken cancellationToken = default); + /// /// We will delete the message data that has not been sstore in the buffer data of current transaction context. /// void Rollback(); + + Task RollbackAsync(CancellationToken cancellationToken = default); } } \ No newline at end of file From d5314e1ae318b87a4146f0a9f8153752edaee6af Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 31 Oct 2019 16:42:56 +0800 Subject: [PATCH 15/76] bug fixed --- .../Controllers/ValuesController.cs | 9 +-- .../Sample.RabbitMQ.MySql.csproj | 2 +- src/DotNetCore.CAP.MySql/MySqlDataStorage.cs | 75 ++++++++++++------- .../Abstractions/CapPublisher.cs | 4 +- .../IConsumerRegister.Default.cs | 42 +++++++++-- src/DotNetCore.CAP/Messages/Headers.cs | 2 + src/DotNetCore.CAP/Messages/Message.cs | 5 ++ .../Persistence/IDataStorage.cs | 4 +- 8 files changed, 98 insertions(+), 45 deletions(-) diff --git a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs index b8c920f..8e9ae75 100644 --- a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Data; using System.Threading.Tasks; using Dapper; @@ -36,7 +35,7 @@ namespace Sample.RabbitMQ.MySql.Controllers { using (var connection = new MySqlConnection(AppDbContext.ConnectionString)) { - using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false)) + using (var transaction = connection.BeginTransaction(_capBus, true)) { //your business code connection.Execute("insert into test(name) values('test')", transaction: (IDbTransaction)transaction.DbTransaction); @@ -45,8 +44,6 @@ namespace Sample.RabbitMQ.MySql.Controllers //{ _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); //} - - transaction.Commit(); } } @@ -60,7 +57,7 @@ namespace Sample.RabbitMQ.MySql.Controllers { dbContext.Persons.Add(new Person() { Name = "ef.transaction" }); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 1; i++) { _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); } @@ -74,7 +71,7 @@ namespace Sample.RabbitMQ.MySql.Controllers [NonAction] [CapSubscribe("sample.rabbitmq.mysql")] - public void Subscriber(Person2 p) + public void Subscriber(DateTime p) { Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); } diff --git a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj index 8756e56..ce72296 100644 --- a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj +++ b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs index 96aff83..f629203 100644 --- a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs +++ b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs @@ -34,8 +34,8 @@ namespace DotNetCore.CAP.MySql await connection.ExecuteAsync(sql, new { Id = message.DbId, - Retries = message.Retries, - ExpiresAt = message.ExpiresAt, + message.Retries, + message.ExpiresAt, StatusName = state.ToString("G") }); } @@ -50,8 +50,8 @@ namespace DotNetCore.CAP.MySql await connection.ExecuteAsync(sql, new { Id = message.DbId, - Retries = message.Retries, - ExpiresAt = message.ExpiresAt, + message.Retries, + message.ExpiresAt, StatusName = state.ToString("G") }); } @@ -61,7 +61,7 @@ namespace DotNetCore.CAP.MySql { var sql = $"INSERT INTO `{_options.Value.TableNamePrefix}.published`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var message = new MediumMessage() + var message = new MediumMessage { DbId = content.GetId(), Origin = content, @@ -75,9 +75,9 @@ namespace DotNetCore.CAP.MySql Id = message.DbId, Name = name, Content = StringSerializer.Serialize(message.Origin), - Retries = message.Retries, - Added = message.Added, - ExpiresAt = message.ExpiresAt, + message.Retries, + message.Added, + message.ExpiresAt, StatusName = StatusName.Scheduled }; @@ -103,37 +103,56 @@ namespace DotNetCore.CAP.MySql return message; } - public Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default) + public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) { var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var message = new MediumMessage() + using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + { + await connection.ExecuteAsync(sql, new + { + Id = SnowflakeId.Default().NextId().ToString(), + Group = group, + Name = name, + Content = content, + Retries = _capOptions.Value.FailedRetryCount, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + StatusName = nameof(StatusName.Failed) + }); + } + } + + public Task StoreReceivedMessageAsync(string name, string group, Message message) + { + var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var mdMessage = new MediumMessage { DbId = SnowflakeId.Default().NextId().ToString(), - Origin = content, + Origin = message, Added = DateTime.Now, ExpiresAt = null, Retries = 0 }; - - var po = new - { - Id = message.DbId, - Group = group, - Name = name, - Content = StringSerializer.Serialize(message.Origin), - Retries = message.Retries, - Added = message.Added, - ExpiresAt = message.ExpiresAt, - StatusName = nameof(StatusName.Scheduled) - }; - + var content = StringSerializer.Serialize(mdMessage.Origin); using (var connection = new MySqlConnection(_options.Value.ConnectionString)) { - connection.Execute(sql, po); + + connection.Execute(sql, new + { + Id = mdMessage.DbId, + Group = group, + Name = name, + Content = content, + mdMessage.Retries, + mdMessage.Added, + mdMessage.ExpiresAt, + StatusName = nameof(StatusName.Scheduled) + }); } - return Task.FromResult(message); + return Task.FromResult(mdMessage); } public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default) @@ -157,7 +176,7 @@ namespace DotNetCore.CAP.MySql var reader = await connection.ExecuteReaderAsync(sql); while (reader.Read()) { - result.Add(new MediumMessage() + result.Add(new MediumMessage { DbId = reader.GetInt64(0).ToString(), Origin = StringSerializer.DeSerialize(reader.GetString(3)), @@ -181,7 +200,7 @@ namespace DotNetCore.CAP.MySql var reader = await connection.ExecuteReaderAsync(sql); while (reader.Read()) { - result.Add(new MediumMessage() + result.Add(new MediumMessage { DbId = reader.GetInt64(0).ToString(), Origin = StringSerializer.DeSerialize(reader.GetString(3)), diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs index 13df6a9..d9dd8de 100644 --- a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs +++ b/src/DotNetCore.CAP/Abstractions/CapPublisher.cs @@ -57,7 +57,7 @@ namespace DotNetCore.CAP.Abstractions optionHeaders.Add(Headers.CorrelationSequence, 0.ToString()); } optionHeaders.Add(Headers.MessageName, name); - optionHeaders.Add(Headers.Type, typeof(T).AssemblyQualifiedName); + optionHeaders.Add(Headers.Type, typeof(T).FullName); optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); var message = new Message(optionHeaders, value); @@ -79,7 +79,7 @@ namespace DotNetCore.CAP.Abstractions { var transaction = (CapTransactionBase)Transaction.Value; - var mediumMessage = await _storage.StoreMessageAsync(name, message, transaction, cancellationToken); + var mediumMessage = await _storage.StoreMessageAsync(name, message, transaction.DbTransaction, cancellationToken); s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); diff --git a/src/DotNetCore.CAP/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/IConsumerRegister.Default.cs index ecfb31c..dd4f2ec 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/IConsumerRegister.Default.cs @@ -4,6 +4,8 @@ using System; using System.Diagnostics; using System.Linq; +using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; @@ -170,18 +172,44 @@ namespace DotNetCore.CAP var type = executor.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType; - var message = await _serializer.DeserializeAsync(transportMessage, type); + Message message; + try + { + message = await _serializer.DeserializeAsync(transportMessage, type); + } + catch (Exception e) + { + transportMessage.Headers.Add(Headers.Exception, e.Message); + var dataUri = $"data:{transportMessage.Headers[Headers.Type]};base64," + Convert.ToBase64String(transportMessage.Body); + message = new Message(transportMessage.Headers, dataUri); + } - var mediumMessage = await _storage.StoreMessageAsync(name, group, message); + if (message.HasException()) + { + var content = StringSerializer.Serialize(message); + await _storage.StoreReceivedExceptionMessageAsync(name, group, content); - client.Commit(); + client.Commit(); - if (operationId != null) - { - TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); + if (operationId != null) + { + TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); + } } + else + { + var mediumMessage = await _storage.StoreReceivedMessageAsync(name, group, message); + mediumMessage.Origin = message; - _dispatcher.EnqueueToExecute(mediumMessage, executor); + client.Commit(); + + if (operationId != null) + { + TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); + } + + _dispatcher.EnqueueToExecute(mediumMessage, executor); + } } catch (Exception e) { diff --git a/src/DotNetCore.CAP/Messages/Headers.cs b/src/DotNetCore.CAP/Messages/Headers.cs index f953bd4..0d9e3da 100644 --- a/src/DotNetCore.CAP/Messages/Headers.cs +++ b/src/DotNetCore.CAP/Messages/Headers.cs @@ -23,5 +23,7 @@ public const string Group = "cap-msg-group"; public const string SentTime = "cap-senttime"; + + public const string Exception = "cap-exception"; } } diff --git a/src/DotNetCore.CAP/Messages/Message.cs b/src/DotNetCore.CAP/Messages/Message.cs index 9fdd778..213193f 100644 --- a/src/DotNetCore.CAP/Messages/Message.cs +++ b/src/DotNetCore.CAP/Messages/Message.cs @@ -51,6 +51,11 @@ namespace DotNetCore.CAP.Messages return 0; } + + public static bool HasException(this Message message) + { + return message.Headers.ContainsKey(Headers.Exception); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/IDataStorage.cs b/src/DotNetCore.CAP/Persistence/IDataStorage.cs index 41255c2..9bdec2a 100644 --- a/src/DotNetCore.CAP/Persistence/IDataStorage.cs +++ b/src/DotNetCore.CAP/Persistence/IDataStorage.cs @@ -15,7 +15,9 @@ namespace DotNetCore.CAP.Persistence Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default); - Task StoreMessageAsync(string name, string group, Message content, CancellationToken cancellationToken = default); + Task StoreReceivedExceptionMessageAsync(string name, string group, string content); + + Task StoreReceivedMessageAsync(string name, string group, Message content); Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default); From c633a6e58930489aaf264fb4d6dadafd4d8723c0 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 4 Nov 2019 11:45:25 +0800 Subject: [PATCH 16/76] Typo: "Getting Stared" --- docs/mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 01c5b09..ecc1058 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -74,7 +74,7 @@ markdown_extensions: nav: - Home: index.md - Documentation: - - Getting Stared: + - Getting Started: - Quick Start: user-guide/en/getting-started/quick-start.md - Introduction: user-guide/en/getting-started/introduction.md - Contributing: user-guide/en/getting-started/contributing.md From 1d67da713a36c5fc42f430431ec70863ce68a7e3 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 5 Nov 2019 18:21:54 +0800 Subject: [PATCH 17/76] Add dashboard api interface --- .../IMonitoringApi.MySql.cs | 217 ++++++++++++++++++ .../Monitoring/IMonitoringApi.cs | 34 +++ src/DotNetCore.CAP/Monitoring/MessageDto.cs | 28 +++ .../Monitoring/MessageQueryDto.cs | 23 ++ .../Monitoring/StatisticsDto.cs | 16 ++ 5 files changed, 318 insertions(+) create mode 100644 src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs create mode 100644 src/DotNetCore.CAP/Monitoring/IMonitoringApi.cs create mode 100644 src/DotNetCore.CAP/Monitoring/MessageDto.cs create mode 100644 src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs create mode 100644 src/DotNetCore.CAP/Monitoring/StatisticsDto.cs diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs new file mode 100644 index 0000000..d626599 --- /dev/null +++ b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs @@ -0,0 +1,217 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using Microsoft.Extensions.Options; +using MySql.Data.MySqlClient; + +namespace DotNetCore.CAP.MySql +{ + internal class MySqlMonitoringApi : IMonitoringApi + { + private readonly IOptions _options; + private readonly string _prefix; + + public MySqlMonitoringApi(IOptions options) + { + _options = options; + _prefix = options.Value.TableNamePrefix ?? throw new ArgumentNullException(nameof(options)); + } + + public StatisticsDto GetStatistics() + { + var sql = string.Format(@" +set transaction isolation level read committed; +select count(Id) from `{0}.published` where StatusName = N'Succeeded'; +select count(Id) from `{0}.received` where StatusName = N'Succeeded'; +select count(Id) from `{0}.published` where StatusName = N'Failed'; +select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); + + var statistics = UseConnection(connection => + { + var stats = new StatisticsDto(); + using (var multi = connection.QueryMultiple(sql)) + { + stats.PublishedSucceeded = multi.ReadSingle(); + stats.ReceivedSucceeded = multi.ReadSingle(); + + stats.PublishedFailed = multi.ReadSingle(); + stats.ReceivedFailed = multi.ReadSingle(); + } + + return stats; + }); + return statistics; + } + + public IDictionary HourlyFailedJobs(MessageType type) + { + var tableName = type == MessageType.Publish ? "published" : "received"; + return UseConnection(connection => + GetHourlyTimelineStats(connection, tableName,nameof(StatusName.Failed))); + } + + public IDictionary HourlySucceededJobs(MessageType type) + { + var tableName = type == MessageType.Publish ? "published" : "received"; + return UseConnection(connection => + GetHourlyTimelineStats(connection, tableName, nameof( StatusName.Succeeded))); + } + + public IList Messages(MessageQueryDto queryDto) + { + var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; + var where = string.Empty; + if (!string.IsNullOrEmpty(queryDto.StatusName)) + { + where += " and StatusName=@StatusName"; + } + + if (!string.IsNullOrEmpty(queryDto.Name)) + { + where += " and Name=@Name"; + } + + if (!string.IsNullOrEmpty(queryDto.Group)) + { + where += " and `Group`=@Group"; + } + + if (!string.IsNullOrEmpty(queryDto.Content)) + { + where += " and Content like '%@Content%'"; + } + + var sqlQuery = + $"select * from `{_prefix}.{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; + + return UseConnection(conn => conn.Query(sqlQuery, new + { + queryDto.StatusName, + queryDto.Group, + queryDto.Name, + queryDto.Content, + Offset = queryDto.CurrentPage * queryDto.PageSize, + Limit = queryDto.PageSize + }).ToList()); + } + + public int PublishedFailedCount() + { + return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof( StatusName.Failed))); + } + + public int PublishedSucceededCount() + { + return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Succeeded))); + } + + public int ReceivedFailedCount() + { + return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Failed))); + } + + public int ReceivedSucceededCount() + { + return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Succeeded))); + } + + private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) + { + var sqlQuery = $"select count(Id) from `{_prefix}.{tableName}` where StatusName = @state"; + + var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); + return count; + } + + private T UseConnection(Func action) + { + return action(new MySqlConnection(_options.Value.ConnectionString)); + } + + private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, + string statusName) + { + var endDate = DateTime.Now; + var dates = new List(); + for (var i = 0; i < 24; i++) + { + dates.Add(endDate); + endDate = endDate.AddHours(-1); + } + + var keyMaps = dates.ToDictionary(x => x.ToString("yyyy-MM-dd-HH"), x => x); + + return GetTimelineStats(connection, tableName, statusName, keyMaps); + } + + private Dictionary GetTimelineStats( + IDbConnection connection, + string tableName, + string statusName, + IDictionary keyMaps) + { + var sqlQuery = + $@" +select aggr.* from ( + select date_format(`Added`,'%Y-%m-%d-%H') as `Key`, + count(id) `Count` + from `{_prefix}.{tableName}` + where StatusName = @statusName + group by date_format(`Added`,'%Y-%m-%d-%H') +) aggr where `Key` in @keys;"; + + var valuesMap = connection.Query( + sqlQuery, + new { keys = keyMaps.Keys, statusName }) + .ToDictionary(x => x.Key, x => x.Count); + + foreach (var key in keyMaps.Keys) + { + if (!valuesMap.ContainsKey(key)) + { + valuesMap.Add(key, 0); + } + } + + var result = new Dictionary(); + for (var i = 0; i < keyMaps.Count; i++) + { + var value = valuesMap[keyMaps.ElementAt(i).Key]; + result.Add(keyMaps.ElementAt(i).Value, value); + } + + return result; + } + + public async Task GetPublishedMessageAsync(long id) + { + var sql = $@"SELECT * FROM `{_prefix}.published` WHERE `Id`={id};"; + + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); + } + + public async Task GetReceivedMessageAsync(long id) + { + var sql = $@"SELECT * FROM `{_prefix}.received` WHERE Id={id};"; + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); + } + } + + class TimelineCounter + { + public string Key { get; set; } + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Monitoring/IMonitoringApi.cs b/src/DotNetCore.CAP/Monitoring/IMonitoringApi.cs new file mode 100644 index 0000000..8ebb8cb --- /dev/null +++ b/src/DotNetCore.CAP/Monitoring/IMonitoringApi.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; + +namespace DotNetCore.CAP.Monitoring +{ + public interface IMonitoringApi + { + Task GetPublishedMessageAsync(long id); + + Task GetReceivedMessageAsync(long id); + + StatisticsDto GetStatistics(); + + IList Messages(MessageQueryDto queryDto); + + int PublishedFailedCount(); + + int PublishedSucceededCount(); + + int ReceivedFailedCount(); + + int ReceivedSucceededCount(); + + IDictionary HourlySucceededJobs(MessageType type); + + IDictionary HourlyFailedJobs(MessageType type); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Monitoring/MessageDto.cs b/src/DotNetCore.CAP/Monitoring/MessageDto.cs new file mode 100644 index 0000000..3151193 --- /dev/null +++ b/src/DotNetCore.CAP/Monitoring/MessageDto.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; + +namespace DotNetCore.CAP.Monitoring +{ + public class MessageDto + { + public long Id { get; set; } + + public string Version { get; set; } + + public string Group { get; set; } + + public string Name { get; set; } + + public string Content { get; set; } + + public DateTime Added { get; set; } + + public DateTime? ExpiresAt { get; set; } + + public int Retries { get; set; } + + public string StatusName { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs b/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs new file mode 100644 index 0000000..39b4a56 --- /dev/null +++ b/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Monitoring +{ + public class MessageQueryDto + { + public MessageType MessageType { get; set; } + + public string Group { get; set; } + public string Name { get; set; } + + public string Content { get; set; } + + public string StatusName { get; set; } + + public int CurrentPage { get; set; } + + public int PageSize { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Monitoring/StatisticsDto.cs b/src/DotNetCore.CAP/Monitoring/StatisticsDto.cs new file mode 100644 index 0000000..d698f85 --- /dev/null +++ b/src/DotNetCore.CAP/Monitoring/StatisticsDto.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Monitoring +{ + public class StatisticsDto + { + public int Servers { get; set; } + + public int PublishedSucceeded { get; set; } + public int ReceivedSucceeded { get; set; } + + public int PublishedFailed { get; set; } + public int ReceivedFailed { get; set; } + } +} \ No newline at end of file From 59f90b07bb2e47edf3c1fd8068bf0ae610185178 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 5 Nov 2019 18:22:17 +0800 Subject: [PATCH 18/76] Add Nodediscovry --- .../NodeDiscovery/CAP.DiscoveryOptions.cs | 38 +++++++ .../CAP.DiscoveryOptionsExtensions.cs | 56 +++++++++ .../IDiscoveryProviderFactory.Default.cs | 28 +++++ .../IDiscoveryProviderFactory.cs | 10 ++ .../INodeDiscoveryProvider.Consul.cs | 106 ++++++++++++++++++ .../NodeDiscovery/INodeDiscoveryProvider.cs | 15 +++ .../NodeDiscovery/IProcessingServer.Consul.cs | 35 ++++++ .../NodeDiscovery/Node.cs | 18 +++ 8 files changed, 306 insertions(+) create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptions.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.Default.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.Consul.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs create mode 100644 src/DotNetCore.CAP.Dashboard/NodeDiscovery/Node.cs diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptions.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptions.cs new file mode 100644 index 0000000..6b720eb --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptions.cs @@ -0,0 +1,38 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + public class DiscoveryOptions + { + public const string DefaultDiscoveryServerHost = "localhost"; + public const int DefaultDiscoveryServerPort = 8500; + + public const string DefaultCurrentNodeHostName = "localhost"; + public const int DefaultCurrentNodePort = 5000; + + public const string DefaultMatchPath = "/cap"; + + public DiscoveryOptions() + { + DiscoveryServerHostName = DefaultDiscoveryServerHost; + DiscoveryServerPort = DefaultDiscoveryServerPort; + + CurrentNodeHostName = DefaultCurrentNodeHostName; + CurrentNodePort = DefaultCurrentNodePort; + + MatchPath = DefaultMatchPath; + } + + public string DiscoveryServerHostName { get; set; } + public int DiscoveryServerPort { get; set; } + + public string CurrentNodeHostName { get; set; } + public int CurrentNodePort { get; set; } + + public string NodeId { get; set; } + public string NodeName { get; set; } + + public string MatchPath { get; set; } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs new file mode 100644 index 0000000..400e91c --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs @@ -0,0 +1,56 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using DotNetCore.CAP; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + internal sealed class DiscoveryOptionsExtension : ICapOptionsExtension + { + private readonly Action _options; + + public DiscoveryOptionsExtension(Action option) + { + _options = option; + } + + public void AddServices(IServiceCollection services) + { + var discoveryOptions = new DiscoveryOptions(); + + _options?.Invoke(discoveryOptions); + services.AddSingleton(discoveryOptions); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(x => + { + var configOptions = x.GetService(); + var factory = x.GetService(); + return factory.Create(configOptions); + }); + } + } + + public static class CapDiscoveryOptionsExtensions + { + public static CapOptions UseDiscovery(this CapOptions capOptions) + { + return capOptions.UseDiscovery(opt => { }); + } + + public static CapOptions UseDiscovery(this CapOptions capOptions, Action options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + capOptions.RegisterExtension(new DiscoveryOptionsExtension(options)); + + return capOptions; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.Default.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.Default.cs new file mode 100644 index 0000000..38523b7 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.Default.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + internal class DiscoveryProviderFactory : IDiscoveryProviderFactory + { + private readonly ILoggerFactory _loggerFactory; + + public DiscoveryProviderFactory(ILoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + } + + public INodeDiscoveryProvider Create(DiscoveryOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + return new ConsulNodeDiscoveryProvider(_loggerFactory, options); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.cs new file mode 100644 index 0000000..1839f22 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IDiscoveryProviderFactory.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + internal interface IDiscoveryProviderFactory + { + INodeDiscoveryProvider Create(DiscoveryOptions options); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.Consul.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.Consul.cs new file mode 100644 index 0000000..6947b2d --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.Consul.cs @@ -0,0 +1,106 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Consul; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + public class ConsulNodeDiscoveryProvider : INodeDiscoveryProvider, IDisposable + { + private readonly ILogger _logger; + private readonly DiscoveryOptions _options; + private ConsulClient _consul; + + public ConsulNodeDiscoveryProvider(ILoggerFactory logger, DiscoveryOptions options) + { + _logger = logger.CreateLogger(); + _options = options; + + InitClient(); + } + + public void Dispose() + { + _consul.Dispose(); + } + + public async Task> GetNodes() + { + try + { + var nodes = new List(); + var services = await _consul.Catalog.Services(); + foreach (var service in services.Response) + { + var serviceInfo = await _consul.Catalog.Service(service.Key); + var node = serviceInfo.Response.SkipWhile(x => !x.ServiceTags.Contains("CAP")) + .Select(info => new Node + { + Id = info.ServiceID, + Name = info.ServiceName, + Address = info.ServiceAddress, + Port = info.ServicePort, + Tags = string.Join(", ", info.ServiceTags) + }).ToList(); + + nodes.AddRange(node); + } + + CapCache.Global.AddOrUpdate("cap.nodes.count", nodes.Count, TimeSpan.FromSeconds(60), true); + + return nodes; + } + catch (Exception ex) + { + CapCache.Global.AddOrUpdate("cap.nodes.count", 0, TimeSpan.FromSeconds(20)); + + _logger.LogError( + $"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}"); + return null; + } + } + + public Task RegisterNode() + { + try + { + return _consul.Agent.ServiceRegister(new AgentServiceRegistration + { + ID = _options.NodeId, + Name = _options.NodeName, + Address = _options.CurrentNodeHostName, + Port = _options.CurrentNodePort, + Tags = new[] {"CAP", "Client", "Dashboard"}, + Check = new AgentServiceCheck + { + DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30), + Interval = TimeSpan.FromSeconds(10), + Status = HealthStatus.Passing, + HTTP = + $"http://{_options.CurrentNodeHostName}:{_options.CurrentNodePort}{_options.MatchPath}/health" + } + }); + } + catch (Exception ex) + { + _logger.LogError( + $"Get consul nodes raised an exception. Exception:{ex.Message},{ex.InnerException.Message}"); + return null; + } + } + + private void InitClient() + { + _consul = new ConsulClient(config => + { + config.WaitTime = TimeSpan.FromSeconds(5); + config.Address = new Uri($"http://{_options.DiscoveryServerHostName}:{_options.DiscoveryServerPort}"); + }); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.cs new file mode 100644 index 0000000..a598087 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/INodeDiscoveryProvider.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + public interface INodeDiscoveryProvider + { + Task> GetNodes(); + + Task RegisterNode(); + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs new file mode 100644 index 0000000..c801698 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + internal class ConsulProcessingNodeServer : IProcessingServer + { + private readonly DiscoveryOptions _dashboardOptions; + private readonly IDiscoveryProviderFactory _discoveryProviderFactory; + + public ConsulProcessingNodeServer( + DiscoveryOptions dashboardOptions, + IDiscoveryProviderFactory discoveryProviderFactory) + { + _dashboardOptions = dashboardOptions; + _discoveryProviderFactory = discoveryProviderFactory; + } + + public void Start() + { + var discoveryProvider = _discoveryProviderFactory.Create(_dashboardOptions); + + discoveryProvider.RegisterNode(); + } + + public void Pulse() + { + //ignore + } + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/Node.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/Node.cs new file mode 100644 index 0000000..b016b50 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/Node.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Dashboard.NodeDiscovery +{ + public class Node + { + public string Id { get; set; } + + public string Name { get; set; } + + public string Address { get; set; } + + public int Port { get; set; } + + public string Tags { get; set; } + } +} \ No newline at end of file From 200d14a826650aaa3c10c71d7e6a4e0c1c945434 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 5 Nov 2019 18:22:33 +0800 Subject: [PATCH 19/76] remove unused file --- .../IMonitoringApi.cs | 29 ------------------- .../Monitoring/MessageDto.cs | 28 ------------------ .../Monitoring/MessageQueryDto.cs | 23 --------------- .../Monitoring/ServerDto.cs | 12 -------- .../Monitoring/StatisticsDto.cs | 16 ---------- 5 files changed, 108 deletions(-) delete mode 100644 src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs delete mode 100644 src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs delete mode 100644 src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs delete mode 100644 src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs delete mode 100644 src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs diff --git a/src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs b/src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs deleted file mode 100644 index bc8505e..0000000 --- a/src/DotNetCore.CAP.Dashboard/IMonitoringApi.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Dashboard -{ - public interface IMonitoringApi - { - StatisticsDto GetStatistics(); - - IList Messages(MessageQueryDto queryDto); - - int PublishedFailedCount(); - - int PublishedSucceededCount(); - - int ReceivedFailedCount(); - - int ReceivedSucceededCount(); - - IDictionary HourlySucceededJobs(MessageType type); - - IDictionary HourlyFailedJobs(MessageType type); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs deleted file mode 100644 index 233c5b2..0000000 --- a/src/DotNetCore.CAP.Dashboard/Monitoring/MessageDto.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Dashboard.Monitoring -{ - public class MessageDto - { - public long Id { get; set; } - - public string Version { get; set; } - - public string Group { get; set; } - - public string Name { get; set; } - - public string Content { get; set; } - - public DateTime Added { get; set; } - - public DateTime? ExpiresAt { get; set; } - - public int Retries { get; set; } - - public string StatusName { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs deleted file mode 100644 index 61c4706..0000000 --- a/src/DotNetCore.CAP.Dashboard/Monitoring/MessageQueryDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Dashboard.Monitoring -{ - public class MessageQueryDto - { - public MessageType MessageType { get; set; } - - public string Group { get; set; } - public string Name { get; set; } - - public string Content { get; set; } - - public string StatusName { get; set; } - - public int CurrentPage { get; set; } - - public int PageSize { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs deleted file mode 100644 index f332b5e..0000000 --- a/src/DotNetCore.CAP.Dashboard/Monitoring/ServerDto.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.Dashboard.Monitoring -{ - public class SubscriberDto - { - public string Name { get; set; } - - public string Method { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs b/src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs deleted file mode 100644 index 7c7a529..0000000 --- a/src/DotNetCore.CAP.Dashboard/Monitoring/StatisticsDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -namespace DotNetCore.CAP.Dashboard.Monitoring -{ - public class StatisticsDto - { - public int Servers { get; set; } - - public int PublishedSucceeded { get; set; } - public int ReceivedSucceeded { get; set; } - - public int PublishedFailed { get; set; } - public int ReceivedFailed { get; set; } - } -} \ No newline at end of file From c4f4f5f484942f89853ec3934d6e1461b83f2a6f Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 5 Nov 2019 18:26:28 +0800 Subject: [PATCH 20/76] upgrade dashoboard module --- .../Controllers/ValuesController.cs | 7 + .../Sample.RabbitMQ.MySql.csproj | 1 + samples/Sample.RabbitMQ.MySql/Startup.cs | 2 +- src/DotNetCore.CAP.Dashboard/AwaitableInfo.cs | 128 +++ .../CAP.DashboardMiddleware.cs | 74 +- .../CAP.DashboardOptionsExtensions.cs | 3 + src/DotNetCore.CAP.Dashboard/CapCache.cs | 378 ++++++++ .../CoercedAwaitableInfo.cs | 44 + .../CombinedResourceDispatcher.cs | 11 +- .../DashboardContext.cs | 7 +- .../DashboardRoutes.cs | 10 +- .../DotNetCore.CAP.Dashboard.csproj | 168 +++- .../EmbeddedResourceDispatcher.cs | 15 +- .../GatewayProxy/GatewayProxyMiddleware.cs | 2 +- src/DotNetCore.CAP.Dashboard/HtmlHelper.cs | 2 +- .../JsonDispatcher.cs | 2 +- src/DotNetCore.CAP.Dashboard/JsonStats.cs | 4 +- .../LocalRequestsOnlyAuthorizationFilter.cs | 2 +- .../MessageHistoryRenderer.cs | 18 +- .../Pages/BlockMetric.cs | 4 +- .../Pages/HomePage.generated.cs | 438 +++++---- .../Pages/LayoutPage.generated.cs | 419 +++++---- .../Pages/NodePage.cs | 2 +- .../Pages/NodePage.generated.cs | 325 ++++--- .../Pages/PublishedPage.cs | 9 +- .../Pages/PublishedPage.cshtml | 8 +- .../Pages/PublishedPage.generated.cs | 870 +++++++++--------- .../Pages/ReceivedPage.cs | 3 +- .../Pages/ReceivedPage.cshtml | 2 +- .../Pages/ReceivedPage.generated.cs | 852 ++++++++--------- .../Pages/SubscriberPage.generated.cs | 131 ++- .../Pages/_BlockMetric.cshtml | 11 +- .../Pages/_BlockMetric.generated.cs | 32 +- .../Pages/_Breadcrumbs.generated.cs | 32 +- .../Pages/_InlineMetric.generated.cs | 14 +- .../Pages/_Navigation.generated.cs | 31 +- .../Pages/_Paginator.generated.cs | 50 +- .../Pages/_PerPageSelector.generated.cs | 46 +- .../Pages/_SidebarMenu.generated.cs | 32 +- src/DotNetCore.CAP.Dashboard/RazorPage.cs | 12 +- src/DotNetCore.CAP.MySql/MySqlDataStorage.cs | 29 +- src/DotNetCore.CAP/Internal/Helper.cs | 8 + .../Internal/MethodMatcherCache.cs | 2 +- .../Persistence/IDataStorage.cs | 12 +- .../Persistence/MediumMessage.cs | 2 + 45 files changed, 2481 insertions(+), 1773 deletions(-) create mode 100644 src/DotNetCore.CAP.Dashboard/AwaitableInfo.cs create mode 100644 src/DotNetCore.CAP.Dashboard/CapCache.cs create mode 100644 src/DotNetCore.CAP.Dashboard/CoercedAwaitableInfo.cs diff --git a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs index 8e9ae75..ae934e7 100644 --- a/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.RabbitMQ.MySql/Controllers/ValuesController.cs @@ -75,5 +75,12 @@ namespace Sample.RabbitMQ.MySql.Controllers { Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); } + + [NonAction] + [CapSubscribe("sample.rabbitmq.mysql", Group = "group.test2")] + public void Subscriber2(DateTime p, [FromCap]CapHeader header) + { + Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); + } } } diff --git a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj index ce72296..5e1dcee 100644 --- a/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj +++ b/samples/Sample.RabbitMQ.MySql/Sample.RabbitMQ.MySql.csproj @@ -8,6 +8,7 @@ + diff --git a/samples/Sample.RabbitMQ.MySql/Startup.cs b/samples/Sample.RabbitMQ.MySql/Startup.cs index f29e53f..3b76a4b 100644 --- a/samples/Sample.RabbitMQ.MySql/Startup.cs +++ b/samples/Sample.RabbitMQ.MySql/Startup.cs @@ -15,7 +15,7 @@ namespace Sample.RabbitMQ.MySql { x.UseEntityFramework(); x.UseRabbitMQ("192.168.2.120"); - //x.UseDashboard(); + x.UseDashboard(); x.FailedRetryCount = 5; x.FailedThresholdCallback = (type, msg) => { diff --git a/src/DotNetCore.CAP.Dashboard/AwaitableInfo.cs b/src/DotNetCore.CAP.Dashboard/AwaitableInfo.cs new file mode 100644 index 0000000..5c494e9 --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/AwaitableInfo.cs @@ -0,0 +1,128 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Microsoft.Extensions.Internal +{ + internal struct AwaitableInfo + { + public Type AwaiterType { get; } + public PropertyInfo AwaiterIsCompletedProperty { get; } + public MethodInfo AwaiterGetResultMethod { get; } + public MethodInfo AwaiterOnCompletedMethod { get; } + public MethodInfo AwaiterUnsafeOnCompletedMethod { get; } + public Type ResultType { get; } + public MethodInfo GetAwaiterMethod { get; } + + public AwaitableInfo( + Type awaiterType, + PropertyInfo awaiterIsCompletedProperty, + MethodInfo awaiterGetResultMethod, + MethodInfo awaiterOnCompletedMethod, + MethodInfo awaiterUnsafeOnCompletedMethod, + Type resultType, + MethodInfo getAwaiterMethod) + { + AwaiterType = awaiterType; + AwaiterIsCompletedProperty = awaiterIsCompletedProperty; + AwaiterGetResultMethod = awaiterGetResultMethod; + AwaiterOnCompletedMethod = awaiterOnCompletedMethod; + AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod; + ResultType = resultType; + GetAwaiterMethod = getAwaiterMethod; + } + + public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo) + { + // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347 + + // Awaitable must have method matching "object GetAwaiter()" + var getAwaiterMethod = type.GetRuntimeMethods().FirstOrDefault(m => + m.Name.Equals("GetAwaiter", StringComparison.OrdinalIgnoreCase) + && m.GetParameters().Length == 0 + && m.ReturnType != null); + if (getAwaiterMethod == null) + { + awaitableInfo = default(AwaitableInfo); + return false; + } + + var awaiterType = getAwaiterMethod.ReturnType; + + // Awaiter must have property matching "bool IsCompleted { get; }" + var isCompletedProperty = awaiterType.GetRuntimeProperties().FirstOrDefault(p => + p.Name.Equals("IsCompleted", StringComparison.OrdinalIgnoreCase) + && p.PropertyType == typeof(bool) + && p.GetMethod != null); + if (isCompletedProperty == null) + { + awaitableInfo = default(AwaitableInfo); + return false; + } + + // Awaiter must implement INotifyCompletion + var awaiterInterfaces = awaiterType.GetInterfaces(); + var implementsINotifyCompletion = awaiterInterfaces.Any(t => t == typeof(INotifyCompletion)); + if (!implementsINotifyCompletion) + { + awaitableInfo = default(AwaitableInfo); + return false; + } + + // INotifyCompletion supplies a method matching "void OnCompleted(Action action)" + var iNotifyCompletionMap = awaiterType + .GetTypeInfo() + .GetRuntimeInterfaceMap(typeof(INotifyCompletion)); + var onCompletedMethod = iNotifyCompletionMap.InterfaceMethods.Single(m => + m.Name.Equals("OnCompleted", StringComparison.OrdinalIgnoreCase) + && m.ReturnType == typeof(void) + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(Action)); + + // Awaiter optionally implements ICriticalNotifyCompletion + var implementsICriticalNotifyCompletion = + awaiterInterfaces.Any(t => t == typeof(ICriticalNotifyCompletion)); + MethodInfo unsafeOnCompletedMethod; + if (implementsICriticalNotifyCompletion) + { + // ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)" + var iCriticalNotifyCompletionMap = awaiterType + .GetTypeInfo() + .GetRuntimeInterfaceMap(typeof(ICriticalNotifyCompletion)); + unsafeOnCompletedMethod = iCriticalNotifyCompletionMap.InterfaceMethods.Single(m => + m.Name.Equals("UnsafeOnCompleted", StringComparison.OrdinalIgnoreCase) + && m.ReturnType == typeof(void) + && m.GetParameters().Length == 1 + && m.GetParameters()[0].ParameterType == typeof(Action)); + } + else + { + unsafeOnCompletedMethod = null; + } + + // Awaiter must have method matching "void GetResult" or "T GetResult()" + var getResultMethod = awaiterType.GetRuntimeMethods().FirstOrDefault(m => + m.Name.Equals("GetResult") + && m.GetParameters().Length == 0); + if (getResultMethod == null) + { + awaitableInfo = default(AwaitableInfo); + return false; + } + + awaitableInfo = new AwaitableInfo( + awaiterType, + isCompletedProperty, + getResultMethod, + onCompletedMethod, + unsafeOnCompletedMethod, + getResultMethod.ReturnType, + getAwaiterMethod); + return true; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs b/src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs index 70d85be..543cf33 100644 --- a/src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs +++ b/src/DotNetCore.CAP.Dashboard/CAP.DashboardMiddleware.cs @@ -6,19 +6,89 @@ using System.Linq; using System.Net; using System.Threading.Tasks; using DotNetCore.CAP.Dashboard; +using DotNetCore.CAP.Dashboard.GatewayProxy; +using DotNetCore.CAP.Dashboard.NodeDiscovery; +using DotNetCore.CAP.Persistence; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace namespace DotNetCore.CAP { + public static class CapBuilderExtension + { + public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + CheckRequirement(app); + + var provider = app.ApplicationServices; + + if (provider.GetService() != null) + { + if (provider.GetService() != null) + { + app.UseMiddleware(); + } + + app.UseMiddleware(); + } + + return app; + } + + private static void CheckRequirement(IApplicationBuilder app) + { + var marker = app.ApplicationServices.GetService(); + if (marker == null) + { + throw new InvalidOperationException( + "AddCap() must be called on the service collection. eg: services.AddCap(...)"); + } + + var messageQueueMarker = app.ApplicationServices.GetService(); + if (messageQueueMarker == null) + { + throw new InvalidOperationException( + "You must be config used message queue provider at AddCap() options! eg: services.AddCap(options=>{ options.UseKafka(...) })"); + } + + var databaseMarker = app.ApplicationServices.GetService(); + if (databaseMarker == null) + { + throw new InvalidOperationException( + "You must be config used database provider at AddCap() options! eg: services.AddCap(options=>{ options.UseSqlServer(...) })"); + } + } + } + + sealed class CapStartupFilter : IStartupFilter + { + public Action Configure(Action next) + { + return app => + { + app.UseCapDashboard(); + + next(app); + }; + } + } + public class DashboardMiddleware { private readonly RequestDelegate _next; private readonly DashboardOptions _options; private readonly RouteCollection _routes; - private readonly IStorage _storage; + private readonly IDataStorage _storage; - public DashboardMiddleware(RequestDelegate next, DashboardOptions options, IStorage storage, + public DashboardMiddleware(RequestDelegate next, DashboardOptions options, IDataStorage storage, RouteCollection routes) { _next = next ?? throw new ArgumentNullException(nameof(next)); diff --git a/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs b/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs index cfc1bf5..5a27d66 100644 --- a/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs +++ b/src/DotNetCore.CAP.Dashboard/CAP.DashboardOptionsExtensions.cs @@ -6,6 +6,7 @@ using DotNetCore.CAP; using DotNetCore.CAP.Dashboard; using DotNetCore.CAP.Dashboard.GatewayProxy; using DotNetCore.CAP.Dashboard.GatewayProxy.Requester; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP @@ -23,11 +24,13 @@ namespace DotNetCore.CAP { var dashboardOptions = new DashboardOptions(); _options?.Invoke(dashboardOptions); + services.AddTransient(); services.AddSingleton(dashboardOptions); services.AddSingleton(DashboardRoutes.Routes); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + } } } diff --git a/src/DotNetCore.CAP.Dashboard/CapCache.cs b/src/DotNetCore.CAP.Dashboard/CapCache.cs new file mode 100644 index 0000000..2aa827b --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/CapCache.cs @@ -0,0 +1,378 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace DotNetCore.CAP.Dashboard +{ + #region Cache class + + /// + /// This is a generic cache subsystem based on key/value pairs, where key is generic, too. Key must be unique. + /// Every cache entry has its own timeout. + /// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on + /// threads). + /// + // ReSharper disable once InheritdocConsiderUsage + // ReSharper disable once InconsistentNaming + internal class Cache : IDisposable + { + #region Constructor and class members + + private readonly Dictionary _cache = new Dictionary(); + private readonly Dictionary _timers = new Dictionary(); + private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); + + #endregion + + #region IDisposable implementation & Clear + + private bool disposed; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + disposed = true; + + if (disposing) + { + // Dispose managed resources. + Clear(); + _locker.Dispose(); + } + + // Dispose unmanaged resources + } + } + + /// + /// Clears the entire cache and disposes all active timers. + /// + public void Clear() + { + _locker.EnterWriteLock(); + try + { + try + { + foreach (var t in _timers.Values) + { + t.Dispose(); + } + } + catch + { + } + + _timers.Clear(); + _cache.Clear(); + } + finally + { + _locker.ExitWriteLock(); + } + } + + #endregion + + #region CheckTimer + + // Checks whether a specific timer already exists and adds a new one, if not + private void CheckTimer(K key, TimeSpan? cacheTimeout, bool restartTimerIfExists) + { + Timer timer; + + if (_timers.TryGetValue(key, out timer)) + { + if (restartTimerIfExists) + { + timer.Change( + cacheTimeout ?? Timeout.InfiniteTimeSpan, + Timeout.InfiniteTimeSpan); + } + } + else + { + _timers.Add( + key, + new Timer( + RemoveByTimer, + key, + cacheTimeout ?? Timeout.InfiniteTimeSpan, + Timeout.InfiniteTimeSpan)); + } + } + + private void RemoveByTimer(object state) + { + Remove((K) state); + } + + #endregion + + #region AddOrUpdate, Get, Remove, Exists, Clear + + /// + /// Adds or updates the specified cache-key with the specified cacheObject and applies a specified timeout (in seconds) + /// to this key. + /// + /// The cache-key to add or update. + /// The cache object to store. + /// + /// The cache timeout (lifespan) of this object. Must be 1 or greater. + /// Specify Timeout.Infinite to keep the entry forever. + /// + /// + /// (Optional). If set to true, the timer for this cacheObject will be reset if the object already + /// exists in the cache. (Default = false). + /// + public void AddOrUpdate(K key, T cacheObject, TimeSpan? cacheTimeout, bool restartTimerIfExists = false) + { + if (disposed) + { + return; + } + + _locker.EnterWriteLock(); + try + { + CheckTimer(key, cacheTimeout, restartTimerIfExists); + + if (!_cache.ContainsKey(key)) + { + _cache.Add(key, cacheObject); + } + else + { + _cache[key] = cacheObject; + } + } + finally + { + _locker.ExitWriteLock(); + } + } + + /// + /// Adds or updates the specified cache-key with the specified cacheObject and applies Timeout.Infinite to this + /// key. + /// + /// The cache-key to add or update. + /// The cache object to store. + public void AddOrUpdate(K key, T cacheObject) + { + AddOrUpdate(key, cacheObject, Timeout.InfiniteTimeSpan); + } + + /// + /// Gets the cache entry with the specified key or returns default(T) if the key is not found. + /// + /// The cache-key to retrieve. + /// The object from the cache or default(T), if not found. + public T this[K key] => Get(key); + + /// + /// Gets the cache entry with the specified key or return default(T) if the key is not found. + /// + /// The cache-key to retrieve. + /// The object from the cache or default(T), if not found. + public T Get(K key) + { + if (disposed) + { + return default(T); + } + + _locker.EnterReadLock(); + try + { + T rv; + return _cache.TryGetValue(key, out rv) ? rv : default(T); + } + finally + { + _locker.ExitReadLock(); + } + } + + /// + /// Tries to gets the cache entry with the specified key. + /// + /// The key. + /// (out) The value, if found, or default(T), if not. + /// True, if key exists, otherwise false. + public bool TryGet(K key, out T value) + { + if (disposed) + { + value = default(T); + return false; + } + + _locker.EnterReadLock(); + try + { + return _cache.TryGetValue(key, out value); + } + finally + { + _locker.ExitReadLock(); + } + } + + /// + /// Removes a series of cache entries in a single call for all key that match the specified key pattern. + /// + /// The key pattern to remove. The Predicate has to return true to get key removed. + public void Remove(Predicate keyPattern) + { + if (disposed) + { + return; + } + + _locker.EnterWriteLock(); + try + { + var removers = (from k in _cache.Keys.Cast() + where keyPattern(k) + select k).ToList(); + + foreach (var workKey in removers) + { + try + { + _timers[workKey].Dispose(); + } + catch + { + } + + _timers.Remove(workKey); + _cache.Remove(workKey); + } + } + finally + { + _locker.ExitWriteLock(); + } + } + + /// + /// Removes the specified cache entry with the specified key. + /// If the key is not found, no exception is thrown, the statement is just ignored. + /// + /// The cache-key to remove. + public void Remove(K key) + { + if (disposed) + { + return; + } + + _locker.EnterWriteLock(); + try + { + if (_cache.ContainsKey(key)) + { + try + { + _timers[key].Dispose(); + } + catch + { + } + + _timers.Remove(key); + _cache.Remove(key); + } + } + finally + { + _locker.ExitWriteLock(); + } + } + + /// + /// Checks if a specified key exists in the cache. + /// + /// The cache-key to check. + /// True if the key exists in the cache, otherwise False. + public bool Exists(K key) + { + if (disposed) + { + return false; + } + + _locker.EnterReadLock(); + try + { + return _cache.ContainsKey(key); + } + finally + { + _locker.ExitReadLock(); + } + } + + #endregion + } + + #endregion + + #region Other Cache classes (derived) + + /// + /// This is a generic cache subsystem based on key/value pairs, where key is a string. + /// You can add any item to this cache as long as the key is unique, so treat keys as something like namespaces and + /// build them with a + /// specific system/syntax in your application. + /// Every cache entry has its own timeout. + /// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on + /// threads). + /// + /// + /// The non-generic Cache class instanciates a Cache{object} that can be used with any type of (mixed) contents. + /// It also publishes a static .Global member, so a cache can be used even without creating a dedicated + /// instance. + /// The .Global member is lazy instanciated. + /// + internal class CapCache : Cache + { + #region Static Global Cache instance + + private static readonly Lazy global = new Lazy(); + + /// + /// Gets the global shared cache instance valid for the entire process. + /// + /// + /// The global shared cache instance. + /// + public static CapCache Global => global.Value; + + #endregion + } + + #endregion +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/CoercedAwaitableInfo.cs b/src/DotNetCore.CAP.Dashboard/CoercedAwaitableInfo.cs new file mode 100644 index 0000000..be1725f --- /dev/null +++ b/src/DotNetCore.CAP.Dashboard/CoercedAwaitableInfo.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Linq.Expressions; +using Microsoft.Extensions.Internal; + +namespace DotNetCore.CAP.Dashboard +{ + internal struct CoercedAwaitableInfo + { + public AwaitableInfo AwaitableInfo { get; } + public Expression CoercerExpression { get; } + public Type CoercerResultType { get; } + public bool RequiresCoercion => CoercerExpression != null; + + public CoercedAwaitableInfo(AwaitableInfo awaitableInfo) + { + AwaitableInfo = awaitableInfo; + CoercerExpression = null; + CoercerResultType = null; + } + + public CoercedAwaitableInfo(Expression coercerExpression, Type coercerResultType, + AwaitableInfo coercedAwaitableInfo) + { + CoercerExpression = coercerExpression; + CoercerResultType = coercerResultType; + AwaitableInfo = coercedAwaitableInfo; + } + + public static bool IsTypeAwaitable(Type type, out CoercedAwaitableInfo info) + { + if (AwaitableInfo.IsTypeAwaitable(type, out var directlyAwaitableInfo)) + { + info = new CoercedAwaitableInfo(directlyAwaitableInfo); + return true; + } + + info = default(CoercedAwaitableInfo); + return false; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs b/src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs index 65875c4..e8e5f2a 100644 --- a/src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs +++ b/src/DotNetCore.CAP.Dashboard/CombinedResourceDispatcher.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Reflection; +using System.Threading.Tasks; namespace DotNetCore.CAP.Dashboard { @@ -22,14 +23,14 @@ namespace DotNetCore.CAP.Dashboard _resourceNames = resourceNames; } - protected override void WriteResponse(DashboardResponse response) + protected override async Task WriteResponse(DashboardResponse response) { foreach (var resourceName in _resourceNames) { - WriteResource( - response, - _assembly, - $"{_baseNamespace}.{resourceName}"); + await WriteResource( + response, + _assembly, + $"{_baseNamespace}.{resourceName}"); } } } diff --git a/src/DotNetCore.CAP.Dashboard/DashboardContext.cs b/src/DotNetCore.CAP.Dashboard/DashboardContext.cs index c97a308..00b5655 100644 --- a/src/DotNetCore.CAP.Dashboard/DashboardContext.cs +++ b/src/DotNetCore.CAP.Dashboard/DashboardContext.cs @@ -3,13 +3,14 @@ using System; using System.Text.RegularExpressions; +using DotNetCore.CAP.Persistence; using Microsoft.AspNetCore.Http; namespace DotNetCore.CAP.Dashboard { public abstract class DashboardContext { - protected DashboardContext(IStorage storage, DashboardOptions options) + protected DashboardContext(IDataStorage storage, DashboardOptions options) { if (storage == null) { @@ -25,7 +26,7 @@ namespace DotNetCore.CAP.Dashboard Options = options; } - public IStorage Storage { get; } + public IDataStorage Storage { get; } public DashboardOptions Options { get; } @@ -41,7 +42,7 @@ namespace DotNetCore.CAP.Dashboard public sealed class CapDashboardContext : DashboardContext { public CapDashboardContext( - IStorage storage, + IDataStorage storage, DashboardOptions options, HttpContext httpContext) : base(storage, options) diff --git a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs index 34f3aee..3ba3ba8 100644 --- a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs +++ b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs @@ -83,14 +83,14 @@ namespace DotNetCore.CAP.Dashboard Routes.AddJsonResult("/published/message/(?.+)", x => { var id = long.Parse(x.UriMatch.Groups["Id"].Value); - var message = x.Storage.GetConnection().GetPublishedMessageAsync(id) + var message = x.Storage.GetMonitoringApi().GetPublishedMessageAsync(id) .GetAwaiter().GetResult(); return message.Content; }); Routes.AddJsonResult("/received/message/(?.+)", x => { var id = long.Parse(x.UriMatch.Groups["Id"].Value); - var message = x.Storage.GetConnection().GetReceivedMessageAsync(id) + var message = x.Storage.GetMonitoringApi().GetReceivedMessageAsync(id) .GetAwaiter().GetResult(); return message.Content; }); @@ -99,7 +99,7 @@ namespace DotNetCore.CAP.Dashboard "/published/requeue", (client, messageId) => { - var msg = client.Storage.GetConnection().GetPublishedMessageAsync(messageId) + var msg = client.Storage.GetMonitoringApi().GetPublishedMessageAsync(messageId) .GetAwaiter().GetResult(); client.RequestServices.GetService().EnqueueToPublish(msg); }); @@ -107,9 +107,9 @@ namespace DotNetCore.CAP.Dashboard "/received/requeue", (client, messageId) => { - var msg = client.Storage.GetConnection().GetReceivedMessageAsync(messageId) + var msg = client.Storage.GetMonitoringApi().GetReceivedMessageAsync(messageId) .GetAwaiter().GetResult(); - client.RequestServices.GetService().EnqueueToExecute(msg); + client.RequestServices.GetService().ExecuteAsync(msg); }); Routes.AddRazorPage( diff --git a/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj b/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj index 1d40d14..d934d76 100644 --- a/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj +++ b/src/DotNetCore.CAP.Dashboard/DotNetCore.CAP.Dashboard.csproj @@ -2,8 +2,21 @@ netstandard2.0 + false + 1591 + + C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe + Razor.build + GenerateRazorClasses;Build + + + + + + + @@ -25,83 +38,129 @@ + + + + + + + + - + True True Strings.resx - + + True + True + _BlockMetric.cshtml + + _SidebarMenu.cshtml + True + True - + _SidebarMenu.cshtml - + ReceivedPage.cshtml + True + True - + ReceivedPage.cshtml - - _BlockMetric.cshtml - - + _BlockMetric.cshtml - + _Breadcrumbs.cshtml - + _Breadcrumbs.cshtml + True + True - + _Paginator.cshtml + True + True - + _Paginator.cshtml - + _PerPageSelector.cshtml - + _PerPageSelector.cshtml + True + True - + PublishedPage.cshtml - + PublishedPage.cshtml - + LayoutPage.cshtml - + LayoutPage.cshtml - + _InlineMetric.cshtml - + + True + True + LayoutPage.cshtml + + + True + True + PublishedPage.cshtml + + _InlineMetric.cshtml + True + True - + _Navigation.cshtml + True + True - + HomePage.cshtml + True + True - + HomePage.cshtml - + SubscriberPage.cshtml + True + True + + + NodePage.cshtml - + + + + + True + True NodePage.cshtml @@ -115,11 +174,66 @@ - + PublicResXFileCodeGenerator DotNetCore.CAP.Dashboard.Resources Strings.Designer.cs + + + RazorGenerator + HomePage.generated.cs + + + RazorGenerator + LayoutPage.generated.cs + + + RazorGenerator + NodePage.generated.cs + + + RazorGenerator + PublishedPage.generated.cs + + + RazorGenerator + ReceivedPage.generated.cs + + + RazorGenerator + SubscriberPage.generated.cs + + + RazorGenerator + _BlockMetric.generated.cs + + + RazorGenerator + _Breadcrumbs.generated.cs + + + RazorGenerator + _InlineMetric.generated.cs + + + RazorGenerator + _Navigation.generated.cs + + + RazorGenerator + _Paginator.generated.cs + + + RazorGenerator + _PerPageSelector.generated.cs + + + RazorGenerator + _SidebarMenu.generated.cs + + + diff --git a/src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs b/src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs index c48257c..926bfdf 100644 --- a/src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs +++ b/src/DotNetCore.CAP.Dashboard/EmbeddedResourceDispatcher.cs @@ -30,22 +30,20 @@ namespace DotNetCore.CAP.Dashboard } } - public Task Dispatch(DashboardContext context) + public async Task Dispatch(DashboardContext context) { context.Response.ContentType = _contentType; context.Response.SetExpire(DateTimeOffset.Now.AddYears(1)); - WriteResponse(context.Response); - - return Task.FromResult(true); + await WriteResponse(context.Response); } - protected virtual void WriteResponse(DashboardResponse response) + protected virtual Task WriteResponse(DashboardResponse response) { - WriteResource(response, _assembly, _resourceName); + return WriteResource(response, _assembly, _resourceName); } - protected void WriteResource(DashboardResponse response, Assembly assembly, string resourceName) + protected async Task WriteResource(DashboardResponse response, Assembly assembly, string resourceName) { using (var inputStream = assembly.GetManifestResourceStream(resourceName)) { @@ -54,8 +52,7 @@ namespace DotNetCore.CAP.Dashboard throw new ArgumentException( $@"Resource with name {resourceName} not found in assembly {assembly}."); } - - inputStream.CopyTo(response.Body); + await inputStream.CopyToAsync(response.Body); } } } diff --git a/src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs b/src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs index 000f9b1..57df839 100644 --- a/src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs +++ b/src/DotNetCore.CAP.Dashboard/GatewayProxy/GatewayProxyMiddleware.cs @@ -9,7 +9,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using DotNetCore.CAP.Dashboard.GatewayProxy.Requester; -using DotNetCore.CAP.NodeDiscovery; +using DotNetCore.CAP.Dashboard.NodeDiscovery; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; diff --git a/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs b/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs index 6b896a7..6721235 100644 --- a/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs +++ b/src/DotNetCore.CAP.Dashboard/HtmlHelper.cs @@ -10,7 +10,7 @@ using System.Text; using System.Text.RegularExpressions; using DotNetCore.CAP.Dashboard.Pages; using DotNetCore.CAP.Dashboard.Resources; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using Microsoft.Extensions.Internal; diff --git a/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs b/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs index dc6df96..97e1259 100644 --- a/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs +++ b/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs @@ -38,7 +38,7 @@ namespace DotNetCore.CAP.Dashboard { new StringEnumConverter { - NamingStrategy = new CamelCaseNamingStrategy() + CamelCaseText= true } } }; diff --git a/src/DotNetCore.CAP.Dashboard/JsonStats.cs b/src/DotNetCore.CAP.Dashboard/JsonStats.cs index 126fc42..6e13ccf 100644 --- a/src/DotNetCore.CAP.Dashboard/JsonStats.cs +++ b/src/DotNetCore.CAP.Dashboard/JsonStats.cs @@ -34,7 +34,7 @@ namespace DotNetCore.CAP.Dashboard { new StringEnumConverter { - NamingStrategy = new CamelCaseNamingStrategy() + CamelCaseText = true } } }; @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.Dashboard private class StubPage : RazorPage { - protected override void Execute() + public override void Execute() { } } diff --git a/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs b/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs index dafd845..0a26fad 100644 --- a/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs +++ b/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; namespace DotNetCore.CAP.Dashboard { diff --git a/src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs b/src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs index 2df3b98..32db299 100644 --- a/src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs +++ b/src/DotNetCore.CAP.Dashboard/MessageHistoryRenderer.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Text; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; namespace DotNetCore.CAP.Dashboard { @@ -24,16 +24,16 @@ namespace DotNetCore.CAP.Dashboard [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] static MessageHistoryRenderer() { - Register(StatusName.Succeeded, SucceededRenderer); - Register(StatusName.Failed, FailedRenderer); + Register(nameof(StatusName.Succeeded), SucceededRenderer); + Register(nameof(StatusName.Failed), FailedRenderer); - BackgroundStateColors.Add(StatusName.Succeeded, "#EDF7ED"); - BackgroundStateColors.Add(StatusName.Failed, "#FAEBEA"); - BackgroundStateColors.Add(StatusName.Scheduled, "#E0F3F8"); + BackgroundStateColors.Add(nameof(StatusName.Succeeded), "#EDF7ED"); + BackgroundStateColors.Add(nameof(StatusName.Failed), "#FAEBEA"); + BackgroundStateColors.Add(nameof(StatusName.Scheduled), "#E0F3F8"); - ForegroundStateColors.Add(StatusName.Succeeded, "#5cb85c"); - ForegroundStateColors.Add(StatusName.Failed, "#d9534f"); - ForegroundStateColors.Add(StatusName.Scheduled, "#5bc0de"); + ForegroundStateColors.Add(nameof(StatusName.Succeeded), "#5cb85c"); + ForegroundStateColors.Add(nameof(StatusName.Failed), "#d9534f"); + ForegroundStateColors.Add(nameof(StatusName.Scheduled), "#5bc0de"); } public static void AddBackgroundStateColor(string stateName, string color) diff --git a/src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs b/src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs index faa0c84..d36ec3f 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/BlockMetric.cs @@ -7,9 +7,9 @@ namespace DotNetCore.CAP.Dashboard.Pages { public BlockMetric(DashboardMetric dashboardMetric) { - DashboardMetric = dashboardMetric; + Metric = dashboardMetric; } - public DashboardMetric DashboardMetric { get; } + public DashboardMetric Metric { get; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs index 12947d4..060844e 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/HomePage.generated.cs @@ -1,6 +1,4 @@ -using DotNetCore.CAP.Messages; - -#pragma warning disable 1591 +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -13,63 +11,45 @@ namespace DotNetCore.CAP.Dashboard.Pages { - -#line 2 "..\..\HomePage.cshtml" using System; - -#line default -#line hidden - -#line 3 "..\..\HomePage.cshtml" using System.Collections.Generic; - -#line default -#line hidden using System.Linq; using System.Text; - -#line 5 "..\..\HomePage.cshtml" - using DotNetCore.CAP.Dashboard; - -#line default -#line hidden - -#line 6 "..\..\HomePage.cshtml" + + #line 2 "..\..\Pages\HomePage.cshtml" using DotNetCore.CAP.Dashboard.Pages; - -#line default -#line hidden - -#line 7 "..\..\HomePage.cshtml" + + #line default + #line hidden + + #line 3 "..\..\Pages\HomePage.cshtml" using DotNetCore.CAP.Dashboard.Resources; - -#line default -#line hidden - -#line 4 "..\..\HomePage.cshtml" -#line default -#line hidden - -#line 8 "..\..\HomePage.cshtml" + + #line default + #line hidden + + #line 4 "..\..\Pages\HomePage.cshtml" + using DotNetCore.CAP.Messages; + + #line default + #line hidden + + #line 5 "..\..\Pages\HomePage.cshtml" using Newtonsoft.Json; - -#line default -#line hidden - + + #line default + #line hidden + [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class HomePage : RazorPage + internal partial class HomePage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { - WriteLiteral("\r\n"); - - - - +WriteLiteral("\r\n"); @@ -77,175 +57,177 @@ namespace DotNetCore.CAP.Dashboard.Pages -#line 10 "..\..\HomePage.cshtml" + + #line 7 "..\..\Pages\HomePage.cshtml" + + Layout = new LayoutPage(Strings.HomePage_Title); - Layout = new LayoutPage(Strings.HomePage_Title); + var monitor = Storage.GetMonitoringApi(); + var publishedSucceeded = monitor.HourlySucceededJobs(MessageType.Publish); + var publishedFailed = monitor.HourlyFailedJobs(MessageType.Publish); - var monitor = Storage.GetMonitoringApi(); - IDictionary publishedSucceeded = monitor.HourlySucceededJobs(MessageType.Publish); - IDictionary publishedFailed = monitor.HourlyFailedJobs(MessageType.Publish); + var receivedSucceeded = monitor.HourlySucceededJobs(MessageType.Subscribe); + var receivedFailed = monitor.HourlyFailedJobs(MessageType.Subscribe); - IDictionary receivedSucceeded = monitor.HourlySucceededJobs(MessageType.Subscribe); - IDictionary receivedFailed = monitor.HourlyFailedJobs(MessageType.Subscribe); + + #line default + #line hidden +WriteLiteral("\r\n
\r\n
\r\n

"); -#line default -#line hidden - WriteLiteral("\r\n
\r\n
\r\n

"); - - - -#line 23 "..\..\HomePage.cshtml" - Write(Strings.HomePage_Title); - - -#line default -#line hidden - WriteLiteral("

\r\n"); + + #line 20 "..\..\Pages\HomePage.cshtml" + Write(Strings.HomePage_Title); + + #line default + #line hidden +WriteLiteral("

\r\n"); -#line 24 "..\..\HomePage.cshtml" - if (Metrics.Count > 0) - { - - -#line default -#line hidden - WriteLiteral("
\r\n"); + + #line 21 "..\..\Pages\HomePage.cshtml" + if (Metrics.Count > 0) + { + + #line default + #line hidden +WriteLiteral("
\r\n"); -#line 27 "..\..\HomePage.cshtml" - foreach (var metric in Metrics) + + #line 24 "..\..\Pages\HomePage.cshtml" + foreach (var metric in Metrics) { + + #line default + #line hidden +WriteLiteral("
\r\n "); -#line default -#line hidden - WriteLiteral("
\r\n "); - - - -#line 30 "..\..\HomePage.cshtml" - Write(Html.BlockMetric(metric)); + + #line 27 "..\..\Pages\HomePage.cshtml" + Write(Html.BlockMetric(metric)); -#line default -#line hidden - WriteLiteral("\r\n
\r\n"); - + + #line default + #line hidden +WriteLiteral("\r\n
\r\n"); -#line 32 "..\..\HomePage.cshtml" + + #line 29 "..\..\Pages\HomePage.cshtml" } - -#line default -#line hidden - WriteLiteral("
\r\n"); - - - -#line 34 "..\..\HomePage.cshtml" - } - - -#line default -#line hidden - WriteLiteral("

"); - + + #line default + #line hidden +WriteLiteral("

\r\n"); -#line 35 "..\..\HomePage.cshtml" - Write(Strings.HomePage_RealtimeGraph); - - -#line default -#line hidden - WriteLiteral("\r\n
@@ -257,95 +239,95 @@ namespace DotNetCore.CAP.Dashboard.Pages "); + + #line 51 "..\..\Pages\HomePage.cshtml" + Write(Strings.HomePage_HistoryGraph); -#line 53 "..\..\HomePage.cshtml" - Write(Strings.HomePage_HistoryGraph); - + + #line default + #line hidden +WriteLiteral("\r\n \r\n\r\n \r\n
"); + + #line default + #line hidden +WriteLiteral("\">\r\n
\r\n
\r\n"); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs index 374062b..1e1fccf 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/LayoutPage.generated.cs @@ -11,313 +11,306 @@ namespace DotNetCore.CAP.Dashboard.Pages { - -#line 2 "..\..\LayoutPage.cshtml" + + #line 2 "..\..\Pages\LayoutPage.cshtml" using System; - -#line default -#line hidden + + #line default + #line hidden using System.Collections.Generic; - -#line 3 "..\..\LayoutPage.cshtml" + + #line 3 "..\..\Pages\LayoutPage.cshtml" using System.Globalization; - -#line default -#line hidden + + #line default + #line hidden using System.Linq; - -#line 4 "..\..\LayoutPage.cshtml" + + #line 4 "..\..\Pages\LayoutPage.cshtml" using System.Reflection; - -#line default -#line hidden + + #line default + #line hidden using System.Text; - -#line 5 "..\..\LayoutPage.cshtml" + + #line 5 "..\..\Pages\LayoutPage.cshtml" using DotNetCore.CAP.Dashboard.Pages; - -#line default -#line hidden - -#line 6 "..\..\LayoutPage.cshtml" + + #line default + #line hidden + + #line 6 "..\..\Pages\LayoutPage.cshtml" using DotNetCore.CAP.Dashboard.Resources; - -#line default -#line hidden - + + #line default + #line hidden + [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] public partial class LayoutPage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { - WriteLiteral("\r\n"); - - - - - - +WriteLiteral("\r\n"); - WriteLiteral("\r\n\r\n\r\n "); -#line 11 "..\..\LayoutPage.cshtml" - Write(Title); +WriteLiteral("<!DOCTYPE html>\r\n<html lang=\""); -#line default -#line hidden - WriteLiteral(" - CAP\r\n \r\n \r\n \r\n"); + + #line 9 "..\..\Pages\LayoutPage.cshtml" + Write(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName); + + #line default + #line hidden +WriteLiteral("\">\r\n\r\n "); -#line 15 "..\..\LayoutPage.cshtml" - var version = GetType().GetTypeInfo().Assembly.GetName().Version; + + #line 11 "..\..\Pages\LayoutPage.cshtml" + Write(Title); + + #line default + #line hidden +WriteLiteral(" - CAP\r\n \r\n \r\n \r\n"); -#line default -#line hidden - WriteLiteral(" + + #line default + #line hidden +WriteLiteral(@"""> - -
- - -
-
-
- - \r\n
\r\n
\r\n "); - - - -#line 34 "..\..\LayoutPage.cshtml" - Write(Html.RenderPartial(new Navigation())); - - -#line default -#line hidden - WriteLiteral("\r\n"); - - - -#line 35 "..\..\LayoutPage.cshtml" - if (AppPath != null) - { - - -#line default -#line hidden - WriteLiteral(" \r\n
\r\n
\r\n "); + + #line 34 "..\..\Pages\LayoutPage.cshtml" + Write(Html.RenderPartial(new Navigation())); -#line 45 "..\..\LayoutPage.cshtml" - } + + #line default + #line hidden +WriteLiteral("\r\n"); -#line default -#line hidden - WriteLiteral("
\r\n \r\n \r\n
\r\n\r\n \r\n
\r\n "); + + #line 35 "..\..\Pages\LayoutPage.cshtml" + if (AppPath != null) + { + + #line default + #line hidden +WriteLiteral("
\r\n"); -#line 62 "..\..\LayoutPage.cshtml" - Write($"{version.Major}.{version.Minor}.{version.Build}"); + + #line 45 "..\..\Pages\LayoutPage.cshtml" + } + + #line default + #line hidden +WriteLiteral("
\r\n \r\n
\r\n \r\n\r\n \r\n
\r\n "); -#line default -#line hidden - WriteLiteral("\r\n \r\n \r\n
  • "); + + #line 53 "..\..\Pages\LayoutPage.cshtml" + Write(RenderBody()); + + #line default + #line hidden +WriteLiteral("\r\n
  • \r\n
    \r\n\r\n
    \r\n
    \r\n <" + +"ul class=\"list-inline credit\">\r\n
  • \r\n \r\n CAP "); -#line 65 "..\..\LayoutPage.cshtml" - Write(Storage); + + #line 62 "..\..\Pages\LayoutPage.cshtml" + Write($"{version.Major}.{version.Minor}.{version.Build}"); -#line default -#line hidden - WriteLiteral("
  • \r\n
  • "); + + #line default + #line hidden +WriteLiteral("\r\n \r\n
  • \r\n
  • "); + + #line 65 "..\..\Pages\LayoutPage.cshtml" + Write(Storage); -#line 66 "..\..\LayoutPage.cshtml" - Write(Strings.LayoutPage_Footer_Time); + + #line default + #line hidden +WriteLiteral("
  • \r\n
  • "); -#line default -#line hidden - WriteLiteral(" "); + + #line 66 "..\..\Pages\LayoutPage.cshtml" + Write(Strings.LayoutPage_Footer_Time); + + #line default + #line hidden +WriteLiteral(" "); -#line 66 "..\..\LayoutPage.cshtml" - Write(Html.LocalTime(DateTime.UtcNow)); + + #line 66 "..\..\Pages\LayoutPage.cshtml" + Write(Html.LocalTime(DateTime.UtcNow)); - -#line default -#line hidden - WriteLiteral("
  • \r\n
  • "); + + #line default + #line hidden +WriteLiteral("
  • \r\n
  • "); + + #line 67 "..\..\Pages\LayoutPage.cshtml" + Write(string.Format(Strings.LayoutPage_Footer_Generatedms, GenerationTime.Elapsed.TotalMilliseconds.ToString("N"))); -#line 67 "..\..\LayoutPage.cshtml" - Write(string.Format(Strings.LayoutPage_Footer_Generatedms, GenerationTime.Elapsed.TotalMilliseconds.ToString("N"))); + + #line default + #line hidden +WriteLiteral("
  • \r\n"); -#line default -#line hidden - WriteLiteral("\r\n"); - - - -#line 68 "..\..\LayoutPage.cshtml" - if (NodeName != null) + + #line 68 "..\..\Pages\LayoutPage.cshtml" + if (NodeName != null) { - -#line default -#line hidden - WriteLiteral("
  • "); + + #line default + #line hidden +WriteLiteral("
  • "); + + #line 70 "..\..\Pages\LayoutPage.cshtml" + Write(string.Format(Strings.LayoutPage_Footer_NodeCurrent, NodeName)); -#line 70 "..\..\LayoutPage.cshtml" - Write(string.Format(Strings.LayoutPage_Footer_NodeCurrent, NodeName)); + + #line default + #line hidden +WriteLiteral("
  • \r\n"); -#line default -#line hidden - WriteLiteral("\r\n"); - - - -#line 71 "..\..\LayoutPage.cshtml" + + #line 71 "..\..\Pages\LayoutPage.cshtml" } + + #line default + #line hidden +WriteLiteral(" \r\n
    \r\n
    \r\n\r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n"); + + #line default + #line hidden +WriteLiteral("\">\r\n\r\n"); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs index 9f677b8..c95b4df 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; -using DotNetCore.CAP.NodeDiscovery; +using DotNetCore.CAP.Dashboard.NodeDiscovery; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.Dashboard.Pages diff --git a/src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs index 9b205b1..e7a049d 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/NodePage.generated.cs @@ -15,243 +15,242 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Collections.Generic; using System.Linq; using System.Text; - -#line 2 "..\..\NodePage.cshtml" + + #line 2 "..\..\Pages\NodePage.cshtml" using DotNetCore.CAP.Dashboard.Pages; - -#line default -#line hidden - -#line 3 "..\..\NodePage.cshtml" + + #line default + #line hidden + + #line 3 "..\..\Pages\NodePage.cshtml" using DotNetCore.CAP.Dashboard.Resources; - -#line default -#line hidden - + + #line default + #line hidden + [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] internal partial class NodePage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { - WriteLiteral("\r\n"); - - - - - - -#line 5 "..\..\NodePage.cshtml" - - Layout = new LayoutPage(Strings.NodePage_Title); - - - -#line default -#line hidden - WriteLiteral("
    \r\n
    \r\n

    "); - - - -#line 10 "..\..\NodePage.cshtml" - Write(Strings.NodePage_Title); - - -#line default -#line hidden - WriteLiteral("

    \r\n\r\n"); - - - -#line 12 "..\..\NodePage.cshtml" - if (Nodes == null || Nodes.Count == 0) - { - - -#line default -#line hidden - WriteLiteral("
    \r\n "); - - - -#line 15 "..\..\NodePage.cshtml" - Write(Strings.NodePage_NoNodes); - - -#line default -#line hidden - WriteLiteral("\r\n
    \r\n"); - - - -#line 17 "..\..\NodePage.cshtml" - } - else - { - - -#line default -#line hidden - WriteLiteral("
    \r\n " + - "\r\n \r\n \r\n " + - " \r\n \r\n \r\n \r\n \r\n "); + + #line 10 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_Title); + + #line default + #line hidden +WriteLiteral("\r\n\r\n"); -#line 29 "..\..\NodePage.cshtml" - Write(Strings.NodePage_Switch); + + #line 12 "..\..\Pages\NodePage.cshtml" + if (Nodes == null || Nodes.Count == 0) + { + + #line default + #line hidden +WriteLiteral("
    \r\n "); -#line default -#line hidden - WriteLiteral("\r\n
    \r\n \r\n " + - " \r\n"); + + #line 15 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_NoNodes); + + #line default + #line hidden +WriteLiteral("\r\n \r\n"); -#line 33 "..\..\NodePage.cshtml" - foreach (var node in Nodes) - { + + #line 17 "..\..\Pages\NodePage.cshtml" + } + else + { -#line default -#line hidden - WriteLiteral(" \r\n
    "); - - - -#line 24 "..\..\NodePage.cshtml" - Write(Strings.Common_Id); - - -#line default -#line hidden - WriteLiteral(""); - - - -#line 25 "..\..\NodePage.cshtml" - Write(Strings.NodePage_Table_NodeName); - - -#line default -#line hidden - WriteLiteral(""); - +WriteLiteral("\r\n"); -#line 26 "..\..\NodePage.cshtml" - Write(Strings.NodePage_Table_IP); -#line default -#line hidden - WriteLiteral(""); + + #line 5 "..\..\Pages\NodePage.cshtml" + + Layout = new LayoutPage(Strings.NodePage_Title); -#line 27 "..\..\NodePage.cshtml" - Write(Strings.NodePage_Table_Port); + + #line default + #line hidden +WriteLiteral("
    \r\n
    \r\n

    "); -#line default -#line hidden - WriteLiteral("

    Tags
    " + +"\r\n \r\n \r\n " + +" \r\n \r\n \r\n \r\n \r\n " + +" \r\n"); + + #line 33 "..\..\Pages\NodePage.cshtml" + foreach (var node in Nodes) + { -#line 38 "..\..\NodePage.cshtml" - Write(node.Address); + + #line default + #line hidden +WriteLiteral(" \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"); + + #line 40 "..\..\Pages\NodePage.cshtml" + Write(node.Tags); + + #line default + #line hidden +WriteLiteral("\r\n \r\n \r\n"); -#line default -#line hidden - WriteLiteral(" \r\n
    "); + + #line 24 "..\..\Pages\NodePage.cshtml" + Write(Strings.Common_Id); -#line 35 "..\..\NodePage.cshtml" - Write(CurrentNodeId == node.Id ? "active" : null); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral("\">\r\n "); + + #line 25 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_Table_NodeName); + + #line default + #line hidden +WriteLiteral("\r\n "); -#line 36 "..\..\NodePage.cshtml" - Write(node.Id); + + #line 26 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_Table_IP); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral("\r\n "); + + #line 27 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_Table_Port); + + #line default + #line hidden +WriteLiteral("\r\n Tags"); -#line 37 "..\..\NodePage.cshtml" - Write(node.Name); + + #line 29 "..\..\Pages\NodePage.cshtml" + Write(Strings.NodePage_Switch); -#line default -#line hidden - WriteLiteral("\r\n "); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n "); -#line 45 "..\..\NodePage.cshtml" - } + + #line 42 "..\..\Pages\NodePage.cshtml" + Write(Html.NodeSwitchLink(node.Id)); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n
    \r\n"); + + #line 45 "..\..\Pages\NodePage.cshtml" + } + + #line default + #line hidden +WriteLiteral(" \r\n \r\n
    \r\n"); -#line 49 "..\..\NodePage.cshtml" - } + + #line 49 "..\..\Pages\NodePage.cshtml" + } -#line default -#line hidden - WriteLiteral("
    \r\n"); + + #line default + #line hidden +WriteLiteral(" \r\n"); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs index 2ccece2..d652c17 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cs @@ -2,21 +2,22 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Monitoring; namespace DotNetCore.CAP.Dashboard.Pages { - internal partial class PublishedPage + internal partial class PublishedPage : DotNetCore.CAP.Dashboard.RazorPage { public PublishedPage(string statusName) { - StatusName = statusName; + Name = statusName; } - public string StatusName { get; set; } + public string Name { get; set; } public int GetTotal(IMonitoringApi api) { - if (string.Equals(StatusName, Infrastructure.StatusName.Succeeded, + if (string.Equals(Name, nameof(Internal.StatusName.Succeeded), StringComparison.CurrentCultureIgnoreCase)) { return api.PublishedSucceededCount(); diff --git a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml index d4313db..dba410f 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml @@ -1,10 +1,10 @@ @* Generator: Template TypeVisibility: Internal GeneratePrettyNames: True *@ @using System @using DotNetCore.CAP.Dashboard -@using DotNetCore.CAP.Dashboard.Monitoring @using DotNetCore.CAP.Dashboard.Pages @using DotNetCore.CAP.Dashboard.Resources @using DotNetCore.CAP.Messages +@using DotNetCore.CAP.Monitoring @inherits DotNetCore.CAP.Dashboard.RazorPage @{ Layout = new LayoutPage(Strings.PublishedMessagesPage_Title); @@ -23,7 +23,7 @@ MessageType = MessageType.Publish, Name = name, Content = content, - StatusName = StatusName, + StatusName = Name, CurrentPage = pager.CurrentPage - 1, PageSize = pager.RecordsPerPage }; @@ -84,7 +84,7 @@ @Strings.Common_Version @Strings.MessagesPage_Table_Name @Strings.MessagesPage_Table_Retries - @if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) + @if (string.Equals(Name, "Processing", StringComparison.CurrentCultureIgnoreCase)) { @Strings.MessagesPage_Table_State } @@ -110,7 +110,7 @@ @message.Retries - @if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) + @if (string.Equals(Name, "Processing", StringComparison.CurrentCultureIgnoreCase)) { @message.StatusName diff --git a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs index 250c6c8..8d2bee3 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs @@ -1,6 +1,4 @@ -using DotNetCore.CAP.Messages; - -#pragma warning disable 1591 +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -13,567 +11,581 @@ namespace DotNetCore.CAP.Dashboard.Pages { - -#line 2 "..\..\PublishedPage.cshtml" + + #line 2 "..\..\Pages\PublishedPage.cshtml" using System; - -#line default -#line hidden + + #line default + #line hidden using System.Collections.Generic; using System.Linq; using System.Text; - -#line 4 "..\..\PublishedPage.cshtml" + + #line 3 "..\..\Pages\PublishedPage.cshtml" using DotNetCore.CAP.Dashboard; - -#line default -#line hidden - -#line 6 "..\..\PublishedPage.cshtml" - using DotNetCore.CAP.Dashboard.Monitoring; - -#line default -#line hidden - -#line 5 "..\..\PublishedPage.cshtml" + + #line default + #line hidden + + #line 4 "..\..\Pages\PublishedPage.cshtml" using DotNetCore.CAP.Dashboard.Pages; - -#line default -#line hidden - -#line 7 "..\..\PublishedPage.cshtml" + + #line default + #line hidden + + #line 5 "..\..\Pages\PublishedPage.cshtml" using DotNetCore.CAP.Dashboard.Resources; - -#line default -#line hidden - -#line 3 "..\..\PublishedPage.cshtml" - -#line default -#line hidden - + + #line default + #line hidden + + #line 6 "..\..\Pages\PublishedPage.cshtml" + using DotNetCore.CAP.Messages; + + #line default + #line hidden + + #line 7 "..\..\Pages\PublishedPage.cshtml" + using DotNetCore.CAP.Monitoring; + + #line default + #line hidden + [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class PublishedPage : RazorPage + internal partial class PublishedPage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { - WriteLiteral("\r\n"); - - - - - - - - - - -#line 9 "..\..\PublishedPage.cshtml" - - Layout = new LayoutPage(Strings.PublishedMessagesPage_Title); - - int from, perPage; - - int.TryParse(Query("from"), out from); - int.TryParse(Query("count"), out perPage); - string name = Query("name"); - string content = Query("content"); - - var monitor = Storage.GetMonitoringApi(); - var pager = new Pager(from, perPage, GetTotal(monitor)); - var queryDto = new MessageQueryDto - { - MessageType = MessageType.Publish, - Name = name, - Content = content, - StatusName = StatusName, - CurrentPage = pager.CurrentPage - 1, - PageSize = pager.RecordsPerPage - }; - var succeededMessages = monitor.Messages(queryDto); - - - -#line default -#line hidden - WriteLiteral("\r\n
    \r\n
    \r\n "); - - - -#line 35 "..\..\PublishedPage.cshtml" - Write(Html.MessagesSidebar(MessageType.Publish)); - - -#line default -#line hidden - WriteLiteral("\r\n
    \r\n
    \r\n

    "); - +WriteLiteral("\r\n"); -#line 38 "..\..\PublishedPage.cshtml" - Write(Strings.PublishedPage_Title); -#line default -#line hidden - WriteLiteral("

    \r\n\r\n"); -#line 40 "..\..\PublishedPage.cshtml" - if (succeededMessages.Count == 0) - { -#line default -#line hidden - WriteLiteral("
    \r\n "); + + #line 9 "..\..\Pages\PublishedPage.cshtml" + + Layout = new LayoutPage(Strings.PublishedMessagesPage_Title); + int from, perPage; + int.TryParse(Query("from"), out from); + int.TryParse(Query("count"), out perPage); + var name = Query("name"); + var content = Query("content"); -#line 43 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_NoMessages); + var monitor = Storage.GetMonitoringApi(); + var pager = new Pager(from, perPage, GetTotal(monitor)); + var queryDto = new MessageQueryDto + { + MessageType = MessageType.Publish, + Name = name, + Content = content, + StatusName = Name, + CurrentPage = pager.CurrentPage - 1, + PageSize = pager.RecordsPerPage + }; + var succeededMessages = monitor.Messages(queryDto); -#line default -#line hidden - WriteLiteral("\r\n
    \r\n"); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n
    \r\n "); + + #line 35 "..\..\Pages\PublishedPage.cshtml" + Write(Html.MessagesSidebar(MessageType.Publish)); -#line 45 "..\..\PublishedPage.cshtml" - } - else - { + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n
    \r\n

    "); -#line default -#line hidden - WriteLiteral("
    \r\n
    \r\n
    \r\n
    \r\n \r\n\r\n"); -#line 52 "..\..\PublishedPage.cshtml" - Write(Query(" name")); + + #line 40 "..\..\Pages\PublishedPage.cshtml" + if (succeededMessages.Count == 0) + { + + #line default + #line hidden +WriteLiteral("
    \r\n "); -#line default -#line hidden - WriteLiteral("\" placeholder=\""); + + #line 43 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.MessagesPage_NoMessages); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n"); -#line 52 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_Query_MessageName); + + #line 45 "..\..\Pages\PublishedPage.cshtml" + } + else + { -#line default -#line hidden - WriteLiteral("\" />\r\n
    \r\n
    \r\n " + - "
    \r\n
    -
    -
    +
    + \r\n\r\n "); + + #line 70 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.Common_RequeueMessages); + + #line default + #line hidden +WriteLiteral("\r\n \r\n\r\n "); -#line 73 "..\..\PublishedPage.cshtml" - Write(Html.PerPageSelector(pager)); + + #line 73 "..\..\Pages\PublishedPage.cshtml" + Write(Html.PerPageSelector(pager)); -#line default -#line hidden - WriteLiteral(@" -
    + + #line default + #line hidden +WriteLiteral(@" +
    -
    - - +
    +
    + - - \r\n \r\n \r\n \r\n"); - - - -#line 86 "..\..\PublishedPage.cshtml" - if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) - { - - -#line default -#line hidden - WriteLiteral(" \r\n"); - - - -#line 89 "..\..\PublishedPage.cshtml" - } - - -#line default -#line hidden - WriteLiteral(" \r\n \r\n \r\n " + - " \r\n"); - - - -#line 94 "..\..\PublishedPage.cshtml" - foreach (var message in succeededMessages) - { - - -#line default -#line hidden - WriteLiteral(" \r\n " + - " \r\n \r\n \r\n \r\n \r\n"); - - - -#line 109 "..\..\PublishedPage.cshtml" - if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) - { - - -#line default -#line hidden - WriteLiteral(" \r\n \r\n"); -#line default -#line hidden - -#line 118 "..\..\PublishedPage.cshtml" - - } - - -#line default -#line hidden - WriteLiteral(" \r\n\r\n \r\n"); + + #line 90 "..\..\Pages\PublishedPage.cshtml" + } + + #line default + #line hidden +WriteLiteral(" \r\n \r\n \r\n " + +" \r\n"); -#line default -#line hidden - WriteLiteral(" \r\n
    - + + "); - - - -#line 83 "..\..\PublishedPage.cshtml" - Write(Strings.Common_Id); - - -#line default -#line hidden - WriteLiteral(""); - -#line 84 "..\..\PublishedPage.cshtml" - Write(Strings.Common_Version); - - -#line default -#line hidden - WriteLiteral(""); - -#line 84 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_Table_Name); - - -#line default -#line hidden - WriteLiteral(""); - - - -#line 85 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_Table_Retries); - - -#line default -#line hidden - WriteLiteral(""); - - - -#line 88 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_Table_State); - - -#line default -#line hidden - WriteLiteral(""); - - - -#line 90 "..\..\PublishedPage.cshtml" - Write(Strings.MessagesPage_Table_ExpiresAt); - - -#line default -#line hidden - WriteLiteral("
    \r\n \r\n \r\n "); + + #line 83 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.Common_Id); -#line 101 "..\..\PublishedPage.cshtml" - Write(message.Id); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral("\r\n \r\n \r\n " + - " "); - - -#line 102 "..\..\PublishedPage.cshtml" - Write(message.Version); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n " + - " "); -#line 104 "..\..\PublishedPage.cshtml" - Write(message.Name); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n " + - " "); - - - -#line 107 "..\..\PublishedPage.cshtml" - Write(message.Retries); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n "); - + + #line 84 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.Common_Version); + + #line default + #line hidden +WriteLiteral("\r\n "); -#line 112 "..\..\PublishedPage.cshtml" - Write(message.StatusName); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n"); + + #line 85 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.MessagesPage_Table_Name); + + #line default + #line hidden +WriteLiteral(""); -#line 114 "..\..\PublishedPage.cshtml" - } + + #line 86 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.MessagesPage_Table_Retries); -#line default -#line hidden - WriteLiteral(" \r\n"); + + #line default + #line hidden +WriteLiteral("\r\n"); + + #line 87 "..\..\Pages\PublishedPage.cshtml" + if (string.Equals(Name, "Processing", StringComparison.CurrentCultureIgnoreCase)) + { -#line 116 "..\..\PublishedPage.cshtml" - if (message.ExpiresAt.HasValue) - { + + #line default + #line hidden +WriteLiteral(" "); -#line default -#line hidden + + #line 89 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.MessagesPage_Table_State); -#line 118 "..\..\PublishedPage.cshtml" - Write(Html.RelativeTime(message.ExpiresAt.Value)); + + #line default + #line hidden +WriteLiteral("
    "); -#line 123 "..\..\PublishedPage.cshtml" - } + + #line 91 "..\..\Pages\PublishedPage.cshtml" + Write(Strings.MessagesPage_Table_ExpiresAt); + + #line default + #line hidden +WriteLiteral("
    \r\n
    \r\n " + - " "); + + #line 95 "..\..\Pages\PublishedPage.cshtml" + foreach (var message in succeededMessages) + { + + #line default + #line hidden +WriteLiteral(" \r\n " + +" \r\n \r\n"); + + #line default + #line hidden +WriteLiteral("\" />\r\n \r\n \r\n
    \r\n \r\n \r\n \r\n
    \r\n
    \r\n
    \r\n
    <" + - "!-- /.modal -->\r\n
    \r\n"); + + #line 127 "..\..\Pages\PublishedPage.cshtml" + } + + + #line default + #line hidden +WriteLiteral(" \r\n \r\n <" + +"/div>\r\n "); + + + + #line 131 "..\..\Pages\PublishedPage.cshtml" + Write(Html.Paginator(pager)); + + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n"); + + #line 133 "..\..\Pages\PublishedPage.cshtml" + + + + #line default + #line hidden +WriteLiteral(@"
    +
    +
    +
    +
    + +

    Message Content

    +
    +
    +
    +
    + \r\n \r\n \r\n \r\n
    \r\n
    \r\n
    \r\n " + +"
    \r\n
    \r\n"); -#line 150 "..\..\PublishedPage.cshtml" - } + + #line 156 "..\..\Pages\PublishedPage.cshtml" + } -#line default -#line hidden - WriteLiteral("
    \r\n

    "); + + #line default + #line hidden +WriteLiteral("
    \r\n
    "); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs index 9090876..f8d4249 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Monitoring; namespace DotNetCore.CAP.Dashboard.Pages { @@ -16,7 +17,7 @@ namespace DotNetCore.CAP.Dashboard.Pages public int GetTotal(IMonitoringApi api) { - if (string.Equals(StatusName, Infrastructure.StatusName.Succeeded, + if (string.Equals(StatusName, nameof(Internal.StatusName.Succeeded), StringComparison.CurrentCultureIgnoreCase)) { return api.ReceivedSucceededCount(); diff --git a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml index fb179cf..64affa5 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml @@ -1,10 +1,10 @@ @* Generator: Template TypeVisibility: Internal GeneratePrettyNames: True *@ @using System @using DotNetCore.CAP.Dashboard -@using DotNetCore.CAP.Dashboard.Monitoring @using DotNetCore.CAP.Dashboard.Pages @using DotNetCore.CAP.Dashboard.Resources @using DotNetCore.CAP.Messages +@using DotNetCore.CAP.Monitoring @inherits DotNetCore.CAP.Dashboard.RazorPage @{ Layout = new LayoutPage(Strings.ReceivedMessagesPage_Title); diff --git a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs index 17365c7..7683be2 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs @@ -1,4 +1,4 @@ -using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; #pragma warning disable 1591 //------------------------------------------------------------------------------ @@ -13,58 +13,54 @@ namespace DotNetCore.CAP.Dashboard.Pages { - -#line 2 "..\..\ReceivedPage.cshtml" + + #line 2 "..\..\Pages\ReceivedPage.cshtml" using System; - -#line default -#line hidden + + #line default + #line hidden using System.Collections.Generic; using System.Linq; using System.Text; - -#line 4 "..\..\ReceivedPage.cshtml" + + #line 3 "..\..\Pages\ReceivedPage.cshtml" using DotNetCore.CAP.Dashboard; - -#line default -#line hidden - -#line 6 "..\..\ReceivedPage.cshtml" - using DotNetCore.CAP.Dashboard.Monitoring; - -#line default -#line hidden - -#line 5 "..\..\ReceivedPage.cshtml" + + #line default + #line hidden + + #line 4 "..\..\Pages\ReceivedPage.cshtml" +#line default + #line hidden + + #line 5 "..\..\Pages\ReceivedPage.cshtml" using DotNetCore.CAP.Dashboard.Pages; - -#line default -#line hidden - -#line 7 "..\..\ReceivedPage.cshtml" + + #line default + #line hidden + + #line 6 "..\..\Pages\ReceivedPage.cshtml" using DotNetCore.CAP.Dashboard.Resources; - -#line default -#line hidden - -#line 3 "..\..\ReceivedPage.cshtml" - -#line default -#line hidden - + + #line default + #line hidden + + #line 7 "..\..\Pages\ReceivedPage.cshtml" + using DotNetCore.CAP.Messages; + + #line default + #line hidden + [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class ReceivedPage : RazorPage + internal partial class ReceivedPage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { - WriteLiteral("\r\n"); - - - +WriteLiteral("\r\n"); @@ -72,169 +68,172 @@ namespace DotNetCore.CAP.Dashboard.Pages -#line 9 "..\..\ReceivedPage.cshtml" - Layout = new LayoutPage(Strings.ReceivedMessagesPage_Title); - int from, perPage; + + #line 9 "..\..\Pages\ReceivedPage.cshtml" + + Layout = new LayoutPage(Strings.ReceivedMessagesPage_Title); - int.TryParse(Query("from"), out from); - int.TryParse(Query("count"), out perPage); - string group = Query("group"); - string name = Query("name"); - string content = Query("content"); + int from, perPage; - var monitor = Storage.GetMonitoringApi(); - var pager = new Pager(from, perPage, GetTotal(monitor)); - var queryDto = new MessageQueryDto - { - MessageType = MessageType.Subscribe, - Group = group, - Name = name, - Content = content, - StatusName = StatusName, - CurrentPage = pager.CurrentPage - 1, - PageSize = pager.RecordsPerPage - }; - var succeededMessages = monitor.Messages(queryDto); + int.TryParse(Query("from"), out from); + int.TryParse(Query("count"), out perPage); + var group = Query("group"); + var name = Query("name"); + var content = Query("content"); + var monitor = Storage.GetMonitoringApi(); + var pager = new Pager(from, perPage, GetTotal(monitor)); + var queryDto = new MessageQueryDto + { + MessageType = MessageType.Subscribe, + Group = group, + Name = name, + Content = content, + StatusName = StatusName, + CurrentPage = pager.CurrentPage - 1, + PageSize = pager.RecordsPerPage + }; + var succeededMessages = monitor.Messages(queryDto); -#line default -#line hidden - WriteLiteral("\r\n
    \r\n
    \r\n "); - - - -#line 37 "..\..\ReceivedPage.cshtml" - Write(Html.MessagesSidebar(MessageType.Subscribe)); - - -#line default -#line hidden - WriteLiteral("\r\n
    \r\n
    \r\n

    "); - - - -#line 40 "..\..\ReceivedPage.cshtml" - Write(Strings.ReceivedPage_Title); - - -#line default -#line hidden - WriteLiteral("

    \r\n\r\n"); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n
    \r\n "); + + #line 37 "..\..\Pages\ReceivedPage.cshtml" + Write(Html.MessagesSidebar(MessageType.Subscribe)); -#line 42 "..\..\ReceivedPage.cshtml" - if (succeededMessages.Count == 0) - { + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n
    \r\n

    "); -#line default -#line hidden - WriteLiteral("
    \r\n "); + + #line 40 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.ReceivedPage_Title); + + #line default + #line hidden +WriteLiteral("

    \r\n\r\n"); -#line 45 "..\..\ReceivedPage.cshtml" - Write(Strings.MessagesPage_NoMessages); + + #line 42 "..\..\Pages\ReceivedPage.cshtml" + if (succeededMessages.Count == 0) + { + + #line default + #line hidden +WriteLiteral("
    \r\n "); -#line default -#line hidden - WriteLiteral("\r\n
    \r\n"); + + #line 45 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_NoMessages); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n"); -#line 47 "..\..\ReceivedPage.cshtml" - } - else - { + + #line 47 "..\..\Pages\ReceivedPage.cshtml" + } + else + { -#line default -#line hidden - WriteLiteral(@"
    + + #line default + #line hidden +WriteLiteral(@"
    \r\n
    \r\n
    \r\n \r\n
    \r\n
    \r\n \r\n
    \r\n
    \r\n
    \r\n " + - " \r\n
    \r\n
    \r\n
    \r\n " + +" \r\n \r\n " + - " + + #line default + #line hidden +WriteLiteral(@"
    @@ -245,388 +244,393 @@ namespace DotNetCore.CAP.Dashboard.Pages data-url="""); + + #line 71 "..\..\Pages\ReceivedPage.cshtml" + Write(Url.To("/received/requeue")); -#line 71 "..\..\ReceivedPage.cshtml" - Write(Url.To("/received/requeue")); + + #line default + #line hidden +WriteLiteral("\"\r\n data-loading-text=\""); -#line default -#line hidden - WriteLiteral("\"\r\n data-loading-text=\""); + + #line 72 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.Common_Enqueueing); + + #line default + #line hidden +WriteLiteral("\"\r\n disabled=\"disabled\">\r\n \r\n "); -#line 72 "..\..\ReceivedPage.cshtml" - Write(Strings.Common_Enqueueing); - - -#line default -#line hidden - WriteLiteral("\"\r\n disabled=\"disabled\">\r\n \r\n "); - - - -#line 75 "..\..\ReceivedPage.cshtml" - Write(Strings.Common_ReConsume); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n\r\n "); + + #line 75 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.Common_ReConsume); + + #line default + #line hidden +WriteLiteral("\r\n \r\n\r\n "); -#line 78 "..\..\ReceivedPage.cshtml" - Write(Html.PerPageSelector(pager)); + + #line 78 "..\..\Pages\ReceivedPage.cshtml" + Write(Html.PerPageSelector(pager)); - -#line default -#line hidden - WriteLiteral(@" + + #line default + #line hidden +WriteLiteral(@"
    - - - + + \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n"); -#line 90 "..\..\ReceivedPage.cshtml" - Write(Strings.MessagesPage_Table_Name); + + #line 93 "..\..\Pages\ReceivedPage.cshtml" + if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) + { -#line default -#line hidden - WriteLiteral("\r\n \r\n"); -#line default -#line hidden - WriteLiteral("\r\n"); + + #line 96 "..\..\Pages\ReceivedPage.cshtml" + } + + #line default + #line hidden +WriteLiteral(" \r\n \r\n \r\n " + +" \r\n"); -#line default -#line hidden - WriteLiteral(" \r\n " + +" \r\n \r\n \r\n " + - " \r\n"); - - - -#line 100 "..\..\ReceivedPage.cshtml" - foreach (var message in succeededMessages) - { - - -#line default -#line hidden - WriteLiteral(" \r\n " + - " \r\n " + - " \r\n " + - " \r\n " + - "\r\n " + - "\r\n \r\n"); + + #line default + #line hidden +WriteLiteral("\' class=\"openModal\">#"); + + #line 108 "..\..\Pages\ReceivedPage.cshtml" + Write(message.Id); -#line 118 "..\..\ReceivedPage.cshtml" - if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) - { + + #line default + #line hidden +WriteLiteral("\r\n \r\n \r\n \r\n"); + + #line default + #line hidden +WriteLiteral("\r\n \r\n \r\n \r\n"); -#line 125 "..\..\ReceivedPage.cshtml" - if (message.ExpiresAt.HasValue) - { + + #line 122 "..\..\Pages\ReceivedPage.cshtml" + if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) + { + + #line default + #line hidden +WriteLiteral(" \r\n"); -#line default -#line hidden -#line 127 "..\..\ReceivedPage.cshtml" + + #line 127 "..\..\Pages\ReceivedPage.cshtml" + } - } + + #line default + #line hidden +WriteLiteral(" \r\n\r\n \r\n"); + + #line 129 "..\..\Pages\ReceivedPage.cshtml" + if (message.ExpiresAt.HasValue) + { + + + #line default + #line hidden + + #line 131 "..\..\Pages\ReceivedPage.cshtml" + Write(Html.RelativeTime(message.ExpiresAt.Value)); + + #line default + #line hidden + + #line 131 "..\..\Pages\ReceivedPage.cshtml" + + } + + #line default + #line hidden +WriteLiteral(" \r\n\r\n \r\n"); -#line 132 "..\..\ReceivedPage.cshtml" - } + + #line 136 "..\..\Pages\ReceivedPage.cshtml" + } -#line default -#line hidden - WriteLiteral(" \r\n
    - - "); +
    + + "); + + #line 88 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.Common_Id); -#line 88 "..\..\ReceivedPage.cshtml" - Write(Strings.Common_Id); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral(""); + + #line 89 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.Common_Version); -#line 88 "..\..\ReceivedPage.cshtml" - Write(Strings.Common_Version); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral(""); + + #line 90 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_Table_Group); + + #line default + #line hidden +WriteLiteral(""); -#line 89 "..\..\ReceivedPage.cshtml" - Write(Strings.MessagesPage_Table_Group); + + #line 91 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_Table_Name); + + #line default + #line hidden +WriteLiteral(""); -#line default -#line hidden - WriteLiteral(""); + + #line 92 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_Table_Retries); + + #line default + #line hidden +WriteLiteral(""); + + #line default + #line hidden +WriteLiteral(" "); + + #line 95 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_Table_State); -#line 91 "..\..\ReceivedPage.cshtml" - Write(Strings.MessagesPage_Table_Retries); + + #line default + #line hidden +WriteLiteral(""); -#line 92 "..\..\ReceivedPage.cshtml" - if (string.Equals(StatusName, "Processing", StringComparison.CurrentCultureIgnoreCase)) - { + + #line 97 "..\..\Pages\ReceivedPage.cshtml" + Write(Strings.MessagesPage_Table_ExpiresAt); + + #line default + #line hidden +WriteLiteral("
    "); + + #line 101 "..\..\Pages\ReceivedPage.cshtml" + foreach (var message in succeededMessages) + { + + #line default + #line hidden +WriteLiteral("
    \r\n \r\n"); - - - -#line 95 "..\..\ReceivedPage.cshtml" - } - - -#line default -#line hidden - WriteLiteral(" "); - - - -#line 96 "..\..\ReceivedPage.cshtml" - Write(Strings.MessagesPage_Table_ExpiresAt); - - -#line default -#line hidden - WriteLiteral("
    \r\n \r\n \r\n \r\n \r\n "); - - - -#line 111 "..\..\ReceivedPage.cshtml" - Write(message.Version); - -#line default -#line hidden - WriteLiteral("\r\n \r\n "); - - -#line 110 "..\..\ReceivedPage.cshtml" - Write(message.Group); - - -#line default -#line hidden - WriteLiteral("\r\n \r\n "); + + #line default + #line hidden +WriteLiteral("\"/>\r\n \r\n \r\n "); - - - -#line 116 "..\..\ReceivedPage.cshtml" - Write(message.Retries); - - -#line default -#line hidden - WriteLiteral("\r\n " + +"\r\n "); -#line default -#line hidden - WriteLiteral(" \r\n " + - " "); - + + #line 111 "..\..\Pages\ReceivedPage.cshtml" + Write(message.Version); + + #line default + #line hidden +WriteLiteral("\r\n \r\n "); -#line 121 "..\..\ReceivedPage.cshtml" - Write(message.StatusName); + + #line 114 "..\..\Pages\ReceivedPage.cshtml" + Write(message.Group); -#line default -#line hidden - WriteLiteral("\r\n \r\n " + +" "); + + #line 117 "..\..\Pages\ReceivedPage.cshtml" + Write(message.Name); -#line 123 "..\..\ReceivedPage.cshtml" - } + + #line default + #line hidden +WriteLiteral("\r\n \r\n " + +" "); -#line default -#line hidden - WriteLiteral(" \r\n"); + + #line 120 "..\..\Pages\ReceivedPage.cshtml" + Write(message.Retries); + + #line default + #line hidden +WriteLiteral("\r\n \r\n " + +" "); -#line default -#line hidden -#line 127 "..\..\ReceivedPage.cshtml" - Write(Html.RelativeTime(message.ExpiresAt.Value)); + + #line 125 "..\..\Pages\ReceivedPage.cshtml" + Write(message.StatusName); + + #line default + #line hidden +WriteLiteral("\r\n \r\n"); -#line default -#line hidden - WriteLiteral("
    \r\n <" + - "/div>\r\n "); + + #line default + #line hidden +WriteLiteral(" \r\n \r\n <" + +"/div>\r\n "); + + #line 140 "..\..\Pages\ReceivedPage.cshtml" + Write(Html.Paginator(pager)); -#line 136 "..\..\ReceivedPage.cshtml" - Write(Html.Paginator(pager)); + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n"); -#line default -#line hidden - WriteLiteral("\r\n
    \r\n"); + + #line 142 "..\..\Pages\ReceivedPage.cshtml" - -#line 138 "..\..\ReceivedPage.cshtml" - - - -#line default -#line hidden - WriteLiteral(@"
    + + #line default + #line hidden +WriteLiteral(@"
    - +

    Message Content

    -
    +
    \r\n \r\n \r\n \r\n \r\n \r\n
    \r\n
    \r\n
    \r\n " + +"
    \r\n
    \r\n"); -#line default -#line hidden - WriteLiteral("\r\n \r\n
    \r\n
    \r\n
    \r\n " + - "
    \r\n
    \r\n"); - - - -#line 159 "..\..\ReceivedPage.cshtml" - } - + + #line 165 "..\..\Pages\ReceivedPage.cshtml" + } -#line default -#line hidden - WriteLiteral("
    \r\n
    "); + + #line default + #line hidden +WriteLiteral("
    \r\n"); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs index ebec86b..a16d03a 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs @@ -16,36 +16,30 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 3 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - using DotNetCore.CAP.Dashboard; - - #line default - #line hidden - - #line 4 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 2 "..\..\Pages\SubscriberPage.cshtml" using DotNetCore.CAP.Dashboard.Pages; #line default #line hidden - #line 5 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 3 "..\..\Pages\SubscriberPage.cshtml" using DotNetCore.CAP.Dashboard.Resources; #line default #line hidden - #line 2 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 4 "..\..\Pages\SubscriberPage.cshtml" using DotNetCore.CAP.Internal; #line default #line hidden [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class SubscriberPage : RazorPage + internal partial class SubscriberPage : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { @@ -56,9 +50,8 @@ WriteLiteral("\r\n"); - - #line 7 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 6 "..\..\Pages\SubscriberPage.cshtml" Layout = new LayoutPage(Strings.SubscribersPage_Title); @@ -74,7 +67,7 @@ WriteLiteral("\r\n
    \r\n
    \r\n - #line 16 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 15 "..\..\Pages\SubscriberPage.cshtml" Write(Strings.SubscribersPage_Title); @@ -84,7 +77,7 @@ WriteLiteral("\r\n\r\n"); - #line 18 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 17 "..\..\Pages\SubscriberPage.cshtml" if (subscribers.Count == 0) { @@ -95,7 +88,7 @@ WriteLiteral("
    \r\n - #line 21 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 20 "..\..\Pages\SubscriberPage.cshtml" Write(Strings.SubscribersPage_NoSubscribers); @@ -105,7 +98,7 @@ WriteLiteral("\r\n
    \r\n"); - #line 23 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 22 "..\..\Pages\SubscriberPage.cshtml" } else { @@ -114,77 +107,70 @@ WriteLiteral("\r\n
    \r\n"); #line default #line hidden WriteLiteral("
    \r\n \r\n \r\n \r\n " + -" \r\n \r\n " + +" \r\n \r\n \r\n \r\n \r\n \r\n \r\n " + -" \r\n"); +WriteLiteral("\r\n \r\n \r\n " + +" \r\n"); - #line 38 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - foreach (var subscriber in subscribers) + #line 37 "..\..\Pages\SubscriberPage.cshtml" + foreach (var subscriber in subscribers) + { + var i = 0; + var rowCount = subscriber.Value.Count; + foreach (var column in subscriber.Value) { - var i = 0; - var rowCount = subscriber.Value.Count; - - - #line default - #line hidden - - #line 42 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - foreach (var column in subscriber.Value) - { #line default #line hidden -WriteLiteral(" \r\n"); +WriteLiteral(" \r\n"); - #line 45 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - if (i == 0) - { + #line 44 "..\..\Pages\SubscriberPage.cshtml" + if (i == 0) + { #line default #line hidden -WriteLiteral(" \r\n"); - #line 48 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - } + #line 47 "..\..\Pages\SubscriberPage.cshtml" + } #line default #line hidden -WriteLiteral(" \r\n \r\n \r\n " + -" \r\n"); - +WriteLiteral("\r\n \r\n " + +" \r\n \r\n " + +" \r\n"); - #line 59 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - i++; - } + #line 58 "..\..\Pages\SubscriberPage.cshtml" + i++; } + } #line default @@ -261,7 +246,7 @@ WriteLiteral(" \r\n
    "); +"ubscribe-table\">\r\n
    "); - #line 30 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(Strings.Common_Group); + #line 29 "..\..\Pages\SubscriberPage.cshtml" + Write(Strings.Common_Group); #line default #line hidden -WriteLiteral("\r\n " + -" "); +WriteLiteral("\r\n "); - #line 32 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(Strings.Common_Name); + #line 31 "..\..\Pages\SubscriberPage.cshtml" + Write(Strings.Common_Name); #line default #line hidden -WriteLiteral("\r\n "); +WriteLiteral("\r\n "); - #line 34 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(Strings.Common_Method); + #line 33 "..\..\Pages\SubscriberPage.cshtml" + Write(Strings.Common_Method); #line default #line hidden -WriteLiteral("
    "); - #line 47 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(subscriber.Key); + #line 46 "..\..\Pages\SubscriberPage.cshtml" + Write(subscriber.Key); #line default @@ -203,56 +189,55 @@ WriteLiteral(""); +WriteLiteral(" "); - #line 49 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(column.Attribute.Name); + #line 48 "..\..\Pages\SubscriberPage.cshtml" + Write(column.Attribute.Name); #line default #line hidden -WriteLiteral("\r\n " + -" "); +WriteLiteral("\r\n " + +""); - #line 51 "..\..\Dashboard\Pages\SubscriberPage.cshtml" - Write(column.ImplTypeInfo.Name); + #line 50 "..\..\Pages\SubscriberPage.cshtml" + Write(column.ImplTypeInfo.Name); #line default #line hidden -WriteLiteral(":\r\n
    \r" + -"\n \r\n " + -"
    ");
    +WriteLiteral(":\r\n                                    
    \r\n " + +" \r\n " + +"
    ");
     
     
                 
    -            #line 54 "..\..\Dashboard\Pages\SubscriberPage.cshtml"
    -                                                Write(Html.MethodEscaped(column.MethodInfo));
    +            #line 53 "..\..\Pages\SubscriberPage.cshtml"
    +                                            Write(Html.MethodEscaped(column.MethodInfo));
     
                 
                 #line default
                 #line hidden
    -WriteLiteral("
    \r\n
    \r\n " + -"
    \r\n
    \r\n - #line 65 "..\..\Dashboard\Pages\SubscriberPage.cshtml" + #line 64 "..\..\Pages\SubscriberPage.cshtml" } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml index eacc619..96e1f2a 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.cshtml @@ -1,17 +1,18 @@ @* Generator: Template TypeVisibility: Internal GeneratePrettyNames: True TrimLeadingUnderscores : true *@ -@using DotNetCore.CAP.Dashboard @using DotNetCore.CAP.Dashboard.Resources -@inherits RazorPage + +@inherits DotNetCore.CAP.Dashboard.RazorPage @{ - var metric = DashboardMetric.Func(this); + + var metric = Metric.Func(this); var className = metric == null ? "metric-null" : metric.Style.ToClassName(); var highlighted = metric != null && metric.Highlighted ? "highlighted" : null; }
    -
    +
    @(metric?.Value)
    - @(Strings.ResourceManager.GetString(DashboardMetric.Title) ?? DashboardMetric.Title) + @(Strings.ResourceManager.GetString(Metric.Title) ?? Metric.Title)
    \ No newline at end of file diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs index e29de0b..d6f3c3f 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_BlockMetric.generated.cs @@ -16,37 +16,33 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_BlockMetric.cshtml" - using DotNetCore.CAP.Dashboard; - - #line default - #line hidden - - #line 3 "..\..\Dashboard\Pages\_BlockMetric.cshtml" + #line 2 "..\..\Pages\_BlockMetric.cshtml" using DotNetCore.CAP.Dashboard.Resources; #line default #line hidden [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class BlockMetric : RazorPage + internal partial class BlockMetric : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { WriteLiteral("\r\n"); +WriteLiteral("\r\n"); - #line 5 "..\..\Dashboard\Pages\_BlockMetric.cshtml" + #line 5 "..\..\Pages\_BlockMetric.cshtml" - var metric = DashboardMetric.Func(this); + + var metric = Metric.Func(this); var className = metric == null ? "metric-null" : metric.Style.ToClassName(); var highlighted = metric != null && metric.Highlighted ? "highlighted" : null; @@ -58,7 +54,7 @@ WriteLiteral("
    \r\n
    \r\n "); - #line 12 "..\..\Dashboard\Pages\_BlockMetric.cshtml" + #line 13 "..\..\Pages\_BlockMetric.cshtml" Write(metric?.Value); @@ -98,8 +94,8 @@ WriteLiteral("\r\n
    \r\n
    \r\n - #line 15 "..\..\Dashboard\Pages\_BlockMetric.cshtml" - Write(Strings.ResourceManager.GetString(DashboardMetric.Title) ?? DashboardMetric.Title); + #line 16 "..\..\Pages\_BlockMetric.cshtml" + Write(Strings.ResourceManager.GetString(Metric.Title) ?? Metric.Title); #line default diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs index ce63c17..cc77018 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_Breadcrumbs.generated.cs @@ -16,51 +16,45 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_Breadcrumbs.cshtml" - using DotNetCore.CAP.Dashboard; - - #line default - #line hidden - [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class Breadcrumbs : RazorPage + internal partial class Breadcrumbs : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { WriteLiteral("\r\n"); - -WriteLiteral("\r\n
      \r\n
    1. \r\n
    2. \r\n
    3. \r\n"); +WriteLiteral("\">\r\n \r\n \r\n " + +" \r\n"); - #line 7 "..\..\Dashboard\Pages\_Breadcrumbs.cshtml" + #line 10 "..\..\Pages\_Breadcrumbs.cshtml" foreach (var item in Items) { #line default #line hidden -WriteLiteral("
    4. \r\n "); - #line 9 "..\..\Dashboard\Pages\_Breadcrumbs.cshtml" + #line 13 "..\..\Pages\_Breadcrumbs.cshtml" Write(item.Key); #line default #line hidden -WriteLiteral("
    5. \r\n"); +WriteLiteral("\r\n \r\n"); - #line 10 "..\..\Dashboard\Pages\_Breadcrumbs.cshtml" + #line 15 "..\..\Pages\_Breadcrumbs.cshtml" } @@ -90,7 +84,7 @@ WriteLiteral("
    6. "); - #line 11 "..\..\Dashboard\Pages\_Breadcrumbs.cshtml" + #line 16 "..\..\Pages\_Breadcrumbs.cshtml" Write(Title); diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs index 1f9fcd3..74c8c4f 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_InlineMetric.generated.cs @@ -16,7 +16,7 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_InlineMetric.cshtml" + #line 2 "..\..\Pages\_InlineMetric.cshtml" using DotNetCore.CAP.Dashboard; #line default @@ -27,7 +27,7 @@ namespace DotNetCore.CAP.Dashboard.Pages { #line hidden - protected override void Execute() + public override void Execute() { @@ -37,7 +37,7 @@ WriteLiteral("\r\n"); - #line 4 "..\..\Dashboard\Pages\_InlineMetric.cshtml" + #line 4 "..\..\Pages\_InlineMetric.cshtml" var metric = DashboardMetric.Func(this); var className = metric == null ? "metric-null" : metric.Style.ToClassName(); @@ -51,7 +51,7 @@ WriteLiteral(""); - #line 9 "..\..\Dashboard\Pages\_InlineMetric.cshtml" + #line 9 "..\..\Pages\_InlineMetric.cshtml" Write(metric?.Value); diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs index 273d9eb..25b5ed3 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_Navigation.generated.cs @@ -16,18 +16,18 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_Navigation.cshtml" + #line 2 "..\..\Pages\_Navigation.cshtml" using DotNetCore.CAP.Dashboard; #line default #line hidden [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class Navigation : RazorPage + internal partial class Navigation : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { @@ -37,7 +37,7 @@ WriteLiteral("\r\n"); - #line 4 "..\..\Dashboard\Pages\_Navigation.cshtml" + #line 4 "..\..\Pages\_Navigation.cshtml" if (NavigationMenu.Items.Count > 0) { @@ -48,12 +48,15 @@ WriteLiteral(" \r\n"); - #line 25 "..\..\Dashboard\Pages\_Navigation.cshtml" + #line 28 "..\..\Pages\_Navigation.cshtml" } #line default diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs index 21fdf9c..c7d9e79 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_Paginator.generated.cs @@ -16,24 +16,24 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 2 "..\..\Pages\_Paginator.cshtml" using DotNetCore.CAP.Dashboard; #line default #line hidden - #line 3 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 3 "..\..\Pages\_Paginator.cshtml" using DotNetCore.CAP.Dashboard.Resources; #line default #line hidden [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class Paginator : RazorPage + internal partial class Paginator : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { @@ -41,14 +41,12 @@ WriteLiteral("\r\n"); -WriteLiteral("\r\n"); - WriteLiteral("
      \r\n"); - #line 7 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 6 "..\..\Pages\_Paginator.cshtml" if (_pager.TotalPageCount > 1) { @@ -59,7 +57,7 @@ WriteLiteral("
      \r\n"); - #line 10 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 9 "..\..\Pages\_Paginator.cshtml" foreach (var page in _pager.PagerItems) { switch (page.Type) @@ -73,7 +71,7 @@ WriteLiteral(" \r\n "); - #line 16 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 15 "..\..\Pages\_Paginator.cshtml" Write(page.PageIndex); #line default #line hidden -WriteLiteral(" \r\n \r\n"); +WriteLiteral("\r\n \r\n"); - #line 18 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 17 "..\..\Pages\_Paginator.cshtml" break; case Pager.ItemType.NextPage: @@ -114,7 +112,7 @@ WriteLiteral(" \r\n "); - #line 21 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 20 "..\..\Pages\_Paginator.cshtml" Write(Strings.Paginator_Next); @@ -144,7 +142,7 @@ WriteLiteral("\r\n \r\n"); - #line 23 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 22 "..\..\Pages\_Paginator.cshtml" break; case Pager.ItemType.PrevPage: @@ -155,7 +153,7 @@ WriteLiteral(" \r\n "); - #line 26 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 25 "..\..\Pages\_Paginator.cshtml" Write(Strings.Paginator_Prev); @@ -185,7 +183,7 @@ WriteLiteral("\r\n \r\n"); - #line 28 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 27 "..\..\Pages\_Paginator.cshtml" break; case Pager.ItemType.MorePage: @@ -197,7 +195,7 @@ WriteLiteral("
      \r\n"); - #line 38 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 37 "..\..\Pages\_Paginator.cshtml" } @@ -223,7 +221,7 @@ WriteLiteral("\r\n
      \r\n "); - #line 41 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 40 "..\..\Pages\_Paginator.cshtml" Write(Strings.Paginator_TotalItems); @@ -233,13 +231,13 @@ WriteLiteral(": "); - #line 41 "..\..\Dashboard\Pages\_Paginator.cshtml" + #line 40 "..\..\Pages\_Paginator.cshtml" Write(_pager.TotalRecordCount); #line default #line hidden -WriteLiteral("\r\n
      \r\n
      \r\n"); +WriteLiteral("\r\n
    \r\n
    "); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs index 931ab0d..ed07c62 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_PerPageSelector.generated.cs @@ -16,7 +16,7 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_PerPageSelector.cshtml" + #line 2 "..\..\Pages\_PerPageSelector.cshtml" using DotNetCore.CAP.Dashboard.Resources; #line default @@ -27,7 +27,7 @@ namespace DotNetCore.CAP.Dashboard.Pages { #line hidden - protected override void Execute() + public override void Execute() { @@ -35,69 +35,69 @@ WriteLiteral("\r\n"); -WriteLiteral("\r\n
    \r\n"); +WriteLiteral("\r\n\r\n
    \r\n
    \r\n "); +WriteLiteral("
    \r\n
    \r\n
    \r\n "); - #line 14 "..\..\Dashboard\Pages\_PerPageSelector.cshtml" - Write(Strings.PerPageSelector_ItemsPerPage); + #line 15 "..\..\Pages\_PerPageSelector.cshtml" +Write(Strings.PerPageSelector_ItemsPerPage); #line default #line hidden -WriteLiteral(":\r\n
    \r\n"); +WriteLiteral(":\r\n
    "); } diff --git a/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs index ca8e4ce..52577bd 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/_SidebarMenu.generated.cs @@ -16,18 +16,12 @@ namespace DotNetCore.CAP.Dashboard.Pages using System.Linq; using System.Text; - #line 2 "..\..\Dashboard\Pages\_SidebarMenu.cshtml" - using DotNetCore.CAP.Dashboard; - - #line default - #line hidden - [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - internal partial class SidebarMenu : RazorPage + internal partial class SidebarMenu : DotNetCore.CAP.Dashboard.RazorPage { #line hidden - protected override void Execute() + public override void Execute() { @@ -35,9 +29,8 @@ WriteLiteral("\r\n"); - - #line 4 "..\..\Dashboard\Pages\_SidebarMenu.cshtml" + #line 3 "..\..\Pages\_SidebarMenu.cshtml" if (Items.Any()) { @@ -48,7 +41,7 @@ WriteLiteral(" \r\n"); - #line 21 "..\..\Dashboard\Pages\_SidebarMenu.cshtml" + #line 20 "..\..\Pages\_SidebarMenu.cshtml" } - #line default #line hidden diff --git a/src/DotNetCore.CAP.Dashboard/RazorPage.cs b/src/DotNetCore.CAP.Dashboard/RazorPage.cs index 616441d..acdf72a 100644 --- a/src/DotNetCore.CAP.Dashboard/RazorPage.cs +++ b/src/DotNetCore.CAP.Dashboard/RazorPage.cs @@ -5,9 +5,10 @@ using System; using System.Diagnostics; using System.Net; using System.Text; -using DotNetCore.CAP.Dashboard.Monitoring; +using DotNetCore.CAP.Dashboard.NodeDiscovery; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.NodeDiscovery; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.Dashboard @@ -28,7 +29,7 @@ namespace DotNetCore.CAP.Dashboard protected HtmlHelper Html { get; } public UrlHelper Url { get; private set; } - protected IStorage Storage { get; set; } + protected IDataStorage Storage { get; set; } protected string AppPath { get; set; } protected string NodeName { get; set; } @@ -55,7 +56,7 @@ namespace DotNetCore.CAP.Dashboard public string RequestPath => Request.Path; /// - protected abstract void Execute(); + public abstract void Execute(); protected string Query(string key) { @@ -95,8 +96,7 @@ namespace DotNetCore.CAP.Dashboard _statisticsLazy = new Lazy(() => { - var monitoring = Storage.GetMonitoringApi(); - var dto = monitoring.GetStatistics(); + var dto = Storage.GetMonitoringApi().GetStatistics(); SetServersCount(dto); diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs index f629203..e3b119d 100644 --- a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs +++ b/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Serialization; using Microsoft.EntityFrameworkCore.Storage; @@ -65,6 +66,7 @@ namespace DotNetCore.CAP.MySql { DbId = content.GetId(), Origin = content, + Content = StringSerializer.Serialize(content), Added = DateTime.Now, ExpiresAt = null, Retries = 0 @@ -74,7 +76,7 @@ namespace DotNetCore.CAP.MySql { Id = message.DbId, Name = name, - Content = StringSerializer.Serialize(message.Origin), + message.Content, message.Retries, message.Added, message.ExpiresAt, @@ -138,7 +140,7 @@ namespace DotNetCore.CAP.MySql var content = StringSerializer.Serialize(mdMessage.Origin); using (var connection = new MySqlConnection(_options.Value.ConnectionString)) { - + connection.Execute(sql, new { Id = mdMessage.DbId, @@ -212,24 +214,9 @@ namespace DotNetCore.CAP.MySql return result; } - //public Task GetPublishedMessageAsync(long id) - //{ - // var sql = $@"SELECT * FROM `{_prefix}.published` WHERE `Id`={id};"; - - // using (var connection = new MySqlConnection(Options.ConnectionString)) - // { - // return await connection.QueryFirstOrDefaultAsync(sql); - // } - //} - - //public Task GetReceivedMessageAsync(long id) - //{ - // var sql = - // $@"SELECT * FROM `{_prefix}.received` WHERE Id={id};"; - // using (var connection = new MySqlConnection(Options.ConnectionString)) - // { - // return await connection.QueryFirstOrDefaultAsync(sql); - // } - //} + public IMonitoringApi GetMonitoringApi() + { + return new MySqlMonitoringApi(_options); + } } } diff --git a/src/DotNetCore.CAP/Internal/Helper.cs b/src/DotNetCore.CAP/Internal/Helper.cs index a1084e2..078c740 100644 --- a/src/DotNetCore.CAP/Internal/Helper.cs +++ b/src/DotNetCore.CAP/Internal/Helper.cs @@ -9,6 +9,14 @@ namespace DotNetCore.CAP.Internal { public static class Helper { + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); + + public static long ToTimestamp(DateTime value) + { + var elapsedTime = value - Epoch; + return (long)elapsedTime.TotalSeconds; + } + public static bool IsController(TypeInfo typeInfo) { if (!typeInfo.IsClass) diff --git a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs index f1ca395..ee12b00 100644 --- a/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs +++ b/src/DotNetCore.CAP/Internal/MethodMatcherCache.cs @@ -8,7 +8,7 @@ using System.Linq; namespace DotNetCore.CAP.Internal { - internal class MethodMatcherCache + public class MethodMatcherCache { private readonly IConsumerServiceSelector _selector; diff --git a/src/DotNetCore.CAP/Persistence/IDataStorage.cs b/src/DotNetCore.CAP/Persistence/IDataStorage.cs index 9bdec2a..f7b9e42 100644 --- a/src/DotNetCore.CAP/Persistence/IDataStorage.cs +++ b/src/DotNetCore.CAP/Persistence/IDataStorage.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; namespace DotNetCore.CAP.Persistence { @@ -13,16 +14,21 @@ namespace DotNetCore.CAP.Persistence Task ChangeReceiveStateAsync(MediumMessage message, StatusName state); - Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default); + Task StoreMessageAsync(string name, Message content, object dbTransaction = null, + CancellationToken cancellationToken = default); Task StoreReceivedExceptionMessageAsync(string name, string group, string content); Task StoreReceivedMessageAsync(string name, string group, Message content); - Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default); + Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, + CancellationToken token = default); Task> GetPublishedMessagesOfNeedRetry(); Task> GetReceivedMessagesOfNeedRetry(); + + //dashboard api + IMonitoringApi GetMonitoringApi(); } -} +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Persistence/MediumMessage.cs b/src/DotNetCore.CAP/Persistence/MediumMessage.cs index 638f27d..f5ff86f 100644 --- a/src/DotNetCore.CAP/Persistence/MediumMessage.cs +++ b/src/DotNetCore.CAP/Persistence/MediumMessage.cs @@ -9,6 +9,8 @@ namespace DotNetCore.CAP.Persistence public Message Origin { get; set; } + public string Content { get; set; } + public DateTime Added { get; set; } public DateTime? ExpiresAt { get; set; } From c15ae3172dcbcff41f6ddd26cad39737682acbff Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 11 Nov 2019 19:18:54 +0800 Subject: [PATCH 21/76] Rename file --- ...qlDataStorage.cs => IDataStorage.MySql.cs} | 160 ++++++++---------- ....MySql.cs => IStorageInitializer.MySql.cs} | 6 +- 2 files changed, 78 insertions(+), 88 deletions(-) rename src/DotNetCore.CAP.MySql/{MySqlDataStorage.cs => IDataStorage.MySql.cs} (56%) rename src/DotNetCore.CAP.MySql/{IStorage.MySql.cs => IStorageInitializer.MySql.cs} (92%) diff --git a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs similarity index 56% rename from src/DotNetCore.CAP.MySql/MySqlDataStorage.cs rename to src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs index e3b119d..d4ba6da 100644 --- a/src/DotNetCore.CAP.MySql/MySqlDataStorage.cs +++ b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; using System.Data; using System.Threading; @@ -28,34 +31,32 @@ namespace DotNetCore.CAP.MySql public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) { - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) - { - var sql = $"UPDATE `{_options.Value.TableNamePrefix}.published` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + await using var connection = new MySqlConnection(_options.Value.ConnectionString); - await connection.ExecuteAsync(sql, new - { - Id = message.DbId, - message.Retries, - message.ExpiresAt, - StatusName = state.ToString("G") - }); - } + var sql = $"UPDATE `{_options.Value.TableNamePrefix}.published` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); } public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) { - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) - { - var sql = $"UPDATE `{_options.Value.TableNamePrefix}.received` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + await using var connection = new MySqlConnection(_options.Value.ConnectionString); - await connection.ExecuteAsync(sql, new - { - Id = message.DbId, - message.Retries, - message.ExpiresAt, - StatusName = state.ToString("G") - }); - } + var sql = $"UPDATE `{_options.Value.TableNamePrefix}.received` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); } public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default) @@ -85,10 +86,8 @@ namespace DotNetCore.CAP.MySql if (dbTransaction == null) { - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) - { - await connection.ExecuteAsync(sql, po); - } + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, po); } else { @@ -109,23 +108,21 @@ namespace DotNetCore.CAP.MySql { var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new { - await connection.ExecuteAsync(sql, new - { - Id = SnowflakeId.Default().NextId().ToString(), - Group = group, - Name = name, - Content = content, - Retries = _capOptions.Value.FailedRetryCount, - Added = DateTime.Now, - ExpiresAt = DateTime.Now.AddDays(15), - StatusName = nameof(StatusName.Failed) - }); - } + Id = SnowflakeId.Default().NextId().ToString(), + Group = @group, + Name = name, + Content = content, + Retries = _capOptions.Value.FailedRetryCount, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + StatusName = nameof(StatusName.Failed) + }); } - public Task StoreReceivedMessageAsync(string name, string group, Message message) + public async Task StoreReceivedMessageAsync(string name, string group, Message message) { var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; @@ -138,33 +135,28 @@ namespace DotNetCore.CAP.MySql Retries = 0 }; var content = StringSerializer.Serialize(mdMessage.Origin); - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new { - - connection.Execute(sql, new - { - Id = mdMessage.DbId, - Group = group, - Name = name, - Content = content, - mdMessage.Retries, - mdMessage.Added, - mdMessage.ExpiresAt, - StatusName = nameof(StatusName.Scheduled) - }); - } - - return Task.FromResult(mdMessage); + Id = mdMessage.DbId, + Group = @group, + Name = name, + Content = content, + mdMessage.Retries, + mdMessage.Added, + mdMessage.ExpiresAt, + StatusName = nameof(StatusName.Scheduled) + }); + return mdMessage; } public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default) { - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) - { - return await connection.ExecuteAsync( - $@"DELETE FROM `{table}` WHERE ExpiresAt < @timeout limit @batchCount;", - new { timeout, batchCount }); - } + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + + return await connection.ExecuteAsync( + $@"DELETE FROM `{table}` WHERE ExpiresAt < @timeout limit @batchCount;", + new { timeout, batchCount }); } public async Task> GetPublishedMessagesOfNeedRetry() @@ -173,19 +165,17 @@ namespace DotNetCore.CAP.MySql var sql = $"SELECT * FROM `{_options.Value.TableNamePrefix}.published` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) { - var reader = await connection.ExecuteReaderAsync(sql); - while (reader.Read()) + result.Add(new MediumMessage { - result.Add(new MediumMessage - { - DbId = reader.GetInt64(0).ToString(), - Origin = StringSerializer.DeSerialize(reader.GetString(3)), - Retries = reader.GetInt32(4), - Added = reader.GetDateTime(5) - }); - } + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); } return result; } @@ -197,20 +187,20 @@ namespace DotNetCore.CAP.MySql $"SELECT * FROM `{_options.Value.TableNamePrefix}.received` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + + await using var connection = new MySqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) { - var reader = await connection.ExecuteReaderAsync(sql); - while (reader.Read()) + result.Add(new MediumMessage { - result.Add(new MediumMessage - { - DbId = reader.GetInt64(0).ToString(), - Origin = StringSerializer.DeSerialize(reader.GetString(3)), - Retries = reader.GetInt32(4), - Added = reader.GetDateTime(5) - }); - } + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); } + return result; } diff --git a/src/DotNetCore.CAP.MySql/IStorage.MySql.cs b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs similarity index 92% rename from src/DotNetCore.CAP.MySql/IStorage.MySql.cs rename to src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs index be84cc9..e5b4d72 100644 --- a/src/DotNetCore.CAP.MySql/IStorage.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using System.Threading; using System.Threading.Tasks; using Dapper; @@ -18,8 +19,7 @@ namespace DotNetCore.CAP.MySql public MySqlStorageInitializer( ILogger logger, - IOptions options, - IOptions capOptions) + IOptions options) { _options = options; _logger = logger; @@ -43,7 +43,7 @@ namespace DotNetCore.CAP.MySql } var sql = CreateDbTablesScript(_options.Value.TableNamePrefix); - using (var connection = new MySqlConnection(_options.Value.ConnectionString)) + await using (var connection = new MySqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); } From fbf5fa61da306a5b306f6ed78b10dacfecbedc23 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 12 Nov 2019 17:28:05 +0800 Subject: [PATCH 22/76] Refactoring postgresql implementation for version 3.0 --- .../CAP.Options.Extensions.cs | 10 +- .../CAP.PostgreSqlCapOptionsExtension.cs | 10 +- .../CAP.PostgreSqlOptions.cs | 4 +- .../DotNetCore.CAP.PostgreSql.csproj | 11 +- .../ICapPublisher.PostgreSql.cs | 71 ------ .../ICapTransaction.PostgreSql.cs | 39 +++- .../ICollectlProcessor.PostgreSql.cs | 62 ----- .../IDataStorage.PostgreSql.cs | 220 ++++++++++++++++++ .../IDbContextTransaction.CAP.cs | 17 ++ .../IMonitoringApi.PostgreSql.cs | 87 ++++--- .../IStorageConnection.PostgreSql.cs | 114 --------- ...l.cs => IStorageInitializer.PostgreSql.cs} | 66 +----- .../IStorageTransaction.PostgreSql.cs | 66 ------ .../CAP.RabbitMQCapOptionsExtension.cs | 2 - .../RabbitMQConsumerClient.cs | 1 - 15 files changed, 344 insertions(+), 436 deletions(-) delete mode 100644 src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs delete mode 100644 src/DotNetCore.CAP.PostgreSql/ICollectlProcessor.PostgreSql.cs create mode 100644 src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs delete mode 100644 src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs rename src/DotNetCore.CAP.PostgreSql/{IStorage.PostgreSql.cs => IStorageInitializer.PostgreSql.cs} (53%) delete mode 100644 src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs diff --git a/src/DotNetCore.CAP.PostgreSql/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.PostgreSql/CAP.Options.Extensions.cs index 0f41f1c..8bc7a19 100644 --- a/src/DotNetCore.CAP.PostgreSql/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.PostgreSql/CAP.Options.Extensions.cs @@ -17,10 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapOptions UsePostgreSql(this CapOptions options, Action configure) { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + if (configure == null) throw new ArgumentNullException(nameof(configure)); configure += x => x.Version = options.Version; @@ -38,10 +35,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapOptions UseEntityFramework(this CapOptions options, Action configure) where TContext : DbContext { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + if (configure == null) throw new ArgumentNullException(nameof(configure)); options.RegisterExtension(new PostgreSqlCapOptionsExtension(x => { diff --git a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs index a3abe19..3be4e92 100644 --- a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs @@ -2,8 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Persistence; using DotNetCore.CAP.PostgreSql; -using DotNetCore.CAP.Processor; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -22,12 +22,10 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(provider => (PostgreSqlPublisher)provider.GetService()); - services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); services.AddTransient(); services.Configure(_configure); diff --git a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs index ba30375..db55202 100644 --- a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs +++ b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs @@ -28,16 +28,14 @@ namespace DotNetCore.CAP public void Configure(PostgreSqlOptions options) { if (options.DbContextType != null) - { using (var scope = _serviceScopeFactory.CreateScope()) { var provider = scope.ServiceProvider; - using (var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType)) + using (var dbContext = (DbContext) provider.GetRequiredService(options.DbContextType)) { options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; } } - } } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj b/src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj index fa83a1b..84fdeeb 100644 --- a/src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj +++ b/src/DotNetCore.CAP.PostgreSql/DotNetCore.CAP.PostgreSql.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.1 DotNetCore.CAP.PostgreSql $(PackageTags);PostgreSQL @@ -9,13 +9,14 @@ bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.PostgreSql.xml 1701;1702;1705;CS1591 + 8 - - - - + + + + diff --git a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs deleted file mode 100644 index 2631f7f..0000000 --- a/src/DotNetCore.CAP.PostgreSql/ICapPublisher.PostgreSql.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Npgsql; - -namespace DotNetCore.CAP.PostgreSql -{ - public class PostgreSqlPublisher : CapPublisherBase, ICallbackPublisher - { - private readonly PostgreSqlOptions _options; - - public PostgreSqlPublisher(IServiceProvider provider) : base(provider) - { - _options = provider.GetService>().Value; - } - - public async Task PublishCallbackAsync(CapPublishedMessage message) - { - await PublishAsyncInternal(message); - } - - protected override async Task ExecuteAsync(CapPublishedMessage message, ICapTransaction transaction = null, - CancellationToken cancel = default(CancellationToken)) - { - if (transaction == null) - { - using (var connection = InitDbConnection()) - { - await connection.ExecuteAsync(PrepareSql(), message); - return; - } - } - - var dbTrans = transaction.DbTransaction as IDbTransaction; - if (dbTrans == null && transaction.DbTransaction is IDbContextTransaction dbContextTrans) - { - dbTrans = dbContextTrans.GetDbTransaction(); - } - - var conn = dbTrans?.Connection; - await conn.ExecuteAsync(PrepareSql(), message, dbTrans); - } - - #region private methods - - private string PrepareSql() - { - return - $"INSERT INTO \"{_options.Schema}\".\"published\" (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")VALUES(@Id,'{_options.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - } - - private IDbConnection InitDbConnection() - { - var conn = new NpgsqlConnection(_options.ConnectionString); - conn.Open(); - return conn; - } - - #endregion private methods - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs index e185cbe..012578c 100644 --- a/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs @@ -3,6 +3,8 @@ using System.Data; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; @@ -33,6 +35,23 @@ namespace DotNetCore.CAP Flush(); } + public override async Task CommitAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + switch (DbTransaction) + { + case IDbTransaction dbTransaction: + dbTransaction.Commit(); + break; + case IDbContextTransaction dbContextTransaction: + await dbContextTransaction.CommitAsync(cancellationToken); + break; + } + + Flush(); + } + public override void Rollback() { Debug.Assert(DbTransaction != null); @@ -48,6 +67,21 @@ namespace DotNetCore.CAP } } + public override async Task RollbackAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + switch (DbTransaction) + { + case IDbTransaction dbTransaction: + dbTransaction.Rollback(); + break; + case IDbContextTransaction dbContextTransaction: + await dbContextTransaction.RollbackAsync(cancellationToken); + break; + } + } + public override void Dispose() { (DbTransaction as IDbTransaction)?.Dispose(); @@ -85,10 +119,7 @@ namespace DotNetCore.CAP public static ICapTransaction BeginTransaction(this IDbConnection dbConnection, ICapPublisher publisher, bool autoCommit = false) { - if (dbConnection.State == ConnectionState.Closed) - { - dbConnection.Open(); - } + if (dbConnection.State == ConnectionState.Closed) dbConnection.Open(); var dbTransaction = dbConnection.BeginTransaction(); publisher.Transaction.Value = publisher.ServiceProvider.GetService(); diff --git a/src/DotNetCore.CAP.PostgreSql/ICollectlProcessor.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICollectlProcessor.PostgreSql.cs deleted file mode 100644 index 8235b57..0000000 --- a/src/DotNetCore.CAP.PostgreSql/ICollectlProcessor.PostgreSql.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Processor; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Npgsql; - -namespace DotNetCore.CAP.PostgreSql -{ - internal class PostgreSqlCollectProcessor : ICollectProcessor - { - private const int MaxBatch = 1000; - - private static readonly string[] Tables = - { - "published", "received" - }; - - private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); - private readonly ILogger _logger; - private readonly PostgreSqlOptions _options; - private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); - - public PostgreSqlCollectProcessor(ILogger logger, - IOptions sqlServerOptions) - { - _logger = logger; - _options = sqlServerOptions.Value; - } - - public async Task ProcessAsync(ProcessingContext context) - { - foreach (var table in Tables) - { - _logger.LogDebug($"Collecting expired data from table [{_options.Schema}].[{table}]."); - - var removedCount = 0; - do - { - using (var connection = new NpgsqlConnection(_options.ConnectionString)) - { - removedCount = await connection.ExecuteAsync( - $"DELETE FROM \"{_options.Schema}\".\"{table}\" WHERE \"ExpiresAt\" < @now AND \"Id\" IN (SELECT \"Id\" FROM \"{_options.Schema}\".\"{table}\" LIMIT @count);", - new { now = DateTime.Now, count = MaxBatch }); - } - - if (removedCount != 0) - { - await context.WaitAsync(_delay); - context.ThrowIfStopping(); - } - } while (removedCount != 0); - } - - await context.WaitAsync(_waitingInterval); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs new file mode 100644 index 0000000..d0cc568 --- /dev/null +++ b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs @@ -0,0 +1,220 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Options; +using Npgsql; + +namespace DotNetCore.CAP.PostgreSql +{ + public class PostgreSqlDataStorage : IDataStorage + { + private readonly IOptions _capOptions; + private readonly IOptions _options; + + public PostgreSqlDataStorage( + IOptions options, + IOptions capOptions) + { + _capOptions = capOptions; + _options = options; + } + + public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) + { + var sql = + $"UPDATE \"{_options.Value.Schema}\".\"published\" SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + + public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) + { + var sql = + $"UPDATE \"{_options.Value.Schema}\".\"received\" SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + + public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, + CancellationToken cancellationToken = default) + { + var sql = + $"INSERT INTO \"{_options.Value.Schema}\".\"published\" (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var message = new MediumMessage + { + DbId = content.GetId(), + Origin = content, + Content = StringSerializer.Serialize(content), + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + var po = new + { + Id = message.DbId, + Name = name, + message.Content, + message.Retries, + message.Added, + message.ExpiresAt, + StatusName = StatusName.Scheduled + }; + + if (dbTransaction == null) + { + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, po); + } + else + { + var dbTrans = dbTransaction as IDbTransaction; + if (dbTrans == null && dbTransaction is IDbContextTransaction dbContextTrans) + dbTrans = dbContextTrans.GetDbTransaction(); + + var conn = dbTrans?.Connection; + await conn.ExecuteAsync(sql, po, dbTrans); + } + + return message; + } + + public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) + { + var sql = + $"INSERT INTO \"{_options.Value.Schema}\".\"received\"(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \"Id\";"; + + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = SnowflakeId.Default().NextId().ToString(), + Group = group, + Name = name, + Content = content, + Retries = _capOptions.Value.FailedRetryCount, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + StatusName = nameof(StatusName.Failed) + }); + } + + public async Task StoreReceivedMessageAsync(string name, string group, Message message) + { + var sql = + $"INSERT INTO \"{_options.Value.Schema}\".\"received\"(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \"Id\";"; + + var mdMessage = new MediumMessage + { + DbId = SnowflakeId.Default().NextId().ToString(), + Origin = message, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + var content = StringSerializer.Serialize(mdMessage.Origin); + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = mdMessage.DbId, + Group = group, + Name = name, + Content = content, + mdMessage.Retries, + mdMessage.Added, + mdMessage.ExpiresAt, + StatusName = nameof(StatusName.Scheduled) + }); + return mdMessage; + } + + public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, + CancellationToken token = default) + { + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + + return await connection.ExecuteAsync( + $"DELETE FROM \"{_options.Value.Schema}\".\"{table}\" WHERE \"ExpiresAt\" < @now AND \"Id\" IN (SELECT \"Id\" FROM \"{_options.Value.Schema}\".\"{table}\" LIMIT @count);", + new {timeout, batchCount}); + } + + public async Task> GetPublishedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = + $"SELECT * FROM \"{_options.Value.Schema}\".\"published\" WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; + + var result = new List(); + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + + return result; + } + + public async Task> GetReceivedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = + $"SELECT * FROM \"{_options.Value.Schema}\".\"received\" WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; + + var result = new List(); + + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + + return result; + } + + public IMonitoringApi GetMonitoringApi() + { + return new PostgreSqlMonitoringApi(_options); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IDbContextTransaction.CAP.cs b/src/DotNetCore.CAP.PostgreSql/IDbContextTransaction.CAP.cs index 980dc57..ac5f87d 100644 --- a/src/DotNetCore.CAP.PostgreSql/IDbContextTransaction.CAP.cs +++ b/src/DotNetCore.CAP.PostgreSql/IDbContextTransaction.CAP.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; using DotNetCore.CAP; // ReSharper disable once CheckNamespace @@ -33,6 +35,21 @@ namespace Microsoft.EntityFrameworkCore.Storage _transaction.Rollback(); } + public Task CommitAsync(CancellationToken cancellationToken = default) + { + return _transaction.CommitAsync(cancellationToken); + } + + public Task RollbackAsync(CancellationToken cancellationToken = default) + { + return _transaction.CommitAsync(cancellationToken); + } + public Guid TransactionId { get; } + + public ValueTask DisposeAsync() + { + return new ValueTask(Task.Run(() => _transaction.Dispose())); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs index a2c3bcb..8fde3f5 100644 --- a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs @@ -5,24 +5,45 @@ using System; using System.Collections.Generic; using System.Data; using System.Linq; +using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Dashboard; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Options; +using Npgsql; namespace DotNetCore.CAP.PostgreSql { public class PostgreSqlMonitoringApi : IMonitoringApi { - private readonly PostgreSqlOptions _options; - private readonly PostgreSqlStorage _storage; + private readonly IOptions _options; - public PostgreSqlMonitoringApi(IStorage storage, IOptions options) + public PostgreSqlMonitoringApi(IOptions options) { - _options = options.Value ?? throw new ArgumentNullException(nameof(options)); - _storage = storage as PostgreSqlStorage ?? throw new ArgumentNullException(nameof(storage)); + _options = options ?? throw new ArgumentNullException(nameof(options)); + } + + public async Task GetPublishedMessageAsync(long id) + { + var sql = + $"SELECT * FROM \"{_options.Value.Schema}\".\"published\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; + + using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) + { + return await connection.QueryFirstOrDefaultAsync(sql); + } + } + + public async Task GetReceivedMessageAsync(long id) + { + var sql = + $"SELECT * FROM \"{_options.Value.Schema}\".\"received\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; + using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) + { + return await connection.QueryFirstOrDefaultAsync(sql); + } } public StatisticsDto GetStatistics() @@ -32,7 +53,7 @@ select count(""Id"") from ""{0}"".""published"" where ""StatusName"" = N'Succeed select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Succeeded'; select count(""Id"") from ""{0}"".""published"" where ""StatusName"" = N'Failed'; select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed';", - _options.Schema); + _options.Value.Schema); var statistics = UseConnection(connection => { @@ -56,28 +77,16 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; var where = string.Empty; - if (!string.IsNullOrEmpty(queryDto.StatusName)) - { - where += " and Lower(\"StatusName\") = Lower(@StatusName)"; - } + if (!string.IsNullOrEmpty(queryDto.StatusName)) where += " and Lower(\"StatusName\") = Lower(@StatusName)"; - if (!string.IsNullOrEmpty(queryDto.Name)) - { - where += " and Lower(\"Name\") = Lower(@Name)"; - } + if (!string.IsNullOrEmpty(queryDto.Name)) where += " and Lower(\"Name\") = Lower(@Name)"; - if (!string.IsNullOrEmpty(queryDto.Group)) - { - where += " and Lower(\"Group\") = Lower(@Group)"; - } + if (!string.IsNullOrEmpty(queryDto.Group)) where += " and Lower(\"Group\") = Lower(@Group)"; - if (!string.IsNullOrEmpty(queryDto.Content)) - { - where += " and \"Content\" ILike '%@Content%'"; - } + if (!string.IsNullOrEmpty(queryDto.Content)) where += " and \"Content\" ILike '%@Content%'"; var sqlQuery = - $"select * from \"{_options.Schema}\".\"{tableName}\" where 1=1 {where} order by \"Added\" desc offset @Offset limit @Limit"; + $"select * from \"{_options.Value.Schema}\".\"{tableName}\" where 1=1 {where} order by \"Added\" desc offset @Offset limit @Limit"; return UseConnection(conn => conn.Query(sqlQuery, new { @@ -92,42 +101,42 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' public int PublishedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Failed)); + return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Failed))); } public int PublishedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", StatusName.Succeeded)); + return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Succeeded))); } public int ReceivedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Failed)); + return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Failed))); } public int ReceivedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", StatusName.Succeeded)); + return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Succeeded))); } public IDictionary HourlySucceededJobs(MessageType type) { var tableName = type == MessageType.Publish ? "published" : "received"; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Succeeded)); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Succeeded))); } public IDictionary HourlyFailedJobs(MessageType type) { var tableName = type == MessageType.Publish ? "published" : "received"; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Failed)); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Failed))); } private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) { var sqlQuery = - $"select count(\"Id\") from \"{_options.Schema}\".\"{tableName}\" where Lower(\"StatusName\") = Lower(@state)"; + $"select count(\"Id\") from \"{_options.Value.Schema}\".\"{tableName}\" where Lower(\"StatusName\") = Lower(@state)"; var count = connection.ExecuteScalar(sqlQuery, new {state = statusName}); return count; @@ -135,7 +144,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' private T UseConnection(Func action) { - return _storage.UseConnection(action); + return action(new NpgsqlConnection(_options.Value.ConnectionString)); } private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, @@ -165,7 +174,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' with aggr as ( select to_char(""Added"",'yyyy-MM-dd-HH') as ""Key"", count(""Id"") as ""Count"" - from ""{_options.Schema}"".""{tableName}"" + from ""{_options.Value.Schema}"".""{tableName}"" where ""StatusName"" = @statusName group by to_char(""Added"", 'yyyy-MM-dd-HH') ) @@ -178,9 +187,7 @@ select ""Key"",""Count"" from aggr where ""Key""= Any(@keys);"; foreach (var key in keyMaps.Keys) { if (!valuesMap.ContainsKey(key)) - { valuesMap.Add(key, 0); - } } var result = new Dictionary(); @@ -193,4 +200,10 @@ select ""Key"",""Count"" from aggr where ""Key""= Any(@keys);"; return result; } } + + internal class TimelineCounter + { + public string Key { get; set; } + public int Count { get; set; } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs deleted file mode 100644 index f2c0b5a..0000000 --- a/src/DotNetCore.CAP.PostgreSql/IStorageConnection.PostgreSql.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.Options; -using Npgsql; - -namespace DotNetCore.CAP.PostgreSql -{ - public class PostgreSqlStorageConnection : IStorageConnection - { - private readonly CapOptions _capOptions; - - public PostgreSqlStorageConnection( - IOptions options, - IOptions capOptions) - { - _capOptions = capOptions.Value; - Options = options.Value; - } - - public PostgreSqlOptions Options { get; } - - public IStorageTransaction CreateTransaction() - { - return new PostgreSqlStorageTransaction(this); - } - - public async Task GetPublishedMessageAsync(long id) - { - var sql = $"SELECT * FROM \"{Options.Schema}\".\"published\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; - - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetPublishedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT * FROM \"{Options.Schema}\".\"published\" WHERE \"Retries\"<{_capOptions.FailedRetryCount} AND \"Version\"='{_capOptions.Version}' AND \"Added\"<'{fourMinsAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; - - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public void StoreReceivedMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $"INSERT INTO \"{Options.Schema}\".\"received\"(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")VALUES(@Id,'{_capOptions.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \"Id\";"; - - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - connection.Execute(sql, message); - } - } - - public async Task GetReceivedMessageAsync(long id) - { - var sql = $"SELECT * FROM \"{Options.Schema}\".\"received\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetReceivedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT * FROM \"{Options.Schema}\".\"received\" WHERE \"Retries\"<{_capOptions.FailedRetryCount} AND \"Version\"='{_capOptions.Version}' AND \"Added\"<'{fourMinsAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public bool ChangePublishedState(long messageId, string state) - { - var sql = - $"UPDATE \"{Options.Schema}\".\"published\" SET \"Retries\"=\"Retries\"+1,\"ExpiresAt\"=NULL,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}"; - - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - - public bool ChangeReceivedState(long messageId, string state) - { - var sql = - $"UPDATE \"{Options.Schema}\".\"received\" SET \"Retries\"=\"Retries\"+1,\"ExpiresAt\"=NULL,\"StatusName\" = '{state}' WHERE \"Id\"={messageId}"; - - using (var connection = new NpgsqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IStorage.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs similarity index 53% rename from src/DotNetCore.CAP.PostgreSql/IStorage.PostgreSql.cs rename to src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs index c13d18a..69af3fa 100644 --- a/src/DotNetCore.CAP.PostgreSql/IStorage.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs @@ -1,53 +1,44 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; -using System.Data; using System.Threading; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Dashboard; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Npgsql; namespace DotNetCore.CAP.PostgreSql { - public class PostgreSqlStorage : IStorage + public class PostgreSqlStorageInitializer : IStorageInitializer { - private readonly IOptions _capOptions; - private readonly IDbConnection _existingConnection = null; private readonly ILogger _logger; private readonly IOptions _options; - public PostgreSqlStorage(ILogger logger, - IOptions capOptions, + public PostgreSqlStorageInitializer( + ILogger logger, IOptions options) { _options = options; _logger = logger; - _capOptions = capOptions; } - public IStorageConnection GetConnection() + public string GetPublishedTableName() { - return new PostgreSqlStorageConnection(_options, _capOptions); + return $"{_options.Value.Schema}.published"; } - public IMonitoringApi GetMonitoringApi() + public string GetReceivedTableName() { - return new PostgreSqlMonitoringApi(this, _options); + return $"{_options.Value.Schema}.received"; } public async Task InitializeAsync(CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) - { - return; - } + if (cancellationToken.IsCancellationRequested) return; var sql = CreateDbTablesScript(_options.Value.Schema); - using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); @@ -56,45 +47,6 @@ namespace DotNetCore.CAP.PostgreSql _logger.LogDebug("Ensuring all create database tables script are applied."); } - internal T UseConnection(Func func) - { - IDbConnection connection = null; - - try - { - connection = CreateAndOpenConnection(); - return func(connection); - } - finally - { - ReleaseConnection(connection); - } - } - - internal IDbConnection CreateAndOpenConnection() - { - var connection = _existingConnection ?? new NpgsqlConnection(_options.Value.ConnectionString); - - if (connection.State == ConnectionState.Closed) - { - connection.Open(); - } - - return connection; - } - - internal bool IsExistingConnection(IDbConnection connection) - { - return connection != null && ReferenceEquals(connection, _existingConnection); - } - - internal void ReleaseConnection(IDbConnection connection) - { - if (connection != null && !IsExistingConnection(connection)) - { - connection.Dispose(); - } - } protected virtual string CreateDbTablesScript(string schema) { diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs deleted file mode 100644 index 44750eb..0000000 --- a/src/DotNetCore.CAP.PostgreSql/IStorageTransaction.PostgreSql.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Messages; -using Npgsql; - -namespace DotNetCore.CAP.PostgreSql -{ - public class PostgreSqlStorageTransaction : IStorageTransaction - { - private readonly IDbConnection _dbConnection; - - private readonly IDbTransaction _dbTransaction; - private readonly string _schema; - - public PostgreSqlStorageTransaction(PostgreSqlStorageConnection connection) - { - var options = connection.Options; - _schema = options.Schema; - - _dbConnection = new NpgsqlConnection(options.ConnectionString); - _dbConnection.Open(); - _dbTransaction = _dbConnection.BeginTransaction(IsolationLevel.ReadCommitted); - } - - public void UpdateMessage(CapPublishedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $@"UPDATE ""{_schema}"".""published"" SET ""Retries""=@Retries,""Content""= @Content,""ExpiresAt""=@ExpiresAt,""StatusName""=@StatusName WHERE ""Id""=@Id;"; - _dbConnection.Execute(sql, message, _dbTransaction); - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $@"UPDATE ""{_schema}"".""received"" SET ""Retries""=@Retries,""Content""= @Content,""ExpiresAt""=@ExpiresAt,""StatusName""=@StatusName WHERE ""Id""=@Id;"; - _dbConnection.Execute(sql, message, _dbTransaction); - } - - public Task CommitAsync() - { - _dbTransaction.Commit(); - return Task.CompletedTask; - } - - public void Dispose() - { - _dbTransaction.Dispose(); - _dbConnection.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index 169835f..6f86746 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Internal; using DotNetCore.CAP.RabbitMQ; using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; @@ -27,7 +26,6 @@ namespace DotNetCore.CAP services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index db13dac..ba65bd4 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading; using DotNetCore.CAP.Messages; From e7f11d22b847d480729dcd22f700b298bb197b3d Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 12 Nov 2019 17:28:18 +0800 Subject: [PATCH 23/76] Fixed mysql dashboard query bug --- src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs index d626599..1e735b4 100644 --- a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs @@ -88,7 +88,7 @@ select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); if (!string.IsNullOrEmpty(queryDto.Content)) { - where += " and Content like '%@Content%'"; + where += " and Content like CONCAT('%',@Content,'%')"; } var sqlQuery = From df677948a5616e1bfa08c3831f20b83ff7b3075f Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 12 Nov 2019 17:31:37 +0800 Subject: [PATCH 24/76] Code refactoring --- .../IMonitoringApi.PostgreSql.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs index 8fde3f5..b026034 100644 --- a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs @@ -30,20 +30,16 @@ namespace DotNetCore.CAP.PostgreSql var sql = $"SELECT * FROM \"{_options.Value.Schema}\".\"published\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; - using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); } public async Task GetReceivedMessageAsync(long id) { var sql = $"SELECT * FROM \"{_options.Value.Schema}\".\"received\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; - using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } + await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); } public StatisticsDto GetStatistics() @@ -138,7 +134,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' var sqlQuery = $"select count(\"Id\") from \"{_options.Value.Schema}\".\"{tableName}\" where Lower(\"StatusName\") = Lower(@state)"; - var count = connection.ExecuteScalar(sqlQuery, new {state = statusName}); + var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); return count; } @@ -180,7 +176,7 @@ with aggr as ( ) select ""Key"",""Count"" from aggr where ""Key""= Any(@keys);"; - var valuesMap = connection.Query(sqlQuery, new {keys = keyMaps.Keys.ToList(), statusName}) + var valuesMap = connection.Query(sqlQuery, new { keys = keyMaps.Keys.ToList(), statusName }) .ToList() .ToDictionary(x => x.Key, x => x.Count); From 65a5ea836475a90e486d8a20d7f10ce4b59dfe10 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 13 Nov 2019 10:10:37 +0800 Subject: [PATCH 25/76] Refactoring sqlserver implementation for version 3.0 --- .../CAP.Options.Extensions.cs | 10 +- .../CAP.SqlServerCapOptionsExtension.cs | 10 +- .../CAP.SqlServerOptions.cs | 17 +- .../Diagnostics/DiagnosticObserver.cs | 10 +- .../DiagnosticProcessorObserver.cs | 8 +- .../DotNetCore.CAP.SqlServer.csproj | 19 +- .../ICapPublisher.SqlServer.cs | 64 ----- .../ICapTransaction.SqlServer.cs | 59 +++-- .../ICollectProcessor.SqlServer.cs | 64 ----- .../IDataStorage.SqlServer.cs | 219 ++++++++++++++++++ .../IDbContextTransaction.CAP.cs | 19 +- .../IMonitoringApi.SqlServer.cs | 72 +++--- .../IStorageConnection.SqlServer.cs | 115 --------- ...er.cs => IStorageInitializer.SqlServer.cs} | 75 ++---- .../IStorageTransaction.SqlServer.cs | 61 ----- 15 files changed, 358 insertions(+), 464 deletions(-) delete mode 100644 src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs delete mode 100644 src/DotNetCore.CAP.SqlServer/ICollectProcessor.SqlServer.cs create mode 100644 src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs delete mode 100644 src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs rename src/DotNetCore.CAP.SqlServer/{IStorage.SqlServer.cs => IStorageInitializer.SqlServer.cs} (60%) delete mode 100644 src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs diff --git a/src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs index 75af7aa..f7763d1 100644 --- a/src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.SqlServer/CAP.Options.Extensions.cs @@ -17,10 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapOptions UseSqlServer(this CapOptions options, Action configure) { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + if (configure == null) throw new ArgumentNullException(nameof(configure)); configure += x => x.Version = options.Version; @@ -38,10 +35,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapOptions UseEntityFramework(this CapOptions options, Action configure) where TContext : DbContext { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + if (configure == null) throw new ArgumentNullException(nameof(configure)); options.RegisterExtension(new SqlServerCapOptionsExtension(x => { diff --git a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs index 3fa9f9b..ff25fa6 100644 --- a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer; using DotNetCore.CAP.SqlServer.Diagnostics; using Microsoft.Extensions.DependencyInjection; @@ -25,12 +25,8 @@ namespace DotNetCore.CAP services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(x => (SqlServerPublisher)x.GetService()); - services.AddSingleton(); - + services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); services.Configure(_configure); diff --git a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs index 730e823..513e82e 100644 --- a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs +++ b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerOptions.cs @@ -28,17 +28,12 @@ namespace DotNetCore.CAP public void Configure(SqlServerOptions options) { - if (options.DbContextType != null) - { - using (var scope = _serviceScopeFactory.CreateScope()) - { - var provider = scope.ServiceProvider; - using (var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType)) - { - options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; - } - } - } + if (options.DbContextType == null) return; + + using var scope = _serviceScopeFactory.CreateScope(); + var provider = scope.ServiceProvider; + using var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType); + options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs index 46d1b55..432185a 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs @@ -4,9 +4,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Data.SqlClient; using System.Reflection; -using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; +using Microsoft.Data.SqlClient; namespace DotNetCore.CAP.SqlServer.Diagnostics { @@ -16,11 +16,11 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics public const string SqlAfterCommitTransaction = SqlClientPrefix + "WriteTransactionCommitAfter"; public const string SqlErrorCommitTransaction = SqlClientPrefix + "WriteTransactionCommitError"; - private readonly ConcurrentDictionary> _bufferList; + private readonly ConcurrentDictionary> _bufferList; private readonly IDispatcher _dispatcher; public DiagnosticObserver(IDispatcher dispatcher, - ConcurrentDictionary> bufferList) + ConcurrentDictionary> bufferList) { _dispatcher = dispatcher; _bufferList = bufferList; @@ -41,12 +41,10 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics var sqlConnection = (SqlConnection) GetProperty(evt.Value, "Connection"); var transactionKey = sqlConnection.ClientConnectionId; if (_bufferList.TryRemove(transactionKey, out var msgList)) - { foreach (var message in msgList) { _dispatcher.EnqueueToPublish(message); } - } } else if (evt.Key == SqlErrorCommitTransaction) { diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs index 2e952a2..53b22cc 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP.SqlServer.Diagnostics { @@ -17,10 +17,10 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics public DiagnosticProcessorObserver(IDispatcher dispatcher) { _dispatcher = dispatcher; - BufferList = new ConcurrentDictionary>(); + BufferList = new ConcurrentDictionary>(); } - public ConcurrentDictionary> BufferList { get; } + public ConcurrentDictionary> BufferList { get; } public void OnCompleted() { @@ -33,9 +33,7 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics public void OnNext(DiagnosticListener listener) { if (listener.Name == DiagnosticListenerName) - { listener.Subscribe(new DiagnosticObserver(_dispatcher, BufferList)); - } } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj b/src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj index 3fe74f7..25257d7 100644 --- a/src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj +++ b/src/DotNetCore.CAP.SqlServer/DotNetCore.CAP.SqlServer.csproj @@ -1,26 +1,27 @@  - netstandard2.0 + netstandard2.1 DotNetCore.CAP.SqlServer $(PackageTags);SQL Server - + - + bin\$(Configuration)\netstandard2.0\DotNetCore.CAP.SqlServer.xml 1701;1702;1705;CS1591 + 8 - + - - - - + + + + - + \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs deleted file mode 100644 index 59461eb..0000000 --- a/src/DotNetCore.CAP.SqlServer/ICapPublisher.SqlServer.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.SqlClient; -using System.Threading; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.SqlServer -{ - public class SqlServerPublisher : CapPublisherBase, ICallbackPublisher - { - private readonly SqlServerOptions _options; - - public SqlServerPublisher(IServiceProvider provider) : base(provider) - { - _options = ServiceProvider.GetService>().Value; - } - - public async Task PublishCallbackAsync(CapPublishedMessage message) - { - await PublishAsyncInternal(message); - } - - protected override async Task ExecuteAsync(CapPublishedMessage message, ICapTransaction transaction = null, - CancellationToken cancel = default(CancellationToken)) - { - if (transaction == null) - { - using (var connection = new SqlConnection(_options.ConnectionString)) - { - await connection.ExecuteAsync(PrepareSql(), message); - return; - } - } - - var dbTrans = transaction.DbTransaction as IDbTransaction; - if (dbTrans == null && transaction.DbTransaction is IDbContextTransaction dbContextTrans) - { - dbTrans = dbContextTrans.GetDbTransaction(); - } - - var conn = dbTrans?.Connection; - await conn.ExecuteAsync(PrepareSql(), message, dbTrans); - } - - #region private methods - - private string PrepareSql() - { - return - $"INSERT INTO {_options.Schema}.[Published] ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])VALUES(@Id,'{_options.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - } - - #endregion private methods - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs index 006676b..817c983 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs @@ -4,10 +4,12 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.SqlClient; +using System.Threading; +using System.Threading.Tasks; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer.Diagnostics; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; @@ -28,14 +30,12 @@ namespace DotNetCore.CAP { var sqlServerOptions = serviceProvider.GetService>().Value; if (sqlServerOptions.DbContextType != null) - { _dbContext = serviceProvider.GetService(sqlServerOptions.DbContextType) as DbContext; - } _diagnosticProcessor = serviceProvider.GetRequiredService(); } - protected override void AddToSent(CapPublishedMessage msg) + protected override void AddToSent(MediumMessage msg) { if (DbTransaction is NoopTransaction) { @@ -47,24 +47,19 @@ namespace DotNetCore.CAP if (dbTransaction == null) { if (DbTransaction is IDbContextTransaction dbContextTransaction) - { dbTransaction = dbContextTransaction.GetDbTransaction(); - } - if (dbTransaction == null) - { - throw new ArgumentNullException(nameof(DbTransaction)); - } + if (dbTransaction == null) throw new ArgumentNullException(nameof(DbTransaction)); } - var transactionKey = ((SqlConnection)dbTransaction.Connection).ClientConnectionId; + var transactionKey = ((SqlConnection) dbTransaction.Connection).ClientConnectionId; if (_diagnosticProcessor.BufferList.TryGetValue(transactionKey, out var list)) { list.Add(msg); } else { - var msgList = new List(1) { msg }; + var msgList = new List(1) {msg}; _diagnosticProcessor.BufferList.TryAdd(transactionKey, msgList); } } @@ -86,6 +81,23 @@ namespace DotNetCore.CAP } } + public override async Task CommitAsync(CancellationToken cancellationToken = default) + { + switch (DbTransaction) + { + case NoopTransaction _: + Flush(); + break; + case IDbTransaction dbTransaction: + dbTransaction.Commit(); + break; + case IDbContextTransaction dbContextTransaction: + await _dbContext.SaveChangesAsync(cancellationToken); + await dbContextTransaction.CommitAsync(cancellationToken); + break; + } + } + public override void Rollback() { switch (DbTransaction) @@ -99,6 +111,19 @@ namespace DotNetCore.CAP } } + public override async Task RollbackAsync(CancellationToken cancellationToken = default) + { + switch (DbTransaction) + { + case IDbTransaction dbTransaction: + dbTransaction.Rollback(); + break; + case IDbContextTransaction dbContextTransaction: + await dbContextTransaction.RollbackAsync(cancellationToken); + break; + } + } + public override void Dispose() { switch (DbTransaction) @@ -110,6 +135,7 @@ namespace DotNetCore.CAP dbContextTransaction.Dispose(); break; } + DbTransaction = null; } } @@ -144,15 +170,12 @@ namespace DotNetCore.CAP public static IDbTransaction BeginTransaction(this IDbConnection dbConnection, ICapPublisher publisher, bool autoCommit = false) { - if (dbConnection.State == ConnectionState.Closed) - { - dbConnection.Open(); - } + if (dbConnection.State == ConnectionState.Closed) dbConnection.Open(); var dbTransaction = dbConnection.BeginTransaction(); publisher.Transaction.Value = publisher.ServiceProvider.GetService(); var capTransaction = publisher.Transaction.Value.Begin(dbTransaction, autoCommit); - return (IDbTransaction)capTransaction.DbTransaction; + return (IDbTransaction) capTransaction.DbTransaction; } /// diff --git a/src/DotNetCore.CAP.SqlServer/ICollectProcessor.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICollectProcessor.SqlServer.cs deleted file mode 100644 index ba147d4..0000000 --- a/src/DotNetCore.CAP.SqlServer/ICollectProcessor.SqlServer.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data.SqlClient; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Processor; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.SqlServer -{ - public class SqlServerCollectProcessor : ICollectProcessor - { - private const int MaxBatch = 1000; - - private static readonly string[] Tables = - { - "Published", "Received" - }; - - private readonly ILogger _logger; - private readonly SqlServerOptions _options; - private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); - private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); - - public SqlServerCollectProcessor( - ILogger logger, - IOptions sqlServerOptions) - { - _logger = logger; - _options = sqlServerOptions.Value; - } - - public async Task ProcessAsync(ProcessingContext context) - { - foreach (var table in Tables) - { - _logger.LogDebug($"Collecting expired data from table [{_options.Schema}].[{table}]."); - - int removedCount; - do - { - using (var connection = new SqlConnection(_options.ConnectionString)) - { - removedCount = await connection.ExecuteAsync($@" -DELETE TOP (@count) -FROM [{_options.Schema}].[{table}] WITH (readpast) -WHERE ExpiresAt < @now;", new {now = DateTime.Now, count = MaxBatch}); - } - - if (removedCount != 0) - { - await context.WaitAsync(_delay); - context.ThrowIfStopping(); - } - } while (removedCount != 0); - } - - await context.WaitAsync(_waitingInterval); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs new file mode 100644 index 0000000..a665447 --- /dev/null +++ b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs @@ -0,0 +1,219 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.SqlServer +{ + public class SqlServerDataStorage : IDataStorage + { + private readonly IOptions _capOptions; + private readonly IOptions _options; + + public SqlServerDataStorage( + IOptions capOptions, + IOptions options) + { + _options = options; + _capOptions = capOptions; + } + + public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) + { + var sql = + $"UPDATE [{_options.Value.Schema}].[Published] SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; + await using var connection = new SqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + + public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) + { + var sql = + $"UPDATE [{_options.Value.Schema}].[Received] SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; + await using var connection = new SqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = message.DbId, + message.Retries, + message.ExpiresAt, + StatusName = state.ToString("G") + }); + } + + public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, + CancellationToken cancellationToken = default) + { + var sql = $"INSERT INTO {_options.Value.Schema}.[Published] ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + $"VALUES(@Id,'{_options.Value}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var message = new MediumMessage + { + DbId = content.GetId(), + Origin = content, + Content = StringSerializer.Serialize(content), + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + var po = new + { + Id = message.DbId, + Name = name, + message.Content, + message.Retries, + message.Added, + message.ExpiresAt, + StatusName = StatusName.Scheduled + }; + + if (dbTransaction == null) + { + await using var connection = new SqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, po); + } + else + { + var dbTrans = dbTransaction as IDbTransaction; + if (dbTrans == null && dbTransaction is IDbContextTransaction dbContextTrans) + dbTrans = dbContextTrans.GetDbTransaction(); + + var conn = dbTrans?.Connection; + await conn.ExecuteAsync(sql, po, dbTrans); + } + + return message; + } + + public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) + { + var sql = + $"INSERT INTO [{_options.Value.Schema}].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + await using var connection = new SqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = SnowflakeId.Default().NextId().ToString(), + Group = group, + Name = name, + Content = content, + Retries = _capOptions.Value.FailedRetryCount, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + StatusName = nameof(StatusName.Failed) + }); + } + + public async Task StoreReceivedMessageAsync(string name, string group, Message message) + { + var sql = + $"INSERT INTO [{_options.Value.Schema}].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + + var mdMessage = new MediumMessage + { + DbId = SnowflakeId.Default().NextId().ToString(), + Origin = message, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + var content = StringSerializer.Serialize(mdMessage.Origin); + await using var connection = new SqlConnection(_options.Value.ConnectionString); + await connection.ExecuteAsync(sql, new + { + Id = mdMessage.DbId, + Group = group, + Name = name, + Content = content, + mdMessage.Retries, + mdMessage.Added, + mdMessage.ExpiresAt, + StatusName = nameof(StatusName.Scheduled) + }); + return mdMessage; + } + + public async Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, + CancellationToken token = default) + { + await using var connection = new SqlConnection(_options.Value.ConnectionString); + return await connection.ExecuteAsync( + $"DELETE TOP (@batchCount) FROM [{_options.Value.Schema}].[{table}] WITH (readpast) WHERE ExpiresAt < @timeout;", + new {timeout, batchCount}); + } + + public async Task> GetPublishedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = $"SELECT TOP (200) * FROM [{_options.Value.Schema}].[Published] WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + + $"AND Version='{_capOptions.Value.Version}' AND Added<'{fourMinAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; + + var result = new List(); + await using var connection = new SqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + + return result; + } + + public async Task> GetReceivedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); + var sql = + $"SELECT TOP (200) * FROM [{_options.Value.Schema}].[Received] WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + + $"AND Version='{_capOptions.Value.Version}' AND Added<'{fourMinAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; + + var result = new List(); + + await using var connection = new SqlConnection(_options.Value.ConnectionString); + var reader = await connection.ExecuteReaderAsync(sql); + while (reader.Read()) + { + result.Add(new MediumMessage + { + DbId = reader.GetInt64(0).ToString(), + Origin = StringSerializer.DeSerialize(reader.GetString(3)), + Retries = reader.GetInt32(4), + Added = reader.GetDateTime(5) + }); + } + + return result; + } + + public IMonitoringApi GetMonitoringApi() + { + return new SqlServerMonitoringApi(_options); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IDbContextTransaction.CAP.cs b/src/DotNetCore.CAP.SqlServer/IDbContextTransaction.CAP.cs index 980dc57..e476bb0 100644 --- a/src/DotNetCore.CAP.SqlServer/IDbContextTransaction.CAP.cs +++ b/src/DotNetCore.CAP.SqlServer/IDbContextTransaction.CAP.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; using DotNetCore.CAP; // ReSharper disable once CheckNamespace @@ -18,6 +20,8 @@ namespace Microsoft.EntityFrameworkCore.Storage TransactionId = dbContextTransaction.TransactionId; } + public Guid TransactionId { get; } + public void Dispose() { _transaction.Dispose(); @@ -33,6 +37,19 @@ namespace Microsoft.EntityFrameworkCore.Storage _transaction.Rollback(); } - public Guid TransactionId { get; } + public async Task CommitAsync(CancellationToken cancellationToken = default) + { + await _transaction.CommitAsync(cancellationToken); + } + + public async Task RollbackAsync(CancellationToken cancellationToken = default) + { + await _transaction.RollbackAsync(cancellationToken); + } + + public ValueTask DisposeAsync() + { + return new ValueTask(Task.Run(() => _transaction.Dispose())); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs index a353c51..6172944 100644 --- a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs @@ -5,11 +5,13 @@ using System; using System.Collections.Generic; using System.Data; using System.Linq; +using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Dashboard; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using Microsoft.Data.SqlClient; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.SqlServer @@ -17,12 +19,10 @@ namespace DotNetCore.CAP.SqlServer internal class SqlServerMonitoringApi : IMonitoringApi { private readonly SqlServerOptions _options; - private readonly SqlServerStorage _storage; - public SqlServerMonitoringApi(IStorage storage, IOptions options) + public SqlServerMonitoringApi(IOptions options) { _options = options.Value ?? throw new ArgumentNullException(nameof(options)); - _storage = storage as SqlServerStorage ?? throw new ArgumentNullException(nameof(storage)); } public StatisticsDto GetStatistics() @@ -56,39 +56,27 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; { var tableName = type == MessageType.Publish ? "Published" : "Received"; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Failed)); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Failed))); } public IDictionary HourlySucceededJobs(MessageType type) { var tableName = type == MessageType.Publish ? "Published" : "Received"; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, StatusName.Succeeded)); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Succeeded))); } public IList Messages(MessageQueryDto queryDto) { var tableName = queryDto.MessageType == MessageType.Publish ? "Published" : "Received"; var where = string.Empty; - if (!string.IsNullOrEmpty(queryDto.StatusName)) - { - where += " and statusname=@StatusName"; - } + if (!string.IsNullOrEmpty(queryDto.StatusName)) where += " and statusname=@StatusName"; - if (!string.IsNullOrEmpty(queryDto.Name)) - { - where += " and name=@Name"; - } + if (!string.IsNullOrEmpty(queryDto.Name)) where += " and name=@Name"; - if (!string.IsNullOrEmpty(queryDto.Group)) - { - where += " and [group]=@Group"; - } + if (!string.IsNullOrEmpty(queryDto.Group)) where += " and [group]=@Group"; - if (!string.IsNullOrEmpty(queryDto.Content)) - { - where += " and content like '%@Content%'"; - } + if (!string.IsNullOrEmpty(queryDto.Content)) where += " and content like '%@Content%'"; var sqlQuery2008 = $@"select * from @@ -113,22 +101,36 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; public int PublishedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Published", StatusName.Failed)); + return UseConnection(conn => GetNumberOfMessage(conn, "Published", nameof(StatusName.Failed))); } public int PublishedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Published", StatusName.Succeeded)); + return UseConnection(conn => GetNumberOfMessage(conn, "Published", nameof(StatusName.Succeeded))); } public int ReceivedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Received", StatusName.Failed)); + return UseConnection(conn => GetNumberOfMessage(conn, "Received", nameof(StatusName.Failed))); } public int ReceivedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Received", StatusName.Succeeded)); + return UseConnection(conn => GetNumberOfMessage(conn, "Received", nameof(StatusName.Succeeded))); + } + + public async Task GetPublishedMessageAsync(long id) + { + var sql = $@"SELECT * FROM [{_options.Schema}].[Published] WITH (readpast) WHERE Id={id}"; + await using var connection = new SqlConnection(_options.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); + } + + public async Task GetReceivedMessageAsync(long id) + { + var sql = $@"SELECT * FROM [{_options.Schema}].[Received] WITH (readpast) WHERE Id={id}"; + await using var connection = new SqlConnection(_options.ConnectionString); + return await connection.QueryFirstOrDefaultAsync(sql); } private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) @@ -142,7 +144,7 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; private T UseConnection(Func action) { - return _storage.UseConnection(action); + return action(new SqlConnection(_options.ConnectionString)); } private Dictionary GetHourlyTimelineStats(IDbConnection connection, string tableName, @@ -195,10 +197,7 @@ select [Key], [Count] from aggr with (nolock) where [Key] in @keys;"; foreach (var key in keyMaps.Keys) { - if (!valuesMap.ContainsKey(key)) - { - valuesMap.Add(key, 0); - } + if (!valuesMap.ContainsKey(key)) valuesMap.Add(key, 0); } var result = new Dictionary(); @@ -211,4 +210,11 @@ select [Key], [Count] from aggr with (nolock) where [Key] in @keys;"; return result; } } + + + internal class TimelineCounter + { + public string Key { get; set; } + public int Count { get; set; } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs deleted file mode 100644 index 3ec78ed..0000000 --- a/src/DotNetCore.CAP.SqlServer/IStorageConnection.SqlServer.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.SqlServer -{ - public class SqlServerStorageConnection : IStorageConnection - { - private readonly CapOptions _capOptions; - - public SqlServerStorageConnection( - IOptions options, - IOptions capOptions) - { - _capOptions = capOptions.Value; - Options = options.Value; - } - - public SqlServerOptions Options { get; } - - public IStorageTransaction CreateTransaction() - { - return new SqlServerStorageTransaction(this); - } - - public async Task GetPublishedMessageAsync(long id) - { - var sql = $@"SELECT * FROM [{Options.Schema}].[Published] WITH (readpast) WHERE Id={id}"; - - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetPublishedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT TOP (200) * FROM [{Options.Schema}].[Published] WITH (readpast) WHERE Retries<{_capOptions.FailedRetryCount} AND Version='{_capOptions.Version}' AND Added<'{fourMinsAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; - - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public void StoreReceivedMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = $@" -INSERT INTO [{Options.Schema}].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) -VALUES(@Id,'{_capOptions.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - - using (var connection = new SqlConnection(Options.ConnectionString)) - { - connection.Execute(sql, message); - } - } - - public async Task GetReceivedMessageAsync(long id) - { - var sql = $@"SELECT * FROM [{Options.Schema}].[Received] WITH (readpast) WHERE Id={id}"; - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return await connection.QueryFirstOrDefaultAsync(sql); - } - } - - public async Task> GetReceivedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = - $"SELECT TOP (200) * FROM [{Options.Schema}].[Received] WITH (readpast) WHERE Retries<{_capOptions.FailedRetryCount} AND Version='{_capOptions.Version}' AND Added<'{fourMinsAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return await connection.QueryAsync(sql); - } - } - - public bool ChangePublishedState(long messageId, string state) - { - var sql = - $"UPDATE [{Options.Schema}].[Published] SET Retries=Retries+1,ExpiresAt=NULL,StatusName = '{state}' WHERE Id={messageId}"; - - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - - public bool ChangeReceivedState(long messageId, string state) - { - var sql = - $"UPDATE [{Options.Schema}].[Received] SET Retries=Retries+1,ExpiresAt=NULL,StatusName = '{state}' WHERE Id={messageId}"; - - using (var connection = new SqlConnection(Options.ConnectionString)) - { - return connection.Execute(sql) > 0; - } - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IStorage.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs similarity index 60% rename from src/DotNetCore.CAP.SqlServer/IStorage.SqlServer.cs rename to src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs index f2eec37..e1c83e1 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorage.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs @@ -1,59 +1,49 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; -using System.Data; -using System.Data.SqlClient; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Dapper; -using DotNetCore.CAP.Dashboard; +using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer.Diagnostics; +using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.SqlServer { - public class SqlServerStorage : IStorage + public class SqlServerStorageInitializer : IStorageInitializer { + private readonly DiagnosticProcessorObserver _diagnosticProcessorObserver; private readonly ILogger _logger; - private readonly IOptions _capOptions; private readonly IOptions _options; - private readonly IDbConnection _existingConnection = null; - private readonly DiagnosticProcessorObserver _diagnosticProcessorObserver; - public SqlServerStorage( - ILogger logger, - IOptions capOptions, + public SqlServerStorageInitializer( + ILogger logger, IOptions options, DiagnosticProcessorObserver diagnosticProcessorObserver) { _options = options; _diagnosticProcessorObserver = diagnosticProcessorObserver; _logger = logger; - _capOptions = capOptions; } - public IStorageConnection GetConnection() + public string GetPublishedTableName() { - return new SqlServerStorageConnection(_options, _capOptions); + return $"[{_options.Value.Schema}].[Published]"; } - public IMonitoringApi GetMonitoringApi() + public string GetReceivedTableName() { - return new SqlServerMonitoringApi(this, _options); + return $"[{_options.Value.Schema}].[Received]"; } - public async Task InitializeAsync(CancellationToken cancellationToken = default(CancellationToken)) + public async Task InitializeAsync(CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) - { - return; - } + if (cancellationToken.IsCancellationRequested) return; var sql = CreateDbTablesScript(_options.Value.Schema); - using (var connection = new SqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); @@ -64,6 +54,7 @@ namespace DotNetCore.CAP.SqlServer DiagnosticListener.AllListeners.Subscribe(_diagnosticProcessorObserver); } + protected virtual string CreateDbTablesScript(string schema) { var batchSql = @@ -111,45 +102,5 @@ CREATE TABLE [{schema}].[Published]( END;"; return batchSql; } - - internal T UseConnection(Func func) - { - IDbConnection connection = null; - - try - { - connection = CreateAndOpenConnection(); - return func(connection); - } - finally - { - ReleaseConnection(connection); - } - } - - internal IDbConnection CreateAndOpenConnection() - { - var connection = _existingConnection ?? new SqlConnection(_options.Value.ConnectionString); - - if (connection.State == ConnectionState.Closed) - { - connection.Open(); - } - - return connection; - } - - internal bool IsExistingConnection(IDbConnection connection) - { - return connection != null && ReferenceEquals(connection, _existingConnection); - } - - internal void ReleaseConnection(IDbConnection connection) - { - if (connection != null && !IsExistingConnection(connection)) - { - connection.Dispose(); - } - } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs deleted file mode 100644 index 33fcce7..0000000 --- a/src/DotNetCore.CAP.SqlServer/IStorageTransaction.SqlServer.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.SqlClient; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.SqlServer -{ - public class SqlServerStorageTransaction : IStorageTransaction - { - private readonly IDbConnection _dbConnection; - private readonly string _schema; - - public SqlServerStorageTransaction(SqlServerStorageConnection connection) - { - var options = connection.Options; - _schema = options.Schema; - - _dbConnection = new SqlConnection(options.ConnectionString); - _dbConnection.Open(); - } - - public void UpdateMessage(CapPublishedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $"UPDATE [{_schema}].[Published] SET [Retries] = @Retries,[Content] = @Content,[ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; - _dbConnection.Execute(sql, message); - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var sql = - $"UPDATE [{_schema}].[Received] SET [Retries] = @Retries,[Content] = @Content,[ExpiresAt] = @ExpiresAt,[StatusName]=@StatusName WHERE Id=@Id;"; - _dbConnection.Execute(sql, message); - } - - public Task CommitAsync() - { - return Task.CompletedTask; - } - - public void Dispose() - { - _dbConnection.Dispose(); - } - } -} \ No newline at end of file From d2444936a57bb6729f98b91c1622d551faec6e37 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 13 Nov 2019 17:35:51 +0800 Subject: [PATCH 26/76] Refactoring mongo implementation for version 3.0 --- .../CAP.MongoDBCapOptionsExtension.cs | 9 +- .../CAP.Options.Extensions.cs | 5 +- .../ICapPublisher.MongoDB.cs | 62 ----- .../ICapTransaction.MongoDB.cs | 33 ++- .../IClientSessionHandle.CAP.cs | 8 +- .../ICollectProcessor.MongoDB.cs | 52 ---- .../IDataStorage.MongoDB.cs | 226 ++++++++++++++++++ .../IMonitoringApi.MongoDB.cs | 121 +++++----- .../IStorageConnection.MongoDB.cs | 130 ---------- ...goDB.cs => IStorageInitializer.MongoDB.cs} | 196 +++++++-------- .../IStorageTransaction.MongoDB.cs | 71 ------ src/DotNetCore.CAP.MongoDB/StorageMessage.cs | 41 +++- 12 files changed, 437 insertions(+), 517 deletions(-) delete mode 100644 src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs delete mode 100644 src/DotNetCore.CAP.MongoDB/ICollectProcessor.MongoDB.cs create mode 100644 src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs delete mode 100644 src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs rename src/DotNetCore.CAP.MongoDB/{IStorage.MongoDB.cs => IStorageInitializer.MongoDB.cs} (60%) delete mode 100644 src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs diff --git a/src/DotNetCore.CAP.MongoDB/CAP.MongoDBCapOptionsExtension.cs b/src/DotNetCore.CAP.MongoDB/CAP.MongoDBCapOptionsExtension.cs index a3ae8bf..f9bd36d 100644 --- a/src/DotNetCore.CAP.MongoDB/CAP.MongoDBCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.MongoDB/CAP.MongoDBCapOptionsExtension.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; @@ -23,12 +23,9 @@ namespace DotNetCore.CAP.MongoDB public void AddServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(x => (MongoDBPublisher)x.GetService()); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); diff --git a/src/DotNetCore.CAP.MongoDB/CAP.Options.Extensions.cs b/src/DotNetCore.CAP.MongoDB/CAP.Options.Extensions.cs index bba7b0b..7e70a06 100644 --- a/src/DotNetCore.CAP.MongoDB/CAP.Options.Extensions.cs +++ b/src/DotNetCore.CAP.MongoDB/CAP.Options.Extensions.cs @@ -22,10 +22,7 @@ namespace Microsoft.Extensions.DependencyInjection public static CapOptions UseMongoDB(this CapOptions options, Action configure) { - if (configure == null) - { - throw new ArgumentNullException(nameof(configure)); - } + if (configure == null) throw new ArgumentNullException(nameof(configure)); configure += x => x.Version = options.Version; diff --git a/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs deleted file mode 100644 index 62e2a3e..0000000 --- a/src/DotNetCore.CAP.MongoDB/ICapPublisher.MongoDB.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB -{ - public class MongoDBPublisher : CapPublisherBase, ICallbackPublisher - { - private readonly IMongoClient _client; - private readonly MongoDBOptions _options; - - public MongoDBPublisher(IServiceProvider provider) : base(provider) - { - _options = provider.GetService>().Value; - _client = ServiceProvider.GetRequiredService(); - } - - public async Task PublishCallbackAsync(CapPublishedMessage message) - { - await PublishAsyncInternal(message); - } - - protected override Task ExecuteAsync(CapPublishedMessage message, - ICapTransaction transaction = null, - CancellationToken cancel = default) - { - var insertOptions = new InsertOneOptions { BypassDocumentValidation = false }; - - var collection = _client - .GetDatabase(_options.DatabaseName) - .GetCollection(_options.PublishedCollection); - - var store = new PublishedMessage() - { - Id = message.Id, - Name = message.Name, - Content = message.Content, - Added = message.Added, - StatusName = message.StatusName, - ExpiresAt = message.ExpiresAt, - Retries = message.Retries, - Version = _options.Version, - }; - - if (transaction == null) - { - return collection.InsertOneAsync(store, insertOptions, cancel); - } - - var dbTrans = (IClientSessionHandle)transaction.DbTransaction; - return collection.InsertOneAsync(dbTrans, store, insertOptions, cancel); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs index 7a432c0..ce9aae3 100644 --- a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; @@ -19,10 +21,16 @@ namespace DotNetCore.CAP { Debug.Assert(DbTransaction != null); - if (DbTransaction is IClientSessionHandle session) - { - session.CommitTransaction(); - } + if (DbTransaction is IClientSessionHandle session) session.CommitTransaction(); + + Flush(); + } + + public override async Task CommitAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + if (DbTransaction is IClientSessionHandle session) await session.CommitTransactionAsync(cancellationToken); Flush(); } @@ -31,10 +39,14 @@ namespace DotNetCore.CAP { Debug.Assert(DbTransaction != null); - if (DbTransaction is IClientSessionHandle session) - { - session.AbortTransaction(); - } + if (DbTransaction is IClientSessionHandle session) session.AbortTransaction(); + } + + public override async Task RollbackAsync(CancellationToken cancellationToken = default) + { + Debug.Assert(DbTransaction != null); + + if (DbTransaction is IClientSessionHandle session) await session.AbortTransactionAsync(cancellationToken); } public override void Dispose() @@ -49,10 +61,7 @@ namespace DotNetCore.CAP public static ICapTransaction Begin(this ICapTransaction transaction, IClientSessionHandle dbTransaction, bool autoCommit = false) { - if (!dbTransaction.IsInTransaction) - { - dbTransaction.StartTransaction(); - } + if (!dbTransaction.IsInTransaction) dbTransaction.StartTransaction(); transaction.DbTransaction = dbTransaction; transaction.AutoCommit = autoCommit; diff --git a/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs b/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs index 7a34177..82e5dce 100644 --- a/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs +++ b/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs @@ -26,12 +26,12 @@ namespace MongoDB.Driver _transaction.Dispose(); } - public void AbortTransaction(CancellationToken cancellationToken = default(CancellationToken)) + public void AbortTransaction(CancellationToken cancellationToken = default) { _transaction.Rollback(); } - public Task AbortTransactionAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task AbortTransactionAsync(CancellationToken cancellationToken = default) { _transaction.Rollback(); return Task.CompletedTask; @@ -47,12 +47,12 @@ namespace MongoDB.Driver _sessionHandle.AdvanceOperationTime(newOperationTime); } - public void CommitTransaction(CancellationToken cancellationToken = default(CancellationToken)) + public void CommitTransaction(CancellationToken cancellationToken = default) { _transaction.Commit(); } - public Task CommitTransactionAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task CommitTransactionAsync(CancellationToken cancellationToken = default) { _transaction.Commit(); return Task.CompletedTask; diff --git a/src/DotNetCore.CAP.MongoDB/ICollectProcessor.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICollectProcessor.MongoDB.cs deleted file mode 100644 index 5a9b200..0000000 --- a/src/DotNetCore.CAP.MongoDB/ICollectProcessor.MongoDB.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Processor; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB -{ - public class MongoDBCollectProcessor : ICollectProcessor - { - private readonly IMongoDatabase _database; - private readonly ILogger _logger; - private readonly MongoDBOptions _options; - private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); - - public MongoDBCollectProcessor( - ILogger logger, - IOptions options, - IMongoClient client) - { - _options = options.Value; - _logger = logger; - _database = client.GetDatabase(_options.DatabaseName); - } - - public async Task ProcessAsync(ProcessingContext context) - { - _logger.LogDebug($"Collecting expired data from collection [{_options.PublishedCollection}]."); - - var publishedCollection = _database.GetCollection(_options.PublishedCollection); - var receivedCollection = _database.GetCollection(_options.ReceivedCollection); - - await publishedCollection.BulkWriteAsync(new[] - { - new DeleteManyModel( - Builders.Filter.Lt(x => x.ExpiresAt, DateTime.Now)) - }); - - await receivedCollection.BulkWriteAsync(new[] - { - new DeleteManyModel( - Builders.Filter.Lt(x => x.ExpiresAt, DateTime.Now)) - }); - - await context.WaitAsync(_waitingInterval); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs new file mode 100644 index 0000000..dfa108e --- /dev/null +++ b/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs @@ -0,0 +1,226 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using MongoDB.Driver; + +namespace DotNetCore.CAP.MongoDB +{ + public class MongoDBDataStorage : IDataStorage + { + private readonly IOptions _capOptions; + private readonly IMongoClient _client; + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + private readonly IOptions _options; + + public MongoDBDataStorage( + IOptions capOptions, + IOptions options, + IMongoClient client, + ILogger logger) + { + _capOptions = capOptions; + _options = options; + _client = client; + _logger = logger; + _database = _client.GetDatabase(_options.Value.DatabaseName); + } + + public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) + { + var collection = _database.GetCollection(_options.Value.PublishedCollection); + + var updateDef = Builders.Update + .Set(x => x.Retries, message.Retries) + .Set(x => x.ExpiresAt, message.ExpiresAt) + .Set(x => x.StatusName, state.ToString("G")); + + await collection.UpdateOneAsync(x => x.Id == long.Parse(message.DbId), updateDef); + } + + public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) + { + var collection = _database.GetCollection(_options.Value.PublishedCollection); + + var updateDef = Builders.Update + .Set(x => x.Retries, message.Retries) + .Set(x => x.ExpiresAt, message.ExpiresAt) + .Set(x => x.StatusName, state.ToString("G")); + + await collection.UpdateOneAsync(x => x.Id == long.Parse(message.DbId), updateDef); + } + + public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, + CancellationToken cancellationToken = default) + { + var insertOptions = new InsertOneOptions {BypassDocumentValidation = false}; + + var message = new MediumMessage + { + DbId = content.GetId(), + Origin = content, + Content = StringSerializer.Serialize(content), + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + var collection = _database.GetCollection(_options.Value.PublishedCollection); + + var store = new PublishedMessage + { + Id = long.Parse(message.DbId), + Name = name, + Content = message.Content, + Added = message.Added, + StatusName = nameof(StatusName.Scheduled), + ExpiresAt = message.ExpiresAt, + Retries = message.Retries, + Version = _options.Value.Version + }; + + if (dbTransaction == null) + { + await collection.InsertOneAsync(store, insertOptions, cancellationToken); + } + else + { + var dbTrans = dbTransaction as IClientSessionHandle; + await collection.InsertOneAsync(dbTrans, store, insertOptions, cancellationToken); + } + + return message; + } + + public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) + { + var collection = _database.GetCollection(_options.Value.ReceivedCollection); + + var store = new ReceivedMessage + { + Id = SnowflakeId.Default().NextId(), + Group = group, + Name = name, + Content = content, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + Retries = _capOptions.Value.FailedRetryCount, + Version = _capOptions.Value.Version, + StatusName = nameof(StatusName.Failed) + }; + + await collection.InsertOneAsync(store); + } + + public async Task StoreReceivedMessageAsync(string name, string group, Message message) + { + var mdMessage = new MediumMessage + { + DbId = SnowflakeId.Default().NextId().ToString(), + Origin = message, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + var content = StringSerializer.Serialize(mdMessage.Origin); + + var collection = _database.GetCollection(_options.Value.ReceivedCollection); + + var store = new ReceivedMessage + { + Id = long.Parse(mdMessage.DbId), + Group = group, + Name = name, + Content = content, + Added = mdMessage.Added, + ExpiresAt = mdMessage.ExpiresAt, + Retries = mdMessage.Retries, + Version = _capOptions.Value.Version, + StatusName = nameof(StatusName.Scheduled) + }; + + await collection.InsertOneAsync(store); + + return mdMessage; + } + + public async Task DeleteExpiresAsync(string collection, DateTime timeout, int batchCount = 1000, + CancellationToken cancellationToken = default) + { + if (collection == _options.Value.PublishedCollection) + { + Builders.Filter.Lt(x => x.ExpiresAt, timeout); + + var publishedCollection = _database.GetCollection(_options.Value.PublishedCollection); + var ret = await publishedCollection.DeleteManyAsync(x => x.ExpiresAt < timeout, cancellationToken); + return (int) ret.DeletedCount; + } + else + { + var receivedCollection = _database.GetCollection(_options.Value.ReceivedCollection); + var ret = await receivedCollection.DeleteManyAsync(x => x.ExpiresAt < timeout, cancellationToken); + ; + return (int) ret.DeletedCount; + } + } + + public async Task> GetPublishedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4); + var collection = _database.GetCollection(_options.Value.PublishedCollection); + var queryResult = await collection + .Find(x => x.Retries < _capOptions.Value.FailedRetryCount + && x.Added < fourMinAgo + && x.Version == _capOptions.Value.Version + && (x.StatusName == nameof(StatusName.Failed) || + x.StatusName == nameof(StatusName.Scheduled))) + .Limit(200) + .ToListAsync(); + return queryResult.Select(x => new MediumMessage + { + DbId = x.Id.ToString(), + Origin = StringSerializer.DeSerialize(x.Content), + Retries = x.Retries, + Added = x.Added + }).ToList(); + } + + public async Task> GetReceivedMessagesOfNeedRetry() + { + var fourMinAgo = DateTime.Now.AddMinutes(-4); + var collection = _database.GetCollection(_options.Value.PublishedCollection); + var queryResult = await collection + .Find(x => x.Retries < _capOptions.Value.FailedRetryCount + && x.Added < fourMinAgo + && x.Version == _capOptions.Value.Version + && (x.StatusName == nameof(StatusName.Failed) || + x.StatusName == nameof(StatusName.Scheduled))) + .Limit(200) + .ToListAsync(); + return queryResult.Select(x => new MediumMessage + { + DbId = x.Id.ToString(), + Origin = StringSerializer.DeSerialize(x.Content), + Retries = x.Retries, + Added = x.Added + }).ToList(); + } + + public IMonitoringApi GetMonitoringApi() + { + return new MongoDBMonitoringApi(_client, _options); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs index 3b022f2..532c90e 100644 --- a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs @@ -3,10 +3,11 @@ using System; using System.Collections.Generic; -using DotNetCore.CAP.Dashboard; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; @@ -26,61 +27,64 @@ namespace DotNetCore.CAP.MongoDB _database = mongoClient.GetDatabase(_options.DatabaseName); } - public StatisticsDto GetStatistics() + public async Task GetPublishedMessageAsync(long id) { - var publishedCollection = _database.GetCollection(_options.PublishedCollection); - var receivedCollection = _database.GetCollection(_options.ReceivedCollection); - - var statistics = new StatisticsDto(); - - { - if (int.TryParse( - publishedCollection.CountDocuments(x => x.StatusName == StatusName.Succeeded).ToString(), - out var count)) - { - statistics.PublishedSucceeded = count; - } - } - { - if (int.TryParse(publishedCollection.CountDocuments(x => x.StatusName == StatusName.Failed).ToString(), - out var count)) - { - statistics.PublishedFailed = count; - } - } + var collection = _database.GetCollection(_options.PublishedCollection); + var message = await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); + return new MediumMessage { - if (int.TryParse( - receivedCollection.CountDocuments(x => x.StatusName == StatusName.Succeeded).ToString(), - out var count)) - { - statistics.ReceivedSucceeded = count; - } - } + Added = message.Added, + Content = message.Content, + DbId = message.Id.ToString(), + ExpiresAt = message.ExpiresAt, + Retries = message.Retries + }; + } + + public async Task GetReceivedMessageAsync(long id) + { + var collection = _database.GetCollection(_options.ReceivedCollection); + var message = await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); + return new MediumMessage { - if (int.TryParse(receivedCollection.CountDocuments(x => x.StatusName == StatusName.Failed).ToString(), - out var count)) - { - statistics.ReceivedFailed = count; - } - } + Added = message.Added, + Content = message.Content, + DbId = message.Id.ToString(), + ExpiresAt = message.ExpiresAt, + Retries = message.Retries + }; + } + + public StatisticsDto GetStatistics() + { + var publishedCollection = _database.GetCollection(_options.PublishedCollection); + var receivedCollection = _database.GetCollection(_options.ReceivedCollection); + var statistics = new StatisticsDto + { + PublishedSucceeded = + (int) publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), + PublishedFailed = + (int) publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)), + ReceivedSucceeded = + (int) receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), + ReceivedFailed = (int) receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)) + }; return statistics; } public IDictionary HourlyFailedJobs(MessageType type) { - return GetHourlyTimelineStats(type, StatusName.Failed); + return GetHourlyTimelineStats(type, nameof(StatusName.Failed)); } public IDictionary HourlySucceededJobs(MessageType type) { - return GetHourlyTimelineStats(type, StatusName.Succeeded); + return GetHourlyTimelineStats(type, nameof(StatusName.Succeeded)); } public IList Messages(MessageQueryDto queryDto) { - queryDto.StatusName = StatusName.Standardized(queryDto.StatusName); - var name = queryDto.MessageType == MessageType.Publish ? _options.PublishedCollection : _options.ReceivedCollection; @@ -89,24 +93,14 @@ namespace DotNetCore.CAP.MongoDB var builder = Builders.Filter; var filter = builder.Empty; if (!string.IsNullOrEmpty(queryDto.StatusName)) - { - filter = filter & builder.Eq(x => x.StatusName, queryDto.StatusName); - } + filter &= builder.Eq(x => x.StatusName, queryDto.StatusName); - if (!string.IsNullOrEmpty(queryDto.Name)) - { - filter = filter & builder.Eq(x => x.Name, queryDto.Name); - } + if (!string.IsNullOrEmpty(queryDto.Name)) filter &= builder.Eq(x => x.Name, queryDto.Name); - if (!string.IsNullOrEmpty(queryDto.Group)) - { - filter = filter & builder.Eq(x => x.Group, queryDto.Group); - } + if (!string.IsNullOrEmpty(queryDto.Group)) filter &= builder.Eq(x => x.Group, queryDto.Group); if (!string.IsNullOrEmpty(queryDto.Content)) - { - filter = filter & builder.Regex(x => x.Content, ".*" + queryDto.Content + ".*"); - } + filter &= builder.Regex(x => x.Content, ".*" + queryDto.Content + ".*"); var result = collection .Find(filter) @@ -120,28 +114,28 @@ namespace DotNetCore.CAP.MongoDB public int PublishedFailedCount() { - return GetNumberOfMessage(_options.PublishedCollection, StatusName.Failed); + return GetNumberOfMessage(_options.PublishedCollection, nameof(StatusName.Failed)); } public int PublishedSucceededCount() { - return GetNumberOfMessage(_options.PublishedCollection, StatusName.Succeeded); + return GetNumberOfMessage(_options.PublishedCollection, nameof(StatusName.Succeeded)); } public int ReceivedFailedCount() { - return GetNumberOfMessage(_options.ReceivedCollection, StatusName.Failed); + return GetNumberOfMessage(_options.ReceivedCollection, nameof(StatusName.Failed)); } public int ReceivedSucceededCount() { - return GetNumberOfMessage(_options.ReceivedCollection, StatusName.Succeeded); + return GetNumberOfMessage(_options.ReceivedCollection, nameof(StatusName.Succeeded)); } private int GetNumberOfMessage(string collectionName, string statusName) { var collection = _database.GetCollection(collectionName); - var count = collection.CountDocuments(new BsonDocument { { "StatusName", statusName } }); + var count = collection.CountDocuments(new BsonDocument {{"StatusName", statusName}}); return int.Parse(count.ToString()); } @@ -200,7 +194,7 @@ namespace DotNetCore.CAP.MongoDB } }; - var pipeline = new[] { match, groupby }; + var pipeline = new[] {match, groupby}; var collection = _database.GetCollection(collectionName); var result = collection.Aggregate(pipeline).ToList(); @@ -215,10 +209,7 @@ namespace DotNetCore.CAP.MongoDB result.ForEach(d => { var key = d["_id"].AsBsonDocument["Key"].AsString; - if (DateTime.TryParse(key, out var dateTime)) - { - dic[dateTime.ToLocalTime()] = d["Count"].AsInt32; - } + if (DateTime.TryParse(key, out var dateTime)) dic[dateTime.ToLocalTime()] = d["Count"].AsInt32; }); return dic; diff --git a/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs deleted file mode 100644 index 772ecb1..0000000 --- a/src/DotNetCore.CAP.MongoDB/IStorageConnection.MongoDB.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.Options; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB -{ - public class MongoDBStorageConnection : IStorageConnection - { - private readonly CapOptions _capOptions; - private readonly IMongoClient _client; - private readonly IMongoDatabase _database; - private readonly MongoDBOptions _options; - - public MongoDBStorageConnection( - IOptions capOptions, - IOptions options, - IMongoClient client) - { - _capOptions = capOptions.Value; - _options = options.Value; - _client = client; - _database = _client.GetDatabase(_options.DatabaseName); - } - - public bool ChangePublishedState(long messageId, string state) - { - var collection = _database.GetCollection(_options.PublishedCollection); - - var updateDef = Builders - .Update.Inc(x => x.Retries, 1) - .Set(x => x.ExpiresAt, null) - .Set(x => x.StatusName, state); - - var result = - collection.UpdateOne(x => x.Id == messageId, updateDef); - - return result.ModifiedCount > 0; - } - - public bool ChangeReceivedState(long messageId, string state) - { - var collection = _database.GetCollection(_options.ReceivedCollection); - - var updateDef = Builders - .Update.Inc(x => x.Retries, 1) - .Set(x => x.ExpiresAt, null) - .Set(x => x.StatusName, state); - - var result = - collection.UpdateOne(x => x.Id == messageId, updateDef); - - return result.ModifiedCount > 0; - } - - public IStorageTransaction CreateTransaction() - { - return new MongoDBStorageTransaction(_client, _options); - } - - public async Task GetPublishedMessageAsync(long id) - { - var collection = _database.GetCollection(_options.PublishedCollection); - return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); - } - - public async Task> GetPublishedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4); - var collection = _database.GetCollection(_options.PublishedCollection); - return await collection - .Find(x => x.Retries < _capOptions.FailedRetryCount - && x.Added < fourMinsAgo - && x.Version == _capOptions.Version - && (x.StatusName == StatusName.Failed || x.StatusName == StatusName.Scheduled)) - .Limit(200) - .ToListAsync(); - } - - public async Task GetReceivedMessageAsync(long id) - { - var collection = _database.GetCollection(_options.ReceivedCollection); - return await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); - } - - public async Task> GetReceivedMessagesOfNeedRetry() - { - var fourMinsAgo = DateTime.Now.AddMinutes(-4); - var collection = _database.GetCollection(_options.ReceivedCollection); - - return await collection - .Find(x => x.Retries < _capOptions.FailedRetryCount - && x.Added < fourMinsAgo - && x.Version == _capOptions.Version - && (x.StatusName == StatusName.Failed || x.StatusName == StatusName.Scheduled)) - .Limit(200) - .ToListAsync(); - } - - public void StoreReceivedMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - var collection = _database.GetCollection(_options.ReceivedCollection); - - var store = new ReceivedMessage() - { - Id = message.Id, - Group = message.Group, - Name = message.Name, - Content = message.Content, - Added = message.Added, - StatusName = message.StatusName, - ExpiresAt = message.ExpiresAt, - Retries = message.Retries, - Version = _capOptions.Version - }; - - collection.InsertOne(store); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/IStorage.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IStorageInitializer.MongoDB.cs similarity index 60% rename from src/DotNetCore.CAP.MongoDB/IStorage.MongoDB.cs rename to src/DotNetCore.CAP.MongoDB/IStorageInitializer.MongoDB.cs index f5df9fe..4d88b78 100644 --- a/src/DotNetCore.CAP.MongoDB/IStorage.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IStorageInitializer.MongoDB.cs @@ -1,108 +1,90 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Dashboard; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB -{ - public class MongoDBStorage : IStorage - { - private readonly IOptions _capOptions; - private readonly IMongoClient _client; - private readonly ILogger _logger; - private readonly IOptions _options; - - public MongoDBStorage( - IOptions capOptions, - IOptions options, - IMongoClient client, - ILogger logger) - { - _capOptions = capOptions; - _options = options; - _client = client; - _logger = logger; - } - - public IStorageConnection GetConnection() - { - return new MongoDBStorageConnection(_capOptions, _options, _client); - } - - public IMonitoringApi GetMonitoringApi() - { - return new MongoDBMonitoringApi(_client, _options); - } - - public async Task InitializeAsync(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - var options = _options.Value; - var database = _client.GetDatabase(options.DatabaseName); - var names = (await database.ListCollectionNamesAsync(cancellationToken: cancellationToken)).ToList(); - - if (names.All(n => n != options.ReceivedCollection)) - { - await database.CreateCollectionAsync(options.ReceivedCollection, cancellationToken: cancellationToken); - } - - if (names.All(n => n != options.PublishedCollection)) - { - await database.CreateCollectionAsync(options.PublishedCollection, - cancellationToken: cancellationToken); - } - - var receivedMessageIndexNames = new[] { - nameof(ReceivedMessage.Name), nameof(ReceivedMessage.Added), nameof(ReceivedMessage.ExpiresAt), - nameof(ReceivedMessage.StatusName), nameof(ReceivedMessage.Retries), nameof(ReceivedMessage.Version) }; - - var publishedMessageIndexNames = new[] { - nameof(PublishedMessage.Name), nameof(PublishedMessage.Added), nameof(PublishedMessage.ExpiresAt), - nameof(PublishedMessage.StatusName), nameof(PublishedMessage.Retries), nameof(PublishedMessage.Version) }; - - await Task.WhenAll( - TryCreateIndexesAsync(options.ReceivedCollection, receivedMessageIndexNames), - TryCreateIndexesAsync(options.PublishedCollection, publishedMessageIndexNames) - ); - - _logger.LogDebug("Ensuring all create database tables script are applied."); - - async Task TryCreateIndexesAsync(string collectionName, string[] indexNames) - { - var col = database.GetCollection(collectionName); - using (var cursor = await col.Indexes.ListAsync(cancellationToken)) - { - var existingIndexes = await cursor.ToListAsync(cancellationToken); - var existingIndexNames = existingIndexes.Select(o => o["name"].AsString).ToArray(); - indexNames = indexNames.Except(existingIndexNames).ToArray(); - } - - if (indexNames.Any() == false) - return; - - var indexes = indexNames.Select(indexName => - { - var indexOptions = new CreateIndexOptions - { - Name = indexName, - Background = true, - }; - var indexBuilder = Builders.IndexKeys; - return new CreateIndexModel(indexBuilder.Descending(indexName), indexOptions); - }).ToArray(); - - await col.Indexes.CreateManyAsync(indexes, cancellationToken); - } - } - } +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Persistence; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using MongoDB.Driver; + +namespace DotNetCore.CAP.MongoDB +{ + public class MongoDBStorageInitializer : IStorageInitializer + { + private readonly IMongoClient _client; + private readonly ILogger _logger; + private readonly IOptions _options; + + public MongoDBStorageInitializer( + ILogger logger, + IMongoClient client, + IOptions options) + { + _options = options; + _logger = logger; + _client = client; + } + + public string GetPublishedTableName() + { + return _options.Value.PublishedCollection; + } + + public string GetReceivedTableName() + { + return _options.Value.ReceivedCollection; + } + + public async Task InitializeAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) return; + + var options = _options.Value; + var database = _client.GetDatabase(options.DatabaseName); + var names = (await database.ListCollectionNamesAsync(cancellationToken: cancellationToken)).ToList(); + + if (names.All(n => n != options.ReceivedCollection)) + await database.CreateCollectionAsync(options.ReceivedCollection, cancellationToken: cancellationToken); + + if (names.All(n => n != options.PublishedCollection)) + await database.CreateCollectionAsync(options.PublishedCollection, cancellationToken: cancellationToken); + + await Task.WhenAll( + TryCreateIndexesAsync(options.ReceivedCollection), + TryCreateIndexesAsync(options.PublishedCollection)); + + _logger.LogDebug("Ensuring all create database tables script are applied."); + + + async Task TryCreateIndexesAsync(string collectionName) + { + var indexNames = new[] {"Name", "Added", "ExpiresAt", "StatusName", "Retries", "Version"}; + var col = database.GetCollection(collectionName); + using (var cursor = await col.Indexes.ListAsync(cancellationToken)) + { + var existingIndexes = await cursor.ToListAsync(cancellationToken); + var existingIndexNames = existingIndexes.Select(o => o["name"].AsString).ToArray(); + indexNames = indexNames.Except(existingIndexNames).ToArray(); + } + + if (indexNames.Any() == false) + return; + + var indexes = indexNames.Select(indexName => + { + var indexOptions = new CreateIndexOptions + { + Name = indexName, + Background = true + }; + var indexBuilder = Builders.IndexKeys; + return new CreateIndexModel(indexBuilder.Descending(indexName), indexOptions); + }).ToArray(); + + await col.Indexes.CreateManyAsync(indexes, cancellationToken); + } + } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs deleted file mode 100644 index 992aa8f..0000000 --- a/src/DotNetCore.CAP.MongoDB/IStorageTransaction.MongoDB.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB -{ - internal class MongoDBStorageTransaction : IStorageTransaction - { - private readonly IMongoDatabase _database; - private readonly MongoDBOptions _options; - private readonly IClientSessionHandle _session; - - public MongoDBStorageTransaction(IMongoClient client, MongoDBOptions options) - { - _options = options; - _database = client.GetDatabase(_options.DatabaseName); - _session = client.StartSession(); - _session.StartTransaction(); - } - - public async Task CommitAsync() - { - await _session.CommitTransactionAsync(); - } - - public void Dispose() - { - _session.Dispose(); - } - - public void UpdateMessage(CapPublishedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var collection = _database.GetCollection(_options.PublishedCollection); - - var updateDef = Builders.Update - .Set(x => x.Retries, message.Retries) - .Set(x => x.Content, message.Content) - .Set(x => x.ExpiresAt, message.ExpiresAt) - .Set(x => x.StatusName, message.StatusName); - - collection.FindOneAndUpdate(_session, x => x.Id == message.Id, updateDef); - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var collection = _database.GetCollection(_options.ReceivedCollection); - - var updateDef = Builders.Update - .Set(x => x.Retries, message.Retries) - .Set(x => x.Content, message.Content) - .Set(x => x.ExpiresAt, message.ExpiresAt) - .Set(x => x.StatusName, message.StatusName); - - collection.FindOneAndUpdate(_session, x => x.Id == message.Id, updateDef); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/StorageMessage.cs b/src/DotNetCore.CAP.MongoDB/StorageMessage.cs index ac253be..02cf6b8 100644 --- a/src/DotNetCore.CAP.MongoDB/StorageMessage.cs +++ b/src/DotNetCore.CAP.MongoDB/StorageMessage.cs @@ -1,14 +1,47 @@ -using DotNetCore.CAP.Messages; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; namespace DotNetCore.CAP.MongoDB { - internal class ReceivedMessage : CapReceivedMessage + internal class ReceivedMessage { + public long Id { get; set; } + public string Version { get; set; } + + public string Group { get; set; } + + public string Name { get; set; } + + public string Content { get; set; } + + public DateTime Added { get; set; } + + public DateTime? ExpiresAt { get; set; } + + public int Retries { get; set; } + + public string StatusName { get; set; } } - internal class PublishedMessage : CapPublishedMessage + internal class PublishedMessage { + public long Id { get; set; } + public string Version { get; set; } + + public string Name { get; set; } + + public string Content { get; set; } + + public DateTime Added { get; set; } + + public DateTime? ExpiresAt { get; set; } + + public int Retries { get; set; } + + public string StatusName { get; set; } } -} +} \ No newline at end of file From f36d68692d247c9ab5965aa62870cdd8bdef75f4 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 13 Nov 2019 17:38:26 +0800 Subject: [PATCH 27/76] Add index for mysql table --- src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs index e5b4d72..b08441c 100644 --- a/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs @@ -66,7 +66,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.received` ( `Added` datetime NOT NULL, `ExpiresAt` datetime DEFAULT NULL, `StatusName` varchar(50) NOT NULL, - PRIMARY KEY (`Id`) + PRIMARY KEY (`Id`), + INDEX `IX_ExpiresAt`(`ExpiresAt`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `{prefix}.published` ( @@ -78,7 +79,8 @@ CREATE TABLE IF NOT EXISTS `{prefix}.published` ( `Added` datetime NOT NULL, `ExpiresAt` datetime DEFAULT NULL, `StatusName` varchar(40) NOT NULL, - PRIMARY KEY (`Id`) + PRIMARY KEY (`Id`), + INDEX `IX_ExpiresAt`(`ExpiresAt`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "; return batchSql; From f37fd9ac09f6deae2f8f57ae066b0e5269d2caf6 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 13 Nov 2019 17:38:58 +0800 Subject: [PATCH 28/76] Fixed sqlserver connection async issue --- src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs index e1c83e1..66a3bb3 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs @@ -44,7 +44,7 @@ namespace DotNetCore.CAP.SqlServer if (cancellationToken.IsCancellationRequested) return; var sql = CreateDbTablesScript(_options.Value.Schema); - using (var connection = new SqlConnection(_options.Value.ConnectionString)) + await using (var connection = new SqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); } From 004ed56991f5925fef4cd416126db793280cdf64 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 15 Nov 2019 15:03:13 +0800 Subject: [PATCH 29/76] Refactoring kafka transport implementation for version 3.0 --- .../CAP.KafkaCapOptionsExtension.cs | 6 ++-- .../DotNetCore.CAP.Kafka.csproj | 2 +- .../IConnectionPool.Default.cs | 16 ++++----- src/DotNetCore.CAP.Kafka/IConnectionPool.cs | 4 +-- ...ageSender.Kafka.cs => ITransport.Kafka.cs} | 35 +++++++++++-------- .../KafkaConsumerClient.cs | 21 ++++++----- src/DotNetCore.CAP/Messages/Headers.cs | 2 +- .../Messages/TransportMessage.cs | 5 +++ 8 files changed, 50 insertions(+), 41 deletions(-) rename src/DotNetCore.CAP.Kafka/{IPublishMessageSender.Kafka.cs => ITransport.Kafka.cs} (59%) diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs index 6699eb0..f0950b7 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaCapOptionsExtension.cs @@ -3,6 +3,7 @@ using System; using DotNetCore.CAP.Kafka; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -23,10 +24,9 @@ namespace DotNetCore.CAP services.Configure(_configure); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj b/src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj index c052d29..a6d7aea 100644 --- a/src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj +++ b/src/DotNetCore.CAP.Kafka/DotNetCore.CAP.Kafka.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs index 5417bdd..0271d1d 100644 --- a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs +++ b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs @@ -3,33 +3,33 @@ using System; using System.Collections.Concurrent; +using System.Text.Json; using System.Threading; using Confluent.Kafka; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Newtonsoft.Json; namespace DotNetCore.CAP.Kafka { public class ConnectionPool : IConnectionPool, IDisposable { private readonly KafkaOptions _options; - private readonly ConcurrentQueue> _producerPool; + private readonly ConcurrentQueue> _producerPool; private int _pCount; private int _maxSize; public ConnectionPool(ILogger logger, IOptions options) { _options = options.Value; - _producerPool = new ConcurrentQueue>(); + _producerPool = new ConcurrentQueue>(); _maxSize = _options.ConnectionPoolSize; - - logger.LogDebug("Kafka configuration of CAP :\r\n {0}", JsonConvert.SerializeObject(_options.AsKafkaConfig(), Formatting.Indented)); + + logger.LogDebug("Kafka configuration of CAP :\r\n {0}", JsonSerializer.Serialize(_options.AsKafkaConfig())); } public string ServersAddress => _options.Servers; - public IProducer RentProducer() + public IProducer RentProducer() { if (_producerPool.TryDequeue(out var producer)) { @@ -38,12 +38,12 @@ namespace DotNetCore.CAP.Kafka return producer; } - producer = new ProducerBuilder(_options.AsKafkaConfig()).Build(); + producer = new ProducerBuilder(_options.AsKafkaConfig()).Build(); return producer; } - public bool Return(IProducer producer) + public bool Return(IProducer producer) { if (Interlocked.Increment(ref _pCount) <= _maxSize) { diff --git a/src/DotNetCore.CAP.Kafka/IConnectionPool.cs b/src/DotNetCore.CAP.Kafka/IConnectionPool.cs index cb62a7d..e07786d 100644 --- a/src/DotNetCore.CAP.Kafka/IConnectionPool.cs +++ b/src/DotNetCore.CAP.Kafka/IConnectionPool.cs @@ -9,8 +9,8 @@ namespace DotNetCore.CAP.Kafka { string ServersAddress { get; } - IProducer RentProducer(); + IProducer RentProducer(); - bool Return(IProducer producer); + bool Return(IProducer producer); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.Kafka/IPublishMessageSender.Kafka.cs b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs similarity index 59% rename from src/DotNetCore.CAP.Kafka/IPublishMessageSender.Kafka.cs rename to src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs index 2cd0b3e..29151a9 100644 --- a/src/DotNetCore.CAP.Kafka/IPublishMessageSender.Kafka.cs +++ b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs @@ -2,48 +2,53 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Linq; +using System.Text; using System.Threading.Tasks; using Confluent.Kafka; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Processor.States; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Kafka { - internal class KafkaPublishMessageSender : BasePublishMessageSender + internal class KafkaTransport : ITransport { private readonly IConnectionPool _connectionPool; private readonly ILogger _logger; - public KafkaPublishMessageSender( - ILogger logger, - IOptions options, - IStorageConnection connection, - IConnectionPool connectionPool, - IStateChanger stateChanger) - : base(logger, options, connection, stateChanger) + public KafkaTransport(ILogger logger, IConnectionPool connectionPool) { _logger = logger; _connectionPool = connectionPool; } - protected override string ServersAddress => _connectionPool.ServersAddress; + public string Address => _connectionPool.ServersAddress; - public override async Task PublishAsync(string keyName, string content) + public async Task SendAsync(TransportMessage message) { var producer = _connectionPool.RentProducer(); try { - var result = await producer.ProduceAsync(keyName, new Message() + var headers = new Confluent.Kafka.Headers(); + + foreach (var header in message.Headers.Select(x => new Header(x.Key, Encoding.UTF8.GetBytes(x.Value)))) + { + headers.Add(header); + } + + var result = await producer.ProduceAsync(message.GetName(), new Message { - Value = content + Headers = headers, + Key = message.GetId(), + Value = message.Body }); if (result.Status == PersistenceStatus.Persisted || result.Status == PersistenceStatus.PossiblyPersisted) { - _logger.LogDebug($"kafka topic message [{keyName}] has been published."); + _logger.LogDebug($"kafka topic message [{message.GetName()}] has been published."); return OperateResult.Success; } diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index 2a38cbf..a78eb9f 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -3,8 +3,11 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using Confluent.Kafka; +using DotNetCore.CAP.Messages; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Kafka @@ -15,7 +18,7 @@ namespace DotNetCore.CAP.Kafka private readonly string _groupId; private readonly KafkaOptions _kafkaOptions; - private IConsumer _consumerClient; + private IConsumer _consumerClient; public KafkaConsumerClient(string groupId, IOptions options) { @@ -23,7 +26,7 @@ namespace DotNetCore.CAP.Kafka _kafkaOptions = options.Value ?? throw new ArgumentNullException(nameof(options)); } - public event EventHandler OnMessageReceived; + public event EventHandler OnMessageReceived; public event EventHandler OnLog; @@ -51,12 +54,8 @@ namespace DotNetCore.CAP.Kafka if (consumerResult.IsPartitionEOF || consumerResult.Value == null) continue; - var message = new MessageContext - { - Group = _groupId, - Name = consumerResult.Topic, - Content = consumerResult.Value - }; + var header = consumerResult.Headers.ToDictionary(x => x.Key, y => Encoding.UTF8.GetString(y.GetValueBytes())); + var message = new TransportMessage(header, consumerResult.Value); OnMessageReceived?.Invoke(consumerResult, message); } @@ -97,7 +96,7 @@ namespace DotNetCore.CAP.Kafka _kafkaOptions.MainConfig["auto.offset.reset"] = "earliest"; var config = _kafkaOptions.AsKafkaConfig(); - _consumerClient = new ConsumerBuilder(config) + _consumerClient = new ConsumerBuilder(config) .SetErrorHandler(ConsumerClient_OnConsumeError) .Build(); } @@ -105,10 +104,10 @@ namespace DotNetCore.CAP.Kafka finally { _connectionLock.Release(); - } + } } - private void ConsumerClient_OnConsumeError(IConsumer consumer, Error e) + private void ConsumerClient_OnConsumeError(IConsumer consumer, Error e) { var logArgs = new LogMessageEventArgs { diff --git a/src/DotNetCore.CAP/Messages/Headers.cs b/src/DotNetCore.CAP/Messages/Headers.cs index 0d9e3da..02d1de7 100644 --- a/src/DotNetCore.CAP/Messages/Headers.cs +++ b/src/DotNetCore.CAP/Messages/Headers.cs @@ -3,7 +3,7 @@ public static class Headers { /// - /// Id of the message. Either set the ID explicitly when sending a message, or Rebus will assign one to the message. + /// Id of the message. Either set the ID explicitly when sending a message, or assign one to the message. /// public const string MessageId = "cap-msg-id"; diff --git a/src/DotNetCore.CAP/Messages/TransportMessage.cs b/src/DotNetCore.CAP/Messages/TransportMessage.cs index 7183bb4..365d823 100644 --- a/src/DotNetCore.CAP/Messages/TransportMessage.cs +++ b/src/DotNetCore.CAP/Messages/TransportMessage.cs @@ -24,6 +24,11 @@ namespace DotNetCore.CAP.Messages /// public byte[] Body { get; } + public string GetId() + { + return Headers.TryGetValue(Messages.Headers.MessageId, out var value) ? value : null; + } + public string GetName() { return Headers.TryGetValue(Messages.Headers.MessageName, out var value) ? value : null; From 3f50de25e8f41f1d9019044a29619e457cfe0198 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 15 Nov 2019 17:54:52 +0800 Subject: [PATCH 30/76] Refactoring inmemory storage implementation for version 3.0 --- .../CAP.InMemoryCapOptionsExtension.cs | 10 +- .../DotNetCore.CAP.InMemoryStorage.csproj | 4 - .../ICapPublisher.InMemory.cs | 34 ---- .../ICapTransaction.InMemory.cs | 18 ++- .../ICollectProcessor.InMemory.cs | 34 ---- .../IDataStorage.InMemory.cs | 148 ++++++++++++++++++ .../IMonitoringApi.InMemory.cs | 69 ++++---- .../IStorage.InMemory.cs | 34 ---- .../IStorageConnection.InMemory.cs | 89 ----------- .../IStorageInitializer.InMemory.cs | 27 ++++ .../IStorageTransaction.InMemory.cs | 58 ------- .../MemoryMessage.cs | 17 ++ 12 files changed, 244 insertions(+), 298 deletions(-) delete mode 100644 src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs delete mode 100644 src/DotNetCore.CAP.InMemoryStorage/ICollectProcessor.InMemory.cs create mode 100644 src/DotNetCore.CAP.InMemoryStorage/IDataStorage.InMemory.cs delete mode 100644 src/DotNetCore.CAP.InMemoryStorage/IStorage.InMemory.cs delete mode 100644 src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs create mode 100644 src/DotNetCore.CAP.InMemoryStorage/IStorageInitializer.InMemory.cs delete mode 100644 src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs create mode 100644 src/DotNetCore.CAP.InMemoryStorage/MemoryMessage.cs diff --git a/src/DotNetCore.CAP.InMemoryStorage/CAP.InMemoryCapOptionsExtension.cs b/src/DotNetCore.CAP.InMemoryStorage/CAP.InMemoryCapOptionsExtension.cs index df03218..a1ede44 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/CAP.InMemoryCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/CAP.InMemoryCapOptionsExtension.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using DotNetCore.CAP.InMemoryStorage; -using DotNetCore.CAP.Processor; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -13,14 +13,10 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(x => (InMemoryPublisher)x.GetService()); - services.AddSingleton(); services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/DotNetCore.CAP.InMemoryStorage.csproj b/src/DotNetCore.CAP.InMemoryStorage/DotNetCore.CAP.InMemoryStorage.csproj index 9375b62..f450ce2 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/DotNetCore.CAP.InMemoryStorage.csproj +++ b/src/DotNetCore.CAP.InMemoryStorage/DotNetCore.CAP.InMemoryStorage.csproj @@ -11,10 +11,6 @@ 1701;1702;1705;CS1591 - - - - diff --git a/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs deleted file mode 100644 index 6cb759c..0000000 --- a/src/DotNetCore.CAP.InMemoryStorage/ICapPublisher.InMemory.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP.InMemoryStorage -{ - public class InMemoryPublisher : CapPublisherBase, ICallbackPublisher - { - public InMemoryPublisher(IServiceProvider provider) : base(provider) - { - } - - public async Task PublishCallbackAsync(CapPublishedMessage message) - { - await PublishAsyncInternal(message); - } - - protected override Task ExecuteAsync(CapPublishedMessage message, ICapTransaction transaction, - CancellationToken cancel = default(CancellationToken)) - { - var connection = (InMemoryStorageConnection)ServiceProvider.GetService(); - - connection.PublishedMessages.Add(message); - - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs index 26c84b6..e4813be 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs @@ -2,9 +2,13 @@ // Licensed under the MIT License. See License.txt in the project root for license information. // ReSharper disable once CheckNamespace -namespace DotNetCore.CAP + +using System.Threading; +using System.Threading.Tasks; + +namespace DotNetCore.CAP.InMemoryStorage { - public class InMemoryCapTransaction : CapTransactionBase + internal class InMemoryCapTransaction : CapTransactionBase { public InMemoryCapTransaction(IDispatcher dispatcher) : base(dispatcher) { @@ -15,11 +19,21 @@ namespace DotNetCore.CAP Flush(); } + public override Task CommitAsync(CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + public override void Rollback() { //Ignore } + public override Task RollbackAsync(CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + public override void Dispose() { } diff --git a/src/DotNetCore.CAP.InMemoryStorage/ICollectProcessor.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/ICollectProcessor.InMemory.cs deleted file mode 100644 index 16c0267..0000000 --- a/src/DotNetCore.CAP.InMemoryStorage/ICollectProcessor.InMemory.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Processor; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP.InMemoryStorage -{ - internal class InMemoryCollectProcessor : ICollectProcessor - { - private readonly ILogger _logger; - private readonly TimeSpan _waitingInterval = TimeSpan.FromMinutes(5); - - public InMemoryCollectProcessor(ILogger logger) - { - _logger = logger; - } - - public async Task ProcessAsync(ProcessingContext context) - { - _logger.LogDebug($"Collecting expired data from memory list."); - - var connection = (InMemoryStorageConnection)context.Provider.GetService(); - - connection.PublishedMessages.RemoveAll(x => x.ExpiresAt < DateTime.Now); - connection.ReceivedMessages.RemoveAll(x => x.ExpiresAt < DateTime.Now); - - await context.WaitAsync(_waitingInterval); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/IDataStorage.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IDataStorage.InMemory.cs new file mode 100644 index 0000000..0ced410 --- /dev/null +++ b/src/DotNetCore.CAP.InMemoryStorage/IDataStorage.InMemory.cs @@ -0,0 +1,148 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Serialization; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.InMemoryStorage +{ + internal class InMemoryStorage : IDataStorage + { + private readonly IOptions _capOptions; + + public InMemoryStorage(IOptions capOptions) + { + _capOptions = capOptions; + } + + public static IList PublishedMessages { get; } = new List(); + + public static IList ReceivedMessages { get; } = new List(); + + public Task ChangePublishStateAsync(MediumMessage message, StatusName state) + { + PublishedMessages.First(x => x.DbId == message.DbId).StatusName = state; + return Task.CompletedTask; + } + + public Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) + { + ReceivedMessages.First(x => x.DbId == message.DbId).StatusName = state; + return Task.CompletedTask; + } + + public Task StoreMessageAsync(string name, Message content, object dbTransaction = null, + CancellationToken cancellationToken = default) + { + var message = new MediumMessage + { + DbId = content.GetId(), + Origin = content, + Content = StringSerializer.Serialize(content), + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + PublishedMessages.Add(new MemoryMessage() + { + DbId = message.DbId, + Name = name, + Content = message.Content, + Retries = message.Retries, + Added = message.Added, + ExpiresAt = message.ExpiresAt, + StatusName = StatusName.Scheduled + }); + + return Task.FromResult(message); + } + + public Task StoreReceivedExceptionMessageAsync(string name, string group, string content) + { + ReceivedMessages.Add(new MemoryMessage + { + DbId = SnowflakeId.Default().NextId().ToString(), + Group = group, + Name = name, + Content = content, + Retries = _capOptions.Value.FailedRetryCount, + Added = DateTime.Now, + ExpiresAt = DateTime.Now.AddDays(15), + StatusName = StatusName.Failed + }); + + return Task.CompletedTask; + } + + public Task StoreReceivedMessageAsync(string name, string @group, Message message) + { + var mdMessage = new MediumMessage + { + DbId = SnowflakeId.Default().NextId().ToString(), + Origin = message, + Added = DateTime.Now, + ExpiresAt = null, + Retries = 0 + }; + + ReceivedMessages.Add(new MemoryMessage + { + DbId = mdMessage.DbId, + Group = group, + Name = name, + Content = StringSerializer.Serialize(mdMessage.Origin), + Retries = mdMessage.Retries, + Added = mdMessage.Added, + ExpiresAt = mdMessage.ExpiresAt, + StatusName = StatusName.Failed + }); + + return Task.FromResult(mdMessage); + } + + public Task DeleteExpiresAsync(string table, DateTime timeout, int batchCount = 1000, CancellationToken token = default) + { + var ret = table == nameof(PublishedMessages) + ? ((List)PublishedMessages).RemoveAll(x => x.ExpiresAt < timeout) + : ((List)ReceivedMessages).RemoveAll(x => x.ExpiresAt < timeout); + return Task.FromResult(ret); + } + + public Task> GetPublishedMessagesOfNeedRetry() + { + var ret = PublishedMessages + .Where(x => x.Retries < _capOptions.Value.FailedRetryCount + && x.Added < DateTime.Now.AddSeconds(-10) + && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed)) + .Take(200) + .Select(x => (MediumMessage)x); + return Task.FromResult(ret); + } + + public Task> GetReceivedMessagesOfNeedRetry() + { + var ret = ReceivedMessages + .Where(x => x.Retries < _capOptions.Value.FailedRetryCount + && x.Added < DateTime.Now.AddSeconds(-10) + && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed)) + .Take(200) + .Select(x => (MediumMessage)x); + return Task.FromResult(ret); + } + + public IMonitoringApi GetMonitoringApi() + { + return new InMemoryMonitoringApi(); + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs index 7454435..1db101b 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs @@ -3,56 +3,59 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; -using DotNetCore.CAP.Dashboard; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Monitoring; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP.InMemoryStorage { internal class InMemoryMonitoringApi : IMonitoringApi { - private readonly IStorage _storage; + public Task GetPublishedMessageAsync(long id) + { + return Task.FromResult((MediumMessage)InMemoryStorage.PublishedMessages.First(x => x.DbId == id.ToString(CultureInfo.InvariantCulture))); + } - public InMemoryMonitoringApi(IStorage storage) + public Task GetReceivedMessageAsync(long id) { - _storage = storage; + return Task.FromResult((MediumMessage)InMemoryStorage.ReceivedMessages.First(x => x.DbId == id.ToString(CultureInfo.InvariantCulture))); } public StatisticsDto GetStatistics() { - var connection = GetConnection(); var stats = new StatisticsDto { - PublishedSucceeded = connection.PublishedMessages.Count(x => x.StatusName == StatusName.Succeeded), - ReceivedSucceeded = connection.ReceivedMessages.Count(x => x.StatusName == StatusName.Succeeded), - PublishedFailed = connection.PublishedMessages.Count(x => x.StatusName == StatusName.Failed), - ReceivedFailed = connection.ReceivedMessages.Count(x => x.StatusName == StatusName.Failed) + PublishedSucceeded = InMemoryStorage.PublishedMessages.Count(x => x.StatusName == StatusName.Succeeded), + ReceivedSucceeded = InMemoryStorage.ReceivedMessages.Count(x => x.StatusName == StatusName.Succeeded), + PublishedFailed = InMemoryStorage.PublishedMessages.Count(x => x.StatusName == StatusName.Failed), + ReceivedFailed = InMemoryStorage.ReceivedMessages.Count(x => x.StatusName == StatusName.Failed) }; return stats; } public IDictionary HourlyFailedJobs(MessageType type) { - return GetHourlyTimelineStats(type, StatusName.Failed); + return GetHourlyTimelineStats(type, nameof(StatusName.Failed)); } public IDictionary HourlySucceededJobs(MessageType type) { - return GetHourlyTimelineStats(type, StatusName.Succeeded); + return GetHourlyTimelineStats(type, nameof(StatusName.Succeeded)); } public IList Messages(MessageQueryDto queryDto) { - var connection = GetConnection(); if (queryDto.MessageType == MessageType.Publish) { - var expression = connection.PublishedMessages.Where(x => true); + var expression = InMemoryStorage.PublishedMessages.Where(x => true); if (!string.IsNullOrEmpty(queryDto.StatusName)) { - expression = expression.Where(x => x.StatusName.ToLower() == queryDto.StatusName); + expression = expression.Where(x => x.StatusName.ToString() == queryDto.StatusName); } if (!string.IsNullOrEmpty(queryDto.Name)) @@ -73,19 +76,19 @@ namespace DotNetCore.CAP.InMemoryStorage Added = x.Added, Content = x.Content, ExpiresAt = x.ExpiresAt, - Id = x.Id, + Id = long.Parse(x.DbId), Name = x.Name, Retries = x.Retries, - StatusName = x.StatusName + StatusName = x.StatusName.ToString() }).ToList(); } else { - var expression = connection.ReceivedMessages.Where(x => true); + var expression = InMemoryStorage.ReceivedMessages.Where(x => true); if (!string.IsNullOrEmpty(queryDto.StatusName)) { - expression = expression.Where(x => x.StatusName.ToLower() == queryDto.StatusName); + expression = expression.Where(x => x.StatusName.ToString() == queryDto.StatusName); } if (!string.IsNullOrEmpty(queryDto.Name)) @@ -113,37 +116,32 @@ namespace DotNetCore.CAP.InMemoryStorage Version = "N/A", Content = x.Content, ExpiresAt = x.ExpiresAt, - Id = x.Id, + Id = long.Parse(x.DbId), Name = x.Name, Retries = x.Retries, - StatusName = x.StatusName + StatusName = x.StatusName.ToString() }).ToList(); } } public int PublishedFailedCount() { - return GetConnection().PublishedMessages.Count(x => x.StatusName == StatusName.Failed); + return InMemoryStorage.PublishedMessages.Count(x => x.StatusName == StatusName.Failed); } public int PublishedSucceededCount() { - return GetConnection().PublishedMessages.Count(x => x.StatusName == StatusName.Succeeded); + return InMemoryStorage.PublishedMessages.Count(x => x.StatusName == StatusName.Succeeded); } public int ReceivedFailedCount() { - return GetConnection().ReceivedMessages.Count(x => x.StatusName == StatusName.Failed); + return InMemoryStorage.ReceivedMessages.Count(x => x.StatusName == StatusName.Failed); } public int ReceivedSucceededCount() { - return GetConnection().ReceivedMessages.Count(x => x.StatusName == StatusName.Succeeded); - } - - private InMemoryStorageConnection GetConnection() - { - return (InMemoryStorageConnection)_storage.GetConnection(); + return InMemoryStorage.ReceivedMessages.Count(x => x.StatusName == StatusName.Succeeded); } private Dictionary GetHourlyTimelineStats(MessageType type, string statusName) @@ -158,20 +156,19 @@ namespace DotNetCore.CAP.InMemoryStorage var keyMaps = dates.ToDictionary(x => x.ToString("yyyy-MM-dd-HH"), x => x); - var connection = GetConnection(); Dictionary valuesMap; if (type == MessageType.Publish) { - valuesMap = connection.PublishedMessages - .Where(x => x.StatusName == statusName) + valuesMap = InMemoryStorage.PublishedMessages + .Where(x => x.StatusName.ToString() == statusName) .GroupBy(x => x.Added.ToString("yyyy-MM-dd-HH")) .ToDictionary(x => x.Key, x => x.Count()); } else { - valuesMap = connection.ReceivedMessages - .Where(x => x.StatusName == statusName) + valuesMap = InMemoryStorage.ReceivedMessages + .Where(x => x.StatusName.ToString() == statusName) .GroupBy(x => x.Added.ToString("yyyy-MM-dd-HH")) .ToDictionary(x => x.Key, x => x.Count()); } diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorage.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorage.InMemory.cs deleted file mode 100644 index 55cf139..0000000 --- a/src/DotNetCore.CAP.InMemoryStorage/IStorage.InMemory.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Dashboard; - -namespace DotNetCore.CAP.InMemoryStorage -{ - public class InMemoryStorage : IStorage - { - private readonly IStorageConnection _connection; - - public InMemoryStorage(IStorageConnection connection) - { - _connection = connection; - } - - public IStorageConnection GetConnection() - { - return _connection; - } - - public IMonitoringApi GetMonitoringApi() - { - return new InMemoryMonitoringApi(this); - } - - public Task InitializeAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs deleted file mode 100644 index 22364b0..0000000 --- a/src/DotNetCore.CAP.InMemoryStorage/IStorageConnection.InMemory.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Async; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP.InMemoryStorage -{ - public class InMemoryStorageConnection : IStorageConnection - { - private readonly CapOptions _capOptions; - - public InMemoryStorageConnection(IOptions capOptions) - { - _capOptions = capOptions.Value; - - PublishedMessages = new List(); - ReceivedMessages = new List(); - } - - internal List PublishedMessages { get; } - - internal List ReceivedMessages { get; } - - public IStorageTransaction CreateTransaction() - { - return new InMemoryStorageTransaction(this); - } - - public Task GetPublishedMessageAsync(long id) - { - return PublishedMessages.ToAsyncEnumerable().FirstOrDefaultAsync(x => x.Id == id); - } - - public async Task> GetPublishedMessagesOfNeedRetry() - { - return await PublishedMessages.ToAsyncEnumerable() - .Where(x => x.Retries < _capOptions.FailedRetryCount - && x.Added < DateTime.Now.AddSeconds(-10) - && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed)) - .Take(200) - .ToListAsync(); - } - - public void StoreReceivedMessage(CapReceivedMessage message) - { - ReceivedMessages.Add(message); - } - - public Task GetReceivedMessageAsync(long id) - { - return ReceivedMessages.ToAsyncEnumerable().FirstOrDefaultAsync(x => x.Id == id); - } - - public async Task> GetReceivedMessagesOfNeedRetry() - { - return await ReceivedMessages.ToAsyncEnumerable() - .Where(x => x.Retries < _capOptions.FailedRetryCount - && x.Added < DateTime.Now.AddSeconds(-10) - && (x.StatusName == StatusName.Scheduled || x.StatusName == StatusName.Failed)) - .Take(200) - .ToListAsync(); - } - - public bool ChangePublishedState(long messageId, string state) - { - var msg = PublishedMessages.First(x => x.Id == messageId); - msg.Retries++; - msg.ExpiresAt = null; - msg.StatusName = state; - return true; - } - - public bool ChangeReceivedState(long messageId, string state) - { - var msg = ReceivedMessages.First(x => x.Id == messageId); - msg.Retries++; - msg.ExpiresAt = null; - msg.StatusName = state; - return true; - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorageInitializer.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorageInitializer.InMemory.cs new file mode 100644 index 0000000..544bcf7 --- /dev/null +++ b/src/DotNetCore.CAP.InMemoryStorage/IStorageInitializer.InMemory.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Persistence; + +namespace DotNetCore.CAP.InMemoryStorage +{ + internal class InMemoryStorageInitializer : IStorageInitializer + { + public string GetPublishedTableName() + { + return nameof(InMemoryStorage.PublishedMessages); + } + + public string GetReceivedTableName() + { + return nameof(InMemoryStorage.ReceivedMessages); + } + + public Task InitializeAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs deleted file mode 100644 index a63d8a5..0000000 --- a/src/DotNetCore.CAP.InMemoryStorage/IStorageTransaction.InMemory.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.InMemoryStorage -{ - public class InMemoryStorageTransaction : IStorageTransaction - { - private readonly InMemoryStorageConnection _connection; - - public InMemoryStorageTransaction(InMemoryStorageConnection connection) - { - _connection = connection; - } - - public void UpdateMessage(CapPublishedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - var msg = _connection.PublishedMessages.FirstOrDefault(x => message.Id == x.Id); - if (msg == null) return; - msg.Retries = message.Retries; - msg.Content = message.Content; - msg.ExpiresAt = message.ExpiresAt; - msg.StatusName = message.StatusName; - } - - public void UpdateMessage(CapReceivedMessage message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - var msg = _connection.ReceivedMessages.FirstOrDefault(x => message.Id == x.Id); - if (msg == null) return; - msg.Retries = message.Retries; - msg.Content = message.Content; - msg.ExpiresAt = message.ExpiresAt; - msg.StatusName = message.StatusName; - } - - public Task CommitAsync() - { - return Task.CompletedTask; - } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP.InMemoryStorage/MemoryMessage.cs b/src/DotNetCore.CAP.InMemoryStorage/MemoryMessage.cs new file mode 100644 index 0000000..53bb070 --- /dev/null +++ b/src/DotNetCore.CAP.InMemoryStorage/MemoryMessage.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Persistence; + +namespace DotNetCore.CAP.InMemoryStorage +{ + internal class MemoryMessage : MediumMessage + { + public string Name { get; set; } + + public StatusName StatusName { get; set; } + + public string Group { get; set; } + } +} From 45c8745e0bd7717967a48cda4225012e9a7467d8 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 18 Nov 2019 15:41:35 +0800 Subject: [PATCH 31/76] Refactoring azure serverbus transport implementation for version 3.0 --- .../AzureServiceBusConsumerClient.cs | 14 +++---- .../CAP.AzureServiceBusOptions.cs | 1 - .../CAP.AzureServiceBusOptionsExtension.cs | 4 +- ...ceBus.cs => ITransport.AzureServiceBus.cs} | 38 +++++++++---------- 4 files changed, 28 insertions(+), 29 deletions(-) rename src/DotNetCore.CAP.AzureServiceBus/{IPublishMessageSender.AzureServiceBus.cs => ITransport.AzureServiceBus.cs} (59%) diff --git a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs index 7f61a74..5a69eb7 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs @@ -7,10 +7,12 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Messages; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Management; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Message = Microsoft.Azure.ServiceBus.Message; namespace DotNetCore.CAP.AzureServiceBus { @@ -36,7 +38,7 @@ namespace DotNetCore.CAP.AzureServiceBus _asbOptions = options.Value ?? throw new ArgumentNullException(nameof(options)); } - public event EventHandler OnMessageReceived; + public event EventHandler OnMessageReceived; public event EventHandler OnLog; @@ -160,12 +162,10 @@ namespace DotNetCore.CAP.AzureServiceBus private Task OnConsumerReceived(Message message, CancellationToken token) { _lockToken = message.SystemProperties.LockToken; - var context = new MessageContext - { - Group = _subscriptionName, - Name = message.Label, - Content = Encoding.UTF8.GetString(message.Body) - }; + + var header = message.UserProperties.ToDictionary(x => x.Key, y => y.Value.ToString()); + + var context = new TransportMessage(header, message.Body); OnMessageReceived?.Invoke(null, context); diff --git a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptions.cs b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptions.cs index e6f9f2d..ef78199 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptions.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptions.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Primitives; // ReSharper disable once CheckNamespace diff --git a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs index 1a2feac..9b3ea98 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/CAP.AzureServiceBusOptionsExtension.cs @@ -3,6 +3,7 @@ using System; using DotNetCore.CAP.AzureServiceBus; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace @@ -24,8 +25,7 @@ namespace DotNetCore.CAP services.Configure(_configure); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.AzureServiceBus/IPublishMessageSender.AzureServiceBus.cs b/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs similarity index 59% rename from src/DotNetCore.CAP.AzureServiceBus/IPublishMessageSender.AzureServiceBus.cs rename to src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs index b68039e..74b1f38 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/IPublishMessageSender.AzureServiceBus.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs @@ -2,18 +2,18 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Text; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Processor.States; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Azure.ServiceBus; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.AzureServiceBus { - internal class AzureServiceBusPublishMessageSender : BasePublishMessageSender + internal class AzureServiceBusTransport : ITransport { private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(initialCount: 1, maxCount: 1); @@ -22,38 +22,38 @@ namespace DotNetCore.CAP.AzureServiceBus private ITopicClient _topicClient; - public AzureServiceBusPublishMessageSender( - ILogger logger, + public AzureServiceBusTransport( + ILogger logger, IOptions options, - IOptions asbOptions, - IStateChanger stateChanger, - IStorageConnection connection) - : base(logger, options, connection, stateChanger) + IOptions asbOptions) { _logger = logger; _asbOptions = asbOptions; } - protected override string ServersAddress => _asbOptions.Value.ConnectionString; + public string Address => _asbOptions.Value.ConnectionString; - public override async Task PublishAsync(string keyName, string content) + public async Task SendAsync(TransportMessage transportMessage) { try { Connect(); - var contentBytes = Encoding.UTF8.GetBytes(content); - - var message = new Message + var message = new Microsoft.Azure.ServiceBus.Message { - MessageId = Guid.NewGuid().ToString(), - Body = contentBytes, - Label = keyName, + MessageId = transportMessage.GetId(), + Body = transportMessage.Body, + Label = transportMessage.GetName() }; + foreach (var header in transportMessage.Headers) + { + message.UserProperties.Add(header.Key, header.Value); + } + await _topicClient.SendAsync(message); - _logger.LogDebug($"Azure Service Bus message [{keyName}] has been published."); + _logger.LogDebug($"Azure Service Bus message [{transportMessage.GetName()}] has been published."); return OperateResult.Success; } @@ -78,7 +78,7 @@ namespace DotNetCore.CAP.AzureServiceBus { if (_topicClient == null) { - _topicClient = new TopicClient(ServersAddress, _asbOptions.Value.TopicPath, RetryPolicy.NoRetry); + _topicClient = new TopicClient(Address, _asbOptions.Value.TopicPath, RetryPolicy.NoRetry); } } finally From 9f84d7bfae09de572d863f9bed9c3b011cc8c18c Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 18 Nov 2019 15:49:09 +0800 Subject: [PATCH 32/76] Update samples to netcoreapp3.0 --- .../Sample.AzureServiceBus.InMemory.csproj | 8 +++----- .../Sample.AzureServiceBus.InMemory/Startup.cs | 8 ++++++-- .../Sample.Kafka.MySql.csproj | 8 +++----- samples/Sample.Kafka.MySql/Startup.cs | 8 ++++++-- .../Sample.RabbitMQ.MongoDB.csproj | 6 ++---- samples/Sample.RabbitMQ.MongoDB/Startup.cs | 18 +++++++----------- .../ITransport.AzureServiceBus.cs | 1 - 7 files changed, 27 insertions(+), 30 deletions(-) diff --git a/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj b/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj index faa0a12..740cd66 100644 --- a/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj +++ b/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj @@ -1,16 +1,14 @@  - netcoreapp2.2 + netcoreapp3.0 NU1701 NU1701 - - - - + + diff --git a/samples/Sample.AzureServiceBus.InMemory/Startup.cs b/samples/Sample.AzureServiceBus.InMemory/Startup.cs index 4da741e..75b59f3 100644 --- a/samples/Sample.AzureServiceBus.InMemory/Startup.cs +++ b/samples/Sample.AzureServiceBus.InMemory/Startup.cs @@ -14,12 +14,16 @@ namespace Sample.AzureServiceBus.InMemory x.UseDashboard(); }); - services.AddMvc(); + services.AddControllers(); } public void Configure(IApplicationBuilder app) { - app.UseMvc(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); } } } \ No newline at end of file diff --git a/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj b/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj index 4bb65ec..bf42fb7 100644 --- a/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj +++ b/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj @@ -1,15 +1,13 @@  - netcoreapp2.2 + netcoreapp3.0 NU1701 NU1701 - - - - + + diff --git a/samples/Sample.Kafka.MySql/Startup.cs b/samples/Sample.Kafka.MySql/Startup.cs index 3a6a8f7..edaf074 100644 --- a/samples/Sample.Kafka.MySql/Startup.cs +++ b/samples/Sample.Kafka.MySql/Startup.cs @@ -15,12 +15,16 @@ namespace Sample.Kafka.MySql x.UseDashboard(); }); - services.AddMvc(); + services.AddControllers(); } public void Configure(IApplicationBuilder app) { - app.UseMvc(); + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); } } } \ No newline at end of file diff --git a/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj b/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj index 1725688..08b56d7 100644 --- a/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj +++ b/samples/Sample.RabbitMQ.MongoDB/Sample.RabbitMQ.MongoDB.csproj @@ -1,14 +1,12 @@  - netcoreapp2.2 + netcoreapp3.0 7.1 - - - + diff --git a/samples/Sample.RabbitMQ.MongoDB/Startup.cs b/samples/Sample.RabbitMQ.MongoDB/Startup.cs index da07bd3..bd80f11 100644 --- a/samples/Sample.RabbitMQ.MongoDB/Startup.cs +++ b/samples/Sample.RabbitMQ.MongoDB/Startup.cs @@ -1,7 +1,4 @@ -using System; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; @@ -26,17 +23,16 @@ namespace Sample.RabbitMQ.MongoDB x.UseRabbitMQ("192.168.2.120"); x.UseDashboard(); }); - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddControllers(); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app) { - if (env.IsDevelopment()) + app.UseRouting(); + app.UseEndpoints(endpoints => { - app.UseDeveloperExceptionPage(); - } - - app.UseMvc(); + endpoints.MapControllers(); + }); } } } diff --git a/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs b/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs index 74b1f38..9e20c96 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/ITransport.AzureServiceBus.cs @@ -24,7 +24,6 @@ namespace DotNetCore.CAP.AzureServiceBus public AzureServiceBusTransport( ILogger logger, - IOptions options, IOptions asbOptions) { _logger = logger; From b3aeb1a2479d7d1ca63270004a581ede6c0ac756 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 18 Nov 2019 16:46:10 +0800 Subject: [PATCH 33/76] Refactoring namespace --- .../AzureServiceBusConsumerClient.cs | 1 + .../AzureServiceBusConsumerClientFactory.cs | 1 + .../DashboardRoutes.cs | 2 + .../CAP.DiscoveryOptionsExtensions.cs | 1 + .../NodeDiscovery/IProcessingServer.Consul.cs | 2 + .../ICapTransaction.InMemory.cs | 1 + .../KafkaConsumerClient.cs | 1 + .../KafkaConsumerClientFactory.cs | 1 + .../ICapTransaction.MongoDB.cs | 1 + .../ICapTransaction.MySql.cs | 1 + .../ICapTransaction.PostgreSql.cs | 1 + .../RabbitMQConsumerClient.cs | 1 + .../RabbitMQConsumerClientFactory.cs | 1 + .../Diagnostics/DiagnosticObserver.cs | 1 + .../DiagnosticProcessorObserver.cs | 1 + .../ICapTransaction.SqlServer.cs | 1 + .../Abstractions/IModelBinderFactory.cs | 21 - .../Abstractions/ModelBinding/IModelBinder.cs | 15 - .../ModelBinding/ModelBindingResult.cs | 104 ---- src/DotNetCore.CAP/CAP.Attribute.cs | 2 +- src/DotNetCore.CAP/CAP.Builder.cs | 1 - .../CAP.ServiceCollectionExtensions.cs | 2 +- src/DotNetCore.CAP/ICapTransaction.Base.cs | 1 + .../ConsumerExecutorDescriptor.cs | 3 +- .../Internal/ConsumerInvokerFactory.cs | 1 - .../{ => Internal}/IBootstrapper.Default.cs | 4 +- .../{ => Internal}/IBootstrapper.cs | 2 +- .../ICapPublisher.Default.cs} | 6 +- .../IConsumerRegister.Default.cs | 6 +- .../{ => Internal}/IConsumerRegister.cs | 2 +- .../IConsumerServiceSelector.Default.cs | 464 +++++++++--------- .../IConsumerServiceSelector.cs | 2 +- .../IMongoTransaction.cs | 6 +- .../{ => Internal}/IProcessingServer.cs | 2 +- .../ISubscriberExecutor.Default.cs} | 5 +- .../{ => Internal}/ISubscriberExecutor.cs | 2 +- .../Internal/LoggerExtensions.cs | 2 +- .../TopicAttribute.cs | 2 +- .../Monitoring/MessageQueryDto.cs | 1 + .../Processor/IDispatcher.Default.cs | 1 + .../Processor/IProcessingServer.Cap.cs | 1 + .../Processor/IProcessor.TransportCheck.cs | 1 + .../{ => Transport}/IConsumerClient.cs | 2 +- .../{ => Transport}/IConsumerClientFactory.cs | 2 +- .../{ => Transport}/IDispatcher.cs | 3 +- .../{ => Transport}/MqLogType.cs | 2 +- .../ModelBinderFactoryTest.cs | 46 -- test/DotNetCore.CAP.Test/SnowflakeIdTest.cs | 2 +- 48 files changed, 282 insertions(+), 452 deletions(-) delete mode 100644 src/DotNetCore.CAP/Abstractions/IModelBinderFactory.cs delete mode 100644 src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs delete mode 100644 src/DotNetCore.CAP/Abstractions/ModelBinding/ModelBindingResult.cs rename src/DotNetCore.CAP/{ => Internal}/ConsumerExecutorDescriptor.cs (93%) rename src/DotNetCore.CAP/{ => Internal}/IBootstrapper.Default.cs (95%) rename src/DotNetCore.CAP/{ => Internal}/IBootstrapper.cs (93%) rename src/DotNetCore.CAP/{Abstractions/CapPublisher.cs => Internal/ICapPublisher.Default.cs} (97%) rename src/DotNetCore.CAP/{ => Internal}/IConsumerRegister.Default.cs (99%) rename src/DotNetCore.CAP/{ => Internal}/IConsumerRegister.cs (91%) rename src/DotNetCore.CAP/{ => Internal}/IConsumerServiceSelector.Default.cs (96%) rename src/DotNetCore.CAP/{ => Internal}/IConsumerServiceSelector.cs (97%) rename src/DotNetCore.CAP/{Abstractions => Internal}/IMongoTransaction.cs (73%) rename src/DotNetCore.CAP/{ => Internal}/IProcessingServer.cs (91%) rename src/DotNetCore.CAP/{ISubscribeExecutor.Default.cs => Internal/ISubscriberExecutor.Default.cs} (99%) rename src/DotNetCore.CAP/{ => Internal}/ISubscriberExecutor.cs (94%) rename src/DotNetCore.CAP/{Abstractions => Internal}/TopicAttribute.cs (95%) rename src/DotNetCore.CAP/{ => Transport}/IConsumerClient.cs (97%) rename src/DotNetCore.CAP/{ => Transport}/IConsumerClientFactory.cs (93%) rename src/DotNetCore.CAP/{ => Transport}/IDispatcher.cs (85%) rename src/DotNetCore.CAP/{ => Transport}/MqLogType.cs (94%) delete mode 100644 test/DotNetCore.CAP.Test/ModelBinderFactoryTest.cs diff --git a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs index 5a69eb7..ceb7b13 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClient.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Azure.ServiceBus; using Microsoft.Azure.ServiceBus.Management; using Microsoft.Extensions.Logging; diff --git a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClientFactory.cs b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClientFactory.cs index 20f25f6..d7dd426 100644 --- a/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClientFactory.cs +++ b/src/DotNetCore.CAP.AzureServiceBus/AzureServiceBusConsumerClientFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs index 3ba3ba8..86b04aa 100644 --- a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs +++ b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs @@ -3,6 +3,8 @@ using System.Reflection; using DotNetCore.CAP.Dashboard.Pages; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.Dashboard diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs index 400e91c..488f3cb 100644 --- a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/CAP.DiscoveryOptionsExtensions.cs @@ -3,6 +3,7 @@ using System; using DotNetCore.CAP; +using DotNetCore.CAP.Internal; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.Dashboard.NodeDiscovery diff --git a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs index c801698..9dd565b 100644 --- a/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs +++ b/src/DotNetCore.CAP.Dashboard/NodeDiscovery/IProcessingServer.Consul.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using DotNetCore.CAP.Internal; + namespace DotNetCore.CAP.Dashboard.NodeDiscovery { internal class ConsulProcessingNodeServer : IProcessingServer diff --git a/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs index e4813be..6d99bc5 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/ICapTransaction.InMemory.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Transport; namespace DotNetCore.CAP.InMemoryStorage { diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index a78eb9f..d9e111e 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading; using Confluent.Kafka; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Kafka diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClientFactory.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClientFactory.cs index 1c1ebf0..59374bd 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClientFactory.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClientFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Kafka diff --git a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs index ce9aae3..1694b86 100644 --- a/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/ICapTransaction.MongoDB.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; diff --git a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs index fac7430..66c320e 100644 --- a/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs +++ b/src/DotNetCore.CAP.MySql/ICapTransaction.MySql.cs @@ -5,6 +5,7 @@ using System.Data; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Transport; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; diff --git a/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs index 012578c..76aeb20 100644 --- a/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/ICapTransaction.PostgreSql.cs @@ -5,6 +5,7 @@ using System.Data; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Transport; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs index ba65bd4..2e61906 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClient.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Options; using RabbitMQ.Client; using RabbitMQ.Client.Events; diff --git a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClientFactory.cs b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClientFactory.cs index 0a9d541..ff178b5 100644 --- a/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClientFactory.cs +++ b/src/DotNetCore.CAP.RabbitMQ/RabbitMQConsumerClientFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Options; namespace DotNetCore.CAP.RabbitMQ diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs index 432185a..1f43bd7 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Transport; using Microsoft.Data.SqlClient; namespace DotNetCore.CAP.SqlServer.Diagnostics diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs index 53b22cc..ea14ca2 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticProcessorObserver.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Transport; namespace DotNetCore.CAP.SqlServer.Diagnostics { diff --git a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs index 817c983..7a7d4e9 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer.Diagnostics; +using DotNetCore.CAP.Transport; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/DotNetCore.CAP/Abstractions/IModelBinderFactory.cs b/src/DotNetCore.CAP/Abstractions/IModelBinderFactory.cs deleted file mode 100644 index ce5de92..0000000 --- a/src/DotNetCore.CAP/Abstractions/IModelBinderFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Reflection; -using DotNetCore.CAP.Abstractions.ModelBinding; - -namespace DotNetCore.CAP.Abstractions -{ - /// - /// Model binder factory. - /// - public interface IModelBinderFactory - { - /// - /// Create a model binder by parameter. - /// - /// The method parameter info - /// A model binder instance. - IModelBinder CreateBinder(ParameterInfo parameter); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs b/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs deleted file mode 100644 index 6914c47..0000000 --- a/src/DotNetCore.CAP/Abstractions/ModelBinding/IModelBinder.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Threading.Tasks; - -namespace DotNetCore.CAP.Abstractions.ModelBinding -{ - /// - /// Defines an interface for model binders. - /// - public interface IModelBinder - { - Task BindModelAsync(string content); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Abstractions/ModelBinding/ModelBindingResult.cs b/src/DotNetCore.CAP/Abstractions/ModelBinding/ModelBindingResult.cs deleted file mode 100644 index 62a9337..0000000 --- a/src/DotNetCore.CAP/Abstractions/ModelBinding/ModelBindingResult.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using DotNetCore.CAP.Internal; - -namespace DotNetCore.CAP.Abstractions.ModelBinding -{ - /// - /// Contains the result of model binding. - /// - public struct ModelBindingResult - { - /// - /// Creates a representing a failed model binding operation. - /// - /// A representing a failed model binding operation. - public static ModelBindingResult Failed() - { - return new ModelBindingResult(null, false); - } - - /// - /// Creates a representing a successful model binding operation. - /// - /// The model value. May be null. - /// A representing a successful model bind. - public static ModelBindingResult Success(object model) - { - return new ModelBindingResult(model, true); - } - - private ModelBindingResult(object model, bool isSuccess) - { - Model = model; - IsSuccess = isSuccess; - } - - /// - /// Gets the model associated with this context. - /// - public object Model { get; } - - public bool IsSuccess { get; } - - public override string ToString() - { - if (IsSuccess) - { - return $"Success '{Model}'"; - } - - return "Failed"; - } - - public override bool Equals(object obj) - { - var other = obj as ModelBindingResult?; - if (other == null) - { - return false; - } - - return Equals(other.Value); - } - - public override int GetHashCode() - { - var hashCodeCombiner = HashCodeCombiner.Start(); - hashCodeCombiner.Add(IsSuccess); - hashCodeCombiner.Add(Model); - - return hashCodeCombiner.CombinedHash; - } - - public bool Equals(ModelBindingResult other) - { - return - IsSuccess == other.IsSuccess && - Equals(Model, other.Model); - } - - /// - /// Compares objects for equality. - /// - /// A . - /// A . - /// true if the objects are equal, otherwise false. - public static bool operator ==(ModelBindingResult x, ModelBindingResult y) - { - return x.Equals(y); - } - - /// - /// Compares objects for inequality. - /// - /// A . - /// A . - /// true if the objects are not equal, otherwise false. - public static bool operator !=(ModelBindingResult x, ModelBindingResult y) - { - return !x.Equals(y); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/CAP.Attribute.cs b/src/DotNetCore.CAP/CAP.Attribute.cs index 242bc47..40092a5 100644 --- a/src/DotNetCore.CAP/CAP.Attribute.cs +++ b/src/DotNetCore.CAP/CAP.Attribute.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using DotNetCore.CAP.Abstractions; +using DotNetCore.CAP.Internal; // ReSharper disable once CheckNamespace namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/CAP.Builder.cs b/src/DotNetCore.CAP/CAP.Builder.cs index c737b8a..ba58e2c 100644 --- a/src/DotNetCore.CAP/CAP.Builder.cs +++ b/src/DotNetCore.CAP/CAP.Builder.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Abstractions; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index 2275439..bd59c21 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -3,10 +3,10 @@ using System; using DotNetCore.CAP; -using DotNetCore.CAP.Abstractions; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Processor; using DotNetCore.CAP.Serialization; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection.Extensions; // ReSharper disable once CheckNamespace diff --git a/src/DotNetCore.CAP/ICapTransaction.Base.cs b/src/DotNetCore.CAP/ICapTransaction.Base.cs index 1df1af2..6a9a92e 100644 --- a/src/DotNetCore.CAP/ICapTransaction.Base.cs +++ b/src/DotNetCore.CAP/ICapTransaction.Base.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Transport; namespace DotNetCore.CAP { diff --git a/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs b/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs similarity index 93% rename from src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs rename to src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs index 6a7795a..b7a0f8f 100644 --- a/src/DotNetCore.CAP/ConsumerExecutorDescriptor.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerExecutorDescriptor.cs @@ -4,9 +4,8 @@ using System; using System.Collections.Generic; using System.Reflection; -using DotNetCore.CAP.Abstractions; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// A descriptor of user definition method. diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index cb7247a..10381af 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using DotNetCore.CAP.Abstractions; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Internal diff --git a/src/DotNetCore.CAP/IBootstrapper.Default.cs b/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs similarity index 95% rename from src/DotNetCore.CAP/IBootstrapper.Default.cs rename to src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs index f580efa..9f09318 100644 --- a/src/DotNetCore.CAP/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs @@ -9,10 +9,10 @@ using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// - /// Default implement of . + /// Default implement of . /// internal class DefaultBootstrapper : BackgroundService, IBootstrapper { diff --git a/src/DotNetCore.CAP/IBootstrapper.cs b/src/DotNetCore.CAP/Internal/IBootstrapper.cs similarity index 93% rename from src/DotNetCore.CAP/IBootstrapper.cs rename to src/DotNetCore.CAP/Internal/IBootstrapper.cs index b781c55..67fc601 100644 --- a/src/DotNetCore.CAP/IBootstrapper.cs +++ b/src/DotNetCore.CAP/Internal/IBootstrapper.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// Represents bootstrapping logic. For example, adding initial state to the storage or querying certain entities. diff --git a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs similarity index 97% rename from src/DotNetCore.CAP/Abstractions/CapPublisher.cs rename to src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index d9dd8de..e822fb6 100644 --- a/src/DotNetCore.CAP/Abstractions/CapPublisher.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -7,14 +7,14 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.DependencyInjection; -namespace DotNetCore.CAP.Abstractions +namespace DotNetCore.CAP.Internal { - public class CapPublisher : ICapPublisher + internal class CapPublisher : ICapPublisher { private readonly IDispatcher _dispatcher; private readonly IDataStorage _storage; diff --git a/src/DotNetCore.CAP/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs similarity index 99% rename from src/DotNetCore.CAP/IConsumerRegister.Default.cs rename to src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index dd4f2ec..70e800c 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -4,19 +4,17 @@ using System; using System.Diagnostics; using System.Linq; -using System.Text; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Serialization; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { internal class ConsumerRegister : IConsumerRegister { diff --git a/src/DotNetCore.CAP/IConsumerRegister.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.cs similarity index 91% rename from src/DotNetCore.CAP/IConsumerRegister.cs rename to src/DotNetCore.CAP/Internal/IConsumerRegister.cs index 58b7327..1ae1323 100644 --- a/src/DotNetCore.CAP/IConsumerRegister.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// Handler received message of subscribed. diff --git a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs similarity index 96% rename from src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs rename to src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs index e7b9a56..7233980 100644 --- a/src/DotNetCore.CAP/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs @@ -1,233 +1,231 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; -using DotNetCore.CAP.Abstractions; -using Microsoft.Extensions.DependencyInjection; -using System.Collections.Concurrent; -using DotNetCore.CAP.Internal; -using Microsoft.Extensions.Options; - -namespace DotNetCore.CAP -{ - /// - /// - /// A default implementation. - /// - public class DefaultConsumerServiceSelector : IConsumerServiceSelector - { - private readonly CapOptions _capOptions; - private readonly IServiceProvider _serviceProvider; - - /// - /// since this class be designed as a Singleton service,the following two list must be thread safe! - /// - private readonly ConcurrentDictionary>> _asteriskList; - private readonly ConcurrentDictionary>> _poundList; - - /// - /// Creates a new . - /// - public DefaultConsumerServiceSelector(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - _capOptions = serviceProvider.GetService>().Value; - - _asteriskList = new ConcurrentDictionary>>(); - _poundList = new ConcurrentDictionary>>(); - } - - public IReadOnlyList SelectCandidates() - { - var executorDescriptorList = new List(); - - executorDescriptorList.AddRange(FindConsumersFromInterfaceTypes(_serviceProvider)); - - executorDescriptorList.AddRange(FindConsumersFromControllerTypes()); - - return executorDescriptorList; - } - - public ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList executeDescriptor) - { - var result = MatchUsingName(key, executeDescriptor); - if (result != null) - { - return result; - } - - //[*] match with regex, i.e. foo.*.abc - result = MatchAsteriskUsingRegex(key, executeDescriptor); - if (result != null) - { - return result; - } - - //[#] match regex, i.e. foo.# - result = MatchPoundUsingRegex(key, executeDescriptor); - return result; - } - - protected virtual IEnumerable FindConsumersFromInterfaceTypes( - IServiceProvider provider) - { - var executorDescriptorList = new List(); - - var capSubscribeTypeInfo = typeof(ICapSubscribe).GetTypeInfo(); - - foreach (var service in ServiceCollectionExtensions.ServiceCollection.Where(o => o.ImplementationType != null && o.ServiceType != null)) - { - var typeInfo = service.ImplementationType.GetTypeInfo(); - if (!capSubscribeTypeInfo.IsAssignableFrom(typeInfo)) - { - continue; - } - var serviceTypeInfo = service.ServiceType.GetTypeInfo(); - - executorDescriptorList.AddRange(GetTopicAttributesDescription(typeInfo, serviceTypeInfo)); - } - - return executorDescriptorList; - } - - protected virtual IEnumerable FindConsumersFromControllerTypes() - { - var executorDescriptorList = new List(); - - var types = Assembly.GetEntryAssembly().ExportedTypes; - foreach (var type in types) - { - var typeInfo = type.GetTypeInfo(); - if (Helper.IsController(typeInfo)) - { - executorDescriptorList.AddRange(GetTopicAttributesDescription(typeInfo)); - } - } - - return executorDescriptorList; - } - - protected IEnumerable GetTopicAttributesDescription(TypeInfo typeInfo, TypeInfo serviceTypeInfo = null) - { - foreach (var method in typeInfo.DeclaredMethods) - { - var topicAttr = method.GetCustomAttributes(true); - var topicAttributes = topicAttr as IList ?? topicAttr.ToList(); - - if (!topicAttributes.Any()) - { - continue; - } - - foreach (var attr in topicAttributes) - { - if (attr.Group == null) - { - attr.Group = _capOptions.DefaultGroup + "." + _capOptions.Version; - } - else - { - attr.Group = attr.Group + "." + _capOptions.Version; - } - - var parameters = method.GetParameters() - .Select(parameter => new ParameterDescriptor - { - Name = parameter.Name, - ParameterType = parameter.ParameterType, - IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any() - }).ToList(); - - yield return InitDescriptor(attr, method, typeInfo, serviceTypeInfo, parameters); - } - } - } - - private static ConsumerExecutorDescriptor InitDescriptor( - TopicAttribute attr, - MethodInfo methodInfo, - TypeInfo implType, - TypeInfo serviceTypeInfo, - IList parameters) - { - var descriptor = new ConsumerExecutorDescriptor - { - Attribute = attr, - MethodInfo = methodInfo, - ImplTypeInfo = implType, - ServiceTypeInfo = serviceTypeInfo, - Parameters = parameters - }; - - return descriptor; - } - - private ConsumerExecutorDescriptor MatchUsingName(string key, IReadOnlyList executeDescriptor) - { - return executeDescriptor.FirstOrDefault(x => x.Attribute.Name == key); - } - - private ConsumerExecutorDescriptor MatchAsteriskUsingRegex(string key, IReadOnlyList executeDescriptor) - { - var group = executeDescriptor.First().Attribute.Group; - if (!_asteriskList.TryGetValue(group, out var tmpList)) - { - tmpList = executeDescriptor.Where(x => x.Attribute.Name.IndexOf('*') >= 0) - .Select(x => new RegexExecuteDescriptor - { - Name = ("^" + x.Attribute.Name + "$").Replace("*", "[0-9_a-zA-Z]+").Replace(".", "\\."), - Descriptor = x - }).ToList(); - _asteriskList.TryAdd(group, tmpList); - } - - foreach (var red in tmpList) - { - if (Regex.IsMatch(key, red.Name, RegexOptions.Singleline)) - { - return red.Descriptor; - } - } - - return null; - } - - private ConsumerExecutorDescriptor MatchPoundUsingRegex(string key, IReadOnlyList executeDescriptor) - { - var group = executeDescriptor.First().Attribute.Group; - if (!_poundList.TryGetValue(group, out var tmpList)) - { - tmpList = executeDescriptor - .Where(x => x.Attribute.Name.IndexOf('#') >= 0) - .Select(x => new RegexExecuteDescriptor - { - Name = ("^" + x.Attribute.Name.Replace(".", "\\.") + "$").Replace("#", "[0-9_a-zA-Z\\.]+"), - Descriptor = x - }).ToList(); - _poundList.TryAdd(group, tmpList); - } - - foreach (var red in tmpList) - { - if (Regex.IsMatch(key, red.Name, RegexOptions.Singleline)) - { - return red.Descriptor; - } - } - - return null; - } - - - private class RegexExecuteDescriptor - { - public string Name { get; set; } - - public T Descriptor { get; set; } - } - } -} +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace DotNetCore.CAP.Internal +{ + /// + /// + /// A default implementation. + /// + public class DefaultConsumerServiceSelector : IConsumerServiceSelector + { + private readonly CapOptions _capOptions; + private readonly IServiceProvider _serviceProvider; + + /// + /// since this class be designed as a Singleton service,the following two list must be thread safe! + /// + private readonly ConcurrentDictionary>> _asteriskList; + private readonly ConcurrentDictionary>> _poundList; + + /// + /// Creates a new . + /// + public DefaultConsumerServiceSelector(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _capOptions = serviceProvider.GetService>().Value; + + _asteriskList = new ConcurrentDictionary>>(); + _poundList = new ConcurrentDictionary>>(); + } + + public IReadOnlyList SelectCandidates() + { + var executorDescriptorList = new List(); + + executorDescriptorList.AddRange(FindConsumersFromInterfaceTypes(_serviceProvider)); + + executorDescriptorList.AddRange(FindConsumersFromControllerTypes()); + + return executorDescriptorList; + } + + public ConsumerExecutorDescriptor SelectBestCandidate(string key, IReadOnlyList executeDescriptor) + { + var result = MatchUsingName(key, executeDescriptor); + if (result != null) + { + return result; + } + + //[*] match with regex, i.e. foo.*.abc + result = MatchAsteriskUsingRegex(key, executeDescriptor); + if (result != null) + { + return result; + } + + //[#] match regex, i.e. foo.# + result = MatchPoundUsingRegex(key, executeDescriptor); + return result; + } + + protected virtual IEnumerable FindConsumersFromInterfaceTypes( + IServiceProvider provider) + { + var executorDescriptorList = new List(); + + var capSubscribeTypeInfo = typeof(ICapSubscribe).GetTypeInfo(); + + foreach (var service in ServiceCollectionExtensions.ServiceCollection.Where(o => o.ImplementationType != null && o.ServiceType != null)) + { + var typeInfo = service.ImplementationType.GetTypeInfo(); + if (!capSubscribeTypeInfo.IsAssignableFrom(typeInfo)) + { + continue; + } + var serviceTypeInfo = service.ServiceType.GetTypeInfo(); + + executorDescriptorList.AddRange(GetTopicAttributesDescription(typeInfo, serviceTypeInfo)); + } + + return executorDescriptorList; + } + + protected virtual IEnumerable FindConsumersFromControllerTypes() + { + var executorDescriptorList = new List(); + + var types = Assembly.GetEntryAssembly().ExportedTypes; + foreach (var type in types) + { + var typeInfo = type.GetTypeInfo(); + if (Helper.IsController(typeInfo)) + { + executorDescriptorList.AddRange(GetTopicAttributesDescription(typeInfo)); + } + } + + return executorDescriptorList; + } + + protected IEnumerable GetTopicAttributesDescription(TypeInfo typeInfo, TypeInfo serviceTypeInfo = null) + { + foreach (var method in typeInfo.DeclaredMethods) + { + var topicAttr = method.GetCustomAttributes(true); + var topicAttributes = topicAttr as IList ?? topicAttr.ToList(); + + if (!topicAttributes.Any()) + { + continue; + } + + foreach (var attr in topicAttributes) + { + if (attr.Group == null) + { + attr.Group = _capOptions.DefaultGroup + "." + _capOptions.Version; + } + else + { + attr.Group = attr.Group + "." + _capOptions.Version; + } + + var parameters = method.GetParameters() + .Select(parameter => new ParameterDescriptor + { + Name = parameter.Name, + ParameterType = parameter.ParameterType, + IsFromCap = parameter.GetCustomAttributes(typeof(FromCapAttribute)).Any() + }).ToList(); + + yield return InitDescriptor(attr, method, typeInfo, serviceTypeInfo, parameters); + } + } + } + + private static ConsumerExecutorDescriptor InitDescriptor( + TopicAttribute attr, + MethodInfo methodInfo, + TypeInfo implType, + TypeInfo serviceTypeInfo, + IList parameters) + { + var descriptor = new ConsumerExecutorDescriptor + { + Attribute = attr, + MethodInfo = methodInfo, + ImplTypeInfo = implType, + ServiceTypeInfo = serviceTypeInfo, + Parameters = parameters + }; + + return descriptor; + } + + private ConsumerExecutorDescriptor MatchUsingName(string key, IReadOnlyList executeDescriptor) + { + return executeDescriptor.FirstOrDefault(x => x.Attribute.Name == key); + } + + private ConsumerExecutorDescriptor MatchAsteriskUsingRegex(string key, IReadOnlyList executeDescriptor) + { + var group = executeDescriptor.First().Attribute.Group; + if (!_asteriskList.TryGetValue(group, out var tmpList)) + { + tmpList = executeDescriptor.Where(x => x.Attribute.Name.IndexOf('*') >= 0) + .Select(x => new RegexExecuteDescriptor + { + Name = ("^" + x.Attribute.Name + "$").Replace("*", "[0-9_a-zA-Z]+").Replace(".", "\\."), + Descriptor = x + }).ToList(); + _asteriskList.TryAdd(group, tmpList); + } + + foreach (var red in tmpList) + { + if (Regex.IsMatch(key, red.Name, RegexOptions.Singleline)) + { + return red.Descriptor; + } + } + + return null; + } + + private ConsumerExecutorDescriptor MatchPoundUsingRegex(string key, IReadOnlyList executeDescriptor) + { + var group = executeDescriptor.First().Attribute.Group; + if (!_poundList.TryGetValue(group, out var tmpList)) + { + tmpList = executeDescriptor + .Where(x => x.Attribute.Name.IndexOf('#') >= 0) + .Select(x => new RegexExecuteDescriptor + { + Name = ("^" + x.Attribute.Name.Replace(".", "\\.") + "$").Replace("#", "[0-9_a-zA-Z\\.]+"), + Descriptor = x + }).ToList(); + _poundList.TryAdd(group, tmpList); + } + + foreach (var red in tmpList) + { + if (Regex.IsMatch(key, red.Name, RegexOptions.Singleline)) + { + return red.Descriptor; + } + } + + return null; + } + + + private class RegexExecuteDescriptor + { + public string Name { get; set; } + + public T Descriptor { get; set; } + } + } +} diff --git a/src/DotNetCore.CAP/IConsumerServiceSelector.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.cs similarity index 97% rename from src/DotNetCore.CAP/IConsumerServiceSelector.cs rename to src/DotNetCore.CAP/Internal/IConsumerServiceSelector.cs index 555a9d7..baea9af 100644 --- a/src/DotNetCore.CAP/IConsumerServiceSelector.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// Defines an interface for selecting an consumer service method to invoke for the current message. diff --git a/src/DotNetCore.CAP/Abstractions/IMongoTransaction.cs b/src/DotNetCore.CAP/Internal/IMongoTransaction.cs similarity index 73% rename from src/DotNetCore.CAP/Abstractions/IMongoTransaction.cs rename to src/DotNetCore.CAP/Internal/IMongoTransaction.cs index b98caf8..abb0388 100644 --- a/src/DotNetCore.CAP/Abstractions/IMongoTransaction.cs +++ b/src/DotNetCore.CAP/Internal/IMongoTransaction.cs @@ -4,7 +4,7 @@ using System; using System.Threading.Tasks; -namespace DotNetCore.CAP.Abstractions +namespace DotNetCore.CAP.Internal { public interface IMongoTransaction : IDisposable { @@ -14,8 +14,8 @@ namespace DotNetCore.CAP.Abstractions /// bool AutoCommit { get; set; } - Task BegeinAsync(bool autoCommit = true); + Task BeginAsync(bool autoCommit = true); - IMongoTransaction Begein(bool autoCommit = true); + IMongoTransaction Begin(bool autoCommit = true); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/IProcessingServer.cs b/src/DotNetCore.CAP/Internal/IProcessingServer.cs similarity index 91% rename from src/DotNetCore.CAP/IProcessingServer.cs rename to src/DotNetCore.CAP/Internal/IProcessingServer.cs index b7baa9a..8467bab 100644 --- a/src/DotNetCore.CAP/IProcessingServer.cs +++ b/src/DotNetCore.CAP/Internal/IProcessingServer.cs @@ -3,7 +3,7 @@ using System; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// diff --git a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs similarity index 99% rename from src/DotNetCore.CAP/ISubscribeExecutor.Default.cs rename to src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs index 8d2dacd..d3e91b5 100644 --- a/src/DotNetCore.CAP/ISubscribeExecutor.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs @@ -7,15 +7,14 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Processor; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.Extensions.DependencyInjection; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { internal class DefaultSubscriberExecutor : ISubscriberExecutor { diff --git a/src/DotNetCore.CAP/ISubscriberExecutor.cs b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs similarity index 94% rename from src/DotNetCore.CAP/ISubscriberExecutor.cs rename to src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs index b60d5f0..b1ba89b 100644 --- a/src/DotNetCore.CAP/ISubscriberExecutor.cs +++ b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Persistence; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { /// /// Consumer executor diff --git a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs index f44cb17..025c207 100644 --- a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs @@ -5,7 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Internal { [SuppressMessage("ReSharper", "InconsistentNaming")] internal static class LoggerExtensions diff --git a/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs b/src/DotNetCore.CAP/Internal/TopicAttribute.cs similarity index 95% rename from src/DotNetCore.CAP/Abstractions/TopicAttribute.cs rename to src/DotNetCore.CAP/Internal/TopicAttribute.cs index 6b83de4..559cd5f 100644 --- a/src/DotNetCore.CAP/Abstractions/TopicAttribute.cs +++ b/src/DotNetCore.CAP/Internal/TopicAttribute.cs @@ -3,7 +3,7 @@ using System; -namespace DotNetCore.CAP.Abstractions +namespace DotNetCore.CAP.Internal { /// /// diff --git a/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs b/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs index 39b4a56..5f4e78e 100644 --- a/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs +++ b/src/DotNetCore.CAP/Monitoring/MessageQueryDto.cs @@ -10,6 +10,7 @@ namespace DotNetCore.CAP.Monitoring public MessageType MessageType { get; set; } public string Group { get; set; } + public string Name { get; set; } public string Content { get; set; } diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 7f1fb8c..d12f10f 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Internal; using DotNetCore.CAP.Persistence; +using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Processor diff --git a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs index e00128b..d864c7d 100644 --- a/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs +++ b/src/DotNetCore.CAP/Processor/IProcessingServer.Cap.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using DotNetCore.CAP.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs b/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs index d0f4829..3a1c26a 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using DotNetCore.CAP.Internal; namespace DotNetCore.CAP.Processor { diff --git a/src/DotNetCore.CAP/IConsumerClient.cs b/src/DotNetCore.CAP/Transport/IConsumerClient.cs similarity index 97% rename from src/DotNetCore.CAP/IConsumerClient.cs rename to src/DotNetCore.CAP/Transport/IConsumerClient.cs index b918fc8..e74b247 100644 --- a/src/DotNetCore.CAP/IConsumerClient.cs +++ b/src/DotNetCore.CAP/Transport/IConsumerClient.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Threading; using DotNetCore.CAP.Messages; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Transport { /// /// diff --git a/src/DotNetCore.CAP/IConsumerClientFactory.cs b/src/DotNetCore.CAP/Transport/IConsumerClientFactory.cs similarity index 93% rename from src/DotNetCore.CAP/IConsumerClientFactory.cs rename to src/DotNetCore.CAP/Transport/IConsumerClientFactory.cs index a5ce33f..7d7cb22 100644 --- a/src/DotNetCore.CAP/IConsumerClientFactory.cs +++ b/src/DotNetCore.CAP/Transport/IConsumerClientFactory.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Transport { /// /// Consumer client factory to create consumer client instance. diff --git a/src/DotNetCore.CAP/IDispatcher.cs b/src/DotNetCore.CAP/Transport/IDispatcher.cs similarity index 85% rename from src/DotNetCore.CAP/IDispatcher.cs rename to src/DotNetCore.CAP/Transport/IDispatcher.cs index bc47c02..da660d5 100644 --- a/src/DotNetCore.CAP/IDispatcher.cs +++ b/src/DotNetCore.CAP/Transport/IDispatcher.cs @@ -1,9 +1,10 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Persistence; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Transport { public interface IDispatcher { diff --git a/src/DotNetCore.CAP/MqLogType.cs b/src/DotNetCore.CAP/Transport/MqLogType.cs similarity index 94% rename from src/DotNetCore.CAP/MqLogType.cs rename to src/DotNetCore.CAP/Transport/MqLogType.cs index 94c21c0..3412b3a 100644 --- a/src/DotNetCore.CAP/MqLogType.cs +++ b/src/DotNetCore.CAP/Transport/MqLogType.cs @@ -3,7 +3,7 @@ using System; -namespace DotNetCore.CAP +namespace DotNetCore.CAP.Transport { public enum MqLogType { diff --git a/test/DotNetCore.CAP.Test/ModelBinderFactoryTest.cs b/test/DotNetCore.CAP.Test/ModelBinderFactoryTest.cs deleted file mode 100644 index 3006afa..0000000 --- a/test/DotNetCore.CAP.Test/ModelBinderFactoryTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Linq; -using System.Reflection; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Internal; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class ModelBinderFactoryTest - { - private IModelBinderFactory _factory; - - public ModelBinderFactoryTest() - { - var serializer = Mock.Of(); - _factory = new ModelBinderFactory(serializer); - } - - [Theory] - [InlineData(nameof(Sample.DateTimeParam))] - [InlineData(nameof(Sample.StringParam))] - [InlineData(nameof(Sample.IntegerParam))] - [InlineData(nameof(Sample.GuidParam))] - [InlineData(nameof(Sample.UriParam))] - public void CreateSimpleTypeBinderTest(string methodName) - { - var methodInfo = typeof(Sample).GetRuntimeMethods().Single(x => x.Name == methodName); - var binder = _factory.CreateBinder(methodInfo.GetParameters()[0]); - Assert.NotNull(binder); - Assert.True(binder is SimpleTypeModelBinder); - Assert.False(binder is ComplexTypeModelBinder); - } - - [Theory] - [InlineData(nameof(Sample.ComplexTypeParam))] - public void CreateComplexTypeBinderTest(string methodName) - { - var methodInfo = typeof(Sample).GetRuntimeMethods().Single(x => x.Name == methodName); - var binder = _factory.CreateBinder(methodInfo.GetParameters()[0]); - Assert.NotNull(binder); - Assert.False(binder is SimpleTypeModelBinder); - Assert.True(binder is ComplexTypeModelBinder); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/SnowflakeIdTest.cs b/test/DotNetCore.CAP.Test/SnowflakeIdTest.cs index 46553cf..5345168 100644 --- a/test/DotNetCore.CAP.Test/SnowflakeIdTest.cs +++ b/test/DotNetCore.CAP.Test/SnowflakeIdTest.cs @@ -1,6 +1,6 @@ using System.Linq; using System.Threading.Tasks; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using Xunit; namespace DotNetCore.CAP.Test From 02c0eefd0748875fb79674316a0faf74e50b5a38 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 14:14:17 +0800 Subject: [PATCH 34/76] Change System.Text.Json to Json.NET --- .../IConnectionPool.Default.cs | 4 ++-- src/DotNetCore.CAP/DotNetCore.CAP.csproj | 2 +- .../Serialization/ISerializer.JsonUtf8.cs | 14 ++++++++++---- src/DotNetCore.CAP/Serialization/ISerializer.cs | 5 ++++- .../Serialization/StringSerializer.cs | 11 +++++++---- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs index 0271d1d..69d22c5 100644 --- a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs +++ b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs @@ -3,11 +3,11 @@ using System; using System.Collections.Concurrent; -using System.Text.Json; using System.Threading; using Confluent.Kafka; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Newtonsoft.Json; namespace DotNetCore.CAP.Kafka { @@ -24,7 +24,7 @@ namespace DotNetCore.CAP.Kafka _producerPool = new ConcurrentQueue>(); _maxSize = _options.ConnectionPoolSize; - logger.LogDebug("Kafka configuration of CAP :\r\n {0}", JsonSerializer.Serialize(_options.AsKafkaConfig())); + logger.LogDebug("Kafka configuration of CAP :\r\n {0}", JsonConvert.SerializeObject(_options.AsKafkaConfig())); } public string ServersAddress => _options.Servers; diff --git a/src/DotNetCore.CAP/DotNetCore.CAP.csproj b/src/DotNetCore.CAP/DotNetCore.CAP.csproj index b3667f3..2bfc74f 100644 --- a/src/DotNetCore.CAP/DotNetCore.CAP.csproj +++ b/src/DotNetCore.CAP/DotNetCore.CAP.csproj @@ -13,8 +13,8 @@ + - \ No newline at end of file diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs index 5362342..f638751 100644 --- a/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs +++ b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs @@ -1,7 +1,11 @@ -using System; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Text; using System.Threading.Tasks; using DotNetCore.CAP.Messages; -using System.Text.Json; +using Newtonsoft.Json; namespace DotNetCore.CAP.Serialization { @@ -9,7 +13,8 @@ namespace DotNetCore.CAP.Serialization { public Task SerializeAsync(Message message) { - return Task.FromResult(new TransportMessage(message.Headers, JsonSerializer.SerializeToUtf8Bytes(message.Value))); + var json = JsonConvert.SerializeObject(message.Value); + return Task.FromResult(new TransportMessage(message.Headers, Encoding.UTF8.GetBytes(json))); } public Task DeserializeAsync(TransportMessage transportMessage, Type valueType) @@ -19,7 +24,8 @@ namespace DotNetCore.CAP.Serialization return Task.FromResult(new Message(transportMessage.Headers, null)); } - return Task.FromResult(new Message(transportMessage.Headers, JsonSerializer.Deserialize(transportMessage.Body, valueType))); + var json = Encoding.UTF8.GetString(transportMessage.Body); + return Task.FromResult(new Message(transportMessage.Headers, JsonConvert.DeserializeObject(json, valueType))); } } } diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.cs b/src/DotNetCore.CAP/Serialization/ISerializer.cs index c38d064..0c831f7 100644 --- a/src/DotNetCore.CAP/Serialization/ISerializer.cs +++ b/src/DotNetCore.CAP/Serialization/ISerializer.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; using System.Threading.Tasks; using DotNetCore.CAP.Messages; using JetBrains.Annotations; diff --git a/src/DotNetCore.CAP/Serialization/StringSerializer.cs b/src/DotNetCore.CAP/Serialization/StringSerializer.cs index 8e89111..3c96647 100644 --- a/src/DotNetCore.CAP/Serialization/StringSerializer.cs +++ b/src/DotNetCore.CAP/Serialization/StringSerializer.cs @@ -1,5 +1,8 @@ -using DotNetCore.CAP.Messages; -using System.Text.Json; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using DotNetCore.CAP.Messages; +using Newtonsoft.Json; namespace DotNetCore.CAP.Serialization { @@ -7,12 +10,12 @@ namespace DotNetCore.CAP.Serialization { public static string Serialize(Message message) { - return JsonSerializer.Serialize(message); + return JsonConvert.SerializeObject(message); } public static Message DeSerialize(string json) { - return JsonSerializer.Deserialize(json); + return JsonConvert.DeserializeObject(json); } } } \ No newline at end of file From eb90cac6d902c63b3b20e8086ecbe36f3e908940 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 14:15:33 +0800 Subject: [PATCH 35/76] Code refactoring --- .../Internal/ICapPublisher.Default.cs | 6 ++--- .../Internal/IConsumerRegister.Default.cs | 22 ++++++++++--------- .../Internal/IMessageSender.Default.cs | 6 +++-- src/DotNetCore.CAP/Messages/Headers.cs | 10 ++++----- src/DotNetCore.CAP/Transport/ITransport.cs | 5 ++++- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index e822fb6..b904d2f 100644 --- a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -51,14 +51,14 @@ namespace DotNetCore.CAP.Internal var messageId = SnowflakeId.Default().NextId().ToString(); optionHeaders.Add(Headers.MessageId, messageId); + optionHeaders.Add(Headers.MessageName, name); + optionHeaders.Add(Headers.Type, typeof(T).FullName); + optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); if (!optionHeaders.ContainsKey(Headers.CorrelationId)) { optionHeaders.Add(Headers.CorrelationId, messageId); optionHeaders.Add(Headers.CorrelationSequence, 0.ToString()); } - optionHeaders.Add(Headers.MessageName, name); - optionHeaders.Add(Headers.Type, typeof(T).FullName); - optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); var message = new Message(optionHeaders, value); diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index 70e800c..b485edf 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; @@ -162,22 +163,23 @@ namespace DotNetCore.CAP.Internal var name = transportMessage.GetName(); var group = transportMessage.GetGroup(); - if (!_selector.TryGetTopicExecutor(name, group, out var executor)) - { - var error = $"Message can not be found subscriber. Name:{name}, Group:{group}. {Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; - throw new SubscriberNotFoundException(error); - } - - var type = executor.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType; - Message message; + + var canFindSubscriber = _selector.TryGetTopicExecutor(name, group, out var executor); try { + if (!canFindSubscriber) + { + var error = $"Message can not be found subscriber. Name:{name}, Group:{group}. {Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; + throw new SubscriberNotFoundException(error); + } + + var type = executor.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType; message = await _serializer.DeserializeAsync(transportMessage, type); } catch (Exception e) { - transportMessage.Headers.Add(Headers.Exception, e.Message); + transportMessage.Headers.Add(Headers.Exception, nameof(SerializationException) + "-->" + e.Message); var dataUri = $"data:{transportMessage.Headers[Headers.Type]};base64," + Convert.ToBase64String(transportMessage.Body); message = new Message(transportMessage.Headers, dataUri); } @@ -211,7 +213,7 @@ namespace DotNetCore.CAP.Internal } catch (Exception e) { - _logger.LogError(e, "An exception occurred when store received message. Message:'{0}'.", transportMessage); + _logger.LogError(e, "An exception occurred when process received message. Message:'{0}'.", transportMessage); client.Reject(); diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs index 8cf6f5b..76227d9 100644 --- a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -102,10 +102,12 @@ namespace DotNetCore.CAP.Internal private async Task SetFailedState(MediumMessage message, Exception ex) { - //TODO: Add exception to content - var needRetry = UpdateMessageForRetry(message); + if (message.ExpiresAt != null) + { + message.ExpiresAt = DateTime.Now.AddDays(15); + } await _dataStorage.ChangePublishStateAsync(message, StatusName.Failed); return needRetry; diff --git a/src/DotNetCore.CAP/Messages/Headers.cs b/src/DotNetCore.CAP/Messages/Headers.cs index 02d1de7..b36c958 100644 --- a/src/DotNetCore.CAP/Messages/Headers.cs +++ b/src/DotNetCore.CAP/Messages/Headers.cs @@ -9,18 +9,18 @@ public const string MessageName = "cap-msg-name"; - public const string CorrelationId = "cap-corr-id"; - - public const string CorrelationSequence = "cap-corr-seq"; + public const string Group = "cap-msg-group"; /// /// Message value .NET type /// public const string Type = "cap-msg-type"; - public const string CallbackName = "cap-callback-name"; + public const string CorrelationId = "cap-corr-id"; - public const string Group = "cap-msg-group"; + public const string CorrelationSequence = "cap-corr-seq"; + + public const string CallbackName = "cap-callback-name"; public const string SentTime = "cap-senttime"; diff --git a/src/DotNetCore.CAP/Transport/ITransport.cs b/src/DotNetCore.CAP/Transport/ITransport.cs index 7c9e2e0..7cf3b1f 100644 --- a/src/DotNetCore.CAP/Transport/ITransport.cs +++ b/src/DotNetCore.CAP/Transport/ITransport.cs @@ -1,4 +1,7 @@ -using System.Threading.Tasks; +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Threading.Tasks; using DotNetCore.CAP.Messages; namespace DotNetCore.CAP.Transport From a75401d9c699d1c1e80b6471c1998c4ddef638dc Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 15:01:40 +0800 Subject: [PATCH 36/76] Rename class --- .../CAP.RabbitMQCapOptionsExtension.cs | 2 +- ...lishMessageSender.RabbitMQ.cs => ITransport.RabbitMQ.cs} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/DotNetCore.CAP.RabbitMQ/{IPublishMessageSender.RabbitMQ.cs => ITransport.RabbitMQ.cs} (93%) diff --git a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs index 6f86746..55b6d37 100644 --- a/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.RabbitMQ/CAP.RabbitMQCapOptionsExtension.cs @@ -23,7 +23,7 @@ namespace DotNetCore.CAP services.AddSingleton(); services.Configure(_configure); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); } diff --git a/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs b/src/DotNetCore.CAP.RabbitMQ/ITransport.RabbitMQ.cs similarity index 93% rename from src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs rename to src/DotNetCore.CAP.RabbitMQ/ITransport.RabbitMQ.cs index 2cb7efe..d1f9afb 100644 --- a/src/DotNetCore.CAP.RabbitMQ/IPublishMessageSender.RabbitMQ.cs +++ b/src/DotNetCore.CAP.RabbitMQ/ITransport.RabbitMQ.cs @@ -13,14 +13,14 @@ using RabbitMQ.Client.Framing; namespace DotNetCore.CAP.RabbitMQ { - internal sealed class RabbitMQMessageSender : ITransport + internal sealed class RabbitMQTransport : ITransport { private readonly IConnectionChannelPool _connectionChannelPool; private readonly ILogger _logger; private readonly string _exchange; - public RabbitMQMessageSender( - ILogger logger, + public RabbitMQTransport( + ILogger logger, IConnectionChannelPool connectionChannelPool) { _logger = logger; From 835b589ae66cdb422fbbb85c66c8c989a3693a4e Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 15:58:23 +0800 Subject: [PATCH 37/76] Fix obsolete --- src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs | 4 ++-- src/DotNetCore.CAP.Dashboard/JsonStats.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs b/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs index 97e1259..aad6d42 100644 --- a/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs +++ b/src/DotNetCore.CAP.Dashboard/JsonDispatcher.cs @@ -37,8 +37,8 @@ namespace DotNetCore.CAP.Dashboard Converters = new JsonConverter[] { new StringEnumConverter - { - CamelCaseText= true + { + NamingStrategy = new CamelCaseNamingStrategy() } } }; diff --git a/src/DotNetCore.CAP.Dashboard/JsonStats.cs b/src/DotNetCore.CAP.Dashboard/JsonStats.cs index 6e13ccf..35dbf0a 100644 --- a/src/DotNetCore.CAP.Dashboard/JsonStats.cs +++ b/src/DotNetCore.CAP.Dashboard/JsonStats.cs @@ -34,7 +34,7 @@ namespace DotNetCore.CAP.Dashboard { new StringEnumConverter { - CamelCaseText = true + NamingStrategy = new CamelCaseNamingStrategy() } } }; From b9228c4d5b61dec42685b4523fd6f2702fade14e Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 16:01:10 +0800 Subject: [PATCH 38/76] Fix kafka consumer client bugs --- src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs | 6 ++++-- src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 11 +++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs index 29151a9..fe0cfe0 100644 --- a/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs +++ b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs @@ -34,9 +34,11 @@ namespace DotNetCore.CAP.Kafka { var headers = new Confluent.Kafka.Headers(); - foreach (var header in message.Headers.Select(x => new Header(x.Key, Encoding.UTF8.GetBytes(x.Value)))) + foreach (var header in message.Headers) { - headers.Add(header); + headers.Add(header.Value != null + ? new Header(header.Key, Encoding.UTF8.GetBytes(header.Value)) + : new Header(header.Key, null)); } var result = await producer.ProduceAsync(message.GetName(), new Message diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index d9e111e..26547a0 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -55,8 +55,15 @@ namespace DotNetCore.CAP.Kafka if (consumerResult.IsPartitionEOF || consumerResult.Value == null) continue; - var header = consumerResult.Headers.ToDictionary(x => x.Key, y => Encoding.UTF8.GetString(y.GetValueBytes())); - var message = new TransportMessage(header, consumerResult.Value); + var headers = new Dictionary(consumerResult.Headers.Count); + foreach (var header in consumerResult.Headers) + { + var val = header.GetValueBytes(); + headers.Add(header.Key, val != null ? Encoding.UTF8.GetString(val) : null); + } + headers.Add(Messages.Headers.Group, _groupId); + + var message = new TransportMessage(headers, consumerResult.Value); OnMessageReceived?.Invoke(consumerResult, message); } From b6699e1df6a00ad0b40d3694550a58c14668d088 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 19 Nov 2019 16:01:28 +0800 Subject: [PATCH 39/76] Fix sql reader column index error --- src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs | 6 +++--- src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs | 6 +++--- src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs index d4ba6da..7ce514f 100644 --- a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs @@ -195,9 +195,9 @@ namespace DotNetCore.CAP.MySql result.Add(new MediumMessage { DbId = reader.GetInt64(0).ToString(), - Origin = StringSerializer.DeSerialize(reader.GetString(3)), - Retries = reader.GetInt32(4), - Added = reader.GetDateTime(5) + Origin = StringSerializer.DeSerialize(reader.GetString(4)), + Retries = reader.GetInt32(5), + Added = reader.GetDateTime(6) }); } diff --git a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs index d0cc568..b632498 100644 --- a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs @@ -203,9 +203,9 @@ namespace DotNetCore.CAP.PostgreSql result.Add(new MediumMessage { DbId = reader.GetInt64(0).ToString(), - Origin = StringSerializer.DeSerialize(reader.GetString(3)), - Retries = reader.GetInt32(4), - Added = reader.GetDateTime(5) + Origin = StringSerializer.DeSerialize(reader.GetString(4)), + Retries = reader.GetInt32(5), + Added = reader.GetDateTime(6) }); } diff --git a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs index a665447..cdc9406 100644 --- a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs @@ -202,9 +202,9 @@ namespace DotNetCore.CAP.SqlServer result.Add(new MediumMessage { DbId = reader.GetInt64(0).ToString(), - Origin = StringSerializer.DeSerialize(reader.GetString(3)), - Retries = reader.GetInt32(4), - Added = reader.GetDateTime(5) + Origin = StringSerializer.DeSerialize(reader.GetString(4)), + Retries = reader.GetInt32(5), + Added = reader.GetDateTime(6) }); } From ffeb5590e2877be003d76fce5fdf1d13136c3901 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 20 Nov 2019 16:19:02 +0800 Subject: [PATCH 40/76] Introduced rewrite table name option --- samples/Sample.Kafka.MySql/Program.cs | 16 ++++--- .../CAP.MySqlCapOptionsExtension.cs | 3 +- .../IDataStorage.MySql.cs | 21 +++++---- .../IMonitoringApi.MySql.cs | 46 ++++++++++--------- .../IStorageInitializer.MySql.cs | 13 +++--- 5 files changed, 54 insertions(+), 45 deletions(-) diff --git a/samples/Sample.Kafka.MySql/Program.cs b/samples/Sample.Kafka.MySql/Program.cs index d92eedd..d9a19a6 100644 --- a/samples/Sample.Kafka.MySql/Program.cs +++ b/samples/Sample.Kafka.MySql/Program.cs @@ -1,19 +1,21 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; namespace Sample.Kafka.MySql { public class Program { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); + { + CreateHostBuilder(args).Build().Run(); } - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .Build(); + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs index ffffd0e..d1f266f 100644 --- a/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.MySql/CAP.MySqlCapOptionsExtension.cs @@ -5,6 +5,7 @@ using System; using DotNetCore.CAP.MySql; using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; // ReSharper disable once CheckNamespace @@ -24,7 +25,7 @@ namespace DotNetCore.CAP services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.TryAddSingleton(); services.AddTransient(); //Add MySqlOptions diff --git a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs index 7ce514f..5a7b3f6 100644 --- a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs @@ -22,18 +22,23 @@ namespace DotNetCore.CAP.MySql { private readonly IOptions _options; private readonly IOptions _capOptions; + private readonly IStorageInitializer _initializer; - public MySqlDataStorage(IOptions options, IOptions capOptions) + public MySqlDataStorage( + IOptions options, + IOptions capOptions, + IStorageInitializer initializer) { _options = options; _capOptions = capOptions; + _initializer = initializer; } public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) { await using var connection = new MySqlConnection(_options.Value.ConnectionString); - var sql = $"UPDATE `{_options.Value.TableNamePrefix}.published` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + var sql = $"UPDATE `{_initializer.GetPublishedTableName()}` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; await connection.ExecuteAsync(sql, new { @@ -48,7 +53,7 @@ namespace DotNetCore.CAP.MySql { await using var connection = new MySqlConnection(_options.Value.ConnectionString); - var sql = $"UPDATE `{_options.Value.TableNamePrefix}.received` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; + var sql = $"UPDATE `{_initializer.GetReceivedTableName()}` SET `Retries` = @Retries,`ExpiresAt` = @ExpiresAt,`StatusName`=@StatusName WHERE `Id`=@Id;"; await connection.ExecuteAsync(sql, new { @@ -61,7 +66,7 @@ namespace DotNetCore.CAP.MySql public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default) { - var sql = $"INSERT INTO `{_options.Value.TableNamePrefix}.published`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var sql = $"INSERT INTO `{_initializer.GetPublishedTableName()}`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var message = new MediumMessage { @@ -106,7 +111,7 @@ namespace DotNetCore.CAP.MySql public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) { - var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var sql = $@"INSERT INTO `{_initializer.GetReceivedTableName()}`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; await using var connection = new MySqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new @@ -124,7 +129,7 @@ namespace DotNetCore.CAP.MySql public async Task StoreReceivedMessageAsync(string name, string group, Message message) { - var sql = $@"INSERT INTO `{_options.Value.TableNamePrefix}.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + var sql = $@"INSERT INTO `{_initializer.GetReceivedTableName()}`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'{_options.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var mdMessage = new MediumMessage { @@ -162,7 +167,7 @@ namespace DotNetCore.CAP.MySql public async Task> GetPublishedMessagesOfNeedRetry() { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = $"SELECT * FROM `{_options.Value.TableNamePrefix}.published` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; + var sql = $"SELECT * FROM `{_initializer.GetPublishedTableName()}` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); await using var connection = new MySqlConnection(_options.Value.ConnectionString); @@ -184,7 +189,7 @@ namespace DotNetCore.CAP.MySql { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); var sql = - $"SELECT * FROM `{_options.Value.TableNamePrefix}.received` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; + $"SELECT * FROM `{_initializer.GetReceivedTableName()}` WHERE `Retries`<{_capOptions.Value.FailedRetryCount} AND `Version`='{_capOptions.Value.Version}' AND `Added`<'{fourMinAgo}' AND (`StatusName` = '{StatusName.Failed}' OR `StatusName` = '{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); diff --git a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs index 1e735b4..d14bda2 100644 --- a/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IMonitoringApi.MySql.cs @@ -19,22 +19,24 @@ namespace DotNetCore.CAP.MySql internal class MySqlMonitoringApi : IMonitoringApi { private readonly IOptions _options; - private readonly string _prefix; + private readonly string _pubName; + private readonly string _recName; - public MySqlMonitoringApi(IOptions options) + public MySqlMonitoringApi(IOptions options, IStorageInitializer initializer) { _options = options; - _prefix = options.Value.TableNamePrefix ?? throw new ArgumentNullException(nameof(options)); + _pubName = initializer.GetPublishedTableName(); + _recName = initializer.GetReceivedTableName(); } public StatisticsDto GetStatistics() { - var sql = string.Format(@" + var sql = $@" set transaction isolation level read committed; -select count(Id) from `{0}.published` where StatusName = N'Succeeded'; -select count(Id) from `{0}.received` where StatusName = N'Succeeded'; -select count(Id) from `{0}.published` where StatusName = N'Failed'; -select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); +select count(Id) from `{_pubName}` where StatusName = N'Succeeded'; +select count(Id) from `{_recName}` where StatusName = N'Succeeded'; +select count(Id) from `{_pubName}` where StatusName = N'Failed'; +select count(Id) from `{_recName}` where StatusName = N'Failed';"; var statistics = UseConnection(connection => { @@ -55,21 +57,21 @@ select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); public IDictionary HourlyFailedJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "published" : "received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName,nameof(StatusName.Failed))); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Failed))); } public IDictionary HourlySucceededJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "published" : "received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => - GetHourlyTimelineStats(connection, tableName, nameof( StatusName.Succeeded))); + GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Succeeded))); } public IList Messages(MessageQueryDto queryDto) { - var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; + var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName; var where = string.Empty; if (!string.IsNullOrEmpty(queryDto.StatusName)) { @@ -92,7 +94,7 @@ select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); } var sqlQuery = - $"select * from `{_prefix}.{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; + $"select * from `{tableName}` where 1=1 {where} order by Added desc limit @Limit offset @Offset"; return UseConnection(conn => conn.Query(sqlQuery, new { @@ -107,27 +109,27 @@ select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); public int PublishedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof( StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Failed))); } public int PublishedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Succeeded))); } public int ReceivedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Failed))); } public int ReceivedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Succeeded))); } private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) { - var sqlQuery = $"select count(Id) from `{_prefix}.{tableName}` where StatusName = @state"; + var sqlQuery = $"select count(Id) from `{tableName}` where StatusName = @state"; var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); return count; @@ -165,7 +167,7 @@ select count(Id) from `{0}.received` where StatusName = N'Failed';", _prefix); select aggr.* from ( select date_format(`Added`,'%Y-%m-%d-%H') as `Key`, count(id) `Count` - from `{_prefix}.{tableName}` + from `{tableName}` where StatusName = @statusName group by date_format(`Added`,'%Y-%m-%d-%H') ) aggr where `Key` in @keys;"; @@ -195,7 +197,7 @@ select aggr.* from ( public async Task GetPublishedMessageAsync(long id) { - var sql = $@"SELECT * FROM `{_prefix}.published` WHERE `Id`={id};"; + var sql = $@"SELECT * FROM `{_pubName}` WHERE `Id`={id};"; await using var connection = new MySqlConnection(_options.Value.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); @@ -203,7 +205,7 @@ select aggr.* from ( public async Task GetReceivedMessageAsync(long id) { - var sql = $@"SELECT * FROM `{_prefix}.received` WHERE Id={id};"; + var sql = $@"SELECT * FROM `{_recName}` WHERE Id={id};"; await using var connection = new MySqlConnection(_options.Value.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); } diff --git a/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs index b08441c..00c4354 100644 --- a/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IStorageInitializer.MySql.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System; using System.Threading; using System.Threading.Tasks; using Dapper; @@ -25,12 +24,12 @@ namespace DotNetCore.CAP.MySql _logger = logger; } - public string GetPublishedTableName() + public virtual string GetPublishedTableName() { return $"{_options.Value.TableNamePrefix}.published"; } - public string GetReceivedTableName() + public virtual string GetReceivedTableName() { return $"{_options.Value.TableNamePrefix}.received"; } @@ -42,7 +41,7 @@ namespace DotNetCore.CAP.MySql return; } - var sql = CreateDbTablesScript(_options.Value.TableNamePrefix); + var sql = CreateDbTablesScript(); await using (var connection = new MySqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); @@ -52,11 +51,11 @@ namespace DotNetCore.CAP.MySql } - protected virtual string CreateDbTablesScript(string prefix) + protected virtual string CreateDbTablesScript() { var batchSql = $@" -CREATE TABLE IF NOT EXISTS `{prefix}.received` ( +CREATE TABLE IF NOT EXISTS `{GetReceivedTableName()}` ( `Id` bigint NOT NULL, `Version` varchar(20) DEFAULT NULL, `Name` varchar(400) NOT NULL, @@ -70,7 +69,7 @@ CREATE TABLE IF NOT EXISTS `{prefix}.received` ( INDEX `IX_ExpiresAt`(`ExpiresAt`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE IF NOT EXISTS `{prefix}.published` ( +CREATE TABLE IF NOT EXISTS `{GetPublishedTableName()}` ( `Id` bigint NOT NULL, `Version` varchar(20) DEFAULT NULL, `Name` varchar(200) NOT NULL, From 01d231e44e75488c6152c5fc37027b707c82ac42 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 20 Nov 2019 16:19:14 +0800 Subject: [PATCH 41/76] Introduced rewrite table name option --- src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs index 5a7b3f6..2646153 100644 --- a/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs +++ b/src/DotNetCore.CAP.MySql/IDataStorage.MySql.cs @@ -211,7 +211,7 @@ namespace DotNetCore.CAP.MySql public IMonitoringApi GetMonitoringApi() { - return new MySqlMonitoringApi(_options); + return new MySqlMonitoringApi(_options, _initializer); } } } From 14d0b34c78e957be02a40e2785db3a49f7da4ec4 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 21 Nov 2019 11:54:02 +0800 Subject: [PATCH 42/76] Introduced rewrite table name option for pgsql --- .../CAP.PostgreSqlCapOptionsExtension.cs | 6 +-- .../CAP.PostgreSqlOptions.cs | 15 +++---- .../IDataStorage.PostgreSql.cs | 29 ++++++++----- .../IMonitoringApi.PostgreSql.cs | 41 ++++++++++--------- .../IStorageInitializer.PostgreSql.cs | 20 ++++----- 5 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs index 3be4e92..e1f6456 100644 --- a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlCapOptionsExtension.cs @@ -22,14 +22,12 @@ namespace DotNetCore.CAP public void AddServices(IServiceCollection services) { services.AddSingleton(); + services.Configure(_configure); + services.AddSingleton, ConfigurePostgreSqlOptions>(); services.AddSingleton(); - services.AddSingleton(); services.AddTransient(); - - services.Configure(_configure); - services.AddSingleton, ConfigurePostgreSqlOptions>(); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs index db55202..d881b2d 100644 --- a/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs +++ b/src/DotNetCore.CAP.PostgreSql/CAP.PostgreSqlOptions.cs @@ -27,15 +27,12 @@ namespace DotNetCore.CAP public void Configure(PostgreSqlOptions options) { - if (options.DbContextType != null) - using (var scope = _serviceScopeFactory.CreateScope()) - { - var provider = scope.ServiceProvider; - using (var dbContext = (DbContext) provider.GetRequiredService(options.DbContextType)) - { - options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; - } - } + if (options.DbContextType == null) return; + + using var scope = _serviceScopeFactory.CreateScope(); + var provider = scope.ServiceProvider; + using var dbContext = (DbContext) provider.GetRequiredService(options.DbContextType); + options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs index b632498..d4204e3 100644 --- a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs @@ -21,20 +21,27 @@ namespace DotNetCore.CAP.PostgreSql public class PostgreSqlDataStorage : IDataStorage { private readonly IOptions _capOptions; + private readonly IStorageInitializer _initializer; private readonly IOptions _options; + private readonly string _pubName; + private readonly string _recName; public PostgreSqlDataStorage( IOptions options, - IOptions capOptions) + IOptions capOptions, + IStorageInitializer initializer) { _capOptions = capOptions; + _initializer = initializer; _options = options; + _pubName = initializer.GetPublishedTableName(); + _recName = initializer.GetReceivedTableName(); } public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) { var sql = - $"UPDATE \"{_options.Value.Schema}\".\"published\" SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; + $"UPDATE {_pubName} SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { @@ -48,7 +55,7 @@ namespace DotNetCore.CAP.PostgreSql public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) { var sql = - $"UPDATE \"{_options.Value.Schema}\".\"received\" SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; + $"UPDATE {_recName} SET \"Retries\"=@Retries,\"ExpiresAt\"=@ExpiresAt,\"StatusName\"=@StatusName WHERE \"Id\"=@Id"; await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { @@ -63,7 +70,7 @@ namespace DotNetCore.CAP.PostgreSql CancellationToken cancellationToken = default) { var sql = - $"INSERT INTO \"{_options.Value.Schema}\".\"published\" (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"INSERT INTO {_pubName} (\"Id\",\"Version\",\"Name\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + $"VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var message = new MediumMessage @@ -108,7 +115,7 @@ namespace DotNetCore.CAP.PostgreSql public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) { var sql = - $"INSERT INTO \"{_options.Value.Schema}\".\"received\"(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"INSERT INTO {_recName}(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \"Id\";"; await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); @@ -128,7 +135,7 @@ namespace DotNetCore.CAP.PostgreSql public async Task StoreReceivedMessageAsync(string name, string group, Message message) { var sql = - $"INSERT INTO \"{_options.Value.Schema}\".\"received\"(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + + $"INSERT INTO {_recName}(\"Id\",\"Version\",\"Name\",\"Group\",\"Content\",\"Retries\",\"Added\",\"ExpiresAt\",\"StatusName\")" + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName) RETURNING \"Id\";"; var mdMessage = new MediumMessage @@ -161,15 +168,15 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); return await connection.ExecuteAsync( - $"DELETE FROM \"{_options.Value.Schema}\".\"{table}\" WHERE \"ExpiresAt\" < @now AND \"Id\" IN (SELECT \"Id\" FROM \"{_options.Value.Schema}\".\"{table}\" LIMIT @count);", - new {timeout, batchCount}); + $"DELETE FROM {table} WHERE \"ExpiresAt\" < @now AND \"Id\" IN (SELECT \"Id\" FROM {table} LIMIT @count);", + new { timeout, batchCount }); } public async Task> GetPublishedMessagesOfNeedRetry() { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); var sql = - $"SELECT * FROM \"{_options.Value.Schema}\".\"published\" WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; + $"SELECT * FROM {_pubName} WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); @@ -192,7 +199,7 @@ namespace DotNetCore.CAP.PostgreSql { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); var sql = - $"SELECT * FROM \"{_options.Value.Schema}\".\"received\" WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; + $"SELECT * FROM {_recName} WHERE \"Retries\"<{_capOptions.Value.FailedRetryCount} AND \"Version\"='{_capOptions.Value.Version}' AND \"Added\"<'{fourMinAgo}' AND (\"StatusName\"='{StatusName.Failed}' OR \"StatusName\"='{StatusName.Scheduled}') LIMIT 200;"; var result = new List(); @@ -214,7 +221,7 @@ namespace DotNetCore.CAP.PostgreSql public IMonitoringApi GetMonitoringApi() { - return new PostgreSqlMonitoringApi(_options); + return new PostgreSqlMonitoringApi(_options, _initializer); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs index b026034..56e5619 100644 --- a/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IMonitoringApi.PostgreSql.cs @@ -19,16 +19,20 @@ namespace DotNetCore.CAP.PostgreSql public class PostgreSqlMonitoringApi : IMonitoringApi { private readonly IOptions _options; + private readonly string _pubName; + private readonly string _recName; - public PostgreSqlMonitoringApi(IOptions options) + public PostgreSqlMonitoringApi(IOptions options,IStorageInitializer initializer) { _options = options ?? throw new ArgumentNullException(nameof(options)); + _pubName = initializer.GetPublishedTableName(); + _recName = initializer.GetReceivedTableName(); } public async Task GetPublishedMessageAsync(long id) { var sql = - $"SELECT * FROM \"{_options.Value.Schema}\".\"published\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; + $"SELECT * FROM {_pubName} WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); @@ -37,19 +41,18 @@ namespace DotNetCore.CAP.PostgreSql public async Task GetReceivedMessageAsync(long id) { var sql = - $"SELECT * FROM \"{_options.Value.Schema}\".\"received\" WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; + $"SELECT * FROM {_recName} WHERE \"Id\"={id} FOR UPDATE SKIP LOCKED"; await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); } public StatisticsDto GetStatistics() { - var sql = string.Format(@" -select count(""Id"") from ""{0}"".""published"" where ""StatusName"" = N'Succeeded'; -select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Succeeded'; -select count(""Id"") from ""{0}"".""published"" where ""StatusName"" = N'Failed'; -select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed';", - _options.Value.Schema); + var sql = $@" +select count(""Id"") from {_pubName} where ""StatusName"" = N'Succeeded'; +select count(""Id"") from {_recName} where ""StatusName"" = N'Succeeded'; +select count(""Id"") from {_pubName} where ""StatusName"" = N'Failed'; +select count(""Id"") from {_recName} where ""StatusName"" = N'Failed';"; var statistics = UseConnection(connection => { @@ -70,7 +73,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' public IList Messages(MessageQueryDto queryDto) { - var tableName = queryDto.MessageType == MessageType.Publish ? "published" : "received"; + var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName; var where = string.Empty; if (!string.IsNullOrEmpty(queryDto.StatusName)) where += " and Lower(\"StatusName\") = Lower(@StatusName)"; @@ -82,7 +85,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' if (!string.IsNullOrEmpty(queryDto.Content)) where += " and \"Content\" ILike '%@Content%'"; var sqlQuery = - $"select * from \"{_options.Value.Schema}\".\"{tableName}\" where 1=1 {where} order by \"Added\" desc offset @Offset limit @Limit"; + $"select * from {tableName} where 1=1 {where} order by \"Added\" desc offset @Offset limit @Limit"; return UseConnection(conn => conn.Query(sqlQuery, new { @@ -97,34 +100,34 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' public int PublishedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Failed))); } public int PublishedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "published", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Succeeded))); } public int ReceivedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Failed))); } public int ReceivedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "received", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Succeeded))); } public IDictionary HourlySucceededJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "published" : "received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Succeeded))); } public IDictionary HourlyFailedJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "published" : "received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Failed))); } @@ -132,7 +135,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) { var sqlQuery = - $"select count(\"Id\") from \"{_options.Value.Schema}\".\"{tableName}\" where Lower(\"StatusName\") = Lower(@state)"; + $"select count(\"Id\") from {tableName} where Lower(\"StatusName\") = Lower(@state)"; var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); return count; @@ -170,7 +173,7 @@ select count(""Id"") from ""{0}"".""received"" where ""StatusName"" = N'Failed' with aggr as ( select to_char(""Added"",'yyyy-MM-dd-HH') as ""Key"", count(""Id"") as ""Count"" - from ""{_options.Value.Schema}"".""{tableName}"" + from {tableName} where ""StatusName"" = @statusName group by to_char(""Added"", 'yyyy-MM-dd-HH') ) diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs index 69af3fa..ad494c9 100644 --- a/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs @@ -24,14 +24,14 @@ namespace DotNetCore.CAP.PostgreSql _logger = logger; } - public string GetPublishedTableName() + public virtual string GetPublishedTableName() { - return $"{_options.Value.Schema}.published"; + return $"\"{_options.Value.Schema}\".\"published\""; } - public string GetReceivedTableName() + public virtual string GetReceivedTableName() { - return $"{_options.Value.Schema}.received"; + return $"\"{_options.Value.Schema}\".\"received\""; } public async Task InitializeAsync(CancellationToken cancellationToken) @@ -39,7 +39,7 @@ namespace DotNetCore.CAP.PostgreSql if (cancellationToken.IsCancellationRequested) return; var sql = CreateDbTablesScript(_options.Value.Schema); - using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) + await using (var connection = new NpgsqlConnection(_options.Value.ConnectionString)) { await connection.ExecuteAsync(sql); } @@ -53,7 +53,7 @@ namespace DotNetCore.CAP.PostgreSql var batchSql = $@" CREATE SCHEMA IF NOT EXISTS ""{schema}""; -CREATE TABLE IF NOT EXISTS ""{schema}"".""received""( +CREATE TABLE IF NOT EXISTS {GetPublishedTableName()}( ""Id"" BIGINT PRIMARY KEY NOT NULL, ""Version"" VARCHAR(20) NOT NULL, ""Name"" VARCHAR(200) NOT NULL, @@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS ""{schema}"".""received""( ""StatusName"" VARCHAR(50) NOT NULL ); -CREATE TABLE IF NOT EXISTS ""{schema}"".""published""( +CREATE TABLE IF NOT EXISTS {GetReceivedTableName()}( ""Id"" BIGINT PRIMARY KEY NOT NULL, ""Version"" VARCHAR(20) NOT NULL, ""Name"" VARCHAR(200) NOT NULL, @@ -74,11 +74,7 @@ CREATE TABLE IF NOT EXISTS ""{schema}"".""published""( ""Added"" TIMESTAMP NOT NULL, ""ExpiresAt"" TIMESTAMP NULL, ""StatusName"" VARCHAR(50) NOT NULL -); - -ALTER TABLE ""{schema}"".""received"" ADD COLUMN IF NOT EXISTS ""Version"" VARCHAR(20) NOT NULL; -ALTER TABLE ""{schema}"".""published"" ADD COLUMN IF NOT EXISTS ""Version"" VARCHAR(20) NOT NULL; -"; +);"; return batchSql; } } From 71df4dfdd9d95c8419f7af55601fe9ed352d7caf Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 21 Nov 2019 15:14:04 +0800 Subject: [PATCH 43/76] Introduced rewrite table name option --- .../Diagnostics/DiagnosticObserver.cs | 15 ++--- .../IDataStorage.SqlServer.cs | 29 ++++++---- .../IMonitoringApi.SqlServer.cs | 56 ++++++++++--------- .../IStorageInitializer.SqlServer.cs | 8 +-- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs index 1f43bd7..e13f533 100644 --- a/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/DiagnosticObserver.cs @@ -13,10 +13,11 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics { internal class DiagnosticObserver : IObserver> { - private const string SqlClientPrefix = "System.Data.SqlClient."; + public const string SqlAfterCommitTransaction = "System.Data.SqlClient.WriteTransactionCommitAfter"; + public const string SqlAfterCommitTransactionMicrosoft = "Microsoft.Data.SqlClient.WriteTransactionCommitAfter"; + public const string SqlErrorCommitTransaction = "System.Data.SqlClient.WriteTransactionCommitError"; + public const string SqlErrorCommitTransactionMicrosoft = "Microsoft.Data.SqlClient.WriteTransactionCommitError"; - public const string SqlAfterCommitTransaction = SqlClientPrefix + "WriteTransactionCommitAfter"; - public const string SqlErrorCommitTransaction = SqlClientPrefix + "WriteTransactionCommitError"; private readonly ConcurrentDictionary> _bufferList; private readonly IDispatcher _dispatcher; @@ -37,9 +38,9 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics public void OnNext(KeyValuePair evt) { - if (evt.Key == SqlAfterCommitTransaction) + if (evt.Key == SqlAfterCommitTransaction || evt.Key == SqlAfterCommitTransactionMicrosoft) { - var sqlConnection = (SqlConnection) GetProperty(evt.Value, "Connection"); + var sqlConnection = (SqlConnection)GetProperty(evt.Value, "Connection"); var transactionKey = sqlConnection.ClientConnectionId; if (_bufferList.TryRemove(transactionKey, out var msgList)) foreach (var message in msgList) @@ -47,9 +48,9 @@ namespace DotNetCore.CAP.SqlServer.Diagnostics _dispatcher.EnqueueToPublish(message); } } - else if (evt.Key == SqlErrorCommitTransaction) + else if (evt.Key == SqlErrorCommitTransaction || evt.Key == SqlErrorCommitTransactionMicrosoft) { - var sqlConnection = (SqlConnection) GetProperty(evt.Value, "Connection"); + var sqlConnection = (SqlConnection)GetProperty(evt.Value, "Connection"); var transactionKey = sqlConnection.ClientConnectionId; _bufferList.TryRemove(transactionKey, out _); diff --git a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs index cdc9406..cd4c29f 100644 --- a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs @@ -22,19 +22,26 @@ namespace DotNetCore.CAP.SqlServer { private readonly IOptions _capOptions; private readonly IOptions _options; + private readonly IStorageInitializer _initializer; + private readonly string _pubName; + private readonly string _recName; public SqlServerDataStorage( IOptions capOptions, - IOptions options) + IOptions options, + IStorageInitializer initializer) { _options = options; + _initializer = initializer; _capOptions = capOptions; + _pubName = initializer.GetPublishedTableName(); + _recName = initializer.GetReceivedTableName(); } public async Task ChangePublishStateAsync(MediumMessage message, StatusName state) { var sql = - $"UPDATE [{_options.Value.Schema}].[Published] SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; + $"UPDATE {_pubName} SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; await using var connection = new SqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { @@ -48,7 +55,7 @@ namespace DotNetCore.CAP.SqlServer public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) { var sql = - $"UPDATE [{_options.Value.Schema}].[Received] SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; + $"UPDATE {_recName} SET Retries=@Retries,ExpiresAt=@ExpiresAt,StatusName=@StatusName WHERE Id=@Id"; await using var connection = new SqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { @@ -62,7 +69,7 @@ namespace DotNetCore.CAP.SqlServer public async Task StoreMessageAsync(string name, Message content, object dbTransaction = null, CancellationToken cancellationToken = default) { - var sql = $"INSERT INTO {_options.Value.Schema}.[Published] ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + var sql = $"INSERT INTO {_pubName} ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + $"VALUES(@Id,'{_options.Value}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var message = new MediumMessage @@ -107,7 +114,7 @@ namespace DotNetCore.CAP.SqlServer public async Task StoreReceivedExceptionMessageAsync(string name, string group, string content) { var sql = - $"INSERT INTO [{_options.Value.Schema}].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + $"INSERT INTO {_recName}([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; await using var connection = new SqlConnection(_options.Value.ConnectionString); @@ -127,7 +134,7 @@ namespace DotNetCore.CAP.SqlServer public async Task StoreReceivedMessageAsync(string name, string group, Message message) { var sql = - $"INSERT INTO [{_options.Value.Schema}].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + + $"INSERT INTO {_recName}([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + $"VALUES(@Id,'{_capOptions.Value.Version}',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var mdMessage = new MediumMessage @@ -159,14 +166,14 @@ namespace DotNetCore.CAP.SqlServer { await using var connection = new SqlConnection(_options.Value.ConnectionString); return await connection.ExecuteAsync( - $"DELETE TOP (@batchCount) FROM [{_options.Value.Schema}].[{table}] WITH (readpast) WHERE ExpiresAt < @timeout;", - new {timeout, batchCount}); + $"DELETE TOP (@batchCount) FROM {table} WITH (readpast) WHERE ExpiresAt < @timeout;", + new { timeout, batchCount }); } public async Task> GetPublishedMessagesOfNeedRetry() { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); - var sql = $"SELECT TOP (200) * FROM [{_options.Value.Schema}].[Published] WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + + var sql = $"SELECT TOP (200) * FROM {_pubName} WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + $"AND Version='{_capOptions.Value.Version}' AND Added<'{fourMinAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; var result = new List(); @@ -190,7 +197,7 @@ namespace DotNetCore.CAP.SqlServer { var fourMinAgo = DateTime.Now.AddMinutes(-4).ToString("O"); var sql = - $"SELECT TOP (200) * FROM [{_options.Value.Schema}].[Received] WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + + $"SELECT TOP (200) * FROM {_recName} WITH (readpast) WHERE Retries<{_capOptions.Value.FailedRetryCount} " + $"AND Version='{_capOptions.Value.Version}' AND Added<'{fourMinAgo}' AND (StatusName = '{StatusName.Failed}' OR StatusName = '{StatusName.Scheduled}')"; var result = new List(); @@ -213,7 +220,7 @@ namespace DotNetCore.CAP.SqlServer public IMonitoringApi GetMonitoringApi() { - return new SqlServerMonitoringApi(_options); + return new SqlServerMonitoringApi(_options, _initializer); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs index 6172944..9daf00d 100644 --- a/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IMonitoringApi.SqlServer.cs @@ -19,21 +19,24 @@ namespace DotNetCore.CAP.SqlServer internal class SqlServerMonitoringApi : IMonitoringApi { private readonly SqlServerOptions _options; + private readonly string _pubName; + private readonly string _recName; - public SqlServerMonitoringApi(IOptions options) + public SqlServerMonitoringApi(IOptions options, IStorageInitializer initializer) { _options = options.Value ?? throw new ArgumentNullException(nameof(options)); + _pubName = initializer.GetPublishedTableName(); + _recName = initializer.GetReceivedTableName(); } public StatisticsDto GetStatistics() { - var sql = string.Format(@" + var sql = $@" set transaction isolation level read committed; -select count(Id) from [{0}].Published with (nolock) where StatusName = N'Succeeded'; -select count(Id) from [{0}].Received with (nolock) where StatusName = N'Succeeded'; -select count(Id) from [{0}].Published with (nolock) where StatusName = N'Failed'; -select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed';", - _options.Schema); +select count(Id) from {_pubName} with (nolock) where StatusName = N'Succeeded'; +select count(Id) from {_recName} with (nolock) where StatusName = N'Succeeded'; +select count(Id) from {_pubName} with (nolock) where StatusName = N'Failed'; +select count(Id) from {_recName} with (nolock) where StatusName = N'Failed';"; var statistics = UseConnection(connection => { @@ -54,21 +57,21 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; public IDictionary HourlyFailedJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "Published" : "Received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Failed))); } public IDictionary HourlySucceededJobs(MessageType type) { - var tableName = type == MessageType.Publish ? "Published" : "Received"; + var tableName = type == MessageType.Publish ? _pubName : _recName; return UseConnection(connection => GetHourlyTimelineStats(connection, tableName, nameof(StatusName.Succeeded))); } public IList Messages(MessageQueryDto queryDto) { - var tableName = queryDto.MessageType == MessageType.Publish ? "Published" : "Received"; + var tableName = queryDto.MessageType == MessageType.Publish ? _pubName : _recName; var where = string.Empty; if (!string.IsNullOrEmpty(queryDto.StatusName)) where += " and statusname=@StatusName"; @@ -80,13 +83,13 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; var sqlQuery2008 = $@"select * from - (SELECT t.*, ROW_NUMBER() OVER(order by t.Added desc) AS rownumber - from [{_options.Schema}].{tableName} as t + (SELECT t.*, ROW_NUMBER() OVER(order by t.Added desc) AS row_number + from {tableName} as t where 1=1 {where}) as tbl - where tbl.rownumber between @offset and @offset + @limit"; + where tbl.row_number between @offset and @offset + @limit"; var sqlQuery = - $"select * from [{_options.Schema}].{tableName} where 1=1 {where} order by Added desc offset @Offset rows fetch next @Limit rows only"; + $"select * from {tableName} where 1=1 {where} order by Added desc offset @Offset rows fetch next @Limit rows only"; return UseConnection(conn => conn.Query(_options.IsSqlServer2008 ? sqlQuery2008 : sqlQuery, new { @@ -101,34 +104,34 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; public int PublishedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Published", nameof(StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Failed))); } public int PublishedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Published", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _pubName, nameof(StatusName.Succeeded))); } public int ReceivedFailedCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Received", nameof(StatusName.Failed))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Failed))); } public int ReceivedSucceededCount() { - return UseConnection(conn => GetNumberOfMessage(conn, "Received", nameof(StatusName.Succeeded))); + return UseConnection(conn => GetNumberOfMessage(conn, _recName, nameof(StatusName.Succeeded))); } public async Task GetPublishedMessageAsync(long id) { - var sql = $@"SELECT * FROM [{_options.Schema}].[Published] WITH (readpast) WHERE Id={id}"; + var sql = $@"SELECT * FROM {_pubName} WITH (readpast) WHERE Id={id}"; await using var connection = new SqlConnection(_options.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); } public async Task GetReceivedMessageAsync(long id) { - var sql = $@"SELECT * FROM [{_options.Schema}].[Received] WITH (readpast) WHERE Id={id}"; + var sql = $@"SELECT * FROM {_recName} WITH (readpast) WHERE Id={id}"; await using var connection = new SqlConnection(_options.ConnectionString); return await connection.QueryFirstOrDefaultAsync(sql); } @@ -136,9 +139,9 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; private int GetNumberOfMessage(IDbConnection connection, string tableName, string statusName) { var sqlQuery = - $"select count(Id) from [{_options.Schema}].{tableName} with (nolock) where StatusName = @state"; + $"select count(Id) from {tableName} with (nolock) where StatusName = @state"; - var count = connection.ExecuteScalar(sqlQuery, new {state = statusName}); + var count = connection.ExecuteScalar(sqlQuery, new { state = statusName }); return count; } @@ -173,7 +176,7 @@ select count(Id) from [{0}].Received with (nolock) where StatusName = N'Failed'; with aggr as ( select replace(convert(varchar, Added, 111), '/','-') + '-' + CONVERT(varchar, DATEPART(hh, Added)) as [Key], count(id) [Count] - from [{_options.Schema}].{tableName} + from {tableName} where StatusName = @statusName group by replace(convert(varchar, Added, 111), '/','-') + '-' + CONVERT(varchar, DATEPART(hh, Added)) ) @@ -184,15 +187,14 @@ select [Key], [Count] from aggr with (nolock) where [Key] in @keys;"; with aggr as ( select FORMAT(Added,'yyyy-MM-dd-HH') as [Key], count(id) [Count] - from [{_options.Schema}].{tableName} + from {tableName} where StatusName = @statusName group by FORMAT(Added,'yyyy-MM-dd-HH') ) select [Key], [Count] from aggr with (nolock) where [Key] in @keys;"; - var valuesMap = connection.Query( - _options.IsSqlServer2008 ? sqlQuery2008 : sqlQuery, - new {keys = keyMaps.Keys, statusName}) + var valuesMap = connection + .Query(_options.IsSqlServer2008 ? sqlQuery2008 : sqlQuery, new { keys = keyMaps.Keys, statusName }) .ToDictionary(x => x.Key, x => x.Count); foreach (var key in keyMaps.Keys) diff --git a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs index 66a3bb3..9d4c911 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs @@ -29,12 +29,12 @@ namespace DotNetCore.CAP.SqlServer _logger = logger; } - public string GetPublishedTableName() + public virtual string GetPublishedTableName() { return $"[{_options.Value.Schema}].[Published]"; } - public string GetReceivedTableName() + public virtual string GetReceivedTableName() { return $"[{_options.Value.Schema}].[Received]"; } @@ -64,7 +64,7 @@ BEGIN EXEC('CREATE SCHEMA [{schema}]') END; -IF OBJECT_ID(N'[{schema}].[Received]',N'U') IS NULL +IF OBJECT_ID(N'{GetReceivedTableName()}',N'U') IS NULL BEGIN CREATE TABLE [{schema}].[Received]( [Id] [bigint] NOT NULL, @@ -83,7 +83,7 @@ CREATE TABLE [{schema}].[Received]( ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] END; -IF OBJECT_ID(N'[{schema}].[Published]',N'U') IS NULL +IF OBJECT_ID(N'{GetPublishedTableName()}',N'U') IS NULL BEGIN CREATE TABLE [{schema}].[Published]( [Id] [bigint] NOT NULL, From 73438646548ff5e9f085862ac1f8644f25ec911c Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 22 Nov 2019 17:05:03 +0800 Subject: [PATCH 44/76] Fix SqlServer service injection bug --- .../CAP.SqlServerCapOptionsExtension.cs | 3 ++ .../IProcessingServer.DiagnosticRegister.cs | 33 +++++++++++++++++++ .../IStorageInitializer.SqlServer.cs | 10 +----- 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 src/DotNetCore.CAP.SqlServer/Diagnostics/IProcessingServer.DiagnosticRegister.cs diff --git a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs index ff25fa6..b6a6e00 100644 --- a/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs +++ b/src/DotNetCore.CAP.SqlServer/CAP.SqlServerCapOptionsExtension.cs @@ -2,10 +2,12 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer; using DotNetCore.CAP.SqlServer.Diagnostics; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; // ReSharper disable once CheckNamespace @@ -28,6 +30,7 @@ namespace DotNetCore.CAP services.AddSingleton(); services.AddSingleton(); services.AddTransient(); + services.TryAddEnumerable(ServiceDescriptor.Singleton()); services.Configure(_configure); services.AddSingleton, ConfigureSqlServerOptions>(); diff --git a/src/DotNetCore.CAP.SqlServer/Diagnostics/IProcessingServer.DiagnosticRegister.cs b/src/DotNetCore.CAP.SqlServer/Diagnostics/IProcessingServer.DiagnosticRegister.cs new file mode 100644 index 0000000..53b227c --- /dev/null +++ b/src/DotNetCore.CAP.SqlServer/Diagnostics/IProcessingServer.DiagnosticRegister.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Diagnostics; +using DotNetCore.CAP.Internal; + +namespace DotNetCore.CAP.SqlServer.Diagnostics +{ + public class DiagnosticRegister : IProcessingServer + { + private readonly DiagnosticProcessorObserver _diagnosticProcessorObserver; + + public DiagnosticRegister(DiagnosticProcessorObserver diagnosticProcessorObserver) + { + _diagnosticProcessorObserver = diagnosticProcessorObserver; + } + + public void Dispose() + { + + } + + public void Pulse() + { + + } + + public void Start() + { + DiagnosticListener.AllListeners.Subscribe(_diagnosticProcessorObserver); + } + } +} diff --git a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs index 9d4c911..8c0e7c7 100644 --- a/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IStorageInitializer.SqlServer.cs @@ -1,12 +1,10 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Dapper; using DotNetCore.CAP.Persistence; -using DotNetCore.CAP.SqlServer.Diagnostics; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -15,17 +13,14 @@ namespace DotNetCore.CAP.SqlServer { public class SqlServerStorageInitializer : IStorageInitializer { - private readonly DiagnosticProcessorObserver _diagnosticProcessorObserver; private readonly ILogger _logger; private readonly IOptions _options; public SqlServerStorageInitializer( ILogger logger, - IOptions options, - DiagnosticProcessorObserver diagnosticProcessorObserver) + IOptions options) { _options = options; - _diagnosticProcessorObserver = diagnosticProcessorObserver; _logger = logger; } @@ -50,11 +45,8 @@ namespace DotNetCore.CAP.SqlServer } _logger.LogDebug("Ensuring all create database tables script are applied."); - - DiagnosticListener.AllListeners.Subscribe(_diagnosticProcessorObserver); } - protected virtual string CreateDbTablesScript(string schema) { var batchSql = From 72f7094bac28141ddfce0318e67bd7959c0346cd Mon Sep 17 00:00:00 2001 From: Savorboard Date: Fri, 22 Nov 2019 17:51:39 +0800 Subject: [PATCH 45/76] Fix sql bug --- src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs index cd4c29f..9e7a21e 100644 --- a/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/IDataStorage.SqlServer.cs @@ -70,7 +70,7 @@ namespace DotNetCore.CAP.SqlServer CancellationToken cancellationToken = default) { var sql = $"INSERT INTO {_pubName} ([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName])" + - $"VALUES(@Id,'{_options.Value}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; + $"VALUES(@Id,'{_options.Value.Version}',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; var message = new MediumMessage { From 46cdfa17975fa1fa43247ae8bd124538c8c7f4cc Mon Sep 17 00:00:00 2001 From: Savorboard Date: Mon, 25 Nov 2019 18:10:26 +0800 Subject: [PATCH 46/76] Fix Kafka transport check not working bug. #436 --- .../IConnectionPool.Default.cs | 2 +- .../Internal/IConsumerRegister.Default.cs | 4 +++- .../Processor/IDispatcher.Default.cs | 6 +++++- .../Processor/IProcessor.Collector.cs | 2 +- .../Processor/IProcessor.TransportCheck.cs | 15 +++++++++++++-- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs index 69d22c5..714954d 100644 --- a/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs +++ b/src/DotNetCore.CAP.Kafka/IConnectionPool.Default.cs @@ -24,7 +24,7 @@ namespace DotNetCore.CAP.Kafka _producerPool = new ConcurrentQueue>(); _maxSize = _options.ConnectionPoolSize; - logger.LogDebug("Kafka configuration of CAP :\r\n {0}", JsonConvert.SerializeObject(_options.AsKafkaConfig())); + logger.LogDebug("CAP Kafka configuration: {0}", JsonConvert.SerializeObject(_options.AsKafkaConfig(), Formatting.Indented)); } public string ServersAddress => _options.Servers; diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index b485edf..9c7f384 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -27,8 +27,8 @@ namespace DotNetCore.CAP.Internal private readonly TimeSpan _pollingDelay = TimeSpan.FromSeconds(1); private readonly CapOptions _options; private readonly MethodMatcherCache _selector; - private readonly CancellationTokenSource _cts; + private CancellationTokenSource _cts; private string _serverAddress; private Task _compositeTask; private bool _disposed; @@ -111,6 +111,7 @@ namespace DotNetCore.CAP.Internal { Pulse(); + _cts = new CancellationTokenSource(); _isHealthy = true; Start(); @@ -247,6 +248,7 @@ namespace DotNetCore.CAP.Internal _logger.LogError("Kafka client consume error. --> " + logmsg.Reason); break; case MqLogType.ServerConnError: + _isHealthy = false; _logger.LogCritical("Kafka server connection error. --> " + logmsg.Reason); break; case MqLogType.ExceptionReceived: diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index d12f10f..4150b30 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -64,7 +64,11 @@ namespace DotNetCore.CAP.Processor { try { - await _sender.SendAsync(message); + var result = await _sender.SendAsync(message); + if (!result.Succeeded) + { + _logger.LogWarning(result.Exception, "Message send failed! -->" + result); + } } catch (Exception ex) { diff --git a/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs b/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs index c055109..2856a50 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.Collector.cs @@ -38,7 +38,7 @@ namespace DotNetCore.CAP.Processor foreach (var table in tables) { - _logger.LogDebug($"Collecting expired data from table [{table}]."); + _logger.LogDebug($"Collecting expired data from table: {table}"); int deletedCount; var time = DateTime.Now; diff --git a/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs b/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs index 3a1c26a..25f3b9a 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.TransportCheck.cs @@ -4,16 +4,19 @@ using System; using System.Threading.Tasks; using DotNetCore.CAP.Internal; +using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Processor { public class TransportCheckProcessor : IProcessor { + private readonly ILogger _logger; private readonly IConsumerRegister _register; private readonly TimeSpan _waitingInterval; - public TransportCheckProcessor(IConsumerRegister register) + public TransportCheckProcessor(ILogger logger, IConsumerRegister register) { + _logger = logger; _register = register; _waitingInterval = TimeSpan.FromSeconds(30); } @@ -25,12 +28,20 @@ namespace DotNetCore.CAP.Processor throw new ArgumentNullException(nameof(context)); } + _logger.LogDebug("Transport connection checking..."); + if (!_register.IsHealthy()) { + _logger.LogWarning("Transport connection is unhealthy, reconnection..."); + _register.ReStart(); } + else + { + _logger.LogDebug("Transport connection healthy!"); + } await context.WaitAsync(_waitingInterval); - } + } } } \ No newline at end of file From 11d61b469461e85a178b35119f6cffce584ef598 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 26 Nov 2019 10:23:47 +0800 Subject: [PATCH 47/76] code cleanup --- .../Internal/IConsumerInvoker.Default.cs | 12 ++---------- .../Internal/IConsumerRegister.Default.cs | 7 +++---- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs index 577468d..4542032 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs @@ -15,19 +15,11 @@ namespace DotNetCore.CAP.Internal internal class DefaultConsumerInvoker : IConsumerInvoker { private readonly ILogger _logger; - //private readonly IMessagePacker _messagePacker; - //private readonly IModelBinderFactory _modelBinderFactory; private readonly IServiceProvider _serviceProvider; - public DefaultConsumerInvoker(ILoggerFactory loggerFactory, - IServiceProvider serviceProvider - //IMessagePacker messagePacker, - //IModelBinderFactory modelBinderFactory - ) + public DefaultConsumerInvoker(ILoggerFactory loggerFactory,IServiceProvider serviceProvider) { - //_modelBinderFactory = modelBinderFactory; _serviceProvider = serviceProvider; - //_messagePacker = messagePacker; _logger = loggerFactory.CreateLogger(); } @@ -35,7 +27,7 @@ namespace DotNetCore.CAP.Internal { cancellationToken.ThrowIfCancellationRequested(); - _logger.LogDebug("Executing consumer Topic: {0}", context.ConsumerDescriptor.MethodInfo.Name); + _logger.LogDebug("Executing subscriber method : {0}", context.ConsumerDescriptor.MethodInfo.Name); var executor = ObjectMethodExecutor.Create( context.ConsumerDescriptor.MethodInfo, diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index 9c7f384..5e21351 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -39,14 +39,13 @@ namespace DotNetCore.CAP.Internal private static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - public ConsumerRegister( + public ConsumerRegister(ILogger logger, IOptions options, + MethodMatcherCache selector, IConsumerClientFactory consumerClientFactory, IDispatcher dispatcher, ISerializer serializer, - IDataStorage storage, - ILogger logger, - MethodMatcherCache selector) + IDataStorage storage) { _options = options.Value; _selector = selector; From d62785381893dab7d6722fade869ccd4c2f4dc01 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 26 Nov 2019 17:50:51 +0800 Subject: [PATCH 48/76] update samples --- CAP.sln | 14 ++++++------- .../Program.cs | 19 ------------------ .../Controllers/ValuesController.cs | 2 +- samples/Sample.Kafka.InMemory/Program.cs | 20 +++++++++++++++++++ .../Sample.Kafka.InMemory.csproj} | 2 +- .../Startup.cs | 4 ++-- .../appsettings.json | 0 7 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 samples/Sample.AzureServiceBus.InMemory/Program.cs rename samples/{Sample.AzureServiceBus.InMemory => Sample.Kafka.InMemory}/Controllers/ValuesController.cs (93%) create mode 100644 samples/Sample.Kafka.InMemory/Program.cs rename samples/{Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj => Sample.Kafka.InMemory/Sample.Kafka.InMemory.csproj} (82%) rename samples/{Sample.AzureServiceBus.InMemory => Sample.Kafka.InMemory}/Startup.cs (75%) rename samples/{Sample.AzureServiceBus.InMemory => Sample.Kafka.InMemory}/appsettings.json (100%) diff --git a/CAP.sln b/CAP.sln index 66c3488..0fde2c7 100644 --- a/CAP.sln +++ b/CAP.sln @@ -66,9 +66,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.AzureService EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.InMemoryStorage", "src\DotNetCore.CAP.InMemoryStorage\DotNetCore.CAP.InMemoryStorage.csproj", "{58B6E829-C6C8-457C-9DD0-C600650254DF}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.AzureServiceBus.InMemory", "samples\Sample.AzureServiceBus.InMemory\Sample.AzureServiceBus.InMemory.csproj", "{1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Dashboard", "src\DotNetCore.CAP.Dashboard\DotNetCore.CAP.Dashboard.csproj", "{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCore.CAP.Dashboard", "src\DotNetCore.CAP.Dashboard\DotNetCore.CAP.Dashboard.csproj", "{56FB261C-67AF-4715-9A46-4FA4FAB91B2C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka.InMemory", "samples\Sample.Kafka.InMemory\Sample.Kafka.InMemory.csproj", "{1B0371D6-36A4-4C78-A727-8ED732FDBA1D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -141,14 +141,14 @@ Global {58B6E829-C6C8-457C-9DD0-C600650254DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {58B6E829-C6C8-457C-9DD0-C600650254DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {58B6E829-C6C8-457C-9DD0-C600650254DF}.Release|Any CPU.Build.0 = Release|Any CPU - {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8}.Release|Any CPU.Build.0 = Release|Any CPU {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU {56FB261C-67AF-4715-9A46-4FA4FAB91B2C}.Release|Any CPU.Build.0 = Release|Any CPU + {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -171,8 +171,8 @@ Global {11563D1A-27CC-45CF-8C04-C16BCC21250A} = {3A6B6931-A123-477A-9469-8B468B5385AF} {63B2A464-FBEA-42FB-8EFA-98AFA39FC920} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {58B6E829-C6C8-457C-9DD0-C600650254DF} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} - {1E1E959C-3D0E-45C3-ABCA-DAAACE68AAB8} = {3A6B6931-A123-477A-9469-8B468B5385AF} {56FB261C-67AF-4715-9A46-4FA4FAB91B2C} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} + {1B0371D6-36A4-4C78-A727-8ED732FDBA1D} = {3A6B6931-A123-477A-9469-8B468B5385AF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2E70565D-94CF-40B4-BFE1-AC18D5F736AB} diff --git a/samples/Sample.AzureServiceBus.InMemory/Program.cs b/samples/Sample.AzureServiceBus.InMemory/Program.cs deleted file mode 100644 index e2a308c..0000000 --- a/samples/Sample.AzureServiceBus.InMemory/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; - -namespace Sample.AzureServiceBus.InMemory -{ - public class Program - { - - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .Build(); - } -} \ No newline at end of file diff --git a/samples/Sample.AzureServiceBus.InMemory/Controllers/ValuesController.cs b/samples/Sample.Kafka.InMemory/Controllers/ValuesController.cs similarity index 93% rename from samples/Sample.AzureServiceBus.InMemory/Controllers/ValuesController.cs rename to samples/Sample.Kafka.InMemory/Controllers/ValuesController.cs index 74f1cdf..b382b41 100644 --- a/samples/Sample.AzureServiceBus.InMemory/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka.InMemory/Controllers/ValuesController.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using DotNetCore.CAP; using Microsoft.AspNetCore.Mvc; -namespace Sample.AzureServiceBus.InMemory.Controllers +namespace Sample.Kafka.InMemory.Controllers { [Route("api/[controller]")] public class ValuesController : Controller, ICapSubscribe diff --git a/samples/Sample.Kafka.InMemory/Program.cs b/samples/Sample.Kafka.InMemory/Program.cs new file mode 100644 index 0000000..b0af402 --- /dev/null +++ b/samples/Sample.Kafka.InMemory/Program.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Sample.Kafka.InMemory +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} \ No newline at end of file diff --git a/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj b/samples/Sample.Kafka.InMemory/Sample.Kafka.InMemory.csproj similarity index 82% rename from samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj rename to samples/Sample.Kafka.InMemory/Sample.Kafka.InMemory.csproj index 740cd66..9e5e3aa 100644 --- a/samples/Sample.AzureServiceBus.InMemory/Sample.AzureServiceBus.InMemory.csproj +++ b/samples/Sample.Kafka.InMemory/Sample.Kafka.InMemory.csproj @@ -7,9 +7,9 @@ - + diff --git a/samples/Sample.AzureServiceBus.InMemory/Startup.cs b/samples/Sample.Kafka.InMemory/Startup.cs similarity index 75% rename from samples/Sample.AzureServiceBus.InMemory/Startup.cs rename to samples/Sample.Kafka.InMemory/Startup.cs index 75b59f3..281ef24 100644 --- a/samples/Sample.AzureServiceBus.InMemory/Startup.cs +++ b/samples/Sample.Kafka.InMemory/Startup.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -namespace Sample.AzureServiceBus.InMemory +namespace Sample.Kafka.InMemory { public class Startup { @@ -10,7 +10,7 @@ namespace Sample.AzureServiceBus.InMemory services.AddCap(x => { x.UseInMemoryStorage(); - x.UseAzureServiceBus("Endpoint=sb://testcap.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey="); + x.UseKafka("192.168.2.120:9093"); x.UseDashboard(); }); diff --git a/samples/Sample.AzureServiceBus.InMemory/appsettings.json b/samples/Sample.Kafka.InMemory/appsettings.json similarity index 100% rename from samples/Sample.AzureServiceBus.InMemory/appsettings.json rename to samples/Sample.Kafka.InMemory/appsettings.json From 828de686348c29747489bb124168cba21b9c7524 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 26 Nov 2019 17:53:02 +0800 Subject: [PATCH 49/76] Adjust dashboard display --- .../Pages/PublishedPage.cshtml | 2 +- .../Pages/PublishedPage.generated.cs | 4 ++-- .../Pages/ReceivedPage.cshtml | 4 ++-- .../Pages/ReceivedPage.generated.cs | 22 +++++++++---------- .../Pages/SubscriberPage.cshtml | 2 +- .../Pages/SubscriberPage.generated.cs | 2 +- .../IMonitoringApi.InMemory.cs | 11 +++++----- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml index dba410f..7f11913 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.cshtml @@ -80,7 +80,7 @@ - @Strings.Common_Id + @Strings.Common_Id @Strings.Common_Version @Strings.MessagesPage_Table_Name @Strings.MessagesPage_Table_Retries diff --git a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs index 8d2bee3..511e2e1 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/PublishedPage.generated.cs @@ -268,12 +268,12 @@ WriteLiteral(@" - "); + "); #line 83 "..\..\Pages\PublishedPage.cshtml" - Write(Strings.Common_Id); + Write(Strings.Common_Id); #line default diff --git a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml index 64affa5..93636a1 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.cshtml @@ -85,8 +85,8 @@ - @Strings.Common_Id - @Strings.Common_Version + @Strings.Common_Id + @Strings.Common_Version @Strings.MessagesPage_Table_Group @Strings.MessagesPage_Table_Name @Strings.MessagesPage_Table_Retries diff --git a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs index 7683be2..e5f2a01 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/ReceivedPage.generated.cs @@ -1,6 +1,4 @@ -using DotNetCore.CAP.Monitoring; - -#pragma warning disable 1591 +#pragma warning disable 1591 //------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -30,23 +28,25 @@ namespace DotNetCore.CAP.Dashboard.Pages #line hidden #line 4 "..\..\Pages\ReceivedPage.cshtml" -#line default + using DotNetCore.CAP.Dashboard.Pages; + + #line default #line hidden #line 5 "..\..\Pages\ReceivedPage.cshtml" - using DotNetCore.CAP.Dashboard.Pages; + using DotNetCore.CAP.Dashboard.Resources; #line default #line hidden #line 6 "..\..\Pages\ReceivedPage.cshtml" - using DotNetCore.CAP.Dashboard.Resources; + using DotNetCore.CAP.Messages; #line default #line hidden #line 7 "..\..\Pages\ReceivedPage.cshtml" - using DotNetCore.CAP.Messages; + using DotNetCore.CAP.Monitoring; #line default #line hidden @@ -292,22 +292,22 @@ WriteLiteral(@" - "); + "); #line 88 "..\..\Pages\ReceivedPage.cshtml" - Write(Strings.Common_Id); + Write(Strings.Common_Id); #line default #line hidden -WriteLiteral("\r\n "); +WriteLiteral("\r\n "); #line 89 "..\..\Pages\ReceivedPage.cshtml" - Write(Strings.Common_Version); + Write(Strings.Common_Version); #line default diff --git a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml index 75f3459..0b6ba0d 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml +++ b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.cshtml @@ -35,7 +35,7 @@ @foreach (var subscriber in subscribers) - { + { var i = 0; var rowCount = subscriber.Value.Count; foreach (var column in subscriber.Value) diff --git a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs index a16d03a..b243943 100644 --- a/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs +++ b/src/DotNetCore.CAP.Dashboard/Pages/SubscriberPage.generated.cs @@ -145,7 +145,7 @@ WriteLiteral("\r\n \r\n #line 37 "..\..\Pages\SubscriberPage.cshtml" foreach (var subscriber in subscribers) - { + { var i = 0; var rowCount = subscriber.Value.Count; foreach (var column in subscriber.Value) diff --git a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs index 1db101b..55b5773 100644 --- a/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs +++ b/src/DotNetCore.CAP.InMemoryStorage/IMonitoringApi.InMemory.cs @@ -55,12 +55,12 @@ namespace DotNetCore.CAP.InMemoryStorage if (!string.IsNullOrEmpty(queryDto.StatusName)) { - expression = expression.Where(x => x.StatusName.ToString() == queryDto.StatusName); + expression = expression.Where(x => x.StatusName.ToString().Equals(queryDto.StatusName, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(queryDto.Name)) { - expression = expression.Where(x => x.Name == queryDto.Name); + expression = expression.Where(x => x.Name.Equals(queryDto.Name, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(queryDto.Content)) @@ -74,6 +74,7 @@ namespace DotNetCore.CAP.InMemoryStorage return expression.Skip(offset).Take(size).Select(x => new MessageDto() { Added = x.Added, + Version = "N/A", Content = x.Content, ExpiresAt = x.ExpiresAt, Id = long.Parse(x.DbId), @@ -88,17 +89,17 @@ namespace DotNetCore.CAP.InMemoryStorage if (!string.IsNullOrEmpty(queryDto.StatusName)) { - expression = expression.Where(x => x.StatusName.ToString() == queryDto.StatusName); + expression = expression.Where(x => x.StatusName.ToString().Equals(queryDto.StatusName, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(queryDto.Name)) { - expression = expression.Where(x => x.Name == queryDto.Name); + expression = expression.Where(x => x.Name.Equals(queryDto.Name, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(queryDto.Group)) { - expression = expression.Where(x => x.Group == queryDto.Name); + expression = expression.Where(x => x.Group.Equals(queryDto.Group, StringComparison.InvariantCultureIgnoreCase)); } if (!string.IsNullOrEmpty(queryDto.Content)) From fa9b4a3b05a6f2bc0e88df5d3d72dea7205a528e Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 26 Nov 2019 23:44:33 +0800 Subject: [PATCH 50/76] Refacing diagnostics tracing module. --- CAP.sln | 2 + .../Diagnostics/CapDiagnosticListenerNames.cs | 31 +++ .../DiagnosticListenerExtensions.cs | 229 ------------------ .../Diagnostics/EventData.Broker.Consume.cs | 27 --- .../EventData.Broker.ConsumeEnd.cs | 19 -- .../EventData.Broker.ConsumeError.cs | 27 --- .../Diagnostics/EventData.Broker.Publish.cs | 20 -- .../EventData.Broker.PublishEnd.cs | 20 -- .../EventData.Broker.PublishError.cs | 20 -- .../Diagnostics/EventData.Broker.cs | 23 -- .../Diagnostics/EventData.Cap.P.cs | 33 +++ .../Diagnostics/EventData.Cap.S.cs | 41 ++++ .../Diagnostics/EventData.SubscriberInvoke.cs | 35 --- .../EventData.SubscriberInvokeEnd.cs | 20 -- .../EventData.SubscriberInvokeError.cs | 20 -- src/DotNetCore.CAP/Diagnostics/EventData.cs | 20 -- .../Diagnostics/IErrorEventData.cs | 12 - .../Diagnostics/TracingHeaders.cs | 44 ---- .../Internal/ICapPublisher.Default.cs | 71 +++++- .../Internal/IConsumerRegister.Default.cs | 84 ++++--- .../Internal/IMessageSender.Default.cs | 80 +++--- .../Internal/ISubscriberExecutor.Default.cs | 78 +++++- 22 files changed, 339 insertions(+), 617 deletions(-) create mode 100644 src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs create mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Cap.P.cs create mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.Cap.S.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeEnd.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeError.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/EventData.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/IErrorEventData.cs delete mode 100644 src/DotNetCore.CAP/Diagnostics/TracingHeaders.cs diff --git a/CAP.sln b/CAP.sln index 0fde2c7..8e82097 100644 --- a/CAP.sln +++ b/CAP.sln @@ -128,9 +128,11 @@ Global {77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Release|Any CPU.ActiveCfg = Release|Any CPU {77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Release|Any CPU.Build.0 = Release|Any CPU {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.Build.0 = Release|Any CPU {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Debug|Any CPU.Build.0 = Debug|Any CPU {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Release|Any CPU.ActiveCfg = Release|Any CPU {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Release|Any CPU.Build.0 = Release|Any CPU {63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs b/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs new file mode 100644 index 0000000..a724a27 --- /dev/null +++ b/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace DotNetCore.CAP.Diagnostics +{ + /// + /// Extension methods on the DiagnosticListener class to log CAP data + /// + public static class CapDiagnosticListenerNames + { + public const string DiagnosticListenerName = "CapDiagnosticListener"; + + private const string CapPrefix = "DotNetCore.CAP."; + + public const string BeforePublishMessageStore = CapPrefix + "WritePublishMessageStoreBefore"; + public const string AfterPublishMessageStore = CapPrefix + "WritePublishMessageStoreAfter"; + public const string ErrorPublishMessageStore = CapPrefix + "WritePublishMessageStoreError"; + + public const string BeforePublish = CapPrefix + "WritePublishBefore"; + public const string AfterPublish = CapPrefix + "WritePublishAfter"; + public const string ErrorPublish = CapPrefix + "WritePublishError"; + + public const string BeforeConsume = CapPrefix + "WriteConsumeBefore"; + public const string AfterConsume = CapPrefix + "WriteConsumeAfter"; + public const string ErrorConsume = CapPrefix + "WriteConsumeError"; + + public const string BeforeSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeBefore"; + public const string AfterSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeAfter"; + public const string ErrorSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeError"; + } +} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs b/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs deleted file mode 100644 index 0016a4d..0000000 --- a/src/DotNetCore.CAP/Diagnostics/DiagnosticListenerExtensions.cs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - /// - /// Extension methods on the DiagnosticListener class to log CAP data - /// - public static class CapDiagnosticListenerExtensions - { - public const string DiagnosticListenerName = "CapDiagnosticListener"; - - private const string CapPrefix = "DotNetCore.CAP."; - - public const string CapBeforePublishMessageStore = CapPrefix + "WritePublishMessageStoreBefore"; - public const string CapAfterPublishMessageStore = CapPrefix + "WritePublishMessageStoreAfter"; - public const string CapErrorPublishMessageStore = CapPrefix + "WritePublishMessageStoreError"; - - public const string CapBeforePublish = CapPrefix + "WritePublishBefore"; - public const string CapAfterPublish = CapPrefix + "WritePublishAfter"; - public const string CapErrorPublish = CapPrefix + "WritePublishError"; - - public const string CapBeforeConsume = CapPrefix + "WriteConsumeBefore"; - public const string CapAfterConsume = CapPrefix + "WriteConsumeAfter"; - public const string CapErrorConsume = CapPrefix + "WriteConsumeError"; - - public const string CapBeforeSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeBefore"; - public const string CapAfterSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeAfter"; - public const string CapErrorSubscriberInvoke = CapPrefix + "WriteSubscriberInvokeError"; - - - //============================================================================ - //==================== Before publish store message ==================== - //============================================================================ - public static Guid WritePublishMessageStoreBefore(this DiagnosticListener @this, - Message message, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapBeforePublishMessageStore)) - { - var operationId = Guid.NewGuid(); - - @this.Write(CapBeforePublishMessageStore, new - { - OperationId = operationId, - Operation = operation, - Message = message - }); - - return operationId; - } - - return Guid.Empty; - } - - public static void WritePublishMessageStoreAfter(this DiagnosticListener @this, - Guid operationId, - Message message, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapAfterPublishMessageStore)) - { - @this.Write(CapAfterPublishMessageStore, new - { - OperationId = operationId, - Operation = operation, - Message = message, - Timestamp = Stopwatch.GetTimestamp() - }); - } - } - - public static void WritePublishMessageStoreError(this DiagnosticListener @this, - Guid operationId, - Message message, - Exception ex, - [CallerMemberName] string operation = "") - { - if (@this.IsEnabled(CapErrorPublishMessageStore)) - { - @this.Write(CapErrorPublishMessageStore, new - { - OperationId = operationId, - Operation = operation, - Message = message, - Exception = ex, - Timestamp = Stopwatch.GetTimestamp() - }); - } - } - - - ////============================================================================ - ////==================== Publish ==================== - ////============================================================================ - //public static void WritePublishBefore(this DiagnosticListener @this, BrokerPublishEventData eventData) - //{ - // if (@this.IsEnabled(CapBeforePublish)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapBeforePublish, eventData); - // } - //} - - //public static void WritePublishAfter(this DiagnosticListener @this, BrokerPublishEndEventData eventData) - //{ - // if (@this.IsEnabled(CapAfterPublish)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapAfterPublish, eventData); - // } - //} - - //public static void WritePublishError(this DiagnosticListener @this, BrokerPublishErrorEventData eventData) - //{ - // if (@this.IsEnabled(CapErrorPublish)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapErrorPublish, eventData); - // } - //} - - - //============================================================================ - //==================== Consume ==================== - //============================================================================ - //public static Guid WriteConsumeBefore(this DiagnosticListener @this, BrokerConsumeEventData eventData) - //{ - // if (@this.IsEnabled(CapBeforeConsume)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapBeforeConsume, eventData); - // } - - // return Guid.Empty; - //} - - //public static void WriteConsumeAfter(this DiagnosticListener @this, BrokerConsumeEndEventData eventData) - //{ - // if (@this.IsEnabled(CapAfterConsume)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapAfterConsume, eventData); - // } - //} - - //public static void WriteConsumeError(this DiagnosticListener @this, BrokerConsumeErrorEventData eventData) - //{ - // if (@this.IsEnabled(CapErrorConsume)) - // { - // eventData.Headers = new TracingHeaders(); - // @this.Write(CapErrorConsume, eventData); - // } - //} - - - //============================================================================ - //==================== SubscriberInvoke ==================== - //============================================================================ - //public static Guid WriteSubscriberInvokeBefore(this DiagnosticListener @this, - // ConsumerContext context, - // [CallerMemberName] string operation = "") - //{ - // if (@this.IsEnabled(CapBeforeSubscriberInvoke)) - // { - // var operationId = Guid.NewGuid(); - - // var methodName = context.ConsumerDescriptor.MethodInfo.Name; - // var subscribeName = context.ConsumerDescriptor.Attribute.Name; - // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - // var values = context.DeliverMessage.Value; - - // @this.Write(CapBeforeSubscriberInvoke, new SubscriberInvokeEventData(operationId, operation, methodName, - // subscribeName, - // subscribeGroup, parameterValues, DateTimeOffset.UtcNow)); - - // return operationId; - // } - - // return Guid.Empty; - //} - - //public static void WriteSubscriberInvokeAfter(this DiagnosticListener @this, - // Guid operationId, - // ConsumerContext context, - // DateTimeOffset startTime, - // TimeSpan duration, - // [CallerMemberName] string operation = "") - //{ - // if (@this.IsEnabled(CapAfterSubscriberInvoke)) - // { - // var methodName = context.ConsumerDescriptor.MethodInfo.Name; - // var subscribeName = context.ConsumerDescriptor.Attribute.Name; - // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - // var values = context.DeliverMessage.Value; - - // @this.Write(CapAfterSubscriberInvoke, new SubscriberInvokeEndEventData(operationId, operation, methodName, - // subscribeName, - // subscribeGroup, parameterValues, startTime, duration)); - // } - //} - - //public static void WriteSubscriberInvokeError(this DiagnosticListener @this, - // Guid operationId, - // ConsumerContext context, - // Exception ex, - // DateTimeOffset startTime, - // TimeSpan duration, - // [CallerMemberName] string operation = "") - //{ - // if (@this.IsEnabled(CapErrorSubscriberInvoke)) - // { - // var methodName = context.ConsumerDescriptor.MethodInfo.Name; - // var subscribeName = context.ConsumerDescriptor.Attribute.Name; - // var subscribeGroup = context.ConsumerDescriptor.Attribute.Group; - // var parameterValues = context.DeliverMessage.Content; - - // @this.Write(CapErrorSubscriberInvoke, new SubscriberInvokeErrorEventData(operationId, operation, methodName, - // subscribeName, - // subscribeGroup, parameterValues, ex, startTime, duration)); - // } - //} - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs deleted file mode 100644 index 177dcf2..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Consume.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerConsumeEventData - { - public BrokerConsumeEventData(Guid operationId,string brokerAddress, TransportMessage message, DateTimeOffset startTime) - { - OperationId = operationId; - StartTime = startTime; - BrokerAddress = brokerAddress; - Message = message; - } - - public Guid OperationId { get; set; } - - public string BrokerAddress { get; set; } - - public TransportMessage Message { get; set; } - - public DateTimeOffset StartTime { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs deleted file mode 100644 index 135998c..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeEnd.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerConsumeEndEventData : BrokerConsumeEventData - { - public BrokerConsumeEndEventData(Guid operationId, string operation, string brokerAddress, TransportMessage message, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, brokerAddress, message, startTime) - { - Duration = duration; - } - - public TimeSpan Duration { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs deleted file mode 100644 index f6c17b4..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.ConsumeError.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerConsumeErrorEventData : IErrorEventData - { - public BrokerConsumeErrorEventData(Guid operationId, string brokerAddress, TransportMessage message, Exception exception) - { - OperationId = operationId; - BrokerAddress = brokerAddress; - Message = message; - Exception = exception; - } - - public Guid OperationId { get; set; } - - public string BrokerAddress { get; } - - public TransportMessage Message { get; } - - public Exception Exception { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs deleted file mode 100644 index 56b43e9..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.Publish.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerPublishEventData : BrokerEventData - { - public BrokerPublishEventData(Guid operationId, string operation, string brokerAddress, - Message message , DateTimeOffset startTime) - : base(operationId, operation, brokerAddress, message) - { - StartTime = startTime; - } - - public DateTimeOffset StartTime { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs deleted file mode 100644 index 6286dfc..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishEnd.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerPublishEndEventData : BrokerPublishEventData - { - public BrokerPublishEndEventData(Guid operationId, string operation, string brokerAddress, - Message message, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, operation, brokerAddress, message, startTime) - { - Duration = duration; - } - - public TimeSpan Duration { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs deleted file mode 100644 index fbf561a..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.PublishError.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerPublishErrorEventData : BrokerPublishEndEventData, IErrorEventData - { - public BrokerPublishErrorEventData(Guid operationId, string operation, string brokerAddress, - Message message, Exception exception, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, operation, brokerAddress, message, startTime, duration) - { - Exception = exception; - } - - public Exception Exception { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs deleted file mode 100644 index 77a41b1..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.Broker.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using DotNetCore.CAP.Messages; - -namespace DotNetCore.CAP.Diagnostics -{ - public class BrokerEventData : EventData - { - public BrokerEventData(Guid operationId, string operation, string brokerAddress, Message message) - : base(operationId, operation) - { - BrokerAddress = brokerAddress; - - Message = message; - } - - public string BrokerAddress { get; set; } - - public Message Message { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Cap.P.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Cap.P.cs new file mode 100644 index 0000000..9c425fa --- /dev/null +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Cap.P.cs @@ -0,0 +1,33 @@ +using System; +using DotNetCore.CAP.Messages; + +namespace DotNetCore.CAP.Diagnostics +{ + public class CapEventDataPubStore + { + public long? OperationTimestamp { get; set; } + + public string Operation { get; set; } + + public Message Message { get; set; } + + public long? ElapsedTimeMs { get; set; } + + public Exception Exception { get; set; } + } + + public class CapEventDataPubSend + { + public long? OperationTimestamp { get; set; } + + public string Operation { get; set; } + + public TransportMessage TransportMessage { get; set; } + + public string BrokerAddress { get; set; } + + public long? ElapsedTimeMs { get; set; } + + public Exception Exception { get; set; } + } +} diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.Cap.S.cs b/src/DotNetCore.CAP/Diagnostics/EventData.Cap.S.cs new file mode 100644 index 0000000..e83c56f --- /dev/null +++ b/src/DotNetCore.CAP/Diagnostics/EventData.Cap.S.cs @@ -0,0 +1,41 @@ +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Reflection; +using DotNetCore.CAP.Messages; +using JetBrains.Annotations; + +namespace DotNetCore.CAP.Diagnostics +{ + public class CapEventDataSubStore + { + public long? OperationTimestamp { get; set; } + + public string Operation { get; set; } + + public TransportMessage TransportMessage { get; set; } + + public string BrokerAddress { get; set; } + + public long? ElapsedTimeMs { get; set; } + + public Exception Exception { get; set; } + } + + public class CapEventDataSubExecute + { + public long? OperationTimestamp { get; set; } + + public string Operation { get; set; } + + public Message Message { get; set; } + + [CanBeNull] + public MethodInfo MethodInfo { get; set; } + + public long? ElapsedTimeMs { get; set; } + + public Exception Exception { get; set; } + } +} diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs b/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs deleted file mode 100644 index f3c5cb0..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvoke.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Diagnostics -{ - public class SubscriberInvokeEventData : EventData - { - public SubscriberInvokeEventData(Guid operationId, - string operation, - string methodName, - string subscribeName, - string subscribeGroup, - object values, - DateTimeOffset startTime) - : base(operationId, operation) - { - MethodName = methodName; - SubscribeName = subscribeName; - SubscribeGroup = subscribeGroup; - StartTime = startTime; - } - - public DateTimeOffset StartTime { get; } - - public string MethodName { get; set; } - - public string SubscribeName { get; set; } - - public string SubscribeGroup { get; set; } - - public string Values { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeEnd.cs b/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeEnd.cs deleted file mode 100644 index 2a24ca1..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeEnd.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Diagnostics -{ - public class SubscriberInvokeEndEventData : SubscriberInvokeEventData - { - public SubscriberInvokeEndEventData(Guid operationId, string operation, - string methodName, string subscribeName, string subscribeGroup, - string parameterValues, DateTimeOffset startTime, TimeSpan duration) - : base(operationId, operation, methodName, subscribeName, subscribeGroup, parameterValues, startTime) - { - Duration = duration; - } - - public TimeSpan Duration { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeError.cs b/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeError.cs deleted file mode 100644 index 005f70f..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.SubscriberInvokeError.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Diagnostics -{ - public class SubscriberInvokeErrorEventData : SubscriberInvokeEndEventData, IErrorEventData - { - public SubscriberInvokeErrorEventData(Guid operationId, string operation, string methodName, - string subscribeName, string subscribeGroup, string parameterValues, Exception exception, - DateTimeOffset startTime, TimeSpan duration) : base(operationId, operation, methodName, subscribeName, - subscribeGroup, parameterValues, startTime, duration) - { - Exception = exception; - } - - public Exception Exception { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/EventData.cs b/src/DotNetCore.CAP/Diagnostics/EventData.cs deleted file mode 100644 index b773780..0000000 --- a/src/DotNetCore.CAP/Diagnostics/EventData.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Diagnostics -{ - public class EventData - { - public EventData(Guid operationId, string operation) - { - OperationId = operationId; - Operation = operation; - } - - public Guid OperationId { get; set; } - - public string Operation { get; set; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/IErrorEventData.cs b/src/DotNetCore.CAP/Diagnostics/IErrorEventData.cs deleted file mode 100644 index e0217c6..0000000 --- a/src/DotNetCore.CAP/Diagnostics/IErrorEventData.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; - -namespace DotNetCore.CAP.Diagnostics -{ - public interface IErrorEventData - { - Exception Exception { get; } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Diagnostics/TracingHeaders.cs b/src/DotNetCore.CAP/Diagnostics/TracingHeaders.cs deleted file mode 100644 index 8fb7e21..0000000 --- a/src/DotNetCore.CAP/Diagnostics/TracingHeaders.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace DotNetCore.CAP.Diagnostics -{ - public class TracingHeaders : IEnumerable> - { - private List> _dataStore = new List>(); - - public IEnumerator> GetEnumerator() - { - return _dataStore.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void Add(string name, string value) - { - _dataStore.Add(new KeyValuePair(name, value)); - } - - public bool Contains(string name) - { - return _dataStore != null && _dataStore.Any(x => x.Key == name); - } - - public void Remove(string name) - { - _dataStore?.RemoveAll(x => x.Key == name); - } - - public void Cleaar() - { - _dataStore?.Clear(); - } - } -} diff --git a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index b904d2f..2629911 100644 --- a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -21,7 +21,7 @@ namespace DotNetCore.CAP.Internal // ReSharper disable once InconsistentNaming protected static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); public CapPublisher(IServiceProvider service) { @@ -62,16 +62,16 @@ namespace DotNetCore.CAP.Internal var message = new Message(optionHeaders, value); - var operationId = default(Guid); + long? tracingTimestamp = null; try { - operationId = s_diagnosticListener.WritePublishMessageStoreBefore(message); + tracingTimestamp = TracingBefore(message); if (Transaction.Value?.DbTransaction == null) { var mediumMessage = await _storage.StoreMessageAsync(name, message, cancellationToken: cancellationToken); - s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); + TracingAfter(tracingTimestamp, message); _dispatcher.EnqueueToPublish(mediumMessage); } @@ -81,7 +81,7 @@ namespace DotNetCore.CAP.Internal var mediumMessage = await _storage.StoreMessageAsync(name, message, transaction.DbTransaction, cancellationToken); - s_diagnosticListener.WritePublishMessageStoreAfter(operationId, message); + TracingAfter(tracingTimestamp, message); transaction.AddToSent(mediumMessage); @@ -93,7 +93,8 @@ namespace DotNetCore.CAP.Internal } catch (Exception e) { - s_diagnosticListener.WritePublishMessageStoreError(operationId, message, e); + TracingError(tracingTimestamp, message, e); + throw; } } @@ -113,5 +114,63 @@ namespace DotNetCore.CAP.Internal return PublishAsync(name, value, header, cancellationToken); } + + #region tracing + + private long? TracingBefore(Message message) + { + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforePublishMessageStore)) + { + var eventData = new CapEventDataPubStore() + { + OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + Operation = message.GetName(), + Message = message + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforePublishMessageStore, eventData); + + return eventData.OperationTimestamp; + } + + return null; + } + + private void TracingAfter(long? tracingTimestamp, Message message) + { + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterPublishMessageStore)) + { + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataPubStore() + { + OperationTimestamp = now, + Operation = message.GetName(), + Message = message, + ElapsedTimeMs = now - tracingTimestamp.Value + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterPublishMessageStore, eventData); + } + } + + private void TracingError(long? tracingTimestamp, Message message, Exception ex) + { + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorPublishMessageStore)) + { + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataPubStore() + { + OperationTimestamp = now, + Operation = message.GetName(), + Message = message, + ElapsedTimeMs = now - tracingTimestamp.Value, + Exception = ex + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorPublishMessageStore, eventData); + } + } + + #endregion } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index 5e21351..d1f67f4 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -37,7 +37,7 @@ namespace DotNetCore.CAP.Internal // diagnostics listener // ReSharper disable once InconsistentNaming private static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); public ConsumerRegister(ILogger logger, IOptions options, @@ -152,10 +152,10 @@ namespace DotNetCore.CAP.Internal client.OnMessageReceived += async (sender, transportMessage) => { _cts.Token.ThrowIfCancellationRequested(); - Guid? operationId = null; + long? tracingTimestamp = null; try { - operationId = TracingBefore(transportMessage); + tracingTimestamp = TracingBefore(transportMessage, _serverAddress); var startTime = DateTimeOffset.UtcNow; var stopwatch = Stopwatch.StartNew(); @@ -191,10 +191,7 @@ namespace DotNetCore.CAP.Internal client.Commit(); - if (operationId != null) - { - TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); - } + TracingAfter(tracingTimestamp, transportMessage, _serverAddress); } else { @@ -203,10 +200,7 @@ namespace DotNetCore.CAP.Internal client.Commit(); - if (operationId != null) - { - TracingAfter(operationId.Value, message, startTime, stopwatch.Elapsed); - } + TracingAfter(tracingTimestamp, transportMessage, _serverAddress); _dispatcher.EnqueueToExecute(mediumMessage, executor); } @@ -217,10 +211,7 @@ namespace DotNetCore.CAP.Internal client.Reject(); - if (operationId != null) - { - TracingError(operationId.Value, transportMessage, e); - } + TracingError(tracingTimestamp, transportMessage, client.ServersAddress, e); } }; @@ -258,39 +249,66 @@ namespace DotNetCore.CAP.Internal } } - private Guid? TracingBefore(TransportMessage message) + #region tracing + + private long? TracingBefore(TransportMessage message, string broker) { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapBeforeConsume)) + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforeConsume)) { - var operationId = Guid.NewGuid(); - - var eventData = new BrokerConsumeEventData(operationId, _serverAddress, message, DateTimeOffset.UtcNow); + var eventData = new CapEventDataSubStore() + { + OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message + }; - s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapBeforeConsume, eventData); + s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforeConsume, eventData); - return operationId; + return eventData.OperationTimestamp; } return null; } - private void TracingAfter(Guid operationId, Message message, DateTimeOffset startTime, TimeSpan du) + private void TracingAfter(long? tracingTimestamp, TransportMessage message, string broker) { - //if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterConsume)) - //{ - // var eventData = new BrokerConsumeEndEventData(operationId, "", _serverAddress, message, startTime, du); - - // s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapAfterConsume, eventData); - //} + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterConsume)) + { + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataSubStore() + { + OperationTimestamp = now, + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message, + ElapsedTimeMs = now - tracingTimestamp.Value + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterConsume, eventData); + } } - private void TracingError(Guid operationId, TransportMessage message, Exception ex) + private void TracingError(long? tracingTimestamp, TransportMessage message, string broker, Exception ex) { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapErrorConsume)) + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorConsume)) { - var eventData = new BrokerConsumeErrorEventData(operationId, _serverAddress, message, ex); - s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapErrorConsume, eventData); + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + var eventData = new CapEventDataPubSend() + { + OperationTimestamp = now, + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message, + ElapsedTimeMs = now - tracingTimestamp.Value, + Exception = ex + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorConsume, eventData); } } + + #endregion } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs index 76227d9..4bceda8 100644 --- a/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs +++ b/src/DotNetCore.CAP/Internal/IMessageSender.Default.cs @@ -25,7 +25,7 @@ namespace DotNetCore.CAP.Internal // ReSharper disable once InconsistentNaming protected static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); public MessageSender( ILogger logger, @@ -61,32 +61,23 @@ namespace DotNetCore.CAP.Internal private async Task<(bool, OperateResult)> SendWithoutRetryAsync(MediumMessage message) { - var startTime = DateTimeOffset.UtcNow; - var stopwatch = Stopwatch.StartNew(); + var transportMsg = await _serializer.SerializeAsync(message.Origin); - var operationId = TracingBefore(message.Origin); + var tracingTimestamp = TracingBefore(transportMsg, _transport.Address); - var transportMsg = await _serializer.SerializeAsync(message.Origin); var result = await _transport.SendAsync(transportMsg); - stopwatch.Stop(); if (result.Succeeded) { await SetSuccessfulState(message); - if (operationId != null) - { - TracingAfter(operationId.Value, message.Origin, startTime, stopwatch.Elapsed); - } + TracingAfter(tracingTimestamp, transportMsg, _transport.Address); return (false, OperateResult.Success); } else { - if (operationId != null) - { - TracingError(operationId.Value, message.Origin, result, startTime, stopwatch.Elapsed); - } + TracingError(tracingTimestamp, transportMsg, _transport.Address, result); var needRetry = await SetFailedState(message, result.Exception); @@ -144,42 +135,67 @@ namespace DotNetCore.CAP.Internal return true; } - private Guid? TracingBefore(Message message) + #region tracing + + private long? TracingBefore(TransportMessage message, string broker) { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapBeforePublish)) + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforePublish)) { - var operationId = Guid.NewGuid(); - - var eventData = new BrokerPublishEventData(operationId, "",_transport.Address, message,DateTimeOffset.UtcNow); + var eventData = new CapEventDataPubSend() + { + OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message + }; - s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapBeforePublish, eventData); + s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforePublish, eventData); - return operationId; + return eventData.OperationTimestamp; } return null; } - private void TracingAfter(Guid operationId, Message message, DateTimeOffset startTime, TimeSpan du) + private void TracingAfter(long? tracingTimestamp, TransportMessage message, string broker) { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterPublish)) + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterPublish)) { - var eventData = new BrokerPublishEndEventData(operationId, "", _transport.Address, message, startTime, du); - - s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapAfterPublish, eventData); + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataPubSend() + { + OperationTimestamp = now, + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message, + ElapsedTimeMs = now - tracingTimestamp.Value + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterPublish, eventData); } } - private void TracingError(Guid operationId, Message message, OperateResult result, DateTimeOffset startTime, TimeSpan du) + private void TracingError(long? tracingTimestamp, TransportMessage message, string broker, OperateResult result) { - if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerExtensions.CapAfterPublish)) + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorPublish)) { var ex = new PublisherSentFailedException(result.ToString(), result.Exception); - var eventData = new BrokerPublishErrorEventData(operationId, "", _transport.Address, - message, ex, startTime, du); + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - s_diagnosticListener.Write(CapDiagnosticListenerExtensions.CapErrorPublish, eventData); + var eventData = new CapEventDataPubSend() + { + OperationTimestamp = now, + Operation = message.GetName(), + BrokerAddress = broker, + TransportMessage = message, + ElapsedTimeMs = now - tracingTimestamp.Value, + Exception = ex + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorPublish, eventData); } - } + } + + #endregion } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs index d3e91b5..14500b7 100644 --- a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Diagnostics; @@ -26,7 +27,7 @@ namespace DotNetCore.CAP.Internal // diagnostics listener // ReSharper disable once InconsistentNaming private static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); + new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); public DefaultSubscriberExecutor( ILogger logger, @@ -52,6 +53,8 @@ namespace DotNetCore.CAP.Internal $"{Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; _logger.LogError(error); + TracingError(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), message.Origin, null, new Exception(error)); + return Task.FromResult(OperateResult.Failed(new SubscriberNotFoundException(error))); } @@ -168,19 +171,13 @@ namespace DotNetCore.CAP.Internal private async Task InvokeConsumerMethodAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) { - var startTime = DateTimeOffset.UtcNow; - var stopwatch = Stopwatch.StartNew(); - var operationId = Guid.Empty; - var consumerContext = new ConsumerContext(descriptor, message.Origin); - + var tracingTimestamp = TracingBefore(message.Origin, descriptor.MethodInfo); try { - // operationId = s_diagnosticListener.WriteSubscriberInvokeBefore(consumerContext); - var ret = await Invoker.InvokeAsync(consumerContext, cancellationToken); - // s_diagnosticListener.WriteSubscriberInvokeAfter(operationId, consumerContext, startTime,stopwatch.Elapsed); + TracingAfter(tracingTimestamp, message.Origin, descriptor.MethodInfo); if (!string.IsNullOrEmpty(ret.CallbackName)) { @@ -199,10 +196,71 @@ namespace DotNetCore.CAP.Internal } catch (Exception ex) { - // s_diagnosticListener.WriteSubscriberInvokeError(operationId, consumerContext, ex, startTime, stopwatch.Elapsed); + TracingError(tracingTimestamp, message.Origin, descriptor.MethodInfo, ex); throw new SubscriberExecutionFailedException(ex.Message, ex); } } + + #region tracing + + private long? TracingBefore(Message message, MethodInfo method) + { + if (s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.BeforeSubscriberInvoke)) + { + var eventData = new CapEventDataSubExecute() + { + OperationTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + Operation = message.GetName(), + Message = message, + MethodInfo = method + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.BeforeSubscriberInvoke, eventData); + + return eventData.OperationTimestamp; + } + + return null; + } + + private void TracingAfter(long? tracingTimestamp, Message message, MethodInfo method) + { + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.AfterSubscriberInvoke)) + { + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataSubExecute() + { + OperationTimestamp = now, + Operation = message.GetName(), + Message = message, + MethodInfo = method, + ElapsedTimeMs = now - tracingTimestamp.Value + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.AfterSubscriberInvoke, eventData); + } + } + + private void TracingError(long? tracingTimestamp, Message message, MethodInfo method, Exception ex) + { + if (tracingTimestamp != null && s_diagnosticListener.IsEnabled(CapDiagnosticListenerNames.ErrorSubscriberInvoke)) + { + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + var eventData = new CapEventDataSubExecute() + { + OperationTimestamp = now, + Operation = message.GetName(), + Message = message, + MethodInfo = method, + ElapsedTimeMs = now - tracingTimestamp.Value, + Exception = ex + }; + + s_diagnosticListener.Write(CapDiagnosticListenerNames.ErrorSubscriberInvoke, eventData); + } + } + + #endregion } } \ No newline at end of file From 82416af83ac484b455d4c7b1cf2e35bc33d9cb55 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 09:31:24 +0800 Subject: [PATCH 51/76] Code cleanup --- .../Diagnostics/CapDiagnosticListenerNames.cs | 4 +- src/DotNetCore.CAP/Internal/CapCache.cs | 378 ------------------ .../Internal/ConsumerInvokerFactory.cs | 13 +- .../Internal/HashCodeCombiner.cs | 85 ---- .../Internal/IConsumerInvoker.Default.cs | 2 +- .../Internal/IConsumerRegister.Default.cs | 9 +- .../Internal/IMongoTransaction.cs | 21 - .../Internal/ISubscriberExecutor.Default.cs | 6 +- src/DotNetCore.CAP/Internal/WaitHandleEx.cs | 39 -- 9 files changed, 15 insertions(+), 542 deletions(-) delete mode 100644 src/DotNetCore.CAP/Internal/CapCache.cs delete mode 100644 src/DotNetCore.CAP/Internal/HashCodeCombiner.cs delete mode 100644 src/DotNetCore.CAP/Internal/IMongoTransaction.cs delete mode 100644 src/DotNetCore.CAP/Internal/WaitHandleEx.cs diff --git a/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs b/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs index a724a27..91bedb1 100644 --- a/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs +++ b/src/DotNetCore.CAP/Diagnostics/CapDiagnosticListenerNames.cs @@ -8,10 +8,10 @@ namespace DotNetCore.CAP.Diagnostics /// public static class CapDiagnosticListenerNames { - public const string DiagnosticListenerName = "CapDiagnosticListener"; - private const string CapPrefix = "DotNetCore.CAP."; + public const string DiagnosticListenerName = "CapDiagnosticListener"; + public const string BeforePublishMessageStore = CapPrefix + "WritePublishMessageStoreBefore"; public const string AfterPublishMessageStore = CapPrefix + "WritePublishMessageStoreAfter"; public const string ErrorPublishMessageStore = CapPrefix + "WritePublishMessageStoreError"; diff --git a/src/DotNetCore.CAP/Internal/CapCache.cs b/src/DotNetCore.CAP/Internal/CapCache.cs deleted file mode 100644 index 243f935..0000000 --- a/src/DotNetCore.CAP/Internal/CapCache.cs +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -namespace DotNetCore.CAP.Internal -{ - #region Cache class - - /// - /// This is a generic cache subsystem based on key/value pairs, where key is generic, too. Key must be unique. - /// Every cache entry has its own timeout. - /// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on - /// threads). - /// - // ReSharper disable once InheritdocConsiderUsage - // ReSharper disable once InconsistentNaming - internal class Cache : IDisposable - { - #region Constructor and class members - - private readonly Dictionary _cache = new Dictionary(); - private readonly Dictionary _timers = new Dictionary(); - private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); - - #endregion - - #region IDisposable implementation & Clear - - private bool disposed; - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - /// - protected virtual void Dispose(bool disposing) - { - if (!disposed) - { - disposed = true; - - if (disposing) - { - // Dispose managed resources. - Clear(); - _locker.Dispose(); - } - - // Dispose unmanaged resources - } - } - - /// - /// Clears the entire cache and disposes all active timers. - /// - public void Clear() - { - _locker.EnterWriteLock(); - try - { - try - { - foreach (var t in _timers.Values) - { - t.Dispose(); - } - } - catch - { - } - - _timers.Clear(); - _cache.Clear(); - } - finally - { - _locker.ExitWriteLock(); - } - } - - #endregion - - #region CheckTimer - - // Checks whether a specific timer already exists and adds a new one, if not - private void CheckTimer(K key, TimeSpan? cacheTimeout, bool restartTimerIfExists) - { - Timer timer; - - if (_timers.TryGetValue(key, out timer)) - { - if (restartTimerIfExists) - { - timer.Change( - cacheTimeout ?? Timeout.InfiniteTimeSpan, - Timeout.InfiniteTimeSpan); - } - } - else - { - _timers.Add( - key, - new Timer( - RemoveByTimer, - key, - cacheTimeout ?? Timeout.InfiniteTimeSpan, - Timeout.InfiniteTimeSpan)); - } - } - - private void RemoveByTimer(object state) - { - Remove((K) state); - } - - #endregion - - #region AddOrUpdate, Get, Remove, Exists, Clear - - /// - /// Adds or updates the specified cache-key with the specified cacheObject and applies a specified timeout (in seconds) - /// to this key. - /// - /// The cache-key to add or update. - /// The cache object to store. - /// - /// The cache timeout (lifespan) of this object. Must be 1 or greater. - /// Specify Timeout.Infinite to keep the entry forever. - /// - /// - /// (Optional). If set to true, the timer for this cacheObject will be reset if the object already - /// exists in the cache. (Default = false). - /// - public void AddOrUpdate(K key, T cacheObject, TimeSpan? cacheTimeout, bool restartTimerIfExists = false) - { - if (disposed) - { - return; - } - - _locker.EnterWriteLock(); - try - { - CheckTimer(key, cacheTimeout, restartTimerIfExists); - - if (!_cache.ContainsKey(key)) - { - _cache.Add(key, cacheObject); - } - else - { - _cache[key] = cacheObject; - } - } - finally - { - _locker.ExitWriteLock(); - } - } - - /// - /// Adds or updates the specified cache-key with the specified cacheObject and applies Timeout.Infinite to this - /// key. - /// - /// The cache-key to add or update. - /// The cache object to store. - public void AddOrUpdate(K key, T cacheObject) - { - AddOrUpdate(key, cacheObject, Timeout.InfiniteTimeSpan); - } - - /// - /// Gets the cache entry with the specified key or returns default(T) if the key is not found. - /// - /// The cache-key to retrieve. - /// The object from the cache or default(T), if not found. - public T this[K key] => Get(key); - - /// - /// Gets the cache entry with the specified key or return default(T) if the key is not found. - /// - /// The cache-key to retrieve. - /// The object from the cache or default(T), if not found. - public T Get(K key) - { - if (disposed) - { - return default(T); - } - - _locker.EnterReadLock(); - try - { - T rv; - return _cache.TryGetValue(key, out rv) ? rv : default(T); - } - finally - { - _locker.ExitReadLock(); - } - } - - /// - /// Tries to gets the cache entry with the specified key. - /// - /// The key. - /// (out) The value, if found, or default(T), if not. - /// True, if key exists, otherwise false. - public bool TryGet(K key, out T value) - { - if (disposed) - { - value = default(T); - return false; - } - - _locker.EnterReadLock(); - try - { - return _cache.TryGetValue(key, out value); - } - finally - { - _locker.ExitReadLock(); - } - } - - /// - /// Removes a series of cache entries in a single call for all key that match the specified key pattern. - /// - /// The key pattern to remove. The Predicate has to return true to get key removed. - public void Remove(Predicate keyPattern) - { - if (disposed) - { - return; - } - - _locker.EnterWriteLock(); - try - { - var removers = (from k in _cache.Keys.Cast() - where keyPattern(k) - select k).ToList(); - - foreach (var workKey in removers) - { - try - { - _timers[workKey].Dispose(); - } - catch - { - } - - _timers.Remove(workKey); - _cache.Remove(workKey); - } - } - finally - { - _locker.ExitWriteLock(); - } - } - - /// - /// Removes the specified cache entry with the specified key. - /// If the key is not found, no exception is thrown, the statement is just ignored. - /// - /// The cache-key to remove. - public void Remove(K key) - { - if (disposed) - { - return; - } - - _locker.EnterWriteLock(); - try - { - if (_cache.ContainsKey(key)) - { - try - { - _timers[key].Dispose(); - } - catch - { - } - - _timers.Remove(key); - _cache.Remove(key); - } - } - finally - { - _locker.ExitWriteLock(); - } - } - - /// - /// Checks if a specified key exists in the cache. - /// - /// The cache-key to check. - /// True if the key exists in the cache, otherwise False. - public bool Exists(K key) - { - if (disposed) - { - return false; - } - - _locker.EnterReadLock(); - try - { - return _cache.ContainsKey(key); - } - finally - { - _locker.ExitReadLock(); - } - } - - #endregion - } - - #endregion - - #region Other Cache classes (derived) - - /// - /// This is a generic cache subsystem based on key/value pairs, where key is a string. - /// You can add any item to this cache as long as the key is unique, so treat keys as something like namespaces and - /// build them with a - /// specific system/syntax in your application. - /// Every cache entry has its own timeout. - /// Cache is thread safe and will delete expired entries on its own using System.Threading.Timers (which run on - /// threads). - /// - /// - /// The non-generic Cache class instanciates a Cache{object} that can be used with any type of (mixed) contents. - /// It also publishes a static .Global member, so a cache can be used even without creating a dedicated - /// instance. - /// The .Global member is lazy instanciated. - /// - internal class CapCache : Cache - { - #region Static Global Cache instance - - private static readonly Lazy global = new Lazy(); - - /// - /// Gets the global shared cache instance valid for the entire process. - /// - /// - /// The global shared cache instance. - /// - public static CapCache Global => global.Value; - - #endregion - } - - #endregion -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index 10381af..689e608 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -8,21 +8,14 @@ namespace DotNetCore.CAP.Internal { internal class ConsumerInvokerFactory : IConsumerInvokerFactory { - private readonly ILoggerFactory _loggerFactory; - //private readonly IMessagePacker _messagePacker; - // - //private readonly IModelBinderFactory _modelBinderFactory; + private readonly ILoggerFactory _loggerFactory; private readonly IServiceProvider _serviceProvider; public ConsumerInvokerFactory( - ILoggerFactory loggerFactory, - //IMessagePacker messagePacker, - //IModelBinderFactory modelBinderFactory, + ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { - _loggerFactory = loggerFactory; - //_messagePacker = messagePacker; - //_modelBinderFactory = modelBinderFactory; + _loggerFactory = loggerFactory; _serviceProvider = serviceProvider; } diff --git a/src/DotNetCore.CAP/Internal/HashCodeCombiner.cs b/src/DotNetCore.CAP/Internal/HashCodeCombiner.cs deleted file mode 100644 index 43f000e..0000000 --- a/src/DotNetCore.CAP/Internal/HashCodeCombiner.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace DotNetCore.CAP.Internal -{ - internal struct HashCodeCombiner - { - private long _combinedHash64; - - public int CombinedHash - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _combinedHash64.GetHashCode(); } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private HashCodeCombiner(long seed) - { - _combinedHash64 = seed; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(IEnumerable e) - { - if (e == null) - { - Add(0); - } - else - { - var count = 0; - foreach (var o in e) - { - Add(o); - count++; - } - - Add(count); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator int(HashCodeCombiner self) - { - return self.CombinedHash; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(int i) - { - _combinedHash64 = ((_combinedHash64 << 5) + _combinedHash64) ^ i; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(string s) - { - var hashCode = s != null ? s.GetHashCode() : 0; - Add(hashCode); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(object o) - { - var hashCode = o != null ? o.GetHashCode() : 0; - Add(hashCode); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(TValue value, IEqualityComparer comparer) - { - var hashCode = value != null ? comparer.GetHashCode(value) : 0; - Add(hashCode); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HashCodeCombiner Start() - { - return new HashCodeCombiner(0x1505L); - } - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs index 4542032..d50bb50 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs @@ -17,7 +17,7 @@ namespace DotNetCore.CAP.Internal private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; - public DefaultConsumerInvoker(ILoggerFactory loggerFactory,IServiceProvider serviceProvider) + public DefaultConsumerInvoker(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; _logger = loggerFactory.CreateLogger(); diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index d1f67f4..cd7a648 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -157,9 +157,6 @@ namespace DotNetCore.CAP.Internal { tracingTimestamp = TracingBefore(transportMessage, _serverAddress); - var startTime = DateTimeOffset.UtcNow; - var stopwatch = Stopwatch.StartNew(); - var name = transportMessage.GetName(); var group = transportMessage.GetGroup(); @@ -171,7 +168,11 @@ namespace DotNetCore.CAP.Internal if (!canFindSubscriber) { var error = $"Message can not be found subscriber. Name:{name}, Group:{group}. {Environment.NewLine} see: https://github.com/dotnetcore/CAP/issues/63"; - throw new SubscriberNotFoundException(error); + var ex = new SubscriberNotFoundException(error); + + TracingError(tracingTimestamp, transportMessage, client.ServersAddress, ex); + + throw ex; } var type = executor.Parameters.FirstOrDefault(x => x.IsFromCap == false)?.ParameterType; diff --git a/src/DotNetCore.CAP/Internal/IMongoTransaction.cs b/src/DotNetCore.CAP/Internal/IMongoTransaction.cs deleted file mode 100644 index abb0388..0000000 --- a/src/DotNetCore.CAP/Internal/IMongoTransaction.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading.Tasks; - -namespace DotNetCore.CAP.Internal -{ - public interface IMongoTransaction : IDisposable - { - /// - /// If set true, the session.CommitTransaction() will be called automatically. - /// - /// - bool AutoCommit { get; set; } - - Task BeginAsync(bool autoCommit = true); - - IMongoTransaction Begin(bool autoCommit = true); - } -} \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs index 14500b7..4e7d9e3 100644 --- a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs @@ -196,9 +196,11 @@ namespace DotNetCore.CAP.Internal } catch (Exception ex) { - TracingError(tracingTimestamp, message.Origin, descriptor.MethodInfo, ex); + var e = new SubscriberExecutionFailedException(ex.Message, ex); + + TracingError(tracingTimestamp, message.Origin, descriptor.MethodInfo, e); - throw new SubscriberExecutionFailedException(ex.Message, ex); + throw e; } } diff --git a/src/DotNetCore.CAP/Internal/WaitHandleEx.cs b/src/DotNetCore.CAP/Internal/WaitHandleEx.cs deleted file mode 100644 index e5f5ba2..0000000 --- a/src/DotNetCore.CAP/Internal/WaitHandleEx.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace DotNetCore.CAP.Internal -{ - public static class WaitHandleEx - { - public static Task WaitAnyAsync(WaitHandle handle1, WaitHandle handle2, TimeSpan timeout) - { - var t1 = handle1.WaitOneAsync(timeout); - var t2 = handle2.WaitOneAsync(timeout); - return Task.WhenAny(t1, t2); - } - - public static async Task WaitOneAsync(this WaitHandle handle, TimeSpan timeout) - { - RegisteredWaitHandle registeredHandle = null; - try - { - var tcs = new TaskCompletionSource(); - registeredHandle = ThreadPool.RegisterWaitForSingleObject( - handle, - (state, timedOut) => ((TaskCompletionSource) state).TrySetResult(!timedOut), - tcs, - timeout, - true); - return await tcs.Task; - } - finally - { - registeredHandle?.Unregister(null); - } - } - } -} \ No newline at end of file From d222559c1d1d16af2daf375109041dc626ad898d Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 14:13:04 +0800 Subject: [PATCH 52/76] Remove outdated unit tests --- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 59 +---- .../CallbackMessageSenderTest.cs | 87 ------- .../ConsumerInvokerFactoryTest.cs | 80 ------ .../ConsumerInvokerTest.cs | 152 ----------- .../ConsumerServiceSelectorTest.cs | 2 +- .../CustomConsumerSubscribeTest.cs | 1 + test/DotNetCore.CAP.Test/DiagnosticsTest.cs | 241 ------------------ .../FakeDiagnosticListenerObserver.cs | 71 ------ test/DotNetCore.CAP.Test/HelperTest.cs | 85 +----- .../JsonContentSerializerTest.cs | 62 ----- .../Processor/StateChangerTest.cs | 61 ----- .../QueueExecutorFactoryTest.cs | 46 ---- test/DotNetCore.CAP.Test/Sample.cs | 64 ----- 13 files changed, 8 insertions(+), 1003 deletions(-) delete mode 100644 test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs delete mode 100644 test/DotNetCore.CAP.Test/ConsumerInvokerFactoryTest.cs delete mode 100644 test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs delete mode 100644 test/DotNetCore.CAP.Test/DiagnosticsTest.cs delete mode 100644 test/DotNetCore.CAP.Test/FakeDiagnosticListenerObserver.cs delete mode 100644 test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs delete mode 100644 test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs delete mode 100644 test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs delete mode 100644 test/DotNetCore.CAP.Test/Sample.cs diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index f661ff2..f50125a 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Messages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Xunit; @@ -52,30 +50,7 @@ namespace DotNetCore.CAP.Test Assert.NotNull(thingy); } - - [Fact] - public void CanOverrideContentSerialize() - { - var services = new ServiceCollection(); - services.AddCap(x => { }).AddContentSerializer(); - - var thingy = services.BuildServiceProvider() - .GetRequiredService() as MyContentSerializer; - - Assert.NotNull(thingy); - } - - [Fact] - public void CanOverrideMessagePack() - { - var services = new ServiceCollection(); - services.AddCap(x => { }).AddMessagePacker(); - - var thingy = services.BuildServiceProvider() - .GetRequiredService() as MyMessagePacker; - - Assert.NotNull(thingy); - } + [Fact] public void CanResolveCapOptions() @@ -87,38 +62,6 @@ namespace DotNetCore.CAP.Test Assert.NotNull(capOptions); } - private class MyMessagePacker : IMessagePacker - { - public string Pack(CapMessage obj) - { - throw new NotImplementedException(); - } - - public CapMessage UnPack(string packingMessage) - { - throw new NotImplementedException(); - } - } - - - private class MyContentSerializer : IContentSerializer - { - public T DeSerialize(string content) - { - throw new NotImplementedException(); - } - - public object DeSerialize(string content, Type type) - { - throw new NotImplementedException(); - } - - public string Serialize(T obj) - { - throw new NotImplementedException(); - } - } - private class MyProducerService : ICapPublisher { public IServiceProvider ServiceProvider { get; } diff --git a/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs b/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs deleted file mode 100644 index 0509cd3..0000000 --- a/test/DotNetCore.CAP.Test/CallbackMessageSenderTest.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class CallbackMessageSenderTest - { - private IServiceProvider _provider; - private Mock _mockCallbackPublisher; - private Mock _mockContentSerializer; - private Mock _mockMessagePack; - - public CallbackMessageSenderTest() - { - _mockCallbackPublisher = new Mock(); - _mockContentSerializer = new Mock(); - _mockMessagePack = new Mock(); - - var services = new ServiceCollection(); - services.AddTransient(); - services.AddLogging(); - services.AddSingleton(_mockCallbackPublisher.Object); - services.AddSingleton(_mockContentSerializer.Object); - services.AddSingleton(_mockMessagePack.Object); - _provider = services.BuildServiceProvider(); - } - - [Fact] - public async void SendAsync_CanSend() - { - // Arrange - _mockCallbackPublisher - .Setup(x => x.PublishCallbackAsync(It.IsAny())) - .Returns(Task.CompletedTask).Verifiable(); - - _mockContentSerializer - .Setup(x => x.Serialize(It.IsAny())) - .Returns("").Verifiable(); - - _mockMessagePack - .Setup(x => x.Pack(It.IsAny())) - .Returns("").Verifiable(); - - var fixture = Create(); - - // Act - await fixture.SendAsync(null, null, Mock.Of()); - - // Assert - _mockCallbackPublisher.VerifyAll(); - _mockContentSerializer.Verify(); - _mockMessagePack.Verify(); - } - - private CallbackMessageSender Create() - => _provider.GetService(); - } -} - -namespace Samples -{ - - public interface IFoo - { - int Age { get; set; } - string Name { get; set; } - } - - public class FooTest - { - [Fact] - public void CanSetProperty() - { - var mockFoo = new Mock(); - mockFoo.Setup(x => x.Name).Returns("NameProerties"); - - Assert.Equal("NameProerties", mockFoo.Object.Name); - } - } - -} diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerFactoryTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerFactoryTest.cs deleted file mode 100644 index 00998ce..0000000 --- a/test/DotNetCore.CAP.Test/ConsumerInvokerFactoryTest.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Internal; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class ConsumerInvokerFactoryTest - { - private IServiceProvider _serviceProvider; - - private Mock _mockSerialiser; - private Mock _mockMessagePacker; - private Mock _mockModelBinderFactory; - - public ConsumerInvokerFactoryTest() - { - _mockSerialiser = new Mock(); - _mockMessagePacker = new Mock(); - _mockModelBinderFactory = new Mock(); - - var services = new ServiceCollection(); - services.AddSingleton(); - - services.AddLogging(); - services.AddSingleton(_mockSerialiser.Object); - services.AddSingleton(_mockMessagePacker.Object); - services.AddSingleton(_mockModelBinderFactory.Object); - _serviceProvider = services.BuildServiceProvider(); - } - - private ConsumerInvokerFactory Create() => - _serviceProvider.GetService(); - - [Fact] - public void CreateInvokerTest() - { - // Arrange - var fixure = Create(); - - // Act - var invoker = fixure.CreateInvoker(); - - // Assert - Assert.NotNull(invoker); - } - - [Theory] - [InlineData(nameof(Sample.ThrowException))] - [InlineData(nameof(Sample.AsyncMethod))] - public void InvokeMethodTest(string methodName) - { - // Arrange - var fixure = Create(); - - var methodInfo = typeof(Sample).GetRuntimeMethods() - .Single(x => x.Name == methodName); - - var description = new ConsumerExecutorDescriptor - { - MethodInfo = methodInfo, - ImplTypeInfo = typeof(Sample).GetTypeInfo() - }; - var messageContext = new MessageContext(); - - var context = new ConsumerContext(description, messageContext); - - var invoker = fixure.CreateInvoker(); - - Assert.Throws(() => - { - invoker.InvokeAsync(context).GetAwaiter().GetResult(); - }); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs deleted file mode 100644 index 6da7c41..0000000 --- a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class ConsumerInvokerTest - { - private ILoggerFactory _loggerFactory; - private Mock _mockMessagePacker; - private Mock _mockModelBinderFactory; - private MessageContext _messageContext; - - public ConsumerInvokerTest() - { - _loggerFactory = new NullLoggerFactory(); - _mockMessagePacker = new Mock(); - _mockModelBinderFactory = new Mock(); - } - - private Internal.DefaultConsumerInvoker InitDefaultConsumerInvoker(IServiceProvider provider) - { - var invoker = new Internal.DefaultConsumerInvoker( - _loggerFactory, - provider, - _mockMessagePacker.Object, - _mockModelBinderFactory.Object); - - var message = new CapReceivedMessage - { - Id = SnowflakeId.Default().NextId(), - Name = "test", - Content = DateTime.Now.ToString(), - StatusName = StatusName.Scheduled, - Group = "Group.Test" - }; - - _mockMessagePacker - .Setup(x => x.UnPack(It.IsAny())) - .Returns(new CapMessageDto(message.Content)); - - _messageContext = new MessageContext - { - Group = message.Group, - Name = message.Name, - Content = Helper.ToJson(message) - }; - - return invoker; - } - - [Fact] - public async Task CanInvokeServiceTest() - { - var services = new ServiceCollection(); - - services.AddSingleton(); - services.AddSingleton(); - - var provider = services.BuildServiceProvider(); - - var invoker = InitDefaultConsumerInvoker(provider); - - var descriptor = new ConsumerExecutorDescriptor - { - ServiceTypeInfo = typeof(ITestService).GetTypeInfo(), - ImplTypeInfo = typeof(TestService).GetTypeInfo(), - MethodInfo = typeof(TestService).GetMethod("Index") - }; - - descriptor.Attribute = descriptor.MethodInfo.GetCustomAttribute(true); - - var context = new Internal.ConsumerContext(descriptor, _messageContext); - - var result = await invoker.InvokeAsync(context); - - Assert.NotNull(result); - Assert.NotNull(result.Result); - Assert.Equal("test", result.Result.ToString()); - } - - [Fact] - public async Task CanInvokeControllerTest() - { - var services = new ServiceCollection(); - var provider = services.BuildServiceProvider(); - var invoker = InitDefaultConsumerInvoker(provider); - - var descriptor = new ConsumerExecutorDescriptor - { - ServiceTypeInfo = typeof(HomeController).GetTypeInfo(), - ImplTypeInfo = typeof(HomeController).GetTypeInfo(), - MethodInfo = typeof(HomeController).GetMethod("Index") - }; - - descriptor.Attribute = descriptor.MethodInfo.GetCustomAttribute(true); - - var context = new Internal.ConsumerContext(descriptor, _messageContext); - - var result = await invoker.InvokeAsync(context); - - Assert.NotNull(result); - Assert.NotNull(result.Result); - Assert.Equal("test", result.Result.ToString()); - } - - } - - public class HomeController - { - [CapSubscribe("test")] - public string Index() - { - return "test"; - } - } - - public interface ITestService { } - - public class TestService : ITestService, ICapSubscribe - { - [CapSubscribe("test")] - public string Index() - { - return "test"; - } - } - - public class TestService2 : ITestService - { - [CapSubscribe("test")] - public string Index() - { - return "test2"; - } - } - - public class CapSubscribeAttribute : TopicAttribute - { - public CapSubscribeAttribute(string name) : base(name) - { - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs index 0a7394c..605c30a 100644 --- a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using DotNetCore.CAP.Abstractions; +using DotNetCore.CAP.Internal; using Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs index 60ed994..c6aaeb6 100644 --- a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs +++ b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; +using DotNetCore.CAP.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Xunit; diff --git a/test/DotNetCore.CAP.Test/DiagnosticsTest.cs b/test/DotNetCore.CAP.Test/DiagnosticsTest.cs deleted file mode 100644 index b3473a9..0000000 --- a/test/DotNetCore.CAP.Test/DiagnosticsTest.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.CompilerServices; -using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Internal; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - - public class DiagnosticsTest - { - private static readonly DiagnosticListener s_diagnosticListener = - new DiagnosticListener(CapDiagnosticListenerExtensions.DiagnosticListenerName); - - [Fact] - public void WritePublishBeforeTest() - { - Guid operationId = Guid.NewGuid(); - - DiagnosticsWapper(() => - { - var eventData = new BrokerPublishEventData(operationId, "", "", "", "", DateTimeOffset.UtcNow); - s_diagnosticListener.WritePublishBefore(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapBeforePublish)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerPublishEventData)kvp.Value).OperationId); - } - }); - } - - [Fact] - public void WritePublishAfterTest() - { - Guid operationId = Guid.NewGuid(); - - DiagnosticsWapper(() => - { - var eventData = new BrokerPublishEndEventData(operationId, "", "", "", "", DateTimeOffset.UtcNow, TimeSpan.FromMinutes(1)); - s_diagnosticListener.WritePublishAfter(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapAfterPublish)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerPublishEndEventData)kvp.Value).OperationId); - Assert.Equal(TimeSpan.FromMinutes(1), ((BrokerPublishEndEventData)kvp.Value).Duration); - } - }); - } - - [Fact] - public void WritePublishErrorTest() - { - Guid operationId = Guid.NewGuid(); - var ex = new Exception("WritePublishErrorTest"); - DiagnosticsWapper(() => - { - var eventData = new BrokerPublishErrorEventData(operationId, "", "", "", "", ex, DateTimeOffset.UtcNow, default(TimeSpan)); - s_diagnosticListener.WritePublishError(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapErrorPublish)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerPublishErrorEventData)kvp.Value).OperationId); - Assert.Equal(ex, ((BrokerPublishErrorEventData)kvp.Value).Exception); - } - }); - } - - [Fact] - public void WriteConsumeBeforeTest() - { - Guid operationId = Guid.NewGuid(); - - DiagnosticsWapper(() => - { - var eventData = new BrokerConsumeEventData(operationId, "", "", "", "", DateTimeOffset.UtcNow); - s_diagnosticListener.WriteConsumeBefore(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapBeforeConsume)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerConsumeEventData)kvp.Value).OperationId); - } - }); - } - - [Fact] - public void WriteConsumeAfterTest() - { - Guid operationId = Guid.NewGuid(); - - DiagnosticsWapper(() => - { - var eventData = new BrokerConsumeEndEventData(operationId, "", "", "", "", DateTimeOffset.UtcNow, TimeSpan.FromMinutes(1)); - s_diagnosticListener.WriteConsumeAfter(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapAfterConsume)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerConsumeEndEventData)kvp.Value).OperationId); - Assert.Equal(TimeSpan.FromMinutes(1), ((BrokerConsumeEndEventData)kvp.Value).Duration); - } - }); - } - - [Fact] - public void WriteConsumeErrorTest() - { - Guid operationId = Guid.NewGuid(); - var ex = new Exception("WriteConsumeErrorTest"); - DiagnosticsWapper(() => - { - var eventData = new BrokerConsumeErrorEventData(operationId, "", "", "", "", ex, DateTimeOffset.UtcNow, default(TimeSpan)); - s_diagnosticListener.WriteConsumeError(eventData); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapErrorPublish)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((BrokerConsumeErrorEventData)kvp.Value).OperationId); - Assert.Equal(ex, ((BrokerConsumeErrorEventData)kvp.Value).Exception); - } - }); - } - - [Fact] - public void WriteSubscriberInvokeBeforeTest() - { - DiagnosticsWapper(() => - { - s_diagnosticListener.WriteSubscriberInvokeBefore(FackConsumerContext()); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapBeforeSubscriberInvoke)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - } - }); - } - - [Fact] - public void WriteSubscriberInvokeAfterTest() - { - Guid operationId = Guid.NewGuid(); - - DiagnosticsWapper(() => - { - s_diagnosticListener.WriteSubscriberInvokeAfter(operationId, FackConsumerContext(), DateTimeOffset.Now, TimeSpan.FromMinutes(1)); - - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapAfterSubscriberInvoke)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((SubscriberInvokeEndEventData)kvp.Value).OperationId); - - } - }); - } - - [Fact] - public void WriteSubscriberInvokeErrorTest() - { - Guid operationId = Guid.NewGuid(); - - var ex = new Exception("WriteConsumeErrorTest"); - DiagnosticsWapper(() => - { - s_diagnosticListener.WriteSubscriberInvokeError(operationId, FackConsumerContext(), ex, - DateTimeOffset.Now, TimeSpan.MaxValue); - }, kvp => - { - if (kvp.Key.Equals(CapDiagnosticListenerExtensions.CapErrorSubscriberInvoke)) - { - Assert.NotNull(kvp.Value); - Assert.IsType(kvp.Value); - Assert.Equal(operationId, ((SubscriberInvokeErrorEventData)kvp.Value).OperationId); - Assert.Equal(ex, ((SubscriberInvokeErrorEventData)kvp.Value).Exception); - } - }); - } - - private ConsumerContext FackConsumerContext() - { - //Mock description - var description = new ConsumerExecutorDescriptor - { - MethodInfo = GetType().GetMethod("WriteSubscriberInvokeAfterTest"), - Attribute = new CapSubscribeAttribute("xxx"), - ImplTypeInfo = GetType().GetTypeInfo() - }; - - //Mock messageContext - var messageContext = new MessageContext - { - Name= "Name", - Group= "Group", - Content = "Content" - }; - - return new ConsumerContext(description, messageContext); - } - - private void DiagnosticsWapper(Action operation, Action> assert, [CallerMemberName]string methodName = "") - { - FakeDiagnosticListenerObserver diagnosticListenerObserver = new FakeDiagnosticListenerObserver(assert); - - diagnosticListenerObserver.Enable(); - using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver)) - { - Console.WriteLine(string.Format("Test: {0} Enabled Listeners", methodName)); - operation(); - } - } - } -} diff --git a/test/DotNetCore.CAP.Test/FakeDiagnosticListenerObserver.cs b/test/DotNetCore.CAP.Test/FakeDiagnosticListenerObserver.cs deleted file mode 100644 index 81db2c8..0000000 --- a/test/DotNetCore.CAP.Test/FakeDiagnosticListenerObserver.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using DotNetCore.CAP.Diagnostics; - -namespace DotNetCore.CAP.Test -{ - public sealed class FakeDiagnosticListenerObserver : IObserver - { - private class FakeDiagnosticSourceWriteObserver : IObserver> - { - private readonly Action> _writeCallback; - - public FakeDiagnosticSourceWriteObserver(Action> writeCallback) - { - _writeCallback = writeCallback; - } - - public void OnCompleted() - { - } - - public void OnError(Exception error) - { - } - - public void OnNext(KeyValuePair value) - { - _writeCallback(value); - } - } - - private readonly Action> _writeCallback; - private bool _writeObserverEnabled; - - public FakeDiagnosticListenerObserver(Action> writeCallback) - { - _writeCallback = writeCallback; - } - - public void OnCompleted() - { - } - - public void OnError(Exception error) - { - } - - public void OnNext(DiagnosticListener value) - { - if (value.Name.Equals(CapDiagnosticListenerExtensions.DiagnosticListenerName)) - { - value.Subscribe(new FakeDiagnosticSourceWriteObserver(_writeCallback), IsEnabled); - } - } - - public void Enable() - { - _writeObserverEnabled = true; - } - public void Disable() - { - _writeObserverEnabled = false; - } - private bool IsEnabled(string s) - { - return _writeObserverEnabled; - } - } -} diff --git a/test/DotNetCore.CAP.Test/HelperTest.cs b/test/DotNetCore.CAP.Test/HelperTest.cs index 48ee66f..e179193 100644 --- a/test/DotNetCore.CAP.Test/HelperTest.cs +++ b/test/DotNetCore.CAP.Test/HelperTest.cs @@ -1,15 +1,12 @@ using System; using System.Reflection; -using DotNetCore.CAP.Diagnostics; -using DotNetCore.CAP.Infrastructure; -using Newtonsoft.Json.Linq; +using DotNetCore.CAP.Internal; using Xunit; namespace DotNetCore.CAP.Test { public class HelperTest { - [Fact] public void ToTimestampTest() { @@ -23,19 +20,6 @@ namespace DotNetCore.CAP.Test Assert.Equal(1514764800, result); } - [Fact] - public void FromTimestampTest() - { - //Arrange - var time = DateTime.Parse("2018-01-01 00:00:00"); - - //Act - var result = Helper.FromTimestamp(1514764800); - - //Assert - Assert.Equal(time, result); - } - [Fact] public void IsControllerTest() { @@ -69,7 +53,6 @@ namespace DotNetCore.CAP.Test [Theory] [InlineData(typeof(HomeController))] [InlineData(typeof(Exception))] - [InlineData(typeof(Person))] public void IsComplexTypeTest(Type type) { //Act @@ -79,36 +62,6 @@ namespace DotNetCore.CAP.Test Assert.True(result); } - [Fact] - public void AddExceptionPropertyTest() - { - //Arrange - var json = "{}"; - var exception = new Exception("Test Exception Message") - { - Source = "Test Source", - InnerException = { } - }; - - var expected = new - { - ExceptionMessage = new - { - Source = "Test Source", - Message = "Test Exception Message", - InnerMessage = new { } - } - }; - - //Act - var result = Helper.AddExceptionProperty(json, exception); - - //Assert - var jObj = JObject.Parse(result); - Assert.Equal(jObj["ExceptionMessage"]["Source"].Value(), expected.ExceptionMessage.Source); - Assert.Equal(jObj["ExceptionMessage"]["Message"].Value(), expected.ExceptionMessage.Message); - } - [Theory] [InlineData("10.0.0.1")] [InlineData("172.16.0.1")] @@ -117,38 +70,10 @@ namespace DotNetCore.CAP.Test { Assert.True(Helper.IsInnerIP(ipAddress)); } + } - [Fact] - public void AddTracingHeaderPropertyTest() - { - //Arrange - var json = "{}"; - var header = new TracingHeaders { { "key", "value" } }; - - //Act - var result = Helper.AddTracingHeaderProperty(json, header); - - //Assert - var expected = "{\"TracingHeaders\":{\"key\":\"value\"}}"; - Assert.Equal(expected, result); - } - - [Fact] - public void TryExtractTracingHeadersTest() - { - //Arrange - var json = "{\"TracingHeaders\":{\"key\":\"value\"}}"; - TracingHeaders header = null; - string removedHeadersJson = ""; - - //Act - var result = Helper.TryExtractTracingHeaders(json, out header, out removedHeadersJson); - - //Assert - Assert.True(result); - Assert.NotNull(header); - Assert.Single(header); - Assert.Equal("{}", removedHeadersJson); - } + class HomeController + { + } } diff --git a/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs b/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs deleted file mode 100644 index fa7541e..0000000 --- a/test/DotNetCore.CAP.Test/JsonContentSerializerTest.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using DotNetCore.CAP.Internal; -using DotNetCore.CAP.Messages; -using Newtonsoft.Json; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class JsonContentSerializerTest - { - [Fact] - public void CanSerialize() - { - //Arrange - var fixtrue = Create(); - - var message = new CapMessageDto - { - Id = "1", - Content = "Content", - CallbackName = "Callback", - Timestamp = DateTime.Now - }; - - //Act - var ret = fixtrue.Serialize(message); - - //Assert - var expected = JsonConvert.SerializeObject(message); - Assert.NotNull(ret); - Assert.Equal(expected, ret); - } - - [Fact] - public void CanDeSerialize() - { - //Arrange - var fixtrue = Create(); - - var message = new CapMessageDto - { - Id = "1", - Content = "Content", - CallbackName = "Callback", - Timestamp = DateTime.Now - }; - var messageJson = JsonConvert.SerializeObject(message); - - //Act - var ret = fixtrue.DeSerialize(messageJson); - - //Assert - Assert.NotNull(ret); - Assert.Equal(message.Id, ret.Id); - Assert.Equal(message.Content, ret.Content); - Assert.Equal(message.CallbackName, ret.CallbackName); - Assert.Equal(message.Timestamp, ret.Timestamp); - } - - private JsonContentSerializer Create() => new JsonContentSerializer(); - } -} diff --git a/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs b/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs deleted file mode 100644 index b6905e4..0000000 --- a/test/DotNetCore.CAP.Test/Processor/StateChangerTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using DotNetCore.CAP.Processor.States; -using Moq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class StateChangerTest - { - [Fact] - public void ChangeState() - { - // Arrange - var fixture = Create(); - var message = new CapPublishedMessage - { - Id = SnowflakeId.Default().NextId(), - StatusName = StatusName.Scheduled - }; - var state = Mock.Of(s => s.Name == "s" && s.ExpiresAfter == null); - var mockTransaction = new Mock(); - - // Act - fixture.ChangeState(message, state, mockTransaction.Object); - - // Assert - Assert.Equal("s", message.StatusName); - Assert.Null(message.ExpiresAt); - Mock.Get(state).Verify(s => s.Apply(message, mockTransaction.Object), Times.Once); - mockTransaction.Verify(t => t.UpdateMessage(message), Times.Once); - mockTransaction.Verify(t => t.CommitAsync(), Times.Never); - } - - [Fact] - public void ChangeState_ExpiresAfter() - { - // Arrange - var fixture = Create(); - var message = new CapPublishedMessage - { - Id = SnowflakeId.Default().NextId(), - StatusName = StatusName.Scheduled - }; - var state = Mock.Of(s => s.Name == "s" && s.ExpiresAfter == TimeSpan.FromHours(1)); - var mockTransaction = new Mock(); - - // Act - fixture.ChangeState(message, state, mockTransaction.Object); - - // Assert - Assert.Equal("s", message.StatusName); - Assert.NotNull(message.ExpiresAt); - mockTransaction.Verify(t => t.UpdateMessage(message), Times.Once); - mockTransaction.Verify(t => t.CommitAsync(), Times.Never); - } - - private StateChanger Create() => new StateChanger(); - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs b/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs deleted file mode 100644 index 107d074..0000000 --- a/test/DotNetCore.CAP.Test/QueueExecutorFactoryTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -//using System; -//using DotNetCore.CAP.Internal; -//using Microsoft.Extensions.DependencyInjection; -//using Xunit; -//using Moq; - -//namespace DotNetCore.CAP.Test -//{ -// public class QueueExecutorFactoryTest -// { -// private IServiceProvider _provider; - -// public QueueExecutorFactoryTest() -// { -// var services = new ServiceCollection(); -// services.AddLogging(); -// services.AddOptions(); - -// services.AddCap(x => { }); -// _provider = services.BuildServiceProvider(); -// } - -// [Fact] -// public void CanCreateInstance() -// { -// var queueExecutorFactory = _provider.GetService(); -// Assert.NotNull(queueExecutorFactory); - -// var publishExecutor = queueExecutorFactory.GetInstance(Models.MessageType.Publish); -// Assert.Null(publishExecutor); - -// var disPatchExector = queueExecutorFactory.GetInstance(Models.MessageType.Subscribe); -// Assert.NotNull(disPatchExector); -// } - -// [Fact] -// public void CanGetSubscribeExector() -// { -// var queueExecutorFactory = _provider.GetService(); -// Assert.NotNull(queueExecutorFactory); - -// var publishExecutor = queueExecutorFactory.GetInstance(Models.MessageType.Publish); -// Assert.Null(publishExecutor); -// } -// } -//} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/Sample.cs b/test/DotNetCore.CAP.Test/Sample.cs deleted file mode 100644 index c4e1623..0000000 --- a/test/DotNetCore.CAP.Test/Sample.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class Sample - { - - public void DateTimeParam(DateTime dateTime) - { - } - - public void StringParam(string @string) - { - } - - public void GuidParam(Guid guid) - { - } - - public void UriParam(Uri uri) - { - } - - public void IntegerParam(int @int) - { - } - - public void ComplexTypeParam(ComplexType complexType) - { - } - - public void ThrowException() - { - throw new Exception(); - } - - public async Task AsyncMethod() - { - await Task.FromResult(3); - throw new Exception(); - } - } - - public class ComplexType - { - public DateTime Time { get; set; } - - public string String { get; set; } - - public Guid Guid { get; set; } - - public Person Person { get; set; } - } - - public class Person - { - public int Age { get; set; } - - public string Name { get; set; } - } -} \ No newline at end of file From 772a509ce6404de36a269832643b9df5fad74547 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 14:41:24 +0800 Subject: [PATCH 53/76] Add sync publish method with additional header --- src/DotNetCore.CAP/ICapPublisher.cs | 21 ++++++++-- .../Internal/ICapPublisher.Default.cs | 39 ++++++++++--------- test/DotNetCore.CAP.Test/CAP.BuilderTest.cs | 5 +++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index e6f5ef2..58f4181 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -24,13 +24,20 @@ namespace DotNetCore.CAP /// Asynchronous publish an object message. /// /// the topic name or exchange router key. - /// message body content, that will be serialized of json. + /// message body content, that will be serialized. /// callback subscriber name /// Task PublishAsync(string name, T contentObj, string callbackName = null, CancellationToken cancellationToken = default); - - Task PublishAsync(string name, T contentObj, IDictionary optionHeaders, CancellationToken cancellationToken = default); + /// + /// Asynchronous publish an object message with custom headers + /// + /// content object + /// the topic name or exchange router key. + /// message body content, that will be serialized. + /// message additional headers. + /// + Task PublishAsync(string name, T contentObj, IDictionary headers, CancellationToken cancellationToken = default); /// /// Publish an object message. @@ -39,5 +46,13 @@ namespace DotNetCore.CAP /// message body content, that will be serialized of json. /// callback subscriber name void Publish(string name, T contentObj, string callbackName = null); + + /// + /// Publish an object message. + /// + /// the topic name or exchange router key. + /// message body content, that will be serialized of json. + /// message additional headers. + void Publish(string name, T contentObj, IDictionary headers); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs index 2629911..fea0307 100644 --- a/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ICapPublisher.Default.cs @@ -35,32 +35,30 @@ namespace DotNetCore.CAP.Internal public AsyncLocal Transaction { get; } - public async Task PublishAsync(string name, T value, - IDictionary optionHeaders, - CancellationToken cancellationToken = default) + public async Task PublishAsync(string name, T value, IDictionary headers, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } - if (optionHeaders == null) + if (headers == null) { - optionHeaders = new Dictionary(); + headers = new Dictionary(); } var messageId = SnowflakeId.Default().NextId().ToString(); - optionHeaders.Add(Headers.MessageId, messageId); - optionHeaders.Add(Headers.MessageName, name); - optionHeaders.Add(Headers.Type, typeof(T).FullName); - optionHeaders.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); - if (!optionHeaders.ContainsKey(Headers.CorrelationId)) + headers.Add(Headers.MessageId, messageId); + headers.Add(Headers.MessageName, name); + headers.Add(Headers.Type, typeof(T).FullName); + headers.Add(Headers.SentTime, DateTimeOffset.Now.ToString()); + if (!headers.ContainsKey(Headers.CorrelationId)) { - optionHeaders.Add(Headers.CorrelationId, messageId); - optionHeaders.Add(Headers.CorrelationSequence, 0.ToString()); + headers.Add(Headers.CorrelationId, messageId); + headers.Add(Headers.CorrelationSequence, 0.ToString()); } - var message = new Message(optionHeaders, value); + var message = new Message(headers, value); long? tracingTimestamp = null; try @@ -99,11 +97,6 @@ namespace DotNetCore.CAP.Internal } } - public void Publish(string name, T value, string callbackName = null) - { - PublishAsync(name, value, callbackName).GetAwaiter().GetResult(); - } - public Task PublishAsync(string name, T value, string callbackName = null, CancellationToken cancellationToken = default) { @@ -115,6 +108,16 @@ namespace DotNetCore.CAP.Internal return PublishAsync(name, value, header, cancellationToken); } + public void Publish(string name, T value, string callbackName = null) + { + PublishAsync(name, value, callbackName).GetAwaiter().GetResult(); + } + + public void Publish(string name, T value, IDictionary headers) + { + PublishAsync(name, value, headers).GetAwaiter().GetResult(); + } + #region tracing private long? TracingBefore(Message message) diff --git a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs index f50125a..f21a4f0 100644 --- a/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs +++ b/test/DotNetCore.CAP.Test/CAP.BuilderTest.cs @@ -84,6 +84,11 @@ namespace DotNetCore.CAP.Test { throw new NotImplementedException(); } + + public void Publish(string name, T contentObj, IDictionary headers) + { + throw new NotImplementedException(); + } } } } \ No newline at end of file From 4d2587373f92085a3f711c46abf5681ac83343c3 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 17:28:11 +0800 Subject: [PATCH 54/76] update version to 3.0 --- build/version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/version.props b/build/version.props index 0550ced..b5087f2 100644 --- a/build/version.props +++ b/build/version.props @@ -1,7 +1,7 @@ - 2 - 6 + 3 + 0 0 $(VersionMajor).$(VersionMinor).$(VersionPatch) From 971c9db90517c6ea723ce7b340240ce44d9ed2cd Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 17:28:55 +0800 Subject: [PATCH 55/76] Add fake transport fot unit tests --- .../ConsumerInvokerTest.cs | 56 ++++++++++++++ .../DotNetCore.CAP.Test.csproj | 10 +-- .../CAP.FakeQueueOptionsExtension.cs | 18 +++++ .../CAP.Options.Extensions.cs | 11 +++ .../ITransport.FakeInMemory.cs | 41 ++++++++++ .../InMemoryConsumerClient.cs | 75 +++++++++++++++++++ .../InMemoryConsumerClientFactory.cs | 23 ++++++ .../FakeInMemoryQueue/InMemoryQueue.cs | 67 +++++++++++++++++ test/DotNetCore.CAP.Test/HelperTest.cs | 2 +- test/DotNetCore.CAP.Test/OperateResultTest.cs | 26 ------- 10 files changed, 297 insertions(+), 32 deletions(-) create mode 100644 test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs create mode 100644 test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs delete mode 100644 test/DotNetCore.CAP.Test/OperateResultTest.cs diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs new file mode 100644 index 0000000..aa14448 --- /dev/null +++ b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class ConsumerInvokerTest + { + private readonly IServiceProvider _serviceProvider; + + public ConsumerInvokerTest() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(); + serviceCollection.AddSingleton(); + serviceCollection.AddTransient(); + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + private IConsumerInvoker ConsumerInvoker => _serviceProvider.GetService(); + + [Fact] + public async Task InvokeTest() + { + var descriptor = new ConsumerExecutorDescriptor() + { + Attribute = new CandidatesTopic("fake.output.integer"), + ServiceTypeInfo = typeof(FakeSubscriber).GetTypeInfo(), + ImplTypeInfo = typeof(FakeSubscriber).GetTypeInfo(), + MethodInfo = typeof(FakeSubscriber).GetMethod(nameof(FakeSubscriber.OutputIntegerSub)), + Parameters = new List() + }; + + var header = new Dictionary(); + var message = new Message(header, null); + var context = new ConsumerContext(descriptor, message); + + var ret = await ConsumerInvoker.InvokeAsync(context); + Assert.Equal(int.MaxValue, ret.Result); + } + } + + public class FakeSubscriber : ICapSubscribe + { + [CapSubscribe("fake.output.integer")] + public int OutputIntegerSub() + { + return int.MaxValue; + } + } +} diff --git a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj index 838166d..e3d1d65 100644 --- a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj +++ b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj @@ -6,20 +6,20 @@ - - + + + + all runtime; build; native; contentfiles; analyzers - - - + diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs new file mode 100644 index 0000000..23ba908 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.FakeQueueOptionsExtension.cs @@ -0,0 +1,18 @@ +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.DependencyInjection; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class FakeQueueOptionsExtension : ICapOptionsExtension + { + + public void AddServices(IServiceCollection services) + { + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs new file mode 100644 index 0000000..24852f0 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/CAP.Options.Extensions.cs @@ -0,0 +1,11 @@ +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + public static class CapOptionsExtensions + { + public static CapOptions UseFakeTransport(this CapOptions options) + { + options.RegisterExtension(new FakeQueueOptionsExtension()); + return options; + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs new file mode 100644 index 0000000..0647ff4 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/ITransport.FakeInMemory.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal class FakeInMemoryQueueTransport : ITransport + { + private readonly InMemoryQueue _queue; + private readonly ILogger _logger; + + public FakeInMemoryQueueTransport(InMemoryQueue queue, ILogger logger) + { + _queue = queue; + _logger = logger; + } + + public string Address { get; } = string.Empty; + + public Task SendAsync(TransportMessage message) + { + try + { + _queue.Send(message.GetName(), message); + + _logger.LogDebug($"Event message [{message.GetName()}] has been published."); + + return Task.FromResult(OperateResult.Success); + } + catch (Exception ex) + { + var wrapperEx = new PublisherSentFailedException(ex.Message, ex); + + return Task.FromResult(OperateResult.Failed(wrapperEx)); + } + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs new file mode 100644 index 0000000..6879916 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClient.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class InMemoryConsumerClient : IConsumerClient + { + private readonly ILogger _logger; + private readonly InMemoryQueue _queue; + private readonly string _subscriptionName; + + public InMemoryConsumerClient( + ILogger logger, + InMemoryQueue queue, + string subscriptionName) + { + _logger = logger; + _queue = queue; + _subscriptionName = subscriptionName; + } + + public event EventHandler OnMessageReceived; + + public event EventHandler OnLog; + + public string ServersAddress => string.Empty; + + public void Subscribe(IEnumerable topics) + { + if (topics == null) throw new ArgumentNullException(nameof(topics)); + + foreach (var topic in topics) + { + _queue.Subscribe(_subscriptionName, OnConsumerReceived, topic); + + _logger.LogInformation($"InMemory message queue initialize the topic: {topic}"); + } + } + + public void Listening(TimeSpan timeout, CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + cancellationToken.WaitHandle.WaitOne(timeout); + } + } + + public void Commit() + { + // ignore + } + + public void Reject() + { + // ignore + } + + public void Dispose() + { + _queue.ClearSubscriber(); + } + + #region private methods + + private void OnConsumerReceived(TransportMessage e) + { + OnMessageReceived?.Invoke(null, e); + } + #endregion private methods + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs new file mode 100644 index 0000000..3e3c216 --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryConsumerClientFactory.cs @@ -0,0 +1,23 @@ +using DotNetCore.CAP.Transport; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal sealed class InMemoryConsumerClientFactory : IConsumerClientFactory + { + private readonly ILoggerFactory _loggerFactory; + private readonly InMemoryQueue _queue; + + public InMemoryConsumerClientFactory(ILoggerFactory loggerFactory, InMemoryQueue queue) + { + _loggerFactory = loggerFactory; + _queue = queue; + } + + public IConsumerClient Create(string groupId) + { + var logger = _loggerFactory.CreateLogger(typeof(InMemoryConsumerClient)); + return new InMemoryConsumerClient(logger, _queue, groupId); + } + } +} \ No newline at end of file diff --git a/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs new file mode 100644 index 0000000..deab65a --- /dev/null +++ b/test/DotNetCore.CAP.Test/FakeInMemoryQueue/InMemoryQueue.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using DotNetCore.CAP.Messages; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Test.FakeInMemoryQueue +{ + internal class InMemoryQueue + { + private readonly ILogger _logger; + private static readonly object Lock = new object(); + + private readonly Dictionary, List)> _groupTopics; + + public Dictionary Messages { get; } + + public InMemoryQueue(ILogger logger) + { + _logger = logger; + _groupTopics = new Dictionary, List)>(); + Messages = new Dictionary(); + } + + public void Subscribe(string groupId, Action received, string topic) + { + lock (Lock) + { + if (_groupTopics.ContainsKey(groupId)) + { + var topics = _groupTopics[groupId]; + if (!topics.Item2.Contains(topic)) + { + topics.Item2.Add(topic); + } + } + else + { + _groupTopics.Add(groupId, (received, new List { topic })); + } + } + } + + public void ClearSubscriber() + { + _groupTopics.Clear(); + } + + public void Send(string topic, TransportMessage message) + { + Messages.Add(topic, message); + foreach (var groupTopic in _groupTopics) + { + if (groupTopic.Value.Item2.Contains(topic)) + { + try + { + groupTopic.Value.Item1?.Invoke(message); + } + catch (Exception e) + { + _logger.LogError(e, $"Consumption message raises an exception. Group-->{groupTopic.Key} Name-->{topic}"); + } + } + } + } + } +} diff --git a/test/DotNetCore.CAP.Test/HelperTest.cs b/test/DotNetCore.CAP.Test/HelperTest.cs index e179193..2b2b3b1 100644 --- a/test/DotNetCore.CAP.Test/HelperTest.cs +++ b/test/DotNetCore.CAP.Test/HelperTest.cs @@ -72,7 +72,7 @@ namespace DotNetCore.CAP.Test } } - class HomeController + public class HomeController { } diff --git a/test/DotNetCore.CAP.Test/OperateResultTest.cs b/test/DotNetCore.CAP.Test/OperateResultTest.cs deleted file mode 100644 index 5788f19..0000000 --- a/test/DotNetCore.CAP.Test/OperateResultTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Linq; -using Xunit; - -namespace DotNetCore.CAP.Test -{ - public class OperateResultTest - { - [Fact] - public void VerifyDefaultConstructor() - { - var result = new OperateResult(); - - Assert.False(result.Succeeded); - Assert.Empty(result.Errors); - } - - [Fact] - public void NullFaildUsesEmptyErrors() - { - var result = OperateResult.Failed(); - - Assert.False(result.Succeeded); - Assert.Empty(result.Errors); - } - } -} \ No newline at end of file From cb86c9522bcd72d757b64d59537b442fd39b5c3d Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 17:30:11 +0800 Subject: [PATCH 56/76] Support null value of message body. --- src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs | 1 - src/DotNetCore.CAP/ICapPublisher.cs | 19 ++++++++++--------- .../Internal/IConsumerInvoker.Default.cs | 2 +- src/DotNetCore.CAP/Messages/Message.cs | 6 ++++-- .../Messages/TransportMessage.cs | 6 ++++-- .../Serialization/ISerializer.JsonUtf8.cs | 7 ++++++- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs index fe0cfe0..c83d124 100644 --- a/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs +++ b/src/DotNetCore.CAP.Kafka/ITransport.Kafka.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; -using System.Linq; using System.Text; using System.Threading.Tasks; using Confluent.Kafka; diff --git a/src/DotNetCore.CAP/ICapPublisher.cs b/src/DotNetCore.CAP/ICapPublisher.cs index 58f4181..158417d 100644 --- a/src/DotNetCore.CAP/ICapPublisher.cs +++ b/src/DotNetCore.CAP/ICapPublisher.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; namespace DotNetCore.CAP { @@ -17,42 +18,42 @@ namespace DotNetCore.CAP /// /// CAP transaction context object - /// + /// AsyncLocal Transaction { get; } /// /// Asynchronous publish an object message. /// /// the topic name or exchange router key. - /// message body content, that will be serialized. + /// message body content, that will be serialized. (can be null) /// callback subscriber name /// - Task PublishAsync(string name, T contentObj, string callbackName = null, CancellationToken cancellationToken = default); + Task PublishAsync(string name, [CanBeNull] T contentObj, string callbackName = null, CancellationToken cancellationToken = default); /// /// Asynchronous publish an object message with custom headers /// /// content object /// the topic name or exchange router key. - /// message body content, that will be serialized. + /// message body content, that will be serialized. (can be null) /// message additional headers. /// - Task PublishAsync(string name, T contentObj, IDictionary headers, CancellationToken cancellationToken = default); + Task PublishAsync(string name, [CanBeNull] T contentObj, IDictionary headers, CancellationToken cancellationToken = default); /// /// Publish an object message. /// /// the topic name or exchange router key. - /// message body content, that will be serialized of json. + /// message body content, that will be serialized. (can be null) /// callback subscriber name - void Publish(string name, T contentObj, string callbackName = null); + void Publish(string name, [CanBeNull] T contentObj, string callbackName = null); /// /// Publish an object message. /// /// the topic name or exchange router key. - /// message body content, that will be serialized of json. + /// message body content, that will be serialized. (can be null) /// message additional headers. - void Publish(string name, T contentObj, IDictionary headers); + void Publish(string name, [CanBeNull] T contentObj, IDictionary headers); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs index d50bb50..b87dd06 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs @@ -30,7 +30,7 @@ namespace DotNetCore.CAP.Internal _logger.LogDebug("Executing subscriber method : {0}", context.ConsumerDescriptor.MethodInfo.Name); var executor = ObjectMethodExecutor.Create( - context.ConsumerDescriptor.MethodInfo, + context.ConsumerDescriptor.MethodInfo, context.ConsumerDescriptor.ImplTypeInfo); using (var scope = _serviceProvider.CreateScope()) diff --git a/src/DotNetCore.CAP/Messages/Message.cs b/src/DotNetCore.CAP/Messages/Message.cs index 213193f..2b4bfbf 100644 --- a/src/DotNetCore.CAP/Messages/Message.cs +++ b/src/DotNetCore.CAP/Messages/Message.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; namespace DotNetCore.CAP.Messages { public class Message { - public Message(IDictionary headers, object value) + public Message(IDictionary headers, [CanBeNull] object value) { Headers = headers ?? throw new ArgumentNullException(nameof(headers)); - Value = value ?? throw new ArgumentNullException(nameof(value)); + Value = value; } public IDictionary Headers { get; } + [CanBeNull] public object Value { get; } } diff --git a/src/DotNetCore.CAP/Messages/TransportMessage.cs b/src/DotNetCore.CAP/Messages/TransportMessage.cs index 365d823..8f0ae4f 100644 --- a/src/DotNetCore.CAP/Messages/TransportMessage.cs +++ b/src/DotNetCore.CAP/Messages/TransportMessage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; namespace DotNetCore.CAP.Messages { @@ -8,10 +9,10 @@ namespace DotNetCore.CAP.Messages /// public class TransportMessage { - public TransportMessage(IDictionary headers, byte[] body) + public TransportMessage(IDictionary headers, [CanBeNull] byte[] body) { Headers = headers ?? throw new ArgumentNullException(nameof(headers)); - Body = body ?? throw new ArgumentNullException(nameof(body)); + Body = body; } /// @@ -22,6 +23,7 @@ namespace DotNetCore.CAP.Messages /// /// Gets the body object of this message /// + [CanBeNull] public byte[] Body { get; } public string GetId() diff --git a/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs index f638751..b3fdbd9 100644 --- a/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs +++ b/src/DotNetCore.CAP/Serialization/ISerializer.JsonUtf8.cs @@ -13,13 +13,18 @@ namespace DotNetCore.CAP.Serialization { public Task SerializeAsync(Message message) { + if (message.Value == null) + { + return Task.FromResult(new TransportMessage(message.Headers, null)); + } + var json = JsonConvert.SerializeObject(message.Value); return Task.FromResult(new TransportMessage(message.Headers, Encoding.UTF8.GetBytes(json))); } public Task DeserializeAsync(TransportMessage transportMessage, Type valueType) { - if (valueType == null) + if (valueType == null || transportMessage.Body == null) { return Task.FromResult(new Message(transportMessage.Headers, null)); } From 5d7c77965424b1ee5551bf3dd8b8aaa1921d2fec Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 27 Nov 2019 17:58:23 +0800 Subject: [PATCH 57/76] Rename class --- .../DashboardRoutes.cs | 2 +- .../CAP.ServiceCollectionExtensions.cs | 4 +- .../Internal/ConsumerInvokerFactory.cs | 6 +- ...ult.cs => ISubscribeDispatcher.Default.cs} | 16 +- ...berExecutor.cs => ISubscribeDispatcher.cs} | 6 +- ...efault.cs => ISubscribeInvoker.Default.cs} | 166 +++++++++--------- ...onsumerInvoker.cs => ISubscribeInvoker.cs} | 4 +- ...Factory.cs => ISubscribeInvokerFactory.cs} | 4 +- .../Processor/IDispatcher.Default.cs | 6 +- .../Processor/IProcessor.NeedRetry.cs | 8 +- .../ConsumerInvokerTest.cs | 7 +- 11 files changed, 114 insertions(+), 115 deletions(-) rename src/DotNetCore.CAP/Internal/{ISubscriberExecutor.Default.cs => ISubscribeDispatcher.Default.cs} (93%) rename src/DotNetCore.CAP/Internal/{ISubscriberExecutor.cs => ISubscribeDispatcher.cs} (53%) rename src/DotNetCore.CAP/Internal/{IConsumerInvoker.Default.cs => ISubscribeInvoker.Default.cs} (90%) rename src/DotNetCore.CAP/Internal/{IConsumerInvoker.cs => ISubscribeInvoker.cs} (86%) rename src/DotNetCore.CAP/Internal/{IConsumerInvokerFactory.cs => ISubscribeInvokerFactory.cs} (69%) diff --git a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs index 86b04aa..2f6b6da 100644 --- a/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs +++ b/src/DotNetCore.CAP.Dashboard/DashboardRoutes.cs @@ -111,7 +111,7 @@ namespace DotNetCore.CAP.Dashboard { var msg = client.Storage.GetMonitoringApi().GetReceivedMessageAsync(messageId) .GetAwaiter().GetResult(); - client.RequestServices.GetService().ExecuteAsync(msg); + client.RequestServices.GetService().DispatchAsync(msg); }); Routes.AddRazorPage( diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index bd59c21..d06378d 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -39,7 +39,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); // Warning: IPublishMessageSender need to inject at extension project. - services.TryAddSingleton(); + services.TryAddSingleton(); //Options and extension service var options = new CapOptions(); diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index 689e608..3979394 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Internal { - internal class ConsumerInvokerFactory : IConsumerInvokerFactory + internal class ConsumerInvokerFactory : ISubscribeInvokerFactory { private readonly ILoggerFactory _loggerFactory; private readonly IServiceProvider _serviceProvider; @@ -19,9 +19,9 @@ namespace DotNetCore.CAP.Internal _serviceProvider = serviceProvider; } - public IConsumerInvoker CreateInvoker() + public ISubscribeInvoker CreateInvoker() { - return new DefaultConsumerInvoker(_loggerFactory, _serviceProvider); + return new DefaultSubscribeInvoker(_loggerFactory, _serviceProvider); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs similarity index 93% rename from src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs rename to src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs index 4e7d9e3..76ebe25 100644 --- a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs @@ -17,7 +17,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Internal { - internal class DefaultSubscriberExecutor : ISubscriberExecutor + internal class DefaultSubscribeDispatcher : ISubscribeDispatcher { private readonly IDataStorage _dataStorage; private readonly ILogger _logger; @@ -29,8 +29,8 @@ namespace DotNetCore.CAP.Internal private static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); - public DefaultSubscriberExecutor( - ILogger logger, + public DefaultSubscribeDispatcher( + ILogger logger, IOptions options, IServiceProvider provider) { @@ -39,12 +39,12 @@ namespace DotNetCore.CAP.Internal _options = options.Value; _dataStorage = _provider.GetService(); - Invoker = _provider.GetService().CreateInvoker(); + Invoker = _provider.GetService().CreateInvoker(); } - private IConsumerInvoker Invoker { get; } + private ISubscribeInvoker Invoker { get; } - public Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken) + public Task DispatchAsync(MediumMessage message, CancellationToken cancellationToken) { var selector = _provider.GetService(); if (!selector.TryGetTopicExecutor(message.Origin.GetName(), message.Origin.GetGroup(), out var executor)) @@ -58,10 +58,10 @@ namespace DotNetCore.CAP.Internal return Task.FromResult(OperateResult.Failed(new SubscriberNotFoundException(error))); } - return ExecuteAsync(message, executor, cancellationToken); + return DispatchAsync(message, executor, cancellationToken); } - public async Task ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) + public async Task DispatchAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken) { bool retry; OperateResult result; diff --git a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.cs similarity index 53% rename from src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs rename to src/DotNetCore.CAP/Internal/ISubscribeDispatcher.cs index b1ba89b..8e1b698 100644 --- a/src/DotNetCore.CAP/Internal/ISubscriberExecutor.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.cs @@ -10,10 +10,10 @@ namespace DotNetCore.CAP.Internal /// /// Consumer executor /// - public interface ISubscriberExecutor + public interface ISubscribeDispatcher { - Task ExecuteAsync(MediumMessage message, CancellationToken cancellationToken = default); + Task DispatchAsync(MediumMessage message, CancellationToken cancellationToken = default); - Task ExecuteAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken = default); + Task DispatchAsync(MediumMessage message, ConsumerExecutorDescriptor descriptor, CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs similarity index 90% rename from src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs rename to src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs index b87dd06..6a0b155 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs @@ -1,84 +1,84 @@ -// Copyright (c) .NET Core Community. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Logging; - -namespace DotNetCore.CAP.Internal -{ - internal class DefaultConsumerInvoker : IConsumerInvoker - { - private readonly ILogger _logger; - private readonly IServiceProvider _serviceProvider; - - public DefaultConsumerInvoker(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - _logger = loggerFactory.CreateLogger(); - } - - public async Task InvokeAsync(ConsumerContext context, CancellationToken cancellationToken = default) - { - cancellationToken.ThrowIfCancellationRequested(); - - _logger.LogDebug("Executing subscriber method : {0}", context.ConsumerDescriptor.MethodInfo.Name); - - var executor = ObjectMethodExecutor.Create( - context.ConsumerDescriptor.MethodInfo, - context.ConsumerDescriptor.ImplTypeInfo); - - using (var scope = _serviceProvider.CreateScope()) - { - var provider = scope.ServiceProvider; - var srvType = context.ConsumerDescriptor.ServiceTypeInfo?.AsType(); - var implType = context.ConsumerDescriptor.ImplTypeInfo.AsType(); - - object obj = null; - - if (srvType != null) - { - obj = provider.GetServices(srvType).FirstOrDefault(o => o.GetType() == implType); - } - - if (obj == null) - { - obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType); - } - - var message = context.DeliverMessage; - var parameterDescriptors = context.ConsumerDescriptor.Parameters; - var executeParameters = new object[parameterDescriptors.Count]; - for (var i = 0; i < parameterDescriptors.Count; i++) - { - if (parameterDescriptors[i].IsFromCap) - { - executeParameters[i] = new CapHeader(message.Headers); - } - else - { - executeParameters[i] = message.Value; - } - } - - var resultObj = await ExecuteWithParameterAsync(executor, obj, executeParameters); - return new ConsumerExecutedResult(resultObj, message.GetId(), message.GetCallbackName()); - } - } - - private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class, object[] parameter) - { - if (executor.IsMethodAsync) - { - return await executor.ExecuteAsync(@class, parameter); - } - - return executor.Execute(@class, parameter); - } - } +// Copyright (c) .NET Core Community. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using DotNetCore.CAP.Messages; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Logging; + +namespace DotNetCore.CAP.Internal +{ + internal class DefaultSubscribeInvoker : ISubscribeInvoker + { + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + + public DefaultSubscribeInvoker(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _logger = loggerFactory.CreateLogger(); + } + + public async Task InvokeAsync(ConsumerContext context, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + _logger.LogDebug("Executing subscriber method : {0}", context.ConsumerDescriptor.MethodInfo.Name); + + var executor = ObjectMethodExecutor.Create( + context.ConsumerDescriptor.MethodInfo, + context.ConsumerDescriptor.ImplTypeInfo); + + using (var scope = _serviceProvider.CreateScope()) + { + var provider = scope.ServiceProvider; + var srvType = context.ConsumerDescriptor.ServiceTypeInfo?.AsType(); + var implType = context.ConsumerDescriptor.ImplTypeInfo.AsType(); + + object obj = null; + + if (srvType != null) + { + obj = provider.GetServices(srvType).FirstOrDefault(o => o.GetType() == implType); + } + + if (obj == null) + { + obj = ActivatorUtilities.GetServiceOrCreateInstance(provider, implType); + } + + var message = context.DeliverMessage; + var parameterDescriptors = context.ConsumerDescriptor.Parameters; + var executeParameters = new object[parameterDescriptors.Count]; + for (var i = 0; i < parameterDescriptors.Count; i++) + { + if (parameterDescriptors[i].IsFromCap) + { + executeParameters[i] = new CapHeader(message.Headers); + } + else + { + executeParameters[i] = message.Value; + } + } + + var resultObj = await ExecuteWithParameterAsync(executor, obj, executeParameters); + return new ConsumerExecutedResult(resultObj, message.GetId(), message.GetCallbackName()); + } + } + + private async Task ExecuteWithParameterAsync(ObjectMethodExecutor executor, object @class, object[] parameter) + { + if (executor.IsMethodAsync) + { + return await executor.ExecuteAsync(@class, parameter); + } + + return executor.Execute(@class, parameter); + } + } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvoker.cs b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.cs similarity index 86% rename from src/DotNetCore.CAP/Internal/IConsumerInvoker.cs rename to src/DotNetCore.CAP/Internal/ISubscribeInvoker.cs index 2dbf34c..d6acf45 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvoker.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.cs @@ -9,10 +9,10 @@ namespace DotNetCore.CAP.Internal /// /// Perform user definition method of consumers. /// - internal interface IConsumerInvoker + internal interface ISubscribeInvoker { /// - /// Invoke consumer method whit consumer context. + /// Invoke subscribe method with the consumer context. /// /// consumer execute context /// The object of . diff --git a/src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ISubscribeInvokerFactory.cs similarity index 69% rename from src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs rename to src/DotNetCore.CAP/Internal/ISubscribeInvokerFactory.cs index 9fd7e74..c8a582d 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeInvokerFactory.cs @@ -3,8 +3,8 @@ namespace DotNetCore.CAP.Internal { - internal interface IConsumerInvokerFactory + internal interface ISubscribeInvokerFactory { - IConsumerInvoker CreateInvoker(); + ISubscribeInvoker CreateInvoker(); } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index 4150b30..f75db71 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -16,7 +16,7 @@ namespace DotNetCore.CAP.Processor { private readonly CancellationTokenSource _cts = new CancellationTokenSource(); private readonly IMessageSender _sender; - private readonly ISubscriberExecutor _executor; + private readonly ISubscribeDispatcher _executor; private readonly ILogger _logger; private readonly BlockingCollection _publishedMessageQueue = @@ -27,7 +27,7 @@ namespace DotNetCore.CAP.Processor public Dispatcher(ILogger logger, IMessageSender sender, - ISubscriberExecutor executor) + ISubscribeDispatcher executor) { _logger = logger; _sender = sender; @@ -90,7 +90,7 @@ namespace DotNetCore.CAP.Processor { foreach (var message in _receivedMessageQueue.GetConsumingEnumerable(_cts.Token)) { - _executor.ExecuteAsync(message.Item1, message.Item2, _cts.Token); + _executor.DispatchAsync(message.Item1, message.Item2, _cts.Token); } } catch (OperationCanceledException) diff --git a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs index b900e80..005b010 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.NeedRetry.cs @@ -18,17 +18,17 @@ namespace DotNetCore.CAP.Processor private readonly TimeSpan _delay = TimeSpan.FromSeconds(1); private readonly ILogger _logger; private readonly IMessageSender _messageSender; - private readonly ISubscriberExecutor _subscriberExecutor; + private readonly ISubscribeDispatcher _subscribeDispatcher; private readonly TimeSpan _waitingInterval; public MessageNeedToRetryProcessor( IOptions options, ILogger logger, - ISubscriberExecutor subscriberExecutor, + ISubscribeDispatcher subscribeDispatcher, IMessageSender messageSender) { _logger = logger; - _subscriberExecutor = subscriberExecutor; + _subscribeDispatcher = subscribeDispatcher; _messageSender = messageSender; _waitingInterval = TimeSpan.FromSeconds(options.Value.FailedRetryInterval); } @@ -69,7 +69,7 @@ namespace DotNetCore.CAP.Processor foreach (var message in messages) { - await _subscriberExecutor.ExecuteAsync(message); + await _subscribeDispatcher.DispatchAsync(message); await context.WaitAsync(_delay); } diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs index aa14448..2c69d20 100644 --- a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs @@ -17,12 +17,11 @@ namespace DotNetCore.CAP.Test { var serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(); - serviceCollection.AddSingleton(); - serviceCollection.AddTransient(); + serviceCollection.AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); } - private IConsumerInvoker ConsumerInvoker => _serviceProvider.GetService(); + private ISubscribeInvoker SubscribeInvoker => _serviceProvider.GetService(); [Fact] public async Task InvokeTest() @@ -40,7 +39,7 @@ namespace DotNetCore.CAP.Test var message = new Message(header, null); var context = new ConsumerContext(descriptor, message); - var ret = await ConsumerInvoker.InvokeAsync(context); + var ret = await SubscribeInvoker.InvokeAsync(context); Assert.Equal(int.MaxValue, ret.Result); } } From 66b9eb985190db15d600286a6c46bb1197f78414 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 28 Nov 2019 13:52:14 +0800 Subject: [PATCH 58/76] Rename class --- src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs | 6 +++--- src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs | 2 +- src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs | 8 ++++---- .../Internal/IConsumerServiceSelector.Default.cs | 6 +++--- .../Internal/ISubscribeDispatcher.Default.cs | 6 +++--- src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs | 8 ++++---- test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs | 2 +- test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs | 2 +- .../{ConsumerInvokerTest.cs => SubscribeInvokerTest.cs} | 6 +++--- 9 files changed, 23 insertions(+), 23 deletions(-) rename test/DotNetCore.CAP.Test/{ConsumerInvokerTest.cs => SubscribeInvokerTest.cs} (91%) diff --git a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs index d06378d..a12a6dc 100644 --- a/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs +++ b/src/DotNetCore.CAP/CAP.ServiceCollectionExtensions.cs @@ -38,7 +38,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); // Warning: IPublishMessageSender need to inject at extension project. - services.TryAddSingleton(); + services.TryAddSingleton(); //Options and extension service var options = new CapOptions(); @@ -72,7 +72,7 @@ namespace Microsoft.Extensions.DependencyInjection services.Configure(setupAction); //Startup and Hosted - services.AddHostedService(); + services.AddHostedService(); return new CapBuilder(services); } diff --git a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs index 3979394..bfcb3d5 100644 --- a/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs +++ b/src/DotNetCore.CAP/Internal/ConsumerInvokerFactory.cs @@ -21,7 +21,7 @@ namespace DotNetCore.CAP.Internal public ISubscribeInvoker CreateInvoker() { - return new DefaultSubscribeInvoker(_loggerFactory, _serviceProvider); + return new SubscribeInvoker(_loggerFactory, _serviceProvider); } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs b/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs index 9f09318..4dffd40 100644 --- a/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs +++ b/src/DotNetCore.CAP/Internal/IBootstrapper.Default.cs @@ -14,12 +14,12 @@ namespace DotNetCore.CAP.Internal /// /// Default implement of . /// - internal class DefaultBootstrapper : BackgroundService, IBootstrapper + internal class Bootstrapper : BackgroundService, IBootstrapper { - private readonly ILogger _logger; + private readonly ILogger _logger; - public DefaultBootstrapper( - ILogger logger, + public Bootstrapper( + ILogger logger, IStorageInitializer storage, IEnumerable processors) { diff --git a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs index 7233980..ecfe5b3 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs @@ -16,7 +16,7 @@ namespace DotNetCore.CAP.Internal /// /// A default implementation. /// - public class DefaultConsumerServiceSelector : IConsumerServiceSelector + public class ConsumerServiceSelector : IConsumerServiceSelector { private readonly CapOptions _capOptions; private readonly IServiceProvider _serviceProvider; @@ -28,9 +28,9 @@ namespace DotNetCore.CAP.Internal private readonly ConcurrentDictionary>> _poundList; /// - /// Creates a new . + /// Creates a new . /// - public DefaultConsumerServiceSelector(IServiceProvider serviceProvider) + public ConsumerServiceSelector(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; _capOptions = serviceProvider.GetService>().Value; diff --git a/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs index 76ebe25..468f495 100644 --- a/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeDispatcher.Default.cs @@ -17,7 +17,7 @@ using Microsoft.Extensions.Options; namespace DotNetCore.CAP.Internal { - internal class DefaultSubscribeDispatcher : ISubscribeDispatcher + internal class SubscribeDispatcher : ISubscribeDispatcher { private readonly IDataStorage _dataStorage; private readonly ILogger _logger; @@ -29,8 +29,8 @@ namespace DotNetCore.CAP.Internal private static readonly DiagnosticListener s_diagnosticListener = new DiagnosticListener(CapDiagnosticListenerNames.DiagnosticListenerName); - public DefaultSubscribeDispatcher( - ILogger logger, + public SubscribeDispatcher( + ILogger logger, IOptions options, IServiceProvider provider) { diff --git a/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs index 6a0b155..aa801bd 100644 --- a/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs +++ b/src/DotNetCore.CAP/Internal/ISubscribeInvoker.Default.cs @@ -12,15 +12,15 @@ using Microsoft.Extensions.Logging; namespace DotNetCore.CAP.Internal { - internal class DefaultSubscribeInvoker : ISubscribeInvoker + internal class SubscribeInvoker : ISubscribeInvoker { private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; - public DefaultSubscribeInvoker(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) + public SubscribeInvoker(ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory.CreateLogger(); } public async Task InvokeAsync(ConsumerContext context, CancellationToken cancellationToken = default) @@ -30,7 +30,7 @@ namespace DotNetCore.CAP.Internal _logger.LogDebug("Executing subscriber method : {0}", context.ConsumerDescriptor.MethodInfo.Name); var executor = ObjectMethodExecutor.Create( - context.ConsumerDescriptor.MethodInfo, + context.ConsumerDescriptor.MethodInfo, context.ConsumerDescriptor.ImplTypeInfo); using (var scope = _serviceProvider.CreateScope()) diff --git a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs index 605c30a..c84bb64 100644 --- a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs @@ -16,7 +16,7 @@ namespace DotNetCore.CAP.Test ServiceCollectionExtensions.ServiceCollection = services; services.AddOptions(); services.PostConfigure(x=>{}); - services.AddSingleton(); + services.AddSingleton(); services.AddScoped(); services.AddScoped(); services.AddLogging(); diff --git a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs index c6aaeb6..fd9c899 100644 --- a/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs +++ b/test/DotNetCore.CAP.Test/CustomConsumerSubscribeTest.cs @@ -46,7 +46,7 @@ namespace DotNetCore.CAP.Test } } - public class MyConsumerServiceSelector : DefaultConsumerServiceSelector + public class MyConsumerServiceSelector : ConsumerServiceSelector { private readonly CapOptions _capOptions; diff --git a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs b/test/DotNetCore.CAP.Test/SubscribeInvokerTest.cs similarity index 91% rename from test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs rename to test/DotNetCore.CAP.Test/SubscribeInvokerTest.cs index 2c69d20..9815bf0 100644 --- a/test/DotNetCore.CAP.Test/ConsumerInvokerTest.cs +++ b/test/DotNetCore.CAP.Test/SubscribeInvokerTest.cs @@ -9,15 +9,15 @@ using Xunit; namespace DotNetCore.CAP.Test { - public class ConsumerInvokerTest + public class SubscribeInvokerTest { private readonly IServiceProvider _serviceProvider; - public ConsumerInvokerTest() + public SubscribeInvokerTest() { var serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); } From 5dcb72a4167d232620d4828f2575b58fe2677d6b Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 4 Dec 2019 17:28:39 +0800 Subject: [PATCH 59/76] Fix mysql unit tests --- src/DotNetCore.CAP.MySql/CAP.EFOptions.cs | 2 +- src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs | 13 +-- .../DatabaseTestHost.cs | 3 +- .../DotNetCore.CAP.MySql.Test.csproj | 23 +--- .../MySqlStorageConnectionTest.cs | 106 ++++++++---------- test/DotNetCore.CAP.MySql.Test/TestHost.cs | 19 ++-- .../MessageExtensionTest.cs | 92 +++++++++++++++ 7 files changed, 164 insertions(+), 94 deletions(-) create mode 100644 test/DotNetCore.CAP.Test/MessageExtensionTest.cs diff --git a/src/DotNetCore.CAP.MySql/CAP.EFOptions.cs b/src/DotNetCore.CAP.MySql/CAP.EFOptions.cs index 692548c..e770eb1 100644 --- a/src/DotNetCore.CAP.MySql/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.MySql/CAP.EFOptions.cs @@ -23,6 +23,6 @@ namespace DotNetCore.CAP /// /// Data version /// - internal string Version { get; set; } + internal string Version { get; set; } = "v1"; } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs b/src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs index bac37d2..ea1f503 100644 --- a/src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs +++ b/src/DotNetCore.CAP.MySql/CAP.MySqlOptions.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +// ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class MySqlOptions : EFOptions @@ -28,14 +29,10 @@ namespace DotNetCore.CAP { if (options.DbContextType != null) { - using (var scope = _serviceScopeFactory.CreateScope()) - { - var provider = scope.ServiceProvider; - using (var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType)) - { - options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; - } - } + using var scope = _serviceScopeFactory.CreateScope(); + var provider = scope.ServiceProvider; + using var dbContext = (DbContext)provider.GetRequiredService(options.DbContextType); + options.ConnectionString = dbContext.Database.GetDbConnection().ConnectionString; } } } diff --git a/test/DotNetCore.CAP.MySql.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.MySql.Test/DatabaseTestHost.cs index 66ffa33..90f7317 100644 --- a/test/DotNetCore.CAP.MySql.Test/DatabaseTestHost.cs +++ b/test/DotNetCore.CAP.MySql.Test/DatabaseTestHost.cs @@ -1,5 +1,6 @@ using System.Threading; using Dapper; +using DotNetCore.CAP.Persistence; namespace DotNetCore.CAP.MySql.Test { @@ -30,7 +31,7 @@ namespace DotNetCore.CAP.MySql.Test { using (CreateScope()) { - var storage = GetService(); + var storage = GetService(); var token = new CancellationTokenSource().Token; CreateDatabase(); storage.InitializeAsync(token).GetAwaiter().GetResult(); diff --git a/test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj b/test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj index 5a259c7..b78c682 100644 --- a/test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj +++ b/test/DotNetCore.CAP.MySql.Test/DotNetCore.CAP.MySql.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.0 false @@ -11,22 +11,11 @@ - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - - - + + + + + \ No newline at end of file diff --git a/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs b/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs index 82cfdcd..dee1948 100644 --- a/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs +++ b/test/DotNetCore.CAP.MySql.Test/MySqlStorageConnectionTest.cs @@ -1,8 +1,8 @@ -using System; +using System.Collections.Generic; using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; +using DotNetCore.CAP.Internal; using DotNetCore.CAP.Messages; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.Options; using Xunit; @@ -11,86 +11,78 @@ namespace DotNetCore.CAP.MySql.Test [Collection("MySql")] public class MySqlStorageConnectionTest : DatabaseTestHost { - private MySqlStorageConnection _storage; + private readonly MySqlDataStorage _storage; public MySqlStorageConnectionTest() { var options = GetService>(); var capOptions = GetService>(); - _storage = new MySqlStorageConnection(options, capOptions); + var initializer = GetService(); + _storage = new MySqlDataStorage(options, capOptions, initializer); } [Fact] - public async Task GetPublishedMessageAsync_Test() + public async Task StorageMessageTest() { - var sql = "INSERT INTO `cap.published`(`Id`,`Version`,`Name`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) VALUES(@Id,'v1',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var publishMessage = new CapPublishedMessage + var msgId = SnowflakeId.Default().NextId().ToString(); + var header = new Dictionary() { - Id = insertedId, - Name = "MySqlStorageConnectionTest", - Content = "", - StatusName = StatusName.Scheduled + [Headers.MessageId] = msgId }; - using (var connection = ConnectionUtil.CreateConnection()) - { - await connection.ExecuteAsync(sql, publishMessage); - } - var message = await _storage.GetPublishedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal("MySqlStorageConnectionTest", message.Name); - Assert.Equal(StatusName.Scheduled, message.StatusName); + var message = new Message(header, null); + + var mdMessage = await _storage.StoreMessageAsync("test.name", message); + Assert.NotNull(mdMessage); } [Fact] - public void StoreReceivedMessageAsync_Test() + public async Task StoreReceivedMessageTest() { - var receivedMessage = new CapReceivedMessage + var msgId = SnowflakeId.Default().NextId().ToString(); + var header = new Dictionary() { - Id = SnowflakeId.Default().NextId(), - Name = "MySqlStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled + [Headers.MessageId] = msgId }; + var message = new Message(header, null); - Exception exception = null; - try - { - _storage.StoreReceivedMessage(receivedMessage); - } - catch (Exception ex) - { - exception = ex; - } - Assert.Null(exception); + var mdMessage = await _storage.StoreReceivedMessageAsync("test.name", "test.group", message); + Assert.NotNull(mdMessage); + } + + [Fact] + public async Task StoreReceivedExceptionMessageTest() + { + await _storage.StoreReceivedExceptionMessageAsync("test.name", "test.group", ""); } [Fact] - public async Task GetReceivedMessageAsync_Test() + public async Task ChangePublishStateTest() { - var sql = $@" - INSERT INTO `cap.received`(`Id`,`Version`,`Name`,`Group`,`Content`,`Retries`,`Added`,`ExpiresAt`,`StatusName`) - VALUES(@Id,'v1',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var receivedMessage = new CapReceivedMessage + var msgId = SnowflakeId.Default().NextId().ToString(); + var header = new Dictionary() { - Id = insertedId, - Name = "MySqlStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled + [Headers.MessageId] = msgId }; - using (var connection = ConnectionUtil.CreateConnection()) + var message = new Message(header, null); + + var mdMessage = await _storage.StoreMessageAsync("test.name", message); + + await _storage.ChangePublishStateAsync(mdMessage, StatusName.Succeeded); + } + + [Fact] + public async Task ChangeReceiveStateTest() + { + var msgId = SnowflakeId.Default().NextId().ToString(); + var header = new Dictionary() { - await connection.ExecuteAsync(sql, receivedMessage); - } + [Headers.MessageId] = msgId + }; + var message = new Message(header, null); + + var mdMessage = await _storage.StoreMessageAsync("test.name", message); - var message = await _storage.GetReceivedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("MySqlStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); + await _storage.ChangeReceiveStateAsync(mdMessage, StatusName.Succeeded); } } } \ No newline at end of file diff --git a/test/DotNetCore.CAP.MySql.Test/TestHost.cs b/test/DotNetCore.CAP.MySql.Test/TestHost.cs index 3549800..acb9fc0 100644 --- a/test/DotNetCore.CAP.MySql.Test/TestHost.cs +++ b/test/DotNetCore.CAP.MySql.Test/TestHost.cs @@ -1,4 +1,5 @@ using System; +using DotNetCore.CAP.Persistence; using Microsoft.Extensions.DependencyInjection; namespace DotNetCore.CAP.MySql.Test @@ -6,7 +7,7 @@ namespace DotNetCore.CAP.MySql.Test public abstract class TestHost : IDisposable { protected IServiceCollection _services; - protected string _connectionString; + protected string ConnectionString; private IServiceProvider _provider; private IServiceProvider _scopedProvider; @@ -27,12 +28,14 @@ namespace DotNetCore.CAP.MySql.Test services.AddOptions(); services.AddLogging(); - _connectionString = ConnectionUtil.GetConnectionString(); + ConnectionString = ConnectionUtil.GetConnectionString(); services.AddOptions(); - services.Configure(x => x.ConnectionString = _connectionString); - - services.AddSingleton(); - + services.Configure(x => + { + x.ConnectionString = ConnectionString; + }); + services.AddSingleton(); + services.AddSingleton(); _services = services; } @@ -72,10 +75,6 @@ namespace DotNetCore.CAP.MySql.Test public T GetService() => Provider.GetService(); - public T Ensure(ref T service) - where T : class - => service ?? (service = GetService()); - public virtual void Dispose() { (_provider as IDisposable)?.Dispose(); diff --git a/test/DotNetCore.CAP.Test/MessageExtensionTest.cs b/test/DotNetCore.CAP.Test/MessageExtensionTest.cs new file mode 100644 index 0000000..f0fe846 --- /dev/null +++ b/test/DotNetCore.CAP.Test/MessageExtensionTest.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using DotNetCore.CAP.Messages; +using Xunit; + +namespace DotNetCore.CAP.Test +{ + public class MessageExtensionTest + { + [Fact] + public void GetIdTest() + { + var msgId = Guid.NewGuid().ToString(); + var header = new Dictionary() + { + [Headers.MessageId] = msgId + }; + var message = new Message(header, null); + + Assert.NotNull(message.GetId()); + Assert.Equal(msgId,message.GetId()); + } + + [Fact] + public void GetNameTest() + { + var msgName = Guid.NewGuid().ToString(); + var header = new Dictionary() + { + [Headers.MessageName] = msgName + }; + var message = new Message(header, null); + + Assert.NotNull(message.GetName()); + Assert.Equal(msgName, message.GetName()); + } + + [Fact] + public void GetCallbackNameTest() + { + var callbackName = Guid.NewGuid().ToString(); + var header = new Dictionary() + { + [Headers.CallbackName] = callbackName + }; + var message = new Message(header, null); + + Assert.NotNull(message.GetCallbackName()); + Assert.Equal(callbackName, message.GetCallbackName()); + } + + [Fact] + public void GetGroupTest() + { + var group = Guid.NewGuid().ToString(); + var header = new Dictionary() + { + [Headers.Group] = group + }; + var message = new Message(header, null); + + Assert.NotNull(message.GetGroup()); + Assert.Equal(group, message.GetGroup()); + } + + [Fact] + public void GetCorrelationSequenceTest() + { + var seq = 1; + var header = new Dictionary() + { + [Headers.CorrelationSequence] = seq.ToString() + }; + var message = new Message(header, null); + + Assert.Equal(seq, message.GetCorrelationSequence()); + } + + [Fact] + public void HasExceptionTest() + { + var exception = "exception message"; + var header = new Dictionary() + { + [Headers.Exception] = exception + }; + var message = new Message(header, null); + + Assert.True(message.HasException()); + } + } +} From 6583c9aff390bb9f5527e427de6c9e92f63278b8 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 4 Dec 2019 17:58:04 +0800 Subject: [PATCH 60/76] Fix loops when configuration items are abnormal or unreachable. #444 --- src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs b/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs index 9aba0e7..bb34dee 100644 --- a/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs +++ b/src/DotNetCore.CAP/Processor/IProcessor.InfiniteRetry.cs @@ -30,11 +30,12 @@ namespace DotNetCore.CAP.Processor } catch (OperationCanceledException) { - //ignore + //ignore } catch (Exception ex) { - _logger.LogWarning(1, ex, "Processor '{ProcessorName}' failed. Retrying...", _inner.ToString()); + _logger.LogWarning(ex, "Processor '{ProcessorName}' failed. Retrying...", _inner.ToString()); + await context.WaitAsync(TimeSpan.FromSeconds(2)); } } } From 2f4b65b457d2d8608142863c2685c5256d826e11 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Wed, 4 Dec 2019 17:58:20 +0800 Subject: [PATCH 61/76] Refactoring --- src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 1 - src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs | 4 +++- src/DotNetCore.CAP/Internal/LoggerExtensions.cs | 7 ++++++- src/DotNetCore.CAP/Processor/IDispatcher.Default.cs | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index 26547a0..eeecd80 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading; using Confluent.Kafka; diff --git a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs index cd7a648..d5e2fa2 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerRegister.Default.cs @@ -151,6 +151,8 @@ namespace DotNetCore.CAP.Internal { client.OnMessageReceived += async (sender, transportMessage) => { + _logger.MessageReceived(transportMessage.GetId(), transportMessage.GetName()); + _cts.Token.ThrowIfCancellationRequested(); long? tracingTimestamp = null; try @@ -189,7 +191,7 @@ namespace DotNetCore.CAP.Internal { var content = StringSerializer.Serialize(message); await _storage.StoreReceivedExceptionMessageAsync(name, group, content); - + client.Commit(); TracingAfter(tracingTimestamp, transportMessage, _serverAddress); diff --git a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs index 025c207..e3722c4 100644 --- a/src/DotNetCore.CAP/Internal/LoggerExtensions.cs +++ b/src/DotNetCore.CAP/Internal/LoggerExtensions.cs @@ -40,7 +40,12 @@ namespace DotNetCore.CAP.Internal logger.LogDebug($"Message published. name: {name}, content:{content}."); } - public static void MessagePublishException(this ILogger logger, long messageId, string reason, Exception ex) + public static void MessageReceived(this ILogger logger, string messageId, string name) + { + logger.LogDebug($"Received message. id:{messageId}, name: {name}"); + } + + public static void MessagePublishException(this ILogger logger, string messageId, string reason, Exception ex) { logger.LogError(ex, $"An exception occured while publishing a message, reason:{reason}. message id:{messageId}"); } diff --git a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs index f75db71..b404f64 100644 --- a/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs +++ b/src/DotNetCore.CAP/Processor/IDispatcher.Default.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP.Internal; +using DotNetCore.CAP.Messages; using DotNetCore.CAP.Persistence; using DotNetCore.CAP.Transport; using Microsoft.Extensions.Logging; @@ -67,7 +68,7 @@ namespace DotNetCore.CAP.Processor var result = await _sender.SendAsync(message); if (!result.Succeeded) { - _logger.LogWarning(result.Exception, "Message send failed! -->" + result); + _logger.MessagePublishException(message.Origin.GetId(),result.ToString(),result.Exception); } } catch (Exception ex) From aedf82cbde3043cef9858b5a65c78f8e7b3f7fe7 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 5 Dec 2019 14:00:44 +0800 Subject: [PATCH 62/76] Add sqlsever samples --- CAP.sln | 7 ++ .../Sample.RabbitMQ.SqlServer/AppDbContext.cs | 40 ++++++++++ .../Controllers/ValuesController.cs | 76 +++++++++++++++++++ .../20191205032949_FirstMigration.Designer.cs | 40 ++++++++++ .../20191205032949_FirstMigration.cs | 29 +++++++ .../Migrations/AppDbContextModelSnapshot.cs | 38 ++++++++++ samples/Sample.RabbitMQ.SqlServer/Program.cs | 20 +++++ .../Sample.RabbitMQ.SqlServer.csproj | 22 ++++++ samples/Sample.RabbitMQ.SqlServer/Startup.cs | 39 ++++++++++ .../appsettings.json | 8 ++ 10 files changed, 319 insertions(+) create mode 100644 samples/Sample.RabbitMQ.SqlServer/AppDbContext.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Controllers/ValuesController.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.Designer.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Migrations/AppDbContextModelSnapshot.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Program.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/Sample.RabbitMQ.SqlServer.csproj create mode 100644 samples/Sample.RabbitMQ.SqlServer/Startup.cs create mode 100644 samples/Sample.RabbitMQ.SqlServer/appsettings.json diff --git a/CAP.sln b/CAP.sln index 8e82097..fe756d5 100644 --- a/CAP.sln +++ b/CAP.sln @@ -70,6 +70,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Dashboard", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka.InMemory", "samples\Sample.Kafka.InMemory\Sample.Kafka.InMemory.csproj", "{1B0371D6-36A4-4C78-A727-8ED732FDBA1D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RabbitMQ.SqlServer", "samples\Sample.RabbitMQ.SqlServer\Sample.RabbitMQ.SqlServer.csproj", "{F6C5C676-AF05-46D5-A45D-442137B31898}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -151,6 +153,10 @@ Global {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Release|Any CPU.ActiveCfg = Release|Any CPU {1B0371D6-36A4-4C78-A727-8ED732FDBA1D}.Release|Any CPU.Build.0 = Release|Any CPU + {F6C5C676-AF05-46D5-A45D-442137B31898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6C5C676-AF05-46D5-A45D-442137B31898}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -175,6 +181,7 @@ Global {58B6E829-C6C8-457C-9DD0-C600650254DF} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {56FB261C-67AF-4715-9A46-4FA4FAB91B2C} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {1B0371D6-36A4-4C78-A727-8ED732FDBA1D} = {3A6B6931-A123-477A-9469-8B468B5385AF} + {F6C5C676-AF05-46D5-A45D-442137B31898} = {3A6B6931-A123-477A-9469-8B468B5385AF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2E70565D-94CF-40B4-BFE1-AC18D5F736AB} diff --git a/samples/Sample.RabbitMQ.SqlServer/AppDbContext.cs b/samples/Sample.RabbitMQ.SqlServer/AppDbContext.cs new file mode 100644 index 0000000..fdad2a5 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/AppDbContext.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore; + +namespace Sample.RabbitMQ.SqlServer +{ + public class Person + { + public int Id { get; set; } + + public string Name { get; set; } + + public override string ToString() + { + return $"Name:{Name}, Id:{Id}"; + } + } + + public class Person2 + { + public int Id { get; set; } + + public string Name { get; set; } + + public override string ToString() + { + return $"Name:{Name}, Id:{Id}"; + } + } + + public class AppDbContext : DbContext + { + public const string ConnectionString = "Server=192.168.2.120;Database=captest;User Id=sa;Password=P@ssw0rd;"; + + public DbSet Persons { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlServer(ConnectionString); + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Controllers/ValuesController.cs b/samples/Sample.RabbitMQ.SqlServer/Controllers/ValuesController.cs new file mode 100644 index 0000000..24d1848 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Controllers/ValuesController.cs @@ -0,0 +1,76 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Dapper; +using DotNetCore.CAP; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; + +namespace Sample.RabbitMQ.SqlServer.Controllers +{ + [Route("api/[controller]")] + public class ValuesController : Controller + { + private readonly ICapPublisher _capBus; + + public ValuesController(ICapPublisher capPublisher) + { + _capBus = capPublisher; + } + + [Route("~/without/transaction")] + public async Task WithoutTransaction() + { + await _capBus.PublishAsync("sample.rabbitmq.mysql", new Person() + { + Id = 123, + Name = "Bar" + }); + + return Ok(); + } + + [Route("~/adonet/transaction")] + public IActionResult AdonetWithTransaction() + { + using (var connection = new SqlConnection(AppDbContext.ConnectionString)) + { + using (var transaction = connection.BeginTransaction(_capBus, true)) + { + //your business code + connection.Execute("insert into test(name) values('test')", transaction: transaction); + + _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); + } + } + + return Ok(); + } + + [Route("~/ef/transaction")] + public IActionResult EntityFrameworkWithTransaction([FromServices]AppDbContext dbContext) + { + using (dbContext.Database.BeginTransaction(_capBus, autoCommit: true)) + { + dbContext.Persons.Add(new Person() { Name = "ef.transaction" }); + + _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); + } + return Ok(); + } + + [NonAction] + [CapSubscribe("sample.rabbitmq.mysql")] + public void Subscriber(DateTime p) + { + Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); + } + + [NonAction] + [CapSubscribe("sample.rabbitmq.mysql", Group = "group.test2")] + public void Subscriber2(DateTime p, [FromCap]CapHeader header) + { + Console.WriteLine($@"{DateTime.Now} Subscriber invoked, Info: {p}"); + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.Designer.cs b/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.Designer.cs new file mode 100644 index 0000000..7feec6f --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.Designer.cs @@ -0,0 +1,40 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.RabbitMQ.SqlServer; + +namespace Sample.RabbitMQ.SqlServer.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20191205032949_FirstMigration")] + partial class FirstMigration + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Sample.RabbitMQ.SqlServer.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Persons"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.cs b/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.cs new file mode 100644 index 0000000..019bef1 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Migrations/20191205032949_FirstMigration.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Sample.RabbitMQ.SqlServer.Migrations +{ + public partial class FirstMigration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Persons", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Persons", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Persons"); + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Migrations/AppDbContextModelSnapshot.cs b/samples/Sample.RabbitMQ.SqlServer/Migrations/AppDbContextModelSnapshot.cs new file mode 100644 index 0000000..4817bb3 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Migrations/AppDbContextModelSnapshot.cs @@ -0,0 +1,38 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Sample.RabbitMQ.SqlServer; + +namespace Sample.RabbitMQ.SqlServer.Migrations +{ + [DbContext(typeof(AppDbContext))] + partial class AppDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Sample.RabbitMQ.SqlServer.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Persons"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Program.cs b/samples/Sample.RabbitMQ.SqlServer/Program.cs new file mode 100644 index 0000000..fd0c137 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Program.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Sample.RabbitMQ.SqlServer +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/Sample.RabbitMQ.SqlServer.csproj b/samples/Sample.RabbitMQ.SqlServer/Sample.RabbitMQ.SqlServer.csproj new file mode 100644 index 0000000..c68c8ef --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Sample.RabbitMQ.SqlServer.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/samples/Sample.RabbitMQ.SqlServer/Startup.cs b/samples/Sample.RabbitMQ.SqlServer/Startup.cs new file mode 100644 index 0000000..38b91f7 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/Startup.cs @@ -0,0 +1,39 @@ +using System; +using DotNetCore.CAP.Messages; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace Sample.RabbitMQ.SqlServer +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddDbContext(); + + services.AddCap(x => + { + x.UseEntityFramework(); + x.UseRabbitMQ("192.168.2.120"); + x.UseDashboard(); + x.FailedRetryCount = 5; + x.FailedThresholdCallback = (type, msg) => + { + Console.WriteLine( + $@"A message of type {type} failed after executing {x.FailedRetryCount} several times, requiring manual troubleshooting. Message name: {msg.GetName()}"); + }; + }); + + services.AddControllers(); + } + + public void Configure(IApplicationBuilder app) + { + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/samples/Sample.RabbitMQ.SqlServer/appsettings.json b/samples/Sample.RabbitMQ.SqlServer/appsettings.json new file mode 100644 index 0000000..50fe9a3 --- /dev/null +++ b/samples/Sample.RabbitMQ.SqlServer/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Error" + } + } +} From 45286ea2f0508d759a3cc8c19e223084a825ddf5 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 5 Dec 2019 14:01:30 +0800 Subject: [PATCH 63/76] Schema renaming to lowercase is more conformant --- src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs b/src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs index abbe3ab..e3d1cd2 100644 --- a/src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs +++ b/src/DotNetCore.CAP.SqlServer/CAP.EFOptions.cs @@ -8,7 +8,7 @@ namespace DotNetCore.CAP { public class EFOptions { - public const string DefaultSchema = "Cap"; + public const string DefaultSchema = "cap"; /// /// Gets or sets the schema to use when creating database objects. From 5df6c76c8a65a9c5a659dfac74e332be47fa36b0 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 5 Dec 2019 14:02:55 +0800 Subject: [PATCH 64/76] Fix SQL Server tranaction error in entityframework. #402 --- .../ICapTransaction.SqlServer.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs index 7a7d4e9..84c9120 100644 --- a/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs +++ b/src/DotNetCore.CAP.SqlServer/ICapTransaction.SqlServer.cs @@ -11,29 +11,22 @@ using DotNetCore.CAP.Persistence; using DotNetCore.CAP.SqlServer.Diagnostics; using DotNetCore.CAP.Transport; using Microsoft.Data.SqlClient; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; // ReSharper disable once CheckNamespace namespace DotNetCore.CAP { public class SqlServerCapTransaction : CapTransactionBase { - private readonly DbContext _dbContext; private readonly DiagnosticProcessorObserver _diagnosticProcessor; public SqlServerCapTransaction( IDispatcher dispatcher, - IServiceProvider serviceProvider) : base(dispatcher) + DiagnosticProcessorObserver diagnosticProcessor) : base(dispatcher) { - var sqlServerOptions = serviceProvider.GetService>().Value; - if (sqlServerOptions.DbContextType != null) - _dbContext = serviceProvider.GetService(sqlServerOptions.DbContextType) as DbContext; - - _diagnosticProcessor = serviceProvider.GetRequiredService(); + _diagnosticProcessor = diagnosticProcessor; } protected override void AddToSent(MediumMessage msg) @@ -76,7 +69,6 @@ namespace DotNetCore.CAP dbTransaction.Commit(); break; case IDbContextTransaction dbContextTransaction: - _dbContext?.SaveChanges(); dbContextTransaction.Commit(); break; } @@ -93,7 +85,6 @@ namespace DotNetCore.CAP dbTransaction.Commit(); break; case IDbContextTransaction dbContextTransaction: - await _dbContext.SaveChangesAsync(cancellationToken); await dbContextTransaction.CommitAsync(cancellationToken); break; } From e269002a0899f5ada13f72c16ebbadf8751373ce Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 10 Dec 2019 19:47:24 +0800 Subject: [PATCH 65/76] update readme --- .travis.yml | 2 +- CAP.sln | 21 --------------------- README.md | 6 +++++- README.zh-cn.md | 6 ++++++ appveyor.yml | 2 +- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index acb2d1c..bc132b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: csharp sudo: required dist: xenial solution: CAP.sln -dotnet: 2.2 +dotnet: 3.0 mono: none #matrix: diff --git a/CAP.sln b/CAP.sln index fe756d5..4bab9bb 100644 --- a/CAP.sln +++ b/CAP.sln @@ -42,8 +42,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.Test", "test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.SqlServer", "src\DotNetCore.CAP.SqlServer\DotNetCore.CAP.SqlServer.csproj", "{3B577468-6792-4EF1-9237-15180B176A24}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.SqlServer.Test", "test\DotNetCore.CAP.SqlServer.Test\DotNetCore.CAP.SqlServer.Test.csproj", "{DA00FA38-C4B9-4F55-8756-D480FBC1084F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.MySql", "src\DotNetCore.CAP.MySql\DotNetCore.CAP.MySql.csproj", "{FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.MySql.Test", "test\DotNetCore.CAP.MySql.Test\DotNetCore.CAP.MySql.Test.csproj", "{80A84F62-1558-427B-BA74-B47AA8A665B5}" @@ -52,10 +50,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RabbitMQ.MySql", "sa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.PostgreSql", "src\DotNetCore.CAP.PostgreSql\DotNetCore.CAP.PostgreSql.csproj", "{82C403AB-ED68-4084-9A1D-11334F9F08F9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.PostgreSql.Test", "test\DotNetCore.CAP.PostgreSql.Test\DotNetCore.CAP.PostgreSql.Test.csproj", "{7CA3625D-1817-4695-881D-7E79A1E1DED2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.MongoDB.Test", "test\DotNetCore.CAP.MongoDB.Test\DotNetCore.CAP.MongoDB.Test.csproj", "{C143FCDF-E7F3-46F8-987E-A1BA38C1639D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.MongoDB", "src\DotNetCore.CAP.MongoDB\DotNetCore.CAP.MongoDB.csproj", "{77C0AC02-C44B-49D5-B969-7D5305FC20A5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RabbitMQ.MongoDB", "samples\Sample.RabbitMQ.MongoDB\Sample.RabbitMQ.MongoDB.csproj", "{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}" @@ -97,10 +91,6 @@ Global {3B577468-6792-4EF1-9237-15180B176A24}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B577468-6792-4EF1-9237-15180B176A24}.Release|Any CPU.Build.0 = Release|Any CPU - {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA00FA38-C4B9-4F55-8756-D480FBC1084F}.Release|Any CPU.Build.0 = Release|Any CPU {FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA15685A-778A-4D2A-A2FE-27FAD2FFA65B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -117,14 +107,6 @@ Global {82C403AB-ED68-4084-9A1D-11334F9F08F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {82C403AB-ED68-4084-9A1D-11334F9F08F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {82C403AB-ED68-4084-9A1D-11334F9F08F9}.Release|Any CPU.Build.0 = Release|Any CPU - {7CA3625D-1817-4695-881D-7E79A1E1DED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7CA3625D-1817-4695-881D-7E79A1E1DED2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7CA3625D-1817-4695-881D-7E79A1E1DED2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7CA3625D-1817-4695-881D-7E79A1E1DED2}.Release|Any CPU.Build.0 = Release|Any CPU - {C143FCDF-E7F3-46F8-987E-A1BA38C1639D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C143FCDF-E7F3-46F8-987E-A1BA38C1639D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C143FCDF-E7F3-46F8-987E-A1BA38C1639D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C143FCDF-E7F3-46F8-987E-A1BA38C1639D}.Release|Any CPU.Build.0 = Release|Any CPU {77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Debug|Any CPU.Build.0 = Debug|Any CPU {77C0AC02-C44B-49D5-B969-7D5305FC20A5}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -167,13 +149,10 @@ Global {9961B80E-0718-4280-B2A0-271B003DE26B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {F608B509-A99B-4AC7-8227-42051DD4A578} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {3B577468-6792-4EF1-9237-15180B176A24} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} - {DA00FA38-C4B9-4F55-8756-D480FBC1084F} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {FA15685A-778A-4D2A-A2FE-27FAD2FFA65B} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {80A84F62-1558-427B-BA74-B47AA8A665B5} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {9F3F9BFE-7B6A-4A7A-A6E6-8B517D611873} = {3A6B6931-A123-477A-9469-8B468B5385AF} {82C403AB-ED68-4084-9A1D-11334F9F08F9} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} - {7CA3625D-1817-4695-881D-7E79A1E1DED2} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} - {C143FCDF-E7F3-46F8-987E-A1BA38C1639D} = {C09CDAB0-6DD4-46E9-B7F3-3EF2A4741EA0} {77C0AC02-C44B-49D5-B969-7D5305FC20A5} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F} = {3A6B6931-A123-477A-9469-8B468B5385AF} {11563D1A-27CC-45CF-8C04-C16BCC21250A} = {3A6B6931-A123-477A-9469-8B468B5385AF} diff --git a/README.md b/README.md index 1e4704c..35200d8 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,11 @@ services.AddCap(x => ### Dashboard -CAP v2.1+ provides the dashboard pages, you can easily view the sent and received messages. In addition, you can also view the message status in real time on the dashboard. +CAP v2.1+ provides the dashboard pages, you can easily view the sent and received messages. In addition, you can also view the message status in real time on the dashboard. Use the following command to install the Dashboard in your project. + +``` +PM> Install-Package DotNetCore.Dashboard +``` In the distributed environment, the dashboard built-in integrated [Consul](http://consul.io) as a node discovery, while the realization of the gateway agent function, you can also easily view the node or other node data, It's like you are visiting local resources. diff --git a/README.zh-cn.md b/README.zh-cn.md index e5c4c70..04b26af 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -239,6 +239,12 @@ services.AddCap(x => CAP 2.1+ 以上版本中提供了仪表盘(Dashboard)功能,你可以很方便的查看发出和接收到的消息。除此之外,你还可以在仪表盘中实时查看发送或者接收到的消息。 +使用一下命令安装 Dashboard: + +``` +PM> Install-Package DotNetCore.Dashboard +``` + 在分布式环境中,仪表盘内置集成了 [Consul](http://consul.io) 作为节点的注册发现,同时实现了网关代理功能,你同样可以方便的查看本节点或者其他节点的数据,它就像你访问本地资源一样。 ```c# diff --git a/appveyor.yml b/appveyor.yml index 88810e7..2eb7bc2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: '{build}' -os: Visual Studio 2017 +os: Visual Studio 2019 environment: BUILDING_ON_PLATFORM: win BuildEnvironment: appveyor From d55ec90ae48eef0abacb9251670342c3414b63f5 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 10 Dec 2019 21:09:56 +0800 Subject: [PATCH 66/76] update ci yml --- appveyor.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2eb7bc2..b30ac0e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,14 +3,9 @@ os: Visual Studio 2019 environment: BUILDING_ON_PLATFORM: win BuildEnvironment: appveyor - Cap_SqlServer_ConnectionStringTemplate: Server=(local)\SQL2014;Database={0};User ID=sa;Password=Password12! Cap_MySql_ConnectionStringTemplate: Server=localhost;Database={0};Uid=root;Pwd=Password12!;Allow User Variables=True;SslMode=none - Cap_PostgreSql_ConnectionStringTemplate: Server=localhost;Database={0};UserId=postgres;Password=Password12! services: - - mssql2014 - mysql - - postgresql - - mongodb build_script: - ps: ./build.ps1 test: off From 2811ba58f3144a1c264b81ff338a8c04c3b93b39 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 10 Dec 2019 21:13:44 +0800 Subject: [PATCH 67/76] Remove the database integration test --- .../ConnectionUtil.cs | 7 -- .../DatabaseTestHost.cs | 56 ----------- .../DotNetCore.CAP.MongoDB.Test.csproj | 25 ----- .../MongoDBMonitoringApiTest.cs | 73 -------------- .../MongoDBStorageConnectionTest.cs | 85 ---------------- .../MongoDBStorageTest.cs | 21 ---- .../MongoDBTransactionTest.cs | 76 -------------- .../ConnectionUtil.cs | 47 --------- .../DatabaseTestHost.cs | 66 ------------- .../DotNetCore.CAP.PostgreSql.Test.csproj | 24 ----- .../PostgreSqlStorageConnectionTest.cs | 98 ------------------ .../PostgreSqlStorageTest.cs | 44 --------- .../TestHost.cs | 99 ------------------- .../ConnectionUtil.cs | 47 --------- .../DatabaseTestHost.cs | 82 --------------- .../DotNetCore.CAP.SqlServer.Test.csproj | 33 ------- .../SqlServerStorageConnectionTest.cs | 94 ------------------ .../SqlServerStorageTest.cs | 43 -------- 18 files changed, 1020 deletions(-) delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/ConnectionUtil.cs delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/DatabaseTestHost.cs delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageTest.cs delete mode 100644 test/DotNetCore.CAP.MongoDB.Test/MongoDBTransactionTest.cs delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/ConnectionUtil.cs delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/DatabaseTestHost.cs delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageTest.cs delete mode 100644 test/DotNetCore.CAP.PostgreSql.Test/TestHost.cs delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs delete mode 100644 test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs diff --git a/test/DotNetCore.CAP.MongoDB.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.MongoDB.Test/ConnectionUtil.cs deleted file mode 100644 index da8de03..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/ConnectionUtil.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DotNetCore.CAP.MongoDB.Test -{ - public class ConnectionUtil - { - public static string ConnectionString = "mongodb://localhost:27017"; - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.MongoDB.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.MongoDB.Test/DatabaseTestHost.cs deleted file mode 100644 index 582da3f..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/DatabaseTestHost.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using MongoDB.Driver; - -namespace DotNetCore.CAP.MongoDB.Test -{ - public abstract class DatabaseTestHost : IDisposable - { - private string _connectionString; - - protected IServiceProvider Provider { get; private set; } - protected IMongoClient MongoClient => Provider.GetService(); - protected IMongoDatabase Database => MongoClient.GetDatabase(MongoDBOptions.Value.DatabaseName); - protected CapOptions CapOptions => Provider.GetService>().Value; - protected IOptions MongoDBOptions => Provider.GetService>(); - - protected DatabaseTestHost() - { - CreateServiceCollection(); - CreateDatabase(); - } - - private void CreateDatabase() - { - Provider.GetService().InitializeAsync(CancellationToken.None).GetAwaiter().GetResult(); - } - - protected virtual void AddService(ServiceCollection serviceCollection) - { - - } - - private void CreateServiceCollection() - { - var services = new ServiceCollection(); - services.AddOptions(); - services.AddLogging(); - _connectionString = ConnectionUtil.ConnectionString; - services.AddOptions(); - services.Configure(x => x.DatabaseConnection = _connectionString); - - services.AddSingleton(x => new MongoClient(_connectionString)); - services.AddSingleton(); - - AddService(services); - Provider = services.BuildServiceProvider(); - } - - public void Dispose() - { - MongoClient.DropDatabase(MongoDBOptions.Value.DatabaseName); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj b/test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj deleted file mode 100644 index e15a979..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/DotNetCore.CAP.MongoDB.Test.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netcoreapp2.1 - false - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs deleted file mode 100644 index 58a6969..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBMonitoringApiTest.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Linq; -using DotNetCore.CAP.Dashboard.Monitoring; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using FluentAssertions; -using Xunit; - -namespace DotNetCore.CAP.MongoDB.Test -{ - [Collection("MongoDB")] - public class MongoDBMonitoringApiTest : DatabaseTestHost - { - private readonly MongoDBMonitoringApi _api; - - public MongoDBMonitoringApiTest() - { - _api = new MongoDBMonitoringApi(MongoClient, MongoDBOptions); - - var collection = Database.GetCollection(MongoDBOptions.Value.PublishedCollection); - collection.InsertMany(new[] - { - new PublishedMessage - { - Id = SnowflakeId.Default().NextId(), - Added = DateTime.Now.AddHours(-1), - StatusName = "Failed", - Version = "v1", - Content = "abc" - }, - new PublishedMessage - { - Id = SnowflakeId.Default().NextId(), - Added = DateTime.Now, - StatusName = "Failed", - Version = "v1", - Content = "bbc" - } - }); - } - - [Fact] - public void HourlyFailedJobs_Test() - { - var result = _api.HourlyFailedJobs(MessageType.Publish); - result.Should().HaveCount(24); - } - - [Fact] - public void Messages_Test() - { - var messages = - _api.Messages(new MessageQueryDto - { - MessageType = MessageType.Publish, - StatusName = StatusName.Failed, - Content = "b", - CurrentPage = 1, - PageSize = 1 - }); - - messages.Should().HaveCount(1); - messages.First().Content.Should().Contain("b"); - } - - [Fact] - public void PublishedFailedCount_Test() - { - var count = _api.PublishedFailedCount(); - count.Should().BeGreaterThan(1); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs deleted file mode 100644 index 37537f9..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageConnectionTest.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using FluentAssertions; -using Microsoft.Extensions.DependencyInjection; -using MongoDB.Driver; -using Xunit; - -namespace DotNetCore.CAP.MongoDB.Test -{ - [Collection("MongoDB")] - public class MongoDBStorageConnectionTest : DatabaseTestHost - { - private IStorageConnection _connection => - Provider.GetService().GetConnection(); - - [Fact] - public void StoreReceivedMessageAsync_TestAsync() - { - var messageContext = new MessageContext - { - Group = "test", - Name = "test", - Content = "test-content" - }; - - _connection.StoreReceivedMessage(new ReceivedMessage() - { - Id = SnowflakeId.Default().NextId(), - Group=messageContext.Group, - Content=messageContext.Content, - Name=messageContext.Name, - Version="v1" - }); - } - - [Fact] - public void ChangeReceivedState_Test() - { - StoreReceivedMessageAsync_TestAsync(); - var collection = Database.GetCollection(MongoDBOptions.Value.ReceivedCollection); - - var msg = collection.Find(x => true).FirstOrDefault(); - _connection.ChangeReceivedState(msg.Id, StatusName.Scheduled).Should().BeTrue(); - collection.Find(x => x.Id == msg.Id).FirstOrDefault()?.StatusName.Should().Be(StatusName.Scheduled); - } - - [Fact] - public async void GetReceivedMessagesOfNeedRetry_TestAsync() - { - var msgs = await _connection.GetReceivedMessagesOfNeedRetry(); - - msgs.Should().BeEmpty(); - - var id = SnowflakeId.Default().NextId(); - - var msg = new CapReceivedMessage - { - Id = id, - Group = "test", - Name = "test", - Content = "test-content", - StatusName = StatusName.Failed - }; - _connection.StoreReceivedMessage(msg); - - var collection = Database.GetCollection(MongoDBOptions.Value.ReceivedCollection); - - var updateDef = Builders - .Update.Set(x => x.Added, DateTime.Now.AddMinutes(-5)); - - await collection.UpdateOneAsync(x => x.Id == id, updateDef); - - msgs = await _connection.GetReceivedMessagesOfNeedRetry(); - msgs.Should().HaveCountGreaterThan(0); - } - - [Fact] - public void GetReceivedMessageAsync_Test() - { - var msg = _connection.GetReceivedMessageAsync(1); - msg.Should().NotBeNull(); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageTest.cs deleted file mode 100644 index fb15cee..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBStorageTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentAssertions; -using MongoDB.Driver; -using Xunit; - -namespace DotNetCore.CAP.MongoDB.Test -{ - [Collection("MongoDB")] - public class MongoDBStorageTest : DatabaseTestHost - { - [Fact] - public void InitializeAsync_Test() - { - var names = MongoClient.ListDatabaseNames()?.ToList(); - names.Should().Contain(MongoDBOptions.Value.DatabaseName); - - var collections = Database.ListCollectionNames()?.ToList(); - collections.Should().Contain(MongoDBOptions.Value.PublishedCollection); - collections.Should().Contain(MongoDBOptions.Value.ReceivedCollection); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.MongoDB.Test/MongoDBTransactionTest.cs b/test/DotNetCore.CAP.MongoDB.Test/MongoDBTransactionTest.cs deleted file mode 100644 index dd7351a..0000000 --- a/test/DotNetCore.CAP.MongoDB.Test/MongoDBTransactionTest.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using FluentAssertions; -using MongoDB.Bson; -using MongoDB.Driver; -using Xunit; - -namespace DotNetCore.CAP.MongoDB.Test -{ - [Collection("MongoDB")] - public class MongoDBTransactionTest : DatabaseTestHost - { - [Fact] - public void MongoDB_Connection_Test() - { - var names = MongoClient.ListDatabaseNames(); - names.ToList().Should().NotBeNullOrEmpty(); - } - - [Fact(Skip = "Because of Appveyor dose not support MongoDB 4.0, so we skip this test for now.")] - public void Transaction_Test() - { - var document = new BsonDocument - { - { "name", "MongoDB" }, - { "type", "Database" }, - { "count", 1 }, - { "info", new BsonDocument - { - { "x", 203 }, - { "y", 102 } - }} - }; - var db = MongoClient.GetDatabase("test"); - var collection1 = db.GetCollection("test1"); - var collection2 = db.GetCollection("test2"); - using (var sesstion = MongoClient.StartSession()) - { - sesstion.StartTransaction(); - collection1.InsertOne(document); - collection2.InsertOne(document); - sesstion.CommitTransaction(); - } - var filter = new BsonDocument("name", "MongoDB"); - collection1.CountDocuments(filter).Should().BeGreaterThan(0); - collection2.CountDocuments(filter).Should().BeGreaterThan(0); - } - - [Fact(Skip = "Because of Appveyor dose not support MongoDB 4.0, so we skip this test for now.")] - public void Transaction_Rollback_Test() - { - var document = new BsonDocument - { - {"name", "MongoDB"}, - {"date", DateTimeOffset.Now.ToString()} - }; - var db = MongoClient.GetDatabase("test"); - - var collection = db.GetCollection("test3"); - var collection4 = db.GetCollection("test4"); - - using (var session = MongoClient.StartSession()) - { - session.IsInTransaction.Should().BeFalse(); - session.StartTransaction(); - session.IsInTransaction.Should().BeTrue(); - collection.InsertOne(session, document); - collection4.InsertOne(session, new BsonDocument { { "name", "MongoDB" } }); - - session.AbortTransaction(); - } - var filter = new BsonDocument("name", "MongoDB"); - collection.CountDocuments(filter).Should().Be(0); - collection4.CountDocuments(filter).Should().Be(0); - } - } -} diff --git a/test/DotNetCore.CAP.PostgreSql.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.PostgreSql.Test/ConnectionUtil.cs deleted file mode 100644 index b293529..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/ConnectionUtil.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Npgsql; - -namespace DotNetCore.CAP.PostgreSql.Test -{ - public static class ConnectionUtil - { - private const string DatabaseVariable = "Cap_PostgreSql_DatabaseName"; - private const string ConnectionStringTemplateVariable = "Cap_PostgreSql_ConnectionStringTemplate"; - - private const string MasterDatabaseName = "postgres"; - private const string DefaultDatabaseName = @"DotNetCore.CAP.PostgreSql.Test"; - - private const string DefaultConnectionStringTemplate = - @"Server=localhost;Database={0};UserId=postgres;Password=123123;"; - - public static string GetDatabaseName() - { - return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName; - } - - public static string GetMasterConnectionString() - { - return string.Format(GetConnectionStringTemplate(), MasterDatabaseName); - } - - public static string GetConnectionString() - { - return string.Format(GetConnectionStringTemplate(), GetDatabaseName()); - } - - private static string GetConnectionStringTemplate() - { - return - Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ?? - DefaultConnectionStringTemplate; - } - - public static NpgsqlConnection CreateConnection(string connectionString = null) - { - connectionString = connectionString ?? GetConnectionString(); - var connection = new NpgsqlConnection(connectionString); - connection.Open(); - return connection; - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.PostgreSql.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.PostgreSql.Test/DatabaseTestHost.cs deleted file mode 100644 index ec59a74..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/DatabaseTestHost.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Threading; -using Dapper; -using Microsoft.EntityFrameworkCore; - -namespace DotNetCore.CAP.PostgreSql.Test -{ - public abstract class DatabaseTestHost : TestHost - { - private static bool _sqlObjectInstalled; - public static object _lock = new object(); - - protected override void PostBuildServices() - { - base.PostBuildServices(); - lock (_lock) - { - if (!_sqlObjectInstalled) - { - InitializeDatabase(); - } - } - } - - public override void Dispose() - { - DeleteAllData(); - base.Dispose(); - } - - private void InitializeDatabase() - { - using (CreateScope()) - { - var storage = GetService(); - var token = new CancellationTokenSource().Token; - CreateDatabase(); - storage.InitializeAsync(token).GetAwaiter().GetResult(); - _sqlObjectInstalled = true; - } - } - - private void CreateDatabase() - { - var masterConn = ConnectionUtil.GetMasterConnectionString(); - var databaseName = ConnectionUtil.GetDatabaseName(); - using (var connection = ConnectionUtil.CreateConnection(masterConn)) - { - connection.Execute($@" -DROP DATABASE IF EXISTS ""{databaseName}""; -CREATE DATABASE ""{databaseName}"";"); - } - } - - private void DeleteAllData() - { - var conn = ConnectionUtil.GetConnectionString(); - - using (var connection = ConnectionUtil.CreateConnection(conn)) - { - connection.Execute($@" -TRUNCATE TABLE ""cap"".""published""; -TRUNCATE TABLE ""cap"".""received"";"); - } - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj b/test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj deleted file mode 100644 index 3fafd7c..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/DotNetCore.CAP.PostgreSql.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netcoreapp2.1 - false - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - diff --git a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs b/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs deleted file mode 100644 index 323f16d..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageConnectionTest.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Microsoft.Extensions.Options; -using Xunit; - -namespace DotNetCore.CAP.PostgreSql.Test -{ - [Collection("postgresql")] - public class PostgreSqlStorageConnectionTest : DatabaseTestHost - { - private PostgreSqlStorageConnection _storage; - - public PostgreSqlStorageConnectionTest() - { - var options = GetService>(); - var capOptions = GetService>(); - _storage = new PostgreSqlStorageConnection(options, capOptions); - } - - [Fact] - public async Task GetPublishedMessageAsync_Test() - { - var sql = @"INSERT INTO ""cap"".""published""(""Id"",""Version"",""Name"",""Content"",""Retries"",""Added"",""ExpiresAt"",""StatusName"") VALUES(@Id,'v1',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var publishMessage = new CapPublishedMessage - { - Id = insertedId, - Name = "PostgreSqlStorageConnectionTest", - Content = "", - StatusName = StatusName.Scheduled - }; - using (var connection = ConnectionUtil.CreateConnection()) - { - await connection.ExecuteAsync(sql, publishMessage); - } - var message = await _storage.GetPublishedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal("PostgreSqlStorageConnectionTest", message.Name); - Assert.Equal(StatusName.Scheduled, message.StatusName); - } - - [Fact] - public void StoreReceivedMessageAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Id = SnowflakeId.Default().NextId(), - Name = "PostgreSqlStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - - Exception exception = null; - try - { - _storage.StoreReceivedMessage(receivedMessage); - } - catch (Exception ex) - { - exception = ex; - } - Assert.Null(exception); - } - - [Fact] - public async Task GetReceivedMessageAsync_Test() - { - var sql = $@" - INSERT INTO ""cap"".""received""(""Id"",""Version"",""Name"",""Group"",""Content"",""Retries"",""Added"",""ExpiresAt"",""StatusName"") - VALUES(@Id,'v1',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var receivedMessage = new CapReceivedMessage - { - Id = insertedId, - Name = "PostgreSqlStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - - using (var connection = ConnectionUtil.CreateConnection()) - { - await connection.ExecuteAsync(sql, receivedMessage); - } - - var message = await _storage.GetReceivedMessageAsync(insertedId); - - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("PostgreSqlStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageTest.cs b/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageTest.cs deleted file mode 100644 index 4bf1d77..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/PostgreSqlStorageTest.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Dapper; -using Xunit; - -namespace DotNetCore.CAP.PostgreSql.Test -{ - [Collection("postgresql")] - public class SqlServerStorageTest : DatabaseTestHost - { - private readonly string _masterDbConnectionString; - private readonly string _dbConnectionString; - - public SqlServerStorageTest() - { - _masterDbConnectionString = ConnectionUtil.GetMasterConnectionString(); - _dbConnectionString = ConnectionUtil.GetConnectionString(); - } - - [Fact] - public void Database_IsExists() - { - using (var connection = ConnectionUtil.CreateConnection(_masterDbConnectionString)) - { - var databaseName = ConnectionUtil.GetDatabaseName(); - var sql = $@"select * from pg_database where datname = '{databaseName}'"; - var result = connection.QueryFirstOrDefault(sql); - Assert.NotNull(result); - Assert.True(databaseName.Equals(result, System.StringComparison.CurrentCultureIgnoreCase)); - } - } - - [Theory] - [InlineData("cap.published")] - [InlineData("cap.received")] - public void DatabaseTable_IsExists(string tableName) - { - using (var connection = ConnectionUtil.CreateConnection(_dbConnectionString)) - { - var sql = $"SELECT to_regclass('{tableName}') is not null;"; - var result = connection.QueryFirstOrDefault(sql); - Assert.True(result); - } - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.PostgreSql.Test/TestHost.cs b/test/DotNetCore.CAP.PostgreSql.Test/TestHost.cs deleted file mode 100644 index 7c6df65..0000000 --- a/test/DotNetCore.CAP.PostgreSql.Test/TestHost.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace DotNetCore.CAP.PostgreSql.Test -{ - public abstract class TestHost : IDisposable - { - protected IServiceCollection _services; - protected string _connectionString; - private IServiceProvider _provider; - private IServiceProvider _scopedProvider; - - public TestHost() - { - CreateServiceCollection(); - PreBuildServices(); - BuildServices(); - PostBuildServices(); - } - - protected IServiceProvider Provider => _scopedProvider ?? _provider; - - private void CreateServiceCollection() - { - var services = new ServiceCollection(); - - services.AddOptions(); - services.AddLogging(); - - _connectionString = ConnectionUtil.GetConnectionString(); - - services.AddOptions(); - services.Configure(x => x.ConnectionString = _connectionString); - services.AddSingleton(); - - _services = services; - } - - protected virtual void PreBuildServices() - { - } - - private void BuildServices() - { - _provider = _services.BuildServiceProvider(); - } - - protected virtual void PostBuildServices() - { - } - - public IDisposable CreateScope() - { - var scope = CreateScope(_provider); - var loc = scope.ServiceProvider; - _scopedProvider = loc; - return new DelegateDisposable(() => - { - if (_scopedProvider == loc) - { - _scopedProvider = null; - } - scope.Dispose(); - }); - } - - public IServiceScope CreateScope(IServiceProvider provider) - { - var scope = provider.GetService().CreateScope(); - return scope; - } - - public T GetService() => Provider.GetService(); - - public T Ensure(ref T service) - where T : class - => service ?? (service = GetService()); - - public virtual void Dispose() - { - (_provider as IDisposable)?.Dispose(); - } - - private class DelegateDisposable : IDisposable - { - private Action _dispose; - - public DelegateDisposable(Action dispose) - { - _dispose = dispose; - } - - public void Dispose() - { - _dispose(); - } - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs b/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs deleted file mode 100644 index 93e45d1..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/ConnectionUtil.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Data.SqlClient; - -namespace DotNetCore.CAP.SqlServer.Test -{ - public static class ConnectionUtil - { - private const string DatabaseVariable = "Cap_SqlServer_DatabaseName"; - private const string ConnectionStringTemplateVariable = "Cap_SqlServer_ConnectionStringTemplate"; - - private const string MasterDatabaseName = "master"; - private const string DefaultDatabaseName = @"DotNetCore.CAP.SqlServer.Test"; - - private const string DefaultConnectionStringTemplate = - @"Server=192.168.2.206;Initial Catalog={0};User Id=sa;Password=123123;MultipleActiveResultSets=True"; - - public static string GetDatabaseName() - { - return Environment.GetEnvironmentVariable(DatabaseVariable) ?? DefaultDatabaseName; - } - - public static string GetMasterConnectionString() - { - return string.Format(GetConnectionStringTemplate(), MasterDatabaseName); - } - - public static string GetConnectionString() - { - return string.Format(GetConnectionStringTemplate(), GetDatabaseName()); - } - - private static string GetConnectionStringTemplate() - { - return - Environment.GetEnvironmentVariable(ConnectionStringTemplateVariable) ?? - DefaultConnectionStringTemplate; - } - - public static SqlConnection CreateConnection(string connectionString = null) - { - connectionString = connectionString ?? GetConnectionString(); - var connection = new SqlConnection(connectionString); - connection.Open(); - return connection; - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs b/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs deleted file mode 100644 index 4e2e5d7..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/DatabaseTestHost.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Data; -using System.Data.SqlClient; -using Dapper; -using DotNetCore.CAP.SqlServer.Diagnostics; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Moq; - -namespace DotNetCore.CAP.SqlServer.Test -{ - public abstract class DatabaseTestHost : IDisposable - { - protected ILogger Logger; - protected IOptions CapOptions; - protected IOptions SqlSeverOptions; - protected DiagnosticProcessorObserver DiagnosticProcessorObserver; - - public bool SqlObjectInstalled; - - protected DatabaseTestHost() - { - Logger = new Mock>().Object; - - var capOptions = new Mock>(); - capOptions.Setup(x => x.Value).Returns(new CapOptions()); - CapOptions = capOptions.Object; - - var options = new Mock>(); - options.Setup(x => x.Value).Returns(new SqlServerOptions { ConnectionString = ConnectionUtil.GetConnectionString() }); - SqlSeverOptions = options.Object; - - DiagnosticProcessorObserver = new DiagnosticProcessorObserver(new Mock().Object); - - InitializeDatabase(); - } - - public void Dispose() - { - DeleteAllData(); - } - - private void InitializeDatabase() - { - var masterConn = ConnectionUtil.GetMasterConnectionString(); - var databaseName = ConnectionUtil.GetDatabaseName(); - using (var connection = ConnectionUtil.CreateConnection(masterConn)) - { - connection.Execute($@" -IF NOT EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') -CREATE DATABASE [{databaseName}];"); - } - - new SqlServerStorage(Logger, CapOptions, SqlSeverOptions, DiagnosticProcessorObserver).InitializeAsync().GetAwaiter().GetResult(); - SqlObjectInstalled = true; - } - - - private void DeleteAllData() - { - var conn = ConnectionUtil.GetConnectionString(); - using (var connection = new SqlConnection(conn)) - { - var commands = new[] { - "DISABLE TRIGGER ALL ON ?", - "ALTER TABLE ? NOCHECK CONSTRAINT ALL", - "DELETE FROM ?", - "ALTER TABLE ? CHECK CONSTRAINT ALL", - "ENABLE TRIGGER ALL ON ?" - }; - - foreach (var command in commands) - { - connection.Execute( - "sp_MSforeachtable", - new { command1 = command }, - commandType: CommandType.StoredProcedure); - } - } - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj b/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj deleted file mode 100644 index 9f954b0..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/DotNetCore.CAP.SqlServer.Test.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - netcoreapp2.1 - false - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - - - - - - diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs deleted file mode 100644 index b019a18..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageConnectionTest.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Threading.Tasks; -using Dapper; -using DotNetCore.CAP.Infrastructure; -using DotNetCore.CAP.Messages; -using Xunit; - -namespace DotNetCore.CAP.SqlServer.Test -{ - [Collection("sqlserver")] - public class SqlServerStorageConnectionTest : DatabaseTestHost - { - private readonly SqlServerStorageConnection _storage; - - public SqlServerStorageConnectionTest() - { - _storage = new SqlServerStorageConnection(SqlSeverOptions, CapOptions); - } - - [Fact] - public async Task GetPublishedMessageAsync_Test() - { - var sql = "INSERT INTO [Cap].[Published]([Id],[Version],[Name],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) VALUES(@Id,'v1',@Name,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var publishMessage = new CapPublishedMessage - { - Id= insertedId, - Name = "SqlServerStorageConnectionTest", - Content = "", - StatusName = StatusName.Scheduled - }; - - using (var connection = ConnectionUtil.CreateConnection()) - { - await connection.ExecuteAsync(sql, publishMessage); - } - - var message = await _storage.GetPublishedMessageAsync(insertedId); - Assert.NotNull(message); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal(StatusName.Scheduled, message.StatusName); - } - - [Fact] - public void StoreReceivedMessageAsync_Test() - { - var receivedMessage = new CapReceivedMessage - { - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - - Exception exception = null; - try - { - _storage.StoreReceivedMessage(receivedMessage); - } - catch (Exception ex) - { - exception = ex; - } - Assert.Null(exception); - } - - [Fact] - public async Task GetReceivedMessageAsync_Test() - { - var sql = @"INSERT INTO [Cap].[Received]([Id],[Version],[Name],[Group],[Content],[Retries],[Added],[ExpiresAt],[StatusName]) VALUES(@Id,'v1',@Name,@Group,@Content,@Retries,@Added,@ExpiresAt,@StatusName);"; - var insertedId = SnowflakeId.Default().NextId(); - var receivedMessage = new CapReceivedMessage - { - Id= insertedId, - Name = "SqlServerStorageConnectionTest", - Content = "", - Group = "mygroup", - StatusName = StatusName.Scheduled - }; - - using (var connection = ConnectionUtil.CreateConnection()) - { - await connection.ExecuteAsync(sql, receivedMessage); - } - - var message = await _storage.GetReceivedMessageAsync(insertedId); - - Assert.NotNull(message); - Assert.Equal(StatusName.Scheduled, message.StatusName); - Assert.Equal("SqlServerStorageConnectionTest", message.Name); - Assert.Equal("mygroup", message.Group); - } - } -} \ No newline at end of file diff --git a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs b/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs deleted file mode 100644 index 427ed30..0000000 --- a/test/DotNetCore.CAP.SqlServer.Test/SqlServerStorageTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Dapper; -using Xunit; - -namespace DotNetCore.CAP.SqlServer.Test -{ - [Collection("sqlserver")] - public class SqlServerStorageTest : DatabaseTestHost - { - [Fact] - public void Database_IsExists() - { - var master = ConnectionUtil.GetMasterConnectionString(); - using (var connection = ConnectionUtil.CreateConnection(master)) - { - var databaseName = ConnectionUtil.GetDatabaseName(); - var sql = $@" -IF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{databaseName}') -SELECT 'True' -ELSE -SELECT 'False'"; - var result = connection.QueryFirst(sql); - Assert.True(result); - } - } - - [Theory] - [InlineData("[Cap].[Published]")] - [InlineData("[Cap].[Received]")] - public void DatabaseTable_IsExists(string tableName) - { - using (var connection = ConnectionUtil.CreateConnection()) - { - var sql = $@" -IF OBJECT_ID(N'{tableName}',N'U') IS NOT NULL -SELECT 'True' -ELSE -SELECT 'False'"; - var result = connection.QueryFirst(sql); - Assert.True(result); - } - } - } -} \ No newline at end of file From e0769632d8903509d6e5d18e4b04aa757ee05211 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Tue, 10 Dec 2019 21:29:44 +0800 Subject: [PATCH 68/76] fix build error --- test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj index e3d1d65..411962e 100644 --- a/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj +++ b/test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp3.0 false @@ -9,12 +9,10 @@ - - - all - runtime; build; native; contentfiles; analyzers - - + + + + From c08808c126d1a6a85f0c5aa3078c1b5d8b9bf20d Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 09:58:58 +0800 Subject: [PATCH 69/76] upgrade mongo nuget package to 2.10.0, because 2.8.0 have bugs in .net core 3.0 --- src/Directory.Build.props | 2 +- src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2806959..96e0e60 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -23,7 +23,7 @@ - + \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj b/src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj index 2630f85..b50ada1 100644 --- a/src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj +++ b/src/DotNetCore.CAP.MongoDB/DotNetCore.CAP.MongoDB.csproj @@ -16,8 +16,8 @@ - - + + From 24dcba902b06c2dd59618fb5af497e7d399e6dd6 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 09:59:11 +0800 Subject: [PATCH 70/76] Fix mongodb dashboard query bugs --- .../IClientSessionHandle.CAP.cs | 13 ++++++++++++- src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs | 4 ++-- .../IMonitoringApi.MongoDB.cs | 14 +++++++------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs b/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs index 82e5dce..177fb00 100644 --- a/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs +++ b/src/DotNetCore.CAP.MongoDB/IClientSessionHandle.CAP.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using System.Threading; using System.Threading.Tasks; using DotNetCore.CAP; @@ -18,7 +19,7 @@ namespace MongoDB.Driver public CapMongoDbClientSessionHandle(ICapTransaction transaction) { _transaction = transaction; - _sessionHandle = (IClientSessionHandle) _transaction.DbTransaction; + _sessionHandle = (IClientSessionHandle)_transaction.DbTransaction; } public void Dispose() @@ -76,5 +77,15 @@ namespace MongoDB.Driver { return _sessionHandle.Fork(); } + + public TResult WithTransaction(Func callback, TransactionOptions transactionOptions = null, CancellationToken cancellationToken = default) + { + return _sessionHandle.WithTransaction(callback, transactionOptions, cancellationToken); + } + + public Task WithTransactionAsync(Func> callbackAsync, TransactionOptions transactionOptions = null, CancellationToken cancellationToken = default) + { + return _sessionHandle.WithTransactionAsync(callbackAsync, transactionOptions, cancellationToken); + } } } \ No newline at end of file diff --git a/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs index dfa108e..e0de7ad 100644 --- a/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IDataStorage.MongoDB.cs @@ -52,7 +52,7 @@ namespace DotNetCore.CAP.MongoDB public async Task ChangeReceiveStateAsync(MediumMessage message, StatusName state) { - var collection = _database.GetCollection(_options.Value.PublishedCollection); + var collection = _database.GetCollection(_options.Value.ReceivedCollection); var updateDef = Builders.Update .Set(x => x.Retries, message.Retries) @@ -161,7 +161,7 @@ namespace DotNetCore.CAP.MongoDB { if (collection == _options.Value.PublishedCollection) { - Builders.Filter.Lt(x => x.ExpiresAt, timeout); + //Builders.Filter.Lt(x => x.ExpiresAt, timeout); var publishedCollection = _database.GetCollection(_options.Value.PublishedCollection); var ret = await publishedCollection.DeleteManyAsync(x => x.ExpiresAt < timeout, cancellationToken); diff --git a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs index 532c90e..0b7383f 100644 --- a/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs +++ b/src/DotNetCore.CAP.MongoDB/IMonitoringApi.MongoDB.cs @@ -63,12 +63,12 @@ namespace DotNetCore.CAP.MongoDB var statistics = new StatisticsDto { PublishedSucceeded = - (int) publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), + (int)publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), PublishedFailed = - (int) publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)), + (int)publishedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)), ReceivedSucceeded = - (int) receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), - ReceivedFailed = (int) receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)) + (int)receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Succeeded)), + ReceivedFailed = (int)receivedCollection.CountDocuments(x => x.StatusName == nameof(StatusName.Failed)) }; return statistics; } @@ -93,7 +93,7 @@ namespace DotNetCore.CAP.MongoDB var builder = Builders.Filter; var filter = builder.Empty; if (!string.IsNullOrEmpty(queryDto.StatusName)) - filter &= builder.Eq(x => x.StatusName, queryDto.StatusName); + filter &= builder.Where(x => x.StatusName.ToLower() == queryDto.StatusName); if (!string.IsNullOrEmpty(queryDto.Name)) filter &= builder.Eq(x => x.Name, queryDto.Name); @@ -135,7 +135,7 @@ namespace DotNetCore.CAP.MongoDB private int GetNumberOfMessage(string collectionName, string statusName) { var collection = _database.GetCollection(collectionName); - var count = collection.CountDocuments(new BsonDocument {{"StatusName", statusName}}); + var count = collection.CountDocuments(new BsonDocument { { "StatusName", statusName } }); return int.Parse(count.ToString()); } @@ -194,7 +194,7 @@ namespace DotNetCore.CAP.MongoDB } }; - var pipeline = new[] {match, groupby}; + var pipeline = new[] { match, groupby }; var collection = _database.GetCollection(collectionName); var result = collection.Aggregate(pipeline).ToList(); From 99c12441cb501aaf62e170e66a3d024db1ea4a42 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 10:23:37 +0800 Subject: [PATCH 71/76] update samples --- CAP.sln | 14 +++++++------- .../Controllers/ValuesController.cs | 6 +++--- .../Program.cs | 5 ++--- .../Sample.Kafka.PostgreSql.csproj} | 2 +- .../Startup.cs | 2 +- .../appsettings.json | 0 6 files changed, 14 insertions(+), 15 deletions(-) rename samples/{Sample.Kafka.MySql => Sample.Kafka.PostgreSql}/Controllers/ValuesController.cs (91%) rename samples/{Sample.Kafka.MySql => Sample.Kafka.PostgreSql}/Program.cs (82%) rename samples/{Sample.Kafka.MySql/Sample.Kafka.MySql.csproj => Sample.Kafka.PostgreSql/Sample.Kafka.PostgreSql.csproj} (83%) rename samples/{Sample.Kafka.MySql => Sample.Kafka.PostgreSql}/Startup.cs (86%) rename samples/{Sample.Kafka.MySql => Sample.Kafka.PostgreSql}/appsettings.json (100%) diff --git a/CAP.sln b/CAP.sln index 4bab9bb..453b459 100644 --- a/CAP.sln +++ b/CAP.sln @@ -54,8 +54,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.MongoDB", "s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RabbitMQ.MongoDB", "samples\Sample.RabbitMQ.MongoDB\Sample.RabbitMQ.MongoDB.csproj", "{4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka.MySql", "samples\Sample.Kafka.MySql\Sample.Kafka.MySql.csproj", "{11563D1A-27CC-45CF-8C04-C16BCC21250A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.AzureServiceBus", "src\DotNetCore.CAP.AzureServiceBus\DotNetCore.CAP.AzureServiceBus.csproj", "{63B2A464-FBEA-42FB-8EFA-98AFA39FC920}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCore.CAP.InMemoryStorage", "src\DotNetCore.CAP.InMemoryStorage\DotNetCore.CAP.InMemoryStorage.csproj", "{58B6E829-C6C8-457C-9DD0-C600650254DF}" @@ -66,6 +64,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka.InMemory", "sa EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.RabbitMQ.SqlServer", "samples\Sample.RabbitMQ.SqlServer\Sample.RabbitMQ.SqlServer.csproj", "{F6C5C676-AF05-46D5-A45D-442137B31898}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Kafka.PostgreSql", "samples\Sample.Kafka.PostgreSql\Sample.Kafka.PostgreSql.csproj", "{F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -115,10 +115,6 @@ Global {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F}.Release|Any CPU.Build.0 = Release|Any CPU - {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {11563D1A-27CC-45CF-8C04-C16BCC21250A}.Release|Any CPU.Build.0 = Release|Any CPU {63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Debug|Any CPU.Build.0 = Debug|Any CPU {63B2A464-FBEA-42FB-8EFA-98AFA39FC920}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -139,6 +135,10 @@ Global {F6C5C676-AF05-46D5-A45D-442137B31898}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6C5C676-AF05-46D5-A45D-442137B31898}.Release|Any CPU.Build.0 = Release|Any CPU + {F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1EF1D26-8A6B-403E-85B0-250DF44A4A7C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -155,12 +155,12 @@ Global {82C403AB-ED68-4084-9A1D-11334F9F08F9} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {77C0AC02-C44B-49D5-B969-7D5305FC20A5} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {4473DE19-E8D2-4B57-80A8-C8AAA2BFA20F} = {3A6B6931-A123-477A-9469-8B468B5385AF} - {11563D1A-27CC-45CF-8C04-C16BCC21250A} = {3A6B6931-A123-477A-9469-8B468B5385AF} {63B2A464-FBEA-42FB-8EFA-98AFA39FC920} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {58B6E829-C6C8-457C-9DD0-C600650254DF} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {56FB261C-67AF-4715-9A46-4FA4FAB91B2C} = {9B2AE124-6636-4DE9-83A3-70360DABD0C4} {1B0371D6-36A4-4C78-A727-8ED732FDBA1D} = {3A6B6931-A123-477A-9469-8B468B5385AF} {F6C5C676-AF05-46D5-A45D-442137B31898} = {3A6B6931-A123-477A-9469-8B468B5385AF} + {F1EF1D26-8A6B-403E-85B0-250DF44A4A7C} = {3A6B6931-A123-477A-9469-8B468B5385AF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2E70565D-94CF-40B4-BFE1-AC18D5F736AB} diff --git a/samples/Sample.Kafka.MySql/Controllers/ValuesController.cs b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs similarity index 91% rename from samples/Sample.Kafka.MySql/Controllers/ValuesController.cs rename to samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs index 1b935bd..3ba48cc 100644 --- a/samples/Sample.Kafka.MySql/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs @@ -4,9 +4,9 @@ using System.Threading.Tasks; using Dapper; using DotNetCore.CAP; using Microsoft.AspNetCore.Mvc; -using MySql.Data.MySqlClient; +using Npgsql; -namespace Sample.Kafka.MySql.Controllers +namespace Sample.Kafka.PostgreSql.Controllers { [Route("api/[controller]")] public class ValuesController : Controller, ICapSubscribe @@ -29,7 +29,7 @@ namespace Sample.Kafka.MySql.Controllers [Route("~/adonet/transaction")] public IActionResult AdonetWithTransaction() { - using (var connection = new MySqlConnection("")) + using (var connection = new NpgsqlConnection("")) { using (var transaction = connection.BeginTransaction(_capBus, autoCommit: false)) { diff --git a/samples/Sample.Kafka.MySql/Program.cs b/samples/Sample.Kafka.PostgreSql/Program.cs similarity index 82% rename from samples/Sample.Kafka.MySql/Program.cs rename to samples/Sample.Kafka.PostgreSql/Program.cs index d9a19a6..80800d1 100644 --- a/samples/Sample.Kafka.MySql/Program.cs +++ b/samples/Sample.Kafka.PostgreSql/Program.cs @@ -1,8 +1,7 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -namespace Sample.Kafka.MySql +namespace Sample.Kafka.PostgreSql { public class Program { diff --git a/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj b/samples/Sample.Kafka.PostgreSql/Sample.Kafka.PostgreSql.csproj similarity index 83% rename from samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj rename to samples/Sample.Kafka.PostgreSql/Sample.Kafka.PostgreSql.csproj index bf42fb7..701ab23 100644 --- a/samples/Sample.Kafka.MySql/Sample.Kafka.MySql.csproj +++ b/samples/Sample.Kafka.PostgreSql/Sample.Kafka.PostgreSql.csproj @@ -9,7 +9,7 @@ - + diff --git a/samples/Sample.Kafka.MySql/Startup.cs b/samples/Sample.Kafka.PostgreSql/Startup.cs similarity index 86% rename from samples/Sample.Kafka.MySql/Startup.cs rename to samples/Sample.Kafka.PostgreSql/Startup.cs index edaf074..5bda514 100644 --- a/samples/Sample.Kafka.MySql/Startup.cs +++ b/samples/Sample.Kafka.PostgreSql/Startup.cs @@ -10,7 +10,7 @@ namespace Sample.Kafka.MySql { services.AddCap(x => { - x.UseMySql("Server=localhost;Database=testcap;UserId=root;Password=123123;"); + x.UsePostgreSql("Server=localhost;Database=testcap;UserId=root;Password=123123;"); x.UseKafka("localhost:9092"); x.UseDashboard(); }); diff --git a/samples/Sample.Kafka.MySql/appsettings.json b/samples/Sample.Kafka.PostgreSql/appsettings.json similarity index 100% rename from samples/Sample.Kafka.MySql/appsettings.json rename to samples/Sample.Kafka.PostgreSql/appsettings.json From 801b37407972103d11315097e2944e47262a7b26 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 10:57:48 +0800 Subject: [PATCH 72/76] Fix postgresql storage bugs --- .../Controllers/ValuesController.cs | 11 ++++------- samples/Sample.Kafka.PostgreSql/Startup.cs | 9 ++++----- .../IDataStorage.PostgreSql.cs | 14 +++++++------- .../IStorageInitializer.PostgreSql.cs | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs index 3ba48cc..7b8f33c 100644 --- a/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs +++ b/samples/Sample.Kafka.PostgreSql/Controllers/ValuesController.cs @@ -21,7 +21,7 @@ namespace Sample.Kafka.PostgreSql.Controllers [Route("~/without/transaction")] public async Task WithoutTransaction() { - await _capBus.PublishAsync("sample.rabbitmq.mysql", DateTime.Now); + await _capBus.PublishAsync("sample.kafka.postgrsql", DateTime.Now); return Ok(); } @@ -36,10 +36,7 @@ namespace Sample.Kafka.PostgreSql.Controllers //your business code connection.Execute("insert into test(name) values('test')", transaction: (IDbTransaction)transaction.DbTransaction); - for (int i = 0; i < 5; i++) - { - _capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); - } + _capBus.Publish("sample.kafka.postgrsql", DateTime.Now); transaction.Commit(); } @@ -49,8 +46,8 @@ namespace Sample.Kafka.PostgreSql.Controllers } - [CapSubscribe("#.test2")] - public void Test2(int value) + [CapSubscribe("sample.kafka.postgrsql")] + public void Test2(DateTime value) { Console.WriteLine("Subscriber output message: " + value); } diff --git a/samples/Sample.Kafka.PostgreSql/Startup.cs b/samples/Sample.Kafka.PostgreSql/Startup.cs index 5bda514..c47ce69 100644 --- a/samples/Sample.Kafka.PostgreSql/Startup.cs +++ b/samples/Sample.Kafka.PostgreSql/Startup.cs @@ -1,8 +1,7 @@ -using System; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -namespace Sample.Kafka.MySql +namespace Sample.Kafka.PostgreSql { public class Startup { @@ -10,8 +9,8 @@ namespace Sample.Kafka.MySql { services.AddCap(x => { - x.UsePostgreSql("Server=localhost;Database=testcap;UserId=root;Password=123123;"); - x.UseKafka("localhost:9092"); + x.UsePostgreSql(""); + x.UseKafka(""); x.UseDashboard(); }); diff --git a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs index d4204e3..cd3710b 100644 --- a/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IDataStorage.PostgreSql.cs @@ -45,7 +45,7 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { - Id = message.DbId, + Id = long.Parse(message.DbId), message.Retries, message.ExpiresAt, StatusName = state.ToString("G") @@ -59,7 +59,7 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { - Id = message.DbId, + Id = long.Parse(message.DbId), message.Retries, message.ExpiresAt, StatusName = state.ToString("G") @@ -85,13 +85,13 @@ namespace DotNetCore.CAP.PostgreSql var po = new { - Id = message.DbId, + Id = long.Parse(message.DbId), Name = name, message.Content, message.Retries, message.Added, message.ExpiresAt, - StatusName = StatusName.Scheduled + StatusName = nameof(StatusName.Scheduled) }; if (dbTransaction == null) @@ -121,7 +121,7 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { - Id = SnowflakeId.Default().NextId().ToString(), + Id = SnowflakeId.Default().NextId(), Group = group, Name = name, Content = content, @@ -150,7 +150,7 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); await connection.ExecuteAsync(sql, new { - Id = mdMessage.DbId, + Id = long.Parse(mdMessage.DbId), Group = group, Name = name, Content = content, @@ -168,7 +168,7 @@ namespace DotNetCore.CAP.PostgreSql await using var connection = new NpgsqlConnection(_options.Value.ConnectionString); return await connection.ExecuteAsync( - $"DELETE FROM {table} WHERE \"ExpiresAt\" < @now AND \"Id\" IN (SELECT \"Id\" FROM {table} LIMIT @count);", + $"DELETE FROM {table} WHERE \"ExpiresAt\" < @timeout AND \"Id\" IN (SELECT \"Id\" FROM {table} LIMIT @batchCount);", new { timeout, batchCount }); } diff --git a/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs index ad494c9..f8e8ba0 100644 --- a/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs +++ b/src/DotNetCore.CAP.PostgreSql/IStorageInitializer.PostgreSql.cs @@ -53,7 +53,7 @@ namespace DotNetCore.CAP.PostgreSql var batchSql = $@" CREATE SCHEMA IF NOT EXISTS ""{schema}""; -CREATE TABLE IF NOT EXISTS {GetPublishedTableName()}( +CREATE TABLE IF NOT EXISTS {GetReceivedTableName()}( ""Id"" BIGINT PRIMARY KEY NOT NULL, ""Version"" VARCHAR(20) NOT NULL, ""Name"" VARCHAR(200) NOT NULL, @@ -65,7 +65,7 @@ CREATE TABLE IF NOT EXISTS {GetPublishedTableName()}( ""StatusName"" VARCHAR(50) NOT NULL ); -CREATE TABLE IF NOT EXISTS {GetReceivedTableName()}( +CREATE TABLE IF NOT EXISTS {GetPublishedTableName()}( ""Id"" BIGINT PRIMARY KEY NOT NULL, ""Version"" VARCHAR(20) NOT NULL, ""Name"" VARCHAR(200) NOT NULL, From 04a42619ac298c02154bbee8037bfc7c648ecaa0 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 11:15:07 +0800 Subject: [PATCH 73/76] Fix build error --- .../LocalRequestsOnlyAuthorizationFilter.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs b/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs index 0a26fad..6de19e6 100644 --- a/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs +++ b/src/DotNetCore.CAP.Dashboard/LocalRequestsOnlyAuthorizationFilter.cs @@ -1,40 +1,41 @@ // Copyright (c) .NET Core Community. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System.Threading.Tasks; using DotNetCore.CAP.Internal; namespace DotNetCore.CAP.Dashboard { public class LocalRequestsOnlyAuthorizationFilter : IDashboardAuthorizationFilter { - public bool Authorize(DashboardContext context) + public Task AuthorizeAsync(DashboardContext context) { var ipAddress = context.Request.RemoteIpAddress; // if unknown, assume not local if (string.IsNullOrEmpty(ipAddress)) { - return false; + return Task.FromResult(false); } // check if localhost if (ipAddress == "127.0.0.1" || ipAddress == "0.0.0.1") { - return true; + return Task.FromResult(true); } // compare with local address if (ipAddress == context.Request.LocalIpAddress) { - return true; + return Task.FromResult(true); } // check if private ip if (Helper.IsInnerIP(ipAddress)) { - return true; + return Task.FromResult(true); } - return false; + return Task.FromResult(false); } } } \ No newline at end of file From cf3829993b0c17eb404ecad99822ca333b17da37 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 11:20:22 +0800 Subject: [PATCH 74/76] Fix unit tests --- src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs index ecfe5b3..3dda14c 100644 --- a/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs +++ b/src/DotNetCore.CAP/Internal/IConsumerServiceSelector.Default.cs @@ -166,7 +166,7 @@ namespace DotNetCore.CAP.Internal private ConsumerExecutorDescriptor MatchUsingName(string key, IReadOnlyList executeDescriptor) { - return executeDescriptor.FirstOrDefault(x => x.Attribute.Name == key); + return executeDescriptor.FirstOrDefault(x => x.Attribute.Name.Equals(key, StringComparison.InvariantCultureIgnoreCase)); } private ConsumerExecutorDescriptor MatchAsteriskUsingRegex(string key, IReadOnlyList executeDescriptor) From d2093f3c74759514d86da2e60fdf89db1ec84ab1 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 11:31:44 +0800 Subject: [PATCH 75/76] Fix build errorFix unit tests --- .../ConsumerServiceSelectorTest.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs index c84bb64..5f5fd62 100644 --- a/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs +++ b/test/DotNetCore.CAP.Test/ConsumerServiceSelectorTest.cs @@ -63,7 +63,6 @@ namespace DotNetCore.CAP.Test [InlineData("Candidates.Asterisk.AAA")] [InlineData("AAA.BBB.CCC.Asterisk")] [InlineData("aaa.BBB.ccc.Asterisk")] - [InlineData("Asterisk.aaa.bbb")] public void CanNotFindAsteriskTopic(string topic) { var selector = _provider.GetRequiredService(); @@ -73,6 +72,17 @@ namespace DotNetCore.CAP.Test Assert.Null(bestCandidates); } + [Theory] + [InlineData("Asterisk.aaa.bbb")] + public void CanNotFindAsteriskTopic2(string topic) + { + var selector = _provider.GetRequiredService(); + var candidates = selector.SelectCandidates(); + + var bestCandidates = selector.SelectBestCandidate(topic, candidates); + Assert.Null(bestCandidates); + } + [Theory] [InlineData("Candidates.Pound.AAA")] [InlineData("Candidates.Pound.AAA.BBB")] From e15f518532f2a7bd21335324717463b0b2c71c00 Mon Sep 17 00:00:00 2001 From: Savorboard Date: Thu, 12 Dec 2019 12:02:47 +0800 Subject: [PATCH 76/76] Add Kafka options to support custom header to add offset and partition into CapHeader. #374 --- src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs | 6 ++++++ src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs index 97d3f66..9247576 100644 --- a/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs +++ b/src/DotNetCore.CAP.Kafka/CAP.KafkaOptions.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using Confluent.Kafka; // ReSharper disable once CheckNamespace namespace DotNetCore.CAP @@ -43,6 +44,11 @@ namespace DotNetCore.CAP /// public string Servers { get; set; } + /// + /// If you need to get offset and partition and so on.., you can use this function to write additional header into + /// + public Func, List>> CustomHeaders { get; set; } + internal IEnumerable> AsKafkaConfig() { if (_kafkaConfig == null) diff --git a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs index eeecd80..afad455 100644 --- a/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs +++ b/src/DotNetCore.CAP.Kafka/KafkaConsumerClient.cs @@ -62,6 +62,15 @@ namespace DotNetCore.CAP.Kafka } headers.Add(Messages.Headers.Group, _groupId); + if (_kafkaOptions.CustomHeaders != null) + { + var customHeaders = _kafkaOptions.CustomHeaders(consumerResult); + foreach (var customHeader in customHeaders) + { + headers.Add(customHeader.Key, customHeader.Value); + } + } + var message = new TransportMessage(headers, consumerResult.Value); OnMessageReceived?.Invoke(consumerResult, message);