Skip to main content

DotnetYang by Westermo Network Technologies

NuGet / site data

Nuget GitHub last commit GitHub Repo stars

Details

Info

info

Name: DotnetYang

Package Description

Author: Westermo Network Technologies

NuGet: https://www.nuget.org/packages/DotnetYang/

You can find more details at https://github.com/westermo/DotnetYang

Source: https://github.com/westermo/DotnetYang

Original Readme

note

Nuget (Generator) Build License

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.

Features

  • 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 method async 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.

Documentation

Getting Started

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);
}
}

Server creation

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.

About

note

Generating source code from YANG models

How to use

Example (source csproj, source files)

This is the CSharp Project that references DotnetYang

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>


<ItemGroup>
<AdditionalFiles Include="demo.yang" />
</ItemGroup>

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="dotnetYang" Version="0.3.0" />
</ItemGroup>

</Project>

Generated Files

Those are taken from $(BaseIntermediateOutputPath)\GX

using System;
using System.Xml;
using YangSupport;
namespace yangDemo;
///<summary>
///Configuration root object for yangDemo based on provided .yang modules
///</summary>

public class Configuration
{
public Some.Module.YangNode? SomeModule { get; set; }
public async Task WriteXMLAsync(XmlWriter writer)
{
await writer.WriteStartElementAsync(null,"root",null);

if(SomeModule is not null) await SomeModule.WriteXMLAsync(writer);
await writer.WriteEndElementAsync();
}
public static async Task<Configuration> ParseAsync(XmlReader reader)
{
Some.Module.YangNode? _SomeModule = default!;
while(await reader.ReadAsync())
{
switch(reader.NodeType)
{
case XmlNodeType.Element:
switch(reader.Name)
{
case "some-module":
_SomeModule = await Some.Module.YangNode.ParseAsync(reader);
continue;
case "rpc-error": throw await RpcException.ParseAsync(reader);
default: throw new Exception($"Unexpected element '{reader.Name}' under 'root'");
}
case XmlNodeType.EndElement when reader.Name == "root":
return new Configuration{
SomeModule = _SomeModule,
};
case XmlNodeType.Whitespace: break;
default: throw new Exception($"Unexpected node type '{reader.NodeType}' : '{reader.Name}' under 'root'");
}
}
throw new Exception("Reached end-of-readability without ever returning from Configuration.ParseAsync");
}
}
public static class IYangServerExtensions
{
public static async Task Receive(this IYangServer server, global::System.IO.Stream input, global::System.IO.Stream output)
{
var initialPosition = output.Position;
var initialLength = output.Length;
string? id = null;
using XmlReader reader = XmlReader.Create(input, SerializationHelper.GetStandardReaderSettings());
using XmlWriter writer = XmlWriter.Create(output, SerializationHelper.GetStandardWriterSettings());
try
{
await reader.ReadAsync();
switch(reader.Name)
{
case "rpc":
id = reader.ParseMessageId();
await writer.WriteStartElementAsync(null, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0");
await writer.WriteAttributeStringAsync(null, "message-id", null, id);
await reader.ReadAsync();
switch(reader.Name)
{
case "action":
await server.ReceiveAction(reader, writer);
break;
default:
await server.ReceiveRPC(reader, writer);
break;
}
await writer.WriteEndElementAsync();
await writer.FlushAsync();
break;
case "notification":
var eventTime = await reader.ParseEventTime();
await reader.ReadAsync();
await server.ReceiveNotification(reader, eventTime);
break;
}
}
catch(RpcException ex)
{
await writer.FlushAsync();
output.Position = initialPosition;
output.SetLength(initialLength);
await ex.SerializeAsync(output,id);
}
catch(Exception ex)
{
await writer.FlushAsync();
output.Position = initialPosition;
output.SetLength(initialLength);
await output.SerializeRegularExceptionAsync(ex,id);
}
}
public static async Task ReceiveRPC(this IYangServer server, XmlReader reader, XmlWriter writer)
{
switch(reader.Name)
{
case "doSomething" when reader.NamespaceURI is "urn:dotnet:yang:andrei":
{
var input = await Some.Module.YangNode.DoSomethingInput.ParseAsync(reader);
var task = server.OnDoSomething(input);
var response = await task;
await response.WriteXMLAsync(writer);
}
break;
}
}
public static async Task ReceiveAction(this IYangServer server, XmlReader reader, XmlWriter writer)
{
await reader.ReadAsync();
switch(reader.Name)
{

}
}
public static async Task ReceiveNotification(this IYangServer server, XmlReader reader, DateTime eventTime)
{
switch(reader.Name)
{


}
}
}

Useful

Download Example (.NET C# )

Share DotnetYang

https://ignatandrei.github.io/RSCG_Examples/v2/docs/DotnetYang

In the same category (FilesToCode) - 13 other generators

Chorn.EmbeddedResourceAccessGenerator

corecraft

Datacute.EmbeddedResourcePropertyGenerator

EmbedResourceCSharp

LingoGen

NotNotAppSettings

Podimo.ConstEmbed

ResXGenerator

RSCG_JSON2Class

RSCG_Utils

ThisAssembly_Resources

ThisAssembly.Strings

Weave