[skip appveyor] #9 Documentation and examples
Implemented two examples. More needed to get rid of the mess that is the current "Test" project.
This commit is contained in:
parent
93fa25c163
commit
8e0edabeed
19
02-DeclareDurableQueues/02-DeclareDurableQueues.csproj
Normal file
19
02-DeclareDurableQueues/02-DeclareDurableQueues.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<RootNamespace>_02_DeclareDurableQueues</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SimpleInjector" Version="4.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ExampleHelper.cs\ExampleLib.csproj" />
|
||||
<ProjectReference Include="..\Messaging.TapetiExample\Messaging.TapetiExample.csproj" />
|
||||
<ProjectReference Include="..\Tapeti.SimpleInjector\Tapeti.SimpleInjector.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
28
02-DeclareDurableQueues/ExampleMessageController.cs
Normal file
28
02-DeclareDurableQueues/ExampleMessageController.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using ExampleLib;
|
||||
using Messaging.TapetiExample;
|
||||
using Tapeti.Annotations;
|
||||
|
||||
namespace _02_DeclareDurableQueues
|
||||
{
|
||||
[MessageController]
|
||||
[DurableQueue("tapeti.example.02")]
|
||||
public class ExampleMessageController
|
||||
{
|
||||
private readonly IExampleState exampleState;
|
||||
|
||||
|
||||
public ExampleMessageController(IExampleState exampleState)
|
||||
{
|
||||
this.exampleState = exampleState;
|
||||
}
|
||||
|
||||
|
||||
public void HandlePublishSubscribeMessage(PublishSubscribeMessage message)
|
||||
{
|
||||
// Note that if you run example 01 after 02, it's message will also be in this durable queue
|
||||
Console.WriteLine("Received message: " + message.Greeting);
|
||||
exampleState.Done();
|
||||
}
|
||||
}
|
||||
}
|
48
02-DeclareDurableQueues/Program.cs
Normal file
48
02-DeclareDurableQueues/Program.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ExampleLib;
|
||||
using Messaging.TapetiExample;
|
||||
using SimpleInjector;
|
||||
using Tapeti;
|
||||
using Tapeti.Default;
|
||||
using Tapeti.SimpleInjector;
|
||||
|
||||
namespace _02_DeclareDurableQueues
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var container = new Container();
|
||||
var dependencyResolver = new SimpleInjectorDependencyResolver(container);
|
||||
|
||||
container.Register<ILogger, ConsoleLogger>();
|
||||
|
||||
var helper = new ExampleConsoleApp(dependencyResolver);
|
||||
helper.Run(MainAsync);
|
||||
}
|
||||
|
||||
|
||||
internal static async Task MainAsync(IDependencyResolver dependencyResolver, Func<Task> waitForDone)
|
||||
{
|
||||
var config = new TapetiConfig(dependencyResolver)
|
||||
.RegisterAllControllers()
|
||||
.EnableDeclareDurableQueues()
|
||||
.Build();
|
||||
|
||||
using (var connection = new TapetiConnection(config))
|
||||
{
|
||||
// This creates or updates the durable queue
|
||||
await connection.Subscribe();
|
||||
|
||||
await dependencyResolver.Resolve<IPublisher>().Publish(new PublishSubscribeMessage
|
||||
{
|
||||
Greeting = "Hello durable queue!"
|
||||
});
|
||||
|
||||
// Wait for the controller to signal that the message has been received
|
||||
await waitForDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
ExampleHelper.cs/ExampleConsoleApp.cs
Normal file
104
ExampleHelper.cs/ExampleConsoleApp.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Tapeti;
|
||||
|
||||
namespace ExampleLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback method for ExampleConsoleApp.Run
|
||||
/// </summary>
|
||||
/// <param name="dependencyResolver">A reference to the dependency resolver passed to the ExampleConsoleApp</param>
|
||||
/// <param name="waitForDone">Await this function to wait for the Done signal</param>
|
||||
public delegate Task AsyncFunc(IDependencyResolver dependencyResolver, Func<Task> waitForDone);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Since the examples do not run as a service, we need to know when the example has run
|
||||
/// to completion. This helper injects IExampleState into the container which
|
||||
/// can be used to signal that it has finished. It also provides the Wait
|
||||
/// method to wait for this signal.
|
||||
/// </summary>
|
||||
public class ExampleConsoleApp
|
||||
{
|
||||
private readonly IDependencyContainer dependencyResolver;
|
||||
private readonly TaskCompletionSource<bool> doneSignal = new TaskCompletionSource<bool>();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ExampleConsoleApp(IDependencyContainer dependencyResolver)
|
||||
{
|
||||
this.dependencyResolver = dependencyResolver;
|
||||
dependencyResolver.RegisterDefault<IExampleState>(() => new ExampleState(this));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified async method and waits for completion. Handles exceptions and waiting
|
||||
/// for user input when the example application finishes.
|
||||
/// </summary>
|
||||
/// <param name="asyncFunc"></param>
|
||||
public void Run(AsyncFunc asyncFunc)
|
||||
{
|
||||
try
|
||||
{
|
||||
asyncFunc(dependencyResolver, WaitAsync).Wait();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(UnwrapException(e));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.WriteLine("Press any Enter key to continue...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Task which completed when IExampleState.Done is called
|
||||
/// </summary>
|
||||
public async Task WaitAsync()
|
||||
{
|
||||
await doneSignal.Task;
|
||||
}
|
||||
|
||||
|
||||
internal Exception UnwrapException(Exception e)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!(e is AggregateException aggregateException))
|
||||
return e;
|
||||
|
||||
if (aggregateException.InnerExceptions.Count != 1)
|
||||
return e;
|
||||
|
||||
e = aggregateException.InnerExceptions[0];
|
||||
}
|
||||
}
|
||||
|
||||
internal void Done()
|
||||
{
|
||||
doneSignal.TrySetResult(true);
|
||||
}
|
||||
|
||||
|
||||
private class ExampleState : IExampleState
|
||||
{
|
||||
private readonly ExampleConsoleApp owner;
|
||||
|
||||
|
||||
public ExampleState(ExampleConsoleApp owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
|
||||
public void Done()
|
||||
{
|
||||
owner.Done();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
ExampleHelper.cs/ExampleLib.csproj
Normal file
12
ExampleHelper.cs/ExampleLib.csproj
Normal file
@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Tapeti\Tapeti.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
14
ExampleHelper.cs/IExampleState.cs
Normal file
14
ExampleHelper.cs/IExampleState.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace ExampleLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Since the examples do not run as a service, this interface provides a way
|
||||
/// for the implementation to signal that it has finished and the example can be closed.
|
||||
/// </summary>
|
||||
public interface IExampleState
|
||||
{
|
||||
/// <summary>
|
||||
/// Signals the Program that the example has finished and the application can be closed.
|
||||
/// </summary>
|
||||
void Done();
|
||||
}
|
||||
}
|
20
Examples/01-PublishSubscribe/01-PublishSubscribe.csproj
Normal file
20
Examples/01-PublishSubscribe/01-PublishSubscribe.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<RootNamespace>_01_PublishSubscribe</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SimpleInjector" Version="4.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ExampleHelper.cs\ExampleLib.csproj" />
|
||||
<ProjectReference Include="..\..\Messaging.TapetiExample\Messaging.TapetiExample.csproj" />
|
||||
<ProjectReference Include="..\..\Tapeti.SimpleInjector\Tapeti.SimpleInjector.csproj" />
|
||||
<ProjectReference Include="..\..\Tapeti\Tapeti.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
27
Examples/01-PublishSubscribe/ExampleMessageController.cs
Normal file
27
Examples/01-PublishSubscribe/ExampleMessageController.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using ExampleLib;
|
||||
using Messaging.TapetiExample;
|
||||
using Tapeti.Annotations;
|
||||
|
||||
namespace _01_PublishSubscribe
|
||||
{
|
||||
[MessageController]
|
||||
[DynamicQueue("tapeti.example.01")]
|
||||
public class ExampleMessageController
|
||||
{
|
||||
private readonly IExampleState exampleState;
|
||||
|
||||
|
||||
public ExampleMessageController(IExampleState exampleState)
|
||||
{
|
||||
this.exampleState = exampleState;
|
||||
}
|
||||
|
||||
|
||||
public void HandlePublishSubscribeMessage(PublishSubscribeMessage message)
|
||||
{
|
||||
Console.WriteLine("Received message: " + message.Greeting);
|
||||
exampleState.Done();
|
||||
}
|
||||
}
|
||||
}
|
29
Examples/01-PublishSubscribe/ExamplePublisher.cs
Normal file
29
Examples/01-PublishSubscribe/ExamplePublisher.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Threading.Tasks;
|
||||
using Messaging.TapetiExample;
|
||||
using Tapeti;
|
||||
|
||||
namespace _01_PublishSubscribe
|
||||
{
|
||||
public class ExamplePublisher
|
||||
{
|
||||
private readonly IPublisher publisher;
|
||||
|
||||
/// <summary>
|
||||
/// Shows that the IPublisher is registered in the container by Tapeti
|
||||
/// </summary>
|
||||
/// <param name="publisher"></param>
|
||||
public ExamplePublisher(IPublisher publisher)
|
||||
{
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
|
||||
public async Task SendTestMessage()
|
||||
{
|
||||
await publisher.Publish(new PublishSubscribeMessage
|
||||
{
|
||||
Greeting = "Hello world of messaging!"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
64
Examples/01-PublishSubscribe/Program.cs
Normal file
64
Examples/01-PublishSubscribe/Program.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using ExampleLib;
|
||||
using SimpleInjector;
|
||||
using Tapeti;
|
||||
using Tapeti.Default;
|
||||
using Tapeti.SimpleInjector;
|
||||
|
||||
namespace _01_PublishSubscribe
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var container = new Container();
|
||||
var dependencyResolver = new SimpleInjectorDependencyResolver(container);
|
||||
|
||||
container.Register<ILogger, ConsoleLogger>();
|
||||
container.Register<ExamplePublisher>();
|
||||
|
||||
|
||||
// This helper is used because this example is not run as a service. You do not
|
||||
// need it in your own applications.
|
||||
var helper = new ExampleConsoleApp(dependencyResolver);
|
||||
helper.Run(MainAsync);
|
||||
}
|
||||
|
||||
|
||||
internal static async Task MainAsync(IDependencyResolver dependencyResolver, Func<Task> waitForDone)
|
||||
{
|
||||
var config = new TapetiConfig(dependencyResolver)
|
||||
.RegisterAllControllers()
|
||||
.Build();
|
||||
|
||||
using (var connection = new TapetiConnection(config)
|
||||
{
|
||||
// Params is optional if you want to use the defaults, but we'll set it
|
||||
// explicitly for this example
|
||||
Params = new TapetiConnectionParams
|
||||
{
|
||||
HostName = "localhost",
|
||||
Username = "guest",
|
||||
Password = "guest"
|
||||
}
|
||||
})
|
||||
{
|
||||
// Create the queues and start consuming immediately.
|
||||
// If you need to do some processing before processing messages, but after the
|
||||
// queues have initialized, pass false as the startConsuming parameter and store
|
||||
// the returned ISubscriber. Then call Resume on it later.
|
||||
await connection.Subscribe();
|
||||
|
||||
|
||||
// We could get an IPublisher from the container directly, but since you'll usually use
|
||||
// it as an injected constructor parameter this shows
|
||||
await dependencyResolver.Resolve<ExamplePublisher>().SendTestMessage();
|
||||
|
||||
|
||||
// Wait for the controller to signal that the message has been received
|
||||
await waitForDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Messaging.TapetiExample/Messaging.TapetiExample.csproj
Normal file
11
Messaging.TapetiExample/Messaging.TapetiExample.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
13
Messaging.TapetiExample/PublishSubscribeMessage.cs
Normal file
13
Messaging.TapetiExample/PublishSubscribeMessage.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Messaging.TapetiExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Example of a simple broadcast message used in the standard publish - subscribe pattern
|
||||
/// </summary>
|
||||
public class PublishSubscribeMessage
|
||||
{
|
||||
[Required]
|
||||
public string Greeting { get; set; }
|
||||
}
|
||||
}
|
34
Tapeti.sln
34
Tapeti.sln
@ -23,7 +23,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.Serilog", "Tapeti.Se
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.Transient", "Tapeti.Transient\Tapeti.Transient.csproj", "{A6355E63-19AB-47EA-91FA-49B5E9B41F88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tapeti.DataAnnotations.Extensions", "Tapeti.DataAnnotations.Extensions\Tapeti.DataAnnotations.Extensions.csproj", "{1AAA5A2C-EAA8-4C49-96A6-673EA1EEE831}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tapeti.DataAnnotations.Extensions", "Tapeti.DataAnnotations.Extensions\Tapeti.DataAnnotations.Extensions.csproj", "{1AAA5A2C-EAA8-4C49-96A6-673EA1EEE831}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{266B9B94-A4D2-41C2-860C-24A7C3B63B56}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "01-PublishSubscribe", "Examples\01-PublishSubscribe\01-PublishSubscribe.csproj", "{8350A0AB-F0EE-48CF-9CA6-6019467101CF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleLib", "ExampleHelper.cs\ExampleLib.csproj", "{F3B38753-06B4-4932-84B4-A07692AD802D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Messaging.TapetiExample", "Messaging.TapetiExample\Messaging.TapetiExample.csproj", "{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "02-DeclareDurableQueues", "02-DeclareDurableQueues\02-DeclareDurableQueues.csproj", "{85511282-EF91-4B56-B7DC-9E8706556D6E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -75,10 +85,32 @@ Global
|
||||
{1AAA5A2C-EAA8-4C49-96A6-673EA1EEE831}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1AAA5A2C-EAA8-4C49-96A6-673EA1EEE831}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1AAA5A2C-EAA8-4C49-96A6-673EA1EEE831}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8350A0AB-F0EE-48CF-9CA6-6019467101CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8350A0AB-F0EE-48CF-9CA6-6019467101CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8350A0AB-F0EE-48CF-9CA6-6019467101CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8350A0AB-F0EE-48CF-9CA6-6019467101CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F3B38753-06B4-4932-84B4-A07692AD802D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3B38753-06B4-4932-84B4-A07692AD802D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3B38753-06B4-4932-84B4-A07692AD802D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F3B38753-06B4-4932-84B4-A07692AD802D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{85511282-EF91-4B56-B7DC-9E8706556D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{85511282-EF91-4B56-B7DC-9E8706556D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85511282-EF91-4B56-B7DC-9E8706556D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85511282-EF91-4B56-B7DC-9E8706556D6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{8350A0AB-F0EE-48CF-9CA6-6019467101CF} = {266B9B94-A4D2-41C2-860C-24A7C3B63B56}
|
||||
{F3B38753-06B4-4932-84B4-A07692AD802D} = {266B9B94-A4D2-41C2-860C-24A7C3B63B56}
|
||||
{D24120D4-50A2-44B6-A4EA-6ADAAEBABA84} = {266B9B94-A4D2-41C2-860C-24A7C3B63B56}
|
||||
{85511282-EF91-4B56-B7DC-9E8706556D6E} = {266B9B94-A4D2-41C2-860C-24A7C3B63B56}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B09CC2BF-B2AF-4CB6-8728-5D1D8E5C50FA}
|
||||
EndGlobalSection
|
||||
|
Loading…
Reference in New Issue
Block a user