dotnetYang is a Roslyn source generator for using the .yang language to generate C# code, providing access to data models, ease-of-use asynchronous RPC, Action & Notification calls directly from code and generated server interfaces.
- Drop-and-go: Add your .yang files to a C# project as additional files that references this generator, that is it, your .yang defined RPC's and more are now available directly in that C# projects code
- Server-interface: Want to implement a server that responds to NETCONF calls? Look no further than the generated interface
IYangServer
and it's extension methodasync Task Recieve(this IYangServer server, Stream input, Stream output);
which provides a framework for implementing your own server without having to worry about serializing and parsing NETCONF directly, but instead work with well defined C# Datatypes.
In order to start using dotnetYang
on a new .csproj project, start by adding the nuget packages by, for example, using the dotnet CLI in your project directory:
dotnet add package dotnetYang
Afterwards, create or add a .yang file to said project:
some-module.yang
module some-module {
yang-version 1.1;
namespace "urn:dotnet:yang:some:module";
prefix sm;
identity someIdentity;
identity someOtherIdentity
{
base someIdentity;
}
rpc doSomething {
input {
leaf the-big-leaf
{
type uint32;
default "4";
description "The value that is the input of the doSomething rpc";
}
}
output {
leaf response
{
type identityref
{
base someIdentity;
}
default "someOtherIdentity";
description "The identity that is the output of the doSomething rpc";
}
}
}
}
And then add it as an additional file to your .csproj file
<Project Sdk="Microsoft.NET.Sdk">
<!--Other parts of the .csproj file -->
<ItemGroup>
<AdditionalFiles Include="some-module.yang" />
</ItemGroup>
<!--Other parts of the .csproj file -->
</Project>
Now the generated C# code from some-module.yang
will be available, with it's naming conventions adjusted to be C# compliant
namespace MyProject;
public class Program
{
public static async Task Main()
{
IChannel channel = //...Code for setting up whatever channel you want to send the rpc over
int messageID = //...Code for getting message id;
//Set up the rpc input, not the slight name changes
Some.Module.YangNode.DoSomethingInput input = new Some.Module.YangNode.DoSomethingInput
{
TheBigLeaf = 123
};
//Call the rpc function, note the slight name changes and the asynchronous nature of the call
Some.Module.YangNode.DoSomethingOutput output = await Some.Module.YangNode.DoSomething(channel, messageID, input);
//Write the "response" leaf of the output to console.
Console.WriteLine(output.Response);
}
}
Say that you want to create a server that can response to calls defined in some-module.yang
, then you would create a class that implementes the generated IYangServer
interface, which might look something like this:
using Some.Module;
namespace MyProject;
public class Server : IYangServer
{
public async Task<YangNode.DoSomethingOutput> OnDoSomething(YangNode.DoSomethingInput input)
{
//Do whatever it is the server is expected to do when told to "doSomething"...
//Await something, do something else, the options are endless...
//Create the output, not nessecarily like this..
YangNode.DoSomethingOutput output = new YangNode.DoSomethingOutput();
return output;
}
}
Of course, if there are a lot of yang modules in a project, IYangServer
runs the risk of becoming rather big. In such a case, it is recommended to split it's implementation into several partial
server classes in order to maintain readability.