├── XUnitTest
├── UnitTest.cs
└── XUnitTest.csproj
├── Message
├── Message.csproj
├── AbstractEvent.cs
└── OrderCreatedEvent.cs
├── Consumer
├── appsettings.Development.json
├── MongoDbEntity
│ ├── GuidEventLog.cs
│ ├── CommonEventLog.cs
│ └── EventLogBase.cs
├── Option
│ └── MongoConfig.cs
├── AutoMapper
│ ├── OrderCreatedEventProfile.cs
│ └── AutoMapperExtension.cs
├── Mongo
│ └── MongoDbContext.cs
├── appsettings.json
├── Program.cs
├── Properties
│ └── launchSettings.json
├── EventConsumer
│ ├── EasyNetQConsumerBase.cs
│ └── OrderCreatedEventConsumer.cs
├── Controllers
│ └── ValuesController.cs
├── Consumer.csproj
├── EasyNetQ
│ ├── ConsumerMessageDispatcher.cs
│ └── EasyNetQExtension.cs
├── Startup.cs
└── log4net.config
├── Productor
├── Common
│ ├── Check.cs
│ ├── IEventBus.cs
│ ├── KnownException.cs
│ ├── ApiResult.cs
│ └── RabbitMqEventBus.cs
├── appsettings.Development.json
├── AutoMapper
│ ├── BaseProfile.cs
│ └── OrderProfile.cs
├── Config
│ └── RedisConfig.cs
├── Quartz
│ ├── IgnoreJobAttribute.cs
│ ├── JobDescriptionAttribute.cs
│ ├── TestHelloJob.cs
│ ├── ClearHistoryMessageJob.cs
│ ├── JobIntervalTriggerAttribute.cs
│ ├── JobBase.cs
│ ├── ProductorJobFactory.cs
│ ├── PublishToMqServerJob.cs
│ └── QuartzExtension.cs
├── Service
│ ├── IOrderService.cs
│ └── OrderService.cs
├── Data
│ ├── Entity.cs
│ ├── OrderHeader.cs
│ ├── OrderDetail.cs
│ ├── MqMessage.cs
│ ├── EntityTypeMapConfig
│ │ ├── OrderHeaderMapConfig.cs
│ │ ├── MqMessageTypeConfig.cs
│ │ └── OrderDetailMapConfig.cs
│ └── ProductDbContext.cs
├── Hangfire
│ └── HangfireExtension.cs
├── Interceptor
│ ├── TestDebugIAspectCorenterceptorAttribute.cs
│ ├── LogExceptionAspectCoreInterceptorAttribute.cs
│ ├── LogExceptionCastleInterceptor.cs
│ ├── CacheAspectCoreInterceptorAttribute.cs
│ └── RedisCacheAspectCoreInterceptorAttribute.cs
├── appsettings.json
├── Program.cs
├── Migrations
│ ├── 20180414032731_AddColumnToMqMessage.cs
│ ├── 20180414013731_SettingDeciaml.cs
│ ├── 20180413034406_UpdateOrderConfig.cs
│ ├── 20180412155138_InitProductDb.cs
│ ├── 20180413034406_UpdateOrderConfig.Designer.cs
│ ├── 20180414013731_SettingDeciaml.Designer.cs
│ ├── 20180412155138_InitProductDb.Designer.cs
│ ├── ProductDbContextModelSnapshot.cs
│ └── 20180414032731_AddColumnToMqMessage.Designer.cs
├── Properties
│ └── launchSettings.json
├── EventConsumer
│ └── EasyNetQConsumerBase.cs
├── Controllers
│ ├── ControllerBase.cs
│ ├── ValuesController.cs
│ └── OrderController.cs
├── Model
│ ├── OrderInput.cs
│ └── OrderOutput.cs
├── Filter
│ ├── ValidateModelStateAttribute.cs
│ ├── GlobalExceptionFilter.cs
│ └── ExceptionActionFilter.cs
├── EasyNetQ
│ ├── ProductorMessageDispatcher.cs
│ └── EasyNetQExtension.cs
├── Swagger
│ └── SwaggerExtension.cs
├── Productor.csproj
├── Startup.cs
└── log4net.config
├── readme.txt
├── .gitattributes
├── LocalTransactionTableTest.sln
└── .gitignore
/XUnitTest/UnitTest.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Inuyasha-Monster/LocalTransactionTableTest/HEAD/XUnitTest/UnitTest.cs
--------------------------------------------------------------------------------
/Message/Message.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Consumer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Productor/Common/Check.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Common
7 | {
8 | public static class Check
9 | {
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Productor/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Consumer/MongoDbEntity/GuidEventLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Consumer.MongoDbEntity
7 | {
8 | public class GuidEventLog : CommonEventLog
9 | {
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Consumer/Option/MongoConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Consumer.Option
7 | {
8 | public class MongoConfig
9 | {
10 | public string ConnectionString { get; set; }
11 | public string Database { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Productor/AutoMapper/BaseProfile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using AutoMapper;
6 |
7 | namespace Productor.AutoMapper
8 | {
9 | public class BaseProfile : Profile
10 | {
11 | public BaseProfile()
12 | {
13 |
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Productor/Config/RedisConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Config
7 | {
8 | public class RedisConfig
9 | {
10 | public string Configuration { get; set; }
11 | public string InstanceName { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Productor/Quartz/IgnoreJobAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Quartz
7 | {
8 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
9 | public class IgnoreJobAttribute : Attribute
10 | {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Productor/Service/IOrderService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Productor.Interceptor;
3 | using Productor.Model;
4 |
5 | namespace Productor.Service
6 | {
7 | public interface IOrderService
8 | {
9 | //[CacheAspectCoreInterceptor]
10 | [RedisCacheAspectCoreInterceptor]
11 | OrderOutput GetOrderInfo(Guid id);
12 |
13 | void CreateOrder(OrderInput input);
14 | }
15 | }
--------------------------------------------------------------------------------
/Message/AbstractEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Message
6 | {
7 | public abstract class AbstractEvent
8 | {
9 | protected AbstractEvent()
10 | {
11 | EventId = Guid.NewGuid();
12 | EventUtcTime = DateTime.UtcNow;
13 | }
14 | public Guid EventId { get; set; }
15 | public DateTime EventUtcTime { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Productor/Common/IEventBus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Common
7 | {
8 | public interface IEventBus
9 | {
10 | void Publish(T message) where T : class, new();
11 | Task PublishAsync(T message) where T : class, new();
12 |
13 | void Publish(Type messageType, object message);
14 | void PublishAsync(Type messageType, object message);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Productor/Data/Entity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Data
7 | {
8 | public class Entity where TPk : struct
9 | {
10 | public TPk Id { get; set; }
11 | }
12 |
13 | public class EntityGuid : Entity
14 | {
15 |
16 | }
17 |
18 | public class EntityGuidBaseField : EntityGuid
19 | {
20 | public DateTime CreateTime { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Productor/Common/KnownException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Common
7 | {
8 | public class KnownException : Exception
9 | {
10 | public KnownException(string message) : base(message)
11 | {
12 |
13 | }
14 |
15 | public KnownException(string message, Exception innerException) : base(message, innerException)
16 | {
17 |
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Productor/Quartz/JobDescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Quartz
7 | {
8 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
9 | public class JobDescriptionAttribute : Attribute
10 | {
11 | public string Key { get; set; }
12 | public string Group { get; set; }
13 | public string Description { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Consumer/MongoDbEntity/CommonEventLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Consumer.MongoDbEntity
7 | {
8 | public class CommonEventLog : EventLogBase
9 | {
10 | public string MessageAssemblyName { get; set; }
11 | public string MessageClassFullName { get; set; }
12 | public string Body { get; set; }
13 | public T DatabaseId { get; set; }
14 | public DateTime CreateTime { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Consumer/AutoMapper/OrderCreatedEventProfile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using AutoMapper;
6 | using Consumer.MongoDbEntity;
7 | using Message;
8 |
9 | namespace Consumer.AutoMapper
10 | {
11 | public class OrderCreatedEventProfile : Profile
12 | {
13 | public OrderCreatedEventProfile()
14 | {
15 | this.CreateMap().ForMember(d => d.DatabaseId, s => s.MapFrom(soucre => soucre.Id));
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Productor/Data/OrderHeader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Data
7 | {
8 | public class OrderHeader
9 | {
10 | public OrderHeader()
11 | {
12 | Id = Guid.NewGuid();
13 | CreateTime = DateTime.Now;
14 | }
15 | public Guid Id { get; set; }
16 | public decimal Amount { get; set; }
17 | public DateTime CreateTime { get; set; }
18 | public string AppUser { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | todo:
2 | 1、实现serivce方法拦截:Cache应用 --ok
3 |
4 | 2、代码整理分离 迁移到 YiXinFramework --working
5 |
6 | 3、实现 Polly 重试容错处理 --ok 集成消息推送rabbitmqserver容错与消费者消费mq重试 Update: 将 Polly 重试机制迁移到 interceptor 当中去作为公共逻辑
7 |
8 | 4、实现发送消息错误报警接口设计(打算先实现邮件提醒)
9 |
10 | 5、集成分布式缓存 --ok (redis)
11 | 6、启用消费者负载均衡
12 | 7、启用rabbitmq集群模式测试
13 | 8、集成服务发现和治理(多个生产者均衡负载,但是数据库目前是同一个的模式)
14 | 9、集成quartz-ui管理界面
15 | 10、集成hangfire-RAM内存模式测试
16 | 11、集成kafka消息队列测试
17 | 12、关于解析 dbmessage 通过 eventbus 发送,做反射优化以及缓存提升性能
18 | 13、独立出来一个 MessageDbContext 发布nuget package方便使用,在使用migration迁移即可
19 | 14、集成 ExceptionLess / ELK 日志集中式处理
20 |
--------------------------------------------------------------------------------
/Productor/Hangfire/HangfireExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | namespace Productor.Hangfire
9 | {
10 | public static class HangfireExtension
11 | {
12 | public static void AddHangfire(this IServiceCollection service, string connection)
13 | {
14 |
15 | }
16 |
17 | public static void UseHangfire(this IApplicationBuilder app)
18 | {
19 |
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Consumer/MongoDbEntity/EventLogBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using MongoDB.Bson;
6 | using MongoDB.Bson.Serialization.Attributes;
7 |
8 | namespace Consumer.MongoDbEntity
9 | {
10 | public abstract class EventLogBase
11 | {
12 | [BsonId]
13 | // standard BSonId generated by MongoDb
14 | public ObjectId InternalId { get; set; }
15 |
16 | // external ID or key, which may be easier to reference (ex: 1,2,3 etc.)
17 | public Guid EventId { get; set; }
18 |
19 | public DateTime EventUtcTime { get; set; }
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Productor/Interceptor/TestDebugIAspectCorenterceptorAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using AspectCore.DynamicProxy;
7 |
8 | namespace Productor.Interceptor
9 | {
10 | public class TestDebugIAspectCorenterceptorAttribute : AbstractInterceptorAttribute
11 | {
12 | public override async Task Invoke(AspectContext context, AspectDelegate next)
13 | {
14 | Debug.WriteLine("Before service call");
15 | await next(context);
16 | Debug.WriteLine("After service call");
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Productor/Data/OrderDetail.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Data
7 | {
8 | public class OrderDetail
9 | {
10 | public OrderDetail()
11 | {
12 | Id = Guid.NewGuid();
13 | CreateTime = DateTime.Now;
14 | }
15 | public Guid Id { get; set; }
16 | public Guid ParentId { get; set; }
17 | public string Sku { get; set; }
18 | public string SkuName { get; set; }
19 | public int Quantity { get; set; }
20 | public decimal Price { get; set; }
21 | public DateTime CreateTime { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Productor/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "Debug": {
5 | "LogLevel": {
6 | "Default": "Warning"
7 | }
8 | },
9 | "Console": {
10 | "LogLevel": {
11 | "Default": "Warning"
12 | }
13 | }
14 | },
15 | "ConnectionStrings": {
16 | "Mysql": "server=139.199.221.46;userid=djlnet;password=djlnet;database=test_productor;charset=utf8;",
17 | "LocalMysql": "server=localhost;userid=root;password=111111;database=test_productor;",
18 | "RabbitMq": "host=localhost;virtualHost=test;username=djlnet;password=djlnet;publisherConfirms=true;timeout=3;prefetchcount=50"
19 | },
20 | "RedisConfig": {
21 | "Configuration": "139.199.221.46:6379",
22 | "InstanceName": "RedisTest"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Productor/Data/MqMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.EntityFrameworkCore.Metadata.Internal;
7 |
8 | namespace Productor.Data
9 | {
10 | public class MqMessage
11 | {
12 | public MqMessage()
13 | {
14 | Id = Guid.NewGuid();
15 | CreateTime = DateTime.Now;
16 | }
17 | public Guid Id { get; set; }
18 | public bool IsPublished { get; set; }
19 | public string MessageAssemblyName { get; set; }
20 | public string MessageClassFullName { get; set; }
21 | public string Body { get; set; }
22 | public DateTime CreateTime { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Consumer/Mongo/MongoDbContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Consumer.MongoDbEntity;
6 | using Consumer.Option;
7 | using Microsoft.Extensions.Options;
8 | using MongoDB.Driver;
9 |
10 | namespace Consumer.Mongo
11 | {
12 | public class MongoDbContext
13 | {
14 | private readonly IMongoDatabase _database;
15 |
16 | public MongoDbContext(IOptions options)
17 | {
18 | var client = new MongoClient(options.Value.ConnectionString);
19 | _database = client.GetDatabase(options.Value.Database);
20 | }
21 |
22 | public IMongoCollection GuidEventLogs => _database.GetCollection("consumerlog");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Consumer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "Debug": {
5 | "LogLevel": {
6 | "Default": "Warning"
7 | }
8 | },
9 | "Console": {
10 | "LogLevel": {
11 | "Default": "Warning"
12 | }
13 | }
14 | },
15 | "ConnectionStrings": {
16 | "Mysql": "server=139.199.221.46;userid=djlnet;password=djlnet;database=test_consumer;",
17 | "LocalMysql": "server=localhost;userid=root;password=111111;database=test_productor;",
18 | "RabbitMq": "host=localhost;virtualHost=test;username=djlnet;password=djlnet;publisherConfirms=true;timeout=3;prefetchcount=50"
19 | },
20 | "MongoConnection": {
21 | "ConnectionString": "mongodb://djlnet:111111@139.199.221.46:27017",
22 | "Database": "test_consumerlog"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Productor/Quartz/TestHelloJob.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.Extensions.Logging;
7 | using Quartz;
8 |
9 | namespace Productor.Quartz
10 | {
11 | public class TestHelloJob : JobBase
12 | {
13 | private readonly ILogger _logger;
14 |
15 | public TestHelloJob(ILogger logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | protected override ILogger Logger => _logger;
21 | protected override Task ExecuteJob(IJobExecutionContext context)
22 | {
23 | return Task.Run(() =>
24 | {
25 | Debug.WriteLine("Hello djlnet");
26 | });
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Consumer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Consumer
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | BuildWebHost(args).Run();
18 | }
19 |
20 | public static IWebHost BuildWebHost(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseContentRoot(Directory.GetCurrentDirectory())
23 | .UseUrls("http://localhost:9999")
24 | .UseStartup()
25 | .Build();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Consumer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:52737/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "api/values",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "Consumer": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "api/values",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | },
26 | "applicationUrl": "http://localhost:52738/"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Productor/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Productor
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | BuildWebHost(args).Run();
18 | }
19 |
20 | public static IWebHost BuildWebHost(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseContentRoot(Directory.GetCurrentDirectory())
23 | .UseUrls("http://localhost:8888")
24 | .UseStartup()
25 | .Build();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Productor/Migrations/20180414032731_AddColumnToMqMessage.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Productor.Migrations
6 | {
7 | public partial class AddColumnToMqMessage : Migration
8 | {
9 | protected override void Up(MigrationBuilder migrationBuilder)
10 | {
11 | migrationBuilder.AddColumn(
12 | name: "IsPublished",
13 | table: "MqMessages",
14 | nullable: false,
15 | defaultValue: false);
16 | }
17 |
18 | protected override void Down(MigrationBuilder migrationBuilder)
19 | {
20 | migrationBuilder.DropColumn(
21 | name: "IsPublished",
22 | table: "MqMessages");
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Productor/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:52682/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "api/values",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "Productor": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "api/values",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | },
26 | "applicationUrl": "http://localhost:52683/"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Productor/AutoMapper/OrderProfile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using AutoMapper;
6 | using Message;
7 | using Productor.Data;
8 | using Productor.Model;
9 | using OrderDetail = Productor.Data.OrderDetail;
10 |
11 | namespace Productor.AutoMapper
12 | {
13 | public class OrderProfile : Profile
14 | {
15 | public OrderProfile()
16 | {
17 | this.CreateMap();
18 | this.CreateMap();
19 | this.CreateMap();
20 | this.CreateMap();
21 | this.CreateMap();
22 | this.CreateMap();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/XUnitTest/XUnitTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Productor/EventConsumer/EasyNetQConsumerBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using EasyNetQ.AutoSubscribe;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace Productor.EventConsumer
9 | {
10 | public abstract class EasyNetQConsumerBase : IConsume where T : class
11 | {
12 | public void Consume(T message)
13 | {
14 | try
15 | {
16 | ConsumeSync(message);
17 | }
18 | catch (Exception exception)
19 | {
20 | Logger.LogError(exception, $"{message.GetType().Name}消息消费者消费错误");
21 | throw;
22 | }
23 | }
24 |
25 | protected abstract ILogger Logger { get; }
26 | protected abstract void ConsumeSync(T message);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Productor/Quartz/ClearHistoryMessageJob.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Logging;
6 | using Quartz;
7 |
8 | namespace Productor.Quartz
9 | {
10 | ///
11 | /// 清理历史消息记录保证消息表不会过载
12 | ///
13 | [IgnoreJob]
14 | public class ClearHistoryMessageJob : JobBase
15 | {
16 | private readonly ILogger _logger;
17 |
18 | public ClearHistoryMessageJob(ILogger logger)
19 | {
20 | _logger = logger;
21 | }
22 |
23 | protected override ILogger Logger => _logger;
24 | protected override async Task ExecuteJob(IJobExecutionContext context)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Consumer/EventConsumer/EasyNetQConsumerBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using EasyNetQ.AutoSubscribe;
6 | using Message;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace Consumer.EventConsumer
10 | {
11 | public abstract class EasyNetQConsumerBase : IConsume where T : AbstractEvent
12 | {
13 | public void Consume(T message)
14 | {
15 | try
16 | {
17 | ConsumeSync(message);
18 | }
19 | catch (Exception exception)
20 | {
21 | Logger.LogError(exception, $"{message.GetType().Name} 消息消费者消费错误");
22 | throw;
23 | }
24 | }
25 |
26 | protected abstract ILogger Logger { get; }
27 | protected abstract void ConsumeSync(T message);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Productor/Data/EntityTypeMapConfig/OrderHeaderMapConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
7 |
8 | namespace Productor.Data.EntityTypeMapConfig
9 | {
10 | public class OrderHeaderMapConfig : IEntityTypeConfiguration
11 | {
12 | public void Configure(EntityTypeBuilder builder)
13 | {
14 | builder.HasKey(x => x.Id);
15 | builder.Property(x => x.Id).HasColumnType("char(36)");
16 | builder.Property(x => x.AppUser).IsRequired().HasMaxLength(20);
17 | builder.Property(x => x.CreateTime).IsRequired().ValueGeneratedOnAdd();
18 | builder.Property(x => x.Amount).IsRequired().HasColumnType("DECIMAL(18,2)").HasColumnName("Amount");
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Productor/Interceptor/LogExceptionAspectCoreInterceptorAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using AspectCore.DynamicProxy;
6 | using AspectCore.Injector;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace Productor.Interceptor
10 | {
11 | public class LogExceptionAspectCoreInterceptorAttribute : AbstractInterceptor
12 | {
13 | [FromContainer]
14 | public ILogger Logger { get; set; }
15 |
16 | public override async Task Invoke(AspectContext context, AspectDelegate next)
17 | {
18 | try
19 | {
20 | await next(context);
21 | }
22 | catch (Exception e)
23 | {
24 | Logger.LogError(e, $"{context.ProxyMethod.Name}调用异常");
25 | throw;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Productor/Quartz/JobIntervalTriggerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Quartz
7 | {
8 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
9 | public class JobIntervalTriggerAttribute : Attribute
10 | {
11 | public JobIntervalTriggerAttribute(bool startNow = true, bool isRepeatForever = true, int intervalInSeconds = 60)
12 | {
13 | StartNow = startNow;
14 | IsRepeatForever = isRepeatForever;
15 | IntervalInSeconds = intervalInSeconds;
16 | }
17 | public string Key { get; set; }
18 | public string Group { get; set; }
19 | public bool StartNow { get; set; }
20 | public int IntervalInSeconds { get; set; }
21 | public bool IsRepeatForever { get; set; }
22 | public int RepeatCount { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Productor/Interceptor/LogExceptionCastleInterceptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Castle.DynamicProxy;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace Productor.Interceptor
9 | {
10 | public class LogExceptionCastleInterceptor : Castle.DynamicProxy.IInterceptor
11 | {
12 | private readonly ILogger _logger;
13 |
14 | public LogExceptionCastleInterceptor(ILogger logger)
15 | {
16 | _logger = logger;
17 | }
18 |
19 | public void Intercept(IInvocation invocation)
20 | {
21 | try
22 | {
23 | invocation.Proceed();
24 | }
25 | catch (Exception e)
26 | {
27 | _logger.LogError(e, $"{invocation.Method.Name}调用异常");
28 | throw;
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Productor/Data/EntityTypeMapConfig/MqMessageTypeConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
7 |
8 | namespace Productor.Data.EntityTypeMapConfig
9 | {
10 | public class MqMessageTypeConfig : IEntityTypeConfiguration
11 | {
12 | public void Configure(EntityTypeBuilder builder)
13 | {
14 | builder.HasKey(x => x.Id);
15 | builder.Property(x => x.Id).HasColumnType("char(36)");
16 | builder.Property(x => x.IsPublished).HasDefaultValue(false);
17 | builder.Property(x => x.MessageAssemblyName).IsRequired().HasMaxLength(200);
18 | builder.Property(x => x.MessageClassFullName).IsRequired().HasMaxLength(200);
19 | builder.Property(x => x.Body).IsRequired().HasMaxLength(4000);
20 | builder.Property(x => x.CreateTime).IsRequired().ValueGeneratedOnAdd();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Productor/Data/ProductDbContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Productor.Data.EntityTypeMapConfig;
7 |
8 | namespace Productor.Data
9 | {
10 | public class ProductDbContext : DbContext
11 | {
12 | public ProductDbContext(DbContextOptions options) : base(options)
13 | {
14 |
15 | }
16 |
17 | protected override void OnModelCreating(ModelBuilder modelBuilder)
18 | {
19 | modelBuilder.ApplyConfiguration(new MqMessageTypeConfig());
20 | modelBuilder.ApplyConfiguration(new OrderDetailMapConfig());
21 | modelBuilder.ApplyConfiguration(new OrderHeaderMapConfig());
22 |
23 | base.OnModelCreating(modelBuilder);
24 | }
25 |
26 | public DbSet MqMessages { get; set; }
27 | public DbSet OrderHeaders { get; set; }
28 | public DbSet OrderDetails { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Message/OrderCreatedEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Message
5 | {
6 | [Serializable]
7 | public class OrderCreatedEvent : AbstractEvent
8 | {
9 | public OrderCreatedEvent() : base()
10 | {
11 | CreateTime = DateTime.Now;
12 | }
13 | public Guid Id { get; set; }
14 | public decimal Amount { get; set; }
15 | public DateTime CreateTime { get; set; }
16 | public string AppUser { get; set; }
17 |
18 | public IList Details { get; set; }
19 | }
20 |
21 | public class OrderDetail
22 | {
23 | public OrderDetail()
24 | {
25 | CreateTime = DateTime.Now;
26 | }
27 | public Guid Id { get; set; }
28 | public Guid ParentId { get; set; }
29 | public string Sku { get; set; }
30 | public string SkuName { get; set; }
31 | public int Quantity { get; set; }
32 | public decimal Price { get; set; }
33 | public DateTime CreateTime { get; set; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Productor/Quartz/JobBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Logging;
6 | using Quartz;
7 |
8 | namespace Productor.Quartz
9 | {
10 | [DisallowConcurrentExecution]
11 | [PersistJobDataAfterExecution]
12 | public abstract class JobBase : IJob
13 | {
14 | protected abstract ILogger Logger { get; }
15 |
16 | public Task Execute(IJobExecutionContext context)
17 | {
18 | try
19 | {
20 | return ExecuteJob(context);
21 | }
22 | catch (Exception exception)
23 | {
24 | Logger.LogError(exception, $"当前任务key:{context.JobDetail.Key};当前任务描述desc:{context.JobDetail.Description}执行出现未知异常");
25 | JobExecutionException jobExecutionException = new JobExecutionException(exception, refireImmediately: true);
26 | throw jobExecutionException;
27 | }
28 | }
29 |
30 | protected abstract Task ExecuteJob(IJobExecutionContext context);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Consumer/Controllers/ValuesController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 |
7 | namespace Consumer.Controllers
8 | {
9 | [Route("api/[controller]")]
10 | public class ValuesController : Controller
11 | {
12 | // GET api/values
13 | [HttpGet]
14 | public IEnumerable Get()
15 | {
16 | return new string[] { "value1", "value2" };
17 | }
18 |
19 | // GET api/values/5
20 | [HttpGet("{id}")]
21 | public string Get(int id)
22 | {
23 | return "value";
24 | }
25 |
26 | // POST api/values
27 | [HttpPost]
28 | public void Post([FromBody]string value)
29 | {
30 | }
31 |
32 | // PUT api/values/5
33 | [HttpPut("{id}")]
34 | public void Put(int id, [FromBody]string value)
35 | {
36 | }
37 |
38 | // DELETE api/values/5
39 | [HttpDelete("{id}")]
40 | public void Delete(int id)
41 | {
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Productor/Data/EntityTypeMapConfig/OrderDetailMapConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
7 |
8 | namespace Productor.Data.EntityTypeMapConfig
9 | {
10 | public class OrderDetailMapConfig : IEntityTypeConfiguration
11 | {
12 | public void Configure(EntityTypeBuilder builder)
13 | {
14 | builder.HasKey(x => x.Id);
15 | builder.Property(x => x.Id).HasColumnType("char(36)");
16 | builder.Property(x => x.ParentId).IsRequired().HasColumnType("char(36)");
17 | builder.Property(x => x.Sku).IsRequired().HasMaxLength(50);
18 | builder.Property(x => x.SkuName).IsRequired().HasMaxLength(50);
19 | builder.Property(x => x.Quantity).IsRequired().HasColumnName("Quantity");
20 | builder.Property(x => x.Price).IsRequired().HasColumnType("DECIMAL(18,2)").HasColumnName("Price");
21 | builder.Property(x => x.CreateTime).IsRequired().ValueGeneratedOnAdd();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Productor/Common/ApiResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace Productor.Common
7 | {
8 | [Serializable]
9 | public class ApiResult where T : class, new()
10 | {
11 | public ApiResult()
12 | {
13 | this.Message = string.Empty;
14 | this.Successed = true;
15 | this.DevelopMessage = string.Empty;
16 | }
17 |
18 | public ApiResult(bool successed = true)
19 | {
20 | this.Successed = successed;
21 | }
22 |
23 | public bool Successed { get; set; }
24 | public T Data { get; set; }
25 | public object DevelopMessage { get; set; }
26 | public string Message { get; set; }
27 | }
28 |
29 | public class ApiResult : ApiResult