

Build server – client contracts with dotnet CLI
source link: https://andersmalmgren.com/2019/03/14/build-server-client-contracts-with-dotnet-cli/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Build server – client contracts with dotnet CLI
Now days type safety is common within the web-world with TypeScript and on the horizon WebAssembly with .NET Core (Blazor etc). I have for a long time advocated for the importance of this, especially when we are talking the contract between server and client. For example this T4 template that spits out C# CQS types as javascript.
T4 doesn’t play well with Dot Net Core, but we now have the dotnet CLI toolset we can use instead.
First we need to create the tool project, its just a standard .NET Core console project, but the output must be prefixed with dotnet- by convention for the dotnet CLI to understand what todo with it. Edit the .csproj and add <PackageType>DotnetCliTool</PackageType>. This will tell the host project that the included program is a CLI toolset. Now you build and package the console project. Configure a local nuget repo for testing.
Now edit your host project .csproj add
<DotNetCliToolReference Include="dotnet.my-cli" Version="x.x.x" />
Where dotnet.my-cli is your CLI package ID. This will only include the CLI project. To execute we need to add a build target. For example.
<Target Name="MyCliTarget" AfterTargets="Build">
<Exec Command="dotnet mycli arg1 arg2" />
</Target>
Notice that we have removed dotnet- prefix. This will call your tool when you build the project and with two arguments. You can use standard msbuild variables here such as $(OutputPath). Thats it, now your program will be called and the maqic can begin.
Building the contracts CLI program
The target for our CLI could look like this
<Target Name="MyCliTarget" AfterTargets="Build">
<Exec Command="dotnet cqsgen $(OutputPath)Core.Contracts.dll $(MSBuildProjectDirectory)\wwwroot\js\cqs.contracts.js Core.Contracts.Commands.Command;Core.Contracts.Queries.Query" />
</Target>
Msbuild paths are relative from the project root. Lucky for us Directory.GetCurrentDirectory() points to this directory. So to get a project resource we can do $”{Directory.GetCurrentDirectory()}\\{args[0]}”;. Full code of our Program.cs
class
Program
{
static
void
Main(
string
[] args)
{
var
ignoreBaseClassProperties = args.Any(a => a.ToLower() ==
"ignore-properties-on-base"
);
Console.WriteLine(
"Starting parsing cqs contracts!"
);
var
assemblyPath = $
"{Directory.GetCurrentDirectory()}\\{args[0]}"
;
var
outputPath = args[1];
var
parser =
new
Parser(args[2].Split(
";"
), assemblyPath, ignoreBaseClassProperties);
var
result = parser.Parse();
Console.WriteLine($
"Parsing complete, saving: {outputPath}"
);
File.WriteAllText(outputPath, result);
}
}
We basically parse the args and pass them to the Parser class. I’m not going into full detail about the parsing, but it will output a javascript like this.
(
function
() {
window.Core = (window.Core || {});
window.Core.Contracts = (window.Core.Contracts || {});
window.Core.Contracts.Queries = (window.Core.Contracts.Queries || {});
window.Core.Contracts.Queries.Payments = (window.Core.Contracts.Queries.Payments || {});
window.Core.Contracts.Rest = (window.Core.Contracts.Rest || {});
Core.Contracts.Rest.PaymentStatus = {
WaitingApproval: 0,
Approved: 1,
Cancelled: 3,
Error: 4
};
Contracts.Queries.Payments.PaymentsQuery=
function
(status) {
this
.status = status;
};
Core.Contracts.Queries.Payments.PaymentsQuery.constructor.type=
"Core.Contracts.Queries.Payments.PaymentsQuery"
;
})();
It makes sure no closures are overwritten. Also this way we can benefit from full Visual Studio code completion. It also adds the type name to the constructor. This enabled us to lookup the C# type in runtime. For example like.
MyApp.cqs = {
sendQuery:
function
(query) {
return
$.getJSON(url + toQueryString(query));
},
sendCommand:
function
(command) {
$.post(url, { type: command.constructor.type, data: command});
}
};
MyApp.cqs.sendQuery(
new
Core.Contracts.Queries.Payments.PaymentsQuery(Core.Contracts.Rest.PaymentStatus.Approved));
Full code can be found here!
Recommend
-
142
How we use gRPC to build a client/server system in Go
-
39
Using Ethereum smart contracts on the client side I was working on a project recently and was trying to build a smart contract to be deployed from the client side. The idea was to allo...
-
9
dotnet cli 5.0 新特性——dotnet tool search Intro# .NET 5.0 SDK 的发布,给 dotnet cli 引入了一个新的特性,dotnet tool search,主要用于搜索 Nuget...
-
10
Installing the Docker Client CLI on 32-bit Windows April 1, 2016 If you’re unfamiliar with it, Docker is one of the newer development tools on the scene which takes...
-
17
NextDNS CLI Client NextDNS CLI is a DNS53 to DNS-over-HTTPS (DoH) proxy with advanced capabilities to get the most out of the NextDNS service. Although the most advanced features will only work with...
-
6
Let's build a gRPC server and client in Rust with tonic Published Thu, Jul 7, 2022 / by
-
9
-
5
Add All Project to Solution with dotnet CLI Date Published: 15 December 2022
-
7
HTTP Client CLI – Run Requests and Tests on CI ...
-
5
Thunder Client CLIA new way to test APIs inside VS CodeThunder Client CLI provides new way to test APIs inside VSCode and and features like Integration with Thunder Client extensi...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK