Microservices on .net core with Nancy - Part 2
Even though we already have console logging, we'll add a LoggingService so that we can figure out how Microservices might talk to each other. We'll be invoking the service directly over HTTP via a pseudo-RPC mechanism.
Note that we aren't considering a number of things that you'll ordinarily want to consider for a larger microservices project such as the use of a correlation ID, retries, fire and forget, or an event driven architecture.
You can get the starter code for this from Bitbucket - go ahead and grab it, or use your code from Part 1.
Dev Environment
If you haven't followed part 1, here's a rundown:
- The dev environment, all tools & code will run on Mac, PC or Linux
- We are using Visual Studio Code
- Open the Solution root folder in vscode
- Install the following Visual Studio Code Extensions (click "Extensions" in the sidebar): C#, C# Extensions and hit the Restart button once installed
- Open the command palette (CMD-Shift-P on Mac, Ctrl-Shift-P on PC) and use the "OmniSharp: Select Project" command. Set it to the Solution root folder.
Migrate old projects to csproj
Since Part 1 was written, Microsoft have updated their dotnet tools to remove support for project.json (and xproj). Instead, they've reverted back to the MSBuild-based .csproj, but it's much less bloaty. Make sure your .net core SDK is up to date
Navigate into the src/FactorialService and src/FactorialService.Models folders and type "dotnet migrate" in a terminal. This will replace the project.json files with csproj files.
Create new projects
In the "src" folder, either from VSCode built in terminal, or a separate prompt, type:
Delete the "Class1.cs" file from the models project.
Add packages
Another welcome new feature in the dotnet CLI is the ability to add packages.
In LoggingService, run:
In LoggingService.Models, run:
Create the Models
In LoggingService.Models, add a new C# file, called LogRequest.cs, and add a "Message" property.
Then create one more C# file, called LogResponse.cs, add a "Success" property and a property to hold any errors.
Reference LoggingService.Models from LoggingService
Run this command-line from the LoggingService folder:
Reference LoggingService.Models from FactorialService
We'll be referencing the logging service models (but not the service itself) from FactorialService. This is the "contract".
Run the same command as above, from the FactorialService folder:
Create the LoggingService
Similar to FactorialService, we need 4 new c-sharp source files in our LoggingService: a startup file, the nancy bootstrapper, the nancy module, and the validations. We already have a Program.cs file that we will change. This simple structure is copied from our first service, and easily repeatable.
Startup.cs
Typical asp.net core boilerplate. Here we add a console logger and tell our microservice to serve requests with Nancy, and with our Nancy Bootstrapper that we are about to create.
Program.cs
Again, typical boilerplate. We want to serve requests on port 5002 so as to not conflict with our first service, that serves on 5001. Note the asterisk means "any hostname" and is useful for ensuring the same code works in any environment.
Bootstrapper.cs
The nancy bootstrapper is used to copy dependencies from .net core's DI system into Nancy's TinyIOC.
Module.cs
This is the guts of the service. For this implementation, we're simply logging the received message to console. However, you may want to write to file system or a database in a proper implementation.
Validators.cs
We'll just make sure the message we want to log isn't empty.
Testing LoggingService
To test, we simply need to restore packages, and run. In a terminal, from LoggingService:
You should see:
Hosting environment: Production
Content root path: src\LoggingService
Now listening on: http://*:5002
Application started. Press Ctrl+C to shut down.
Now we can test in Postman. Launch it, and test our endpoint.
Invoking LoggingService from FactorialService
Hopefully that all works as-above. Now we simply need to build some plumbing to allow the Factorial service to invoke the Logging service. Normally you might put this plumbing into a small helper assembly, where you could add policies using something like Polly. For now, we'll just add it straight into our FactorialService.
Add Newtonsoft.Json package
Since we're dealing with JSON, we need this. In a terminal, in the FactorialService directory:
ServiceClient.cs
Since we're only calling post, we'll just implement the post method here... but you should implement the other methods as needed, plus any policies you want to implement. This implementation will work for any service call that has a request and response object and takes a POST.
Add a new class to FactorialService:
Inject our client
We need to inject our client - firstly into .net core's application services, then into Nancy's TinyIOC. 2 small changes required.
In FactorialService's Startup class:
In FactorialService's Bootstrapper:
Change Log statements
We replace the log statements in our factorial service with code to call the Logging microservice. Note I've left the old ILogger in there to make it easier to see changes, but it can be safely removed.
In FactorialService's Module.cs
Done! Testing time
All that's left is to test that it all works. Open 2 terminal windows and start both of our services with:
Run this in FactorialService and LoggingService folders, in each terminal:
Now, test our FactorialService in Postman:
There you go! 2 microservices in .net core with nancy; talking to each other over REST.