Skip to content

Commit

Permalink
系列文章第5部分代码
Browse files Browse the repository at this point in the history
  • Loading branch information
daxnet committed Jul 14, 2018
1 parent 5e94064 commit cda58e4
Show file tree
Hide file tree
Showing 21 changed files with 619 additions and 31 deletions.
23 changes: 22 additions & 1 deletion EdaSample.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdaSample.EventBus.RabbitMQ
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2- Tests", "2- Tests", "{0B52AB70-8ABB-4BA2-A2B4-BC0C6CAC110B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EdaSample.Tests", "src\EdaSample.Tests\EdaSample.Tests.csproj", "{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdaSample.Tests", "src\EdaSample.Tests\EdaSample.Tests.csproj", "{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdaSample.Services.Common", "src\EdaSample.Services.Common\EdaSample.Services.Common.csproj", "{D287D127-DB6E-46A3-B475-8AC1069F9ED5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdaSample.Services.Notification", "src\EdaSample.Services.Notification\EdaSample.Services.Notification.csproj", "{9125189E-FFF3-401D-9C76-23CF489439B9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EdaSample.DataAccess.MongoDB", "src\EdaSample.DataAccess.MongoDB\EdaSample.DataAccess.MongoDB.csproj", "{C3340AC8-C7AE-4B68-939F-9F76845F871A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -57,6 +63,18 @@ Global
{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7}.Release|Any CPU.Build.0 = Release|Any CPU
{D287D127-DB6E-46A3-B475-8AC1069F9ED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D287D127-DB6E-46A3-B475-8AC1069F9ED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D287D127-DB6E-46A3-B475-8AC1069F9ED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D287D127-DB6E-46A3-B475-8AC1069F9ED5}.Release|Any CPU.Build.0 = Release|Any CPU
{9125189E-FFF3-401D-9C76-23CF489439B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9125189E-FFF3-401D-9C76-23CF489439B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9125189E-FFF3-401D-9C76-23CF489439B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9125189E-FFF3-401D-9C76-23CF489439B9}.Release|Any CPU.Build.0 = Release|Any CPU
{C3340AC8-C7AE-4B68-939F-9F76845F871A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3340AC8-C7AE-4B68-939F-9F76845F871A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3340AC8-C7AE-4B68-939F-9F76845F871A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3340AC8-C7AE-4B68-939F-9F76845F871A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -69,6 +87,9 @@ Global
{37C1B71F-8BB7-4800-BFCA-FE6DC07DEF17} = {865391C4-CCCF-4B27-A784-C02794202855}
{845C94EC-0023-4DD4-BB9E-32E5A9EBC2F3} = {865391C4-CCCF-4B27-A784-C02794202855}
{890C9EE5-E759-445E-BA3F-0CA0FA9B05B7} = {0B52AB70-8ABB-4BA2-A2B4-BC0C6CAC110B}
{D287D127-DB6E-46A3-B475-8AC1069F9ED5} = {93BE142E-830C-4FBF-9267-8FD7472F088F}
{9125189E-FFF3-401D-9C76-23CF489439B9} = {93BE142E-830C-4FBF-9267-8FD7472F088F}
{C3340AC8-C7AE-4B68-939F-9F76845F871A} = {865391C4-CCCF-4B27-A784-C02794202855}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {735DB5FF-3ED8-4D88-8999-2C02E6AAABB1}
Expand Down
73 changes: 73 additions & 0 deletions src/EdaSample.Common/DataAccess/IDataAccessObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace EdaSample.Common.DataAccess
{
/// <summary>
/// Represents that the implemented classes are data access objects that perform
/// CRUD operations on the given entity type.
/// </summary>
/// <seealso cref="System.IDisposable" />
public interface IDataAccessObject : IDisposable
{
/// <summary>
/// Gets the entity by specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier of the entity.</param>
/// <returns>The task which performs the data retrieval operation.</returns>
Task<TEntity> GetByIdAsync<TEntity>(Guid id)
where TEntity : IEntity;

/// <summary>
/// Gets all of the entities asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <returns>The task which performs the data retrieval operation, and after
/// the operation has completed, would return a list of retrieved entities.
/// </returns>
Task<IEnumerable<TEntity>> GetAllAsync<TEntity>()
where TEntity : IEntity;

/// <summary>
/// Adds the given entity asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="entity">The entity to be added.</param>
/// <returns>The task which performs the adding operation.</returns>
Task AddAsync<TEntity>(TEntity entity)
where TEntity : IEntity;

/// <summary>
/// Updates the entity by the specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier of the entity to be updated.</param>
/// <param name="entity">The entity which contains the updated value.</param>
/// <returns>The task which performs the updating operation.</returns>
Task UpdateByIdAsync<TEntity>(Guid id, TEntity entity)
where TEntity : IEntity;

/// <summary>
/// Finds the entities which match the specified criteria that is defined by the given specification asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="expr">The expression which defines the matching criteria.</param>
/// <returns>The task which performs the data retrieval operation, and after the operation
/// has completed, would return a list of entities that match the specified criteria.</returns>
Task<IEnumerable<TEntity>> FindBySpecificationAsync<TEntity>(Expression<Func<TEntity, bool>> expr)
where TEntity : IEntity;

/// <summary>
/// Deletes the entity by specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier which represents the entity that is going to be deleted.</param>
/// <returns>The task which performs the deletion operation.</returns>
Task DeleteByIdAsync<TEntity>(Guid id)
where TEntity : IEntity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.7.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\EdaSample.Common\EdaSample.Common.csproj" />
</ItemGroup>

</Project>
168 changes: 168 additions & 0 deletions src/EdaSample.DataAccess.MongoDB/MongoDataAccessObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using EdaSample.Common;
using EdaSample.Common.DataAccess;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace EdaSample.DataAccess.MongoDB
{
/// <summary>
/// Represents the data access object which manipulates the MongoDB database.
/// </summary>
/// <seealso cref="WeShare.Service.DataAccess.IDataAccessObject" />
public sealed class MongoDataAccessObject : IDataAccessObject
{
#region Private Fields

private readonly IMongoClient client;
private readonly IMongoDatabase database;

private bool disposedValue = false;

#endregion Private Fields

#region Public Constructors

/// <summary>
/// Initializes a new instance of the <see cref="MongoDataAccessObject"/> class.
/// </summary>
/// <param name="databaseName">Name of the database.</param>
/// <param name="server">The server on which the MongoDB database has deployed.</param>
/// <param name="port">The port number to which the MongoDB database is listening.</param>
public MongoDataAccessObject(string databaseName, string server = "localhost", int port = 27017)
{
this.client = new MongoClient($"mongodb://{server}:{port}/{databaseName}");
this.database = this.client.GetDatabase(databaseName);
}

#endregion Public Constructors

#region Public Methods

/// <summary>
/// Adds the given entity asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="entity">The entity to be added.</param>
/// <returns>
/// The task which performs the adding operation.
/// </returns>
public async Task AddAsync<TEntity>(TEntity entity) where TEntity : IEntity
{
var collection = GetCollection<TEntity>();
var options = new InsertOneOptions { BypassDocumentValidation = true };
await collection.InsertOneAsync(entity, options);
}

/// <summary>
/// Deletes the entity by specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier which represents the entity that is going to be deleted.</param>
/// <returns>
/// The task which performs the deletion operation.
/// </returns>
public async Task DeleteByIdAsync<TEntity>(Guid id) where TEntity : IEntity
{
var filterDefinition = Builders<TEntity>.Filter.Eq(x => x.Id, id);
await GetCollection<TEntity>().DeleteOneAsync(filterDefinition);
}

// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}

/// <summary>
/// Finds the entities which match the specified criteria that is defined by the given specification asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="expr">The expression which defines the matching criteria.</param>
/// <returns>
/// The task which performs the data retrieval operation, and after the operation
/// has completed, would return a list of entities that match the specified criteria.
/// </returns>
public async Task<IEnumerable<TEntity>> FindBySpecificationAsync<TEntity>(Expression<Func<TEntity, bool>> expr) where TEntity : IEntity
=> await (await GetCollection<TEntity>().FindAsync(expr)).ToListAsync();

/// <summary>
/// Gets all of the entities asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <returns>
/// The task which performs the data retrieval operation, and after
/// the operation has completed, would return a list of retrieved entities.
/// </returns>
public async Task<IEnumerable<TEntity>> GetAllAsync<TEntity>() where TEntity : IEntity =>
await FindBySpecificationAsync<TEntity>(_ => true);

/// <summary>
/// Gets the entity by specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier of the entity.</param>
/// <returns>
/// The task which performs the data retrieval operation.
/// </returns>
public async Task<TEntity> GetByIdAsync<TEntity>(Guid id) where TEntity : IEntity =>
(await FindBySpecificationAsync<TEntity>(x => x.Id.Equals(id))).FirstOrDefault();

/// <summary>
/// Updates the entity by the specified identifier asynchronously.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="id">The identifier of the entity to be updated.</param>
/// <param name="entity">The entity which contains the updated value.</param>
/// <returns>
/// The task which performs the updating operation.
/// </returns>
public async Task UpdateByIdAsync<TEntity>(Guid id, TEntity entity) where TEntity : IEntity
{
var filterDefinition = Builders<TEntity>.Filter.Eq(x => x.Id, id);
await GetCollection<TEntity>().ReplaceOneAsync(filterDefinition, entity);
}

#endregion Public Methods

#region Private Methods

/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
private void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}

// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.

disposedValue = true;
}
}

private IMongoCollection<TEntity> GetCollection<TEntity>() where TEntity : IEntity =>
this.database.GetCollection<TEntity>(typeof(TEntity).Name);

#endregion Private Methods

// To detect redundant calls
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~MongoDataAccessObject() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
}
}
13 changes: 10 additions & 3 deletions src/EdaSample.EventBus.RabbitMQ/RabbitMQEventBus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,17 @@ private string InitializeEventConsumer(string queue)
var eventBody = eventArgument.Body;
var json = Encoding.UTF8.GetString(eventBody);
var @event = (IEvent)JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
await this.eventHandlerExecutionContext.HandleEventAsync(@event);
if (!autoAck)
try
{
channel.BasicAck(eventArgument.DeliveryTag, false);
await this.eventHandlerExecutionContext.HandleEventAsync(@event);
if (!autoAck)
{
channel.BasicAck(eventArgument.DeliveryTag, false);
}
}
catch (Exception ex)
{
logger.LogError(ex, "事件处理器执行失败。");
}
};

Expand Down
11 changes: 11 additions & 0 deletions src/EdaSample.Services.Common/EdaSample.Services.Common.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\EdaSample.Common\EdaSample.Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
using EdaSample.Common.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EdaSample.Services.Customer.Events
namespace EdaSample.Services.Common.Events
{
public class CustomerCreatedEvent : IEvent
{
public CustomerCreatedEvent(string customerName)
public CustomerCreatedEvent(Guid customerId, string customerName, string email)
{
this.Id = Guid.NewGuid();
this.Timestamp = DateTime.UtcNow;
this.CustomerId = customerId;
this.CustomerName = customerName;
this.Email = email;
}

public Guid Id { get; }

public DateTime Timestamp { get; }

public Guid CustomerId { get; }

public string CustomerName { get; }

public string Email { get; }
}
}
Loading

0 comments on commit cda58e4

Please sign in to comment.