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)
{


}
}
}

Usefull

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