Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Model from layout bindings #78

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

ivarne
Copy link
Member

@ivarne ivarne commented Apr 27, 2022

This is a very early work in process where I try to explore the feasibility of using Source generators to generate a C# model that supports all the dataModelBindings from the Layout files. This means that for development (at least) we can just add components in the layout definitions in json, and the corresponding C# class will be included in the compilation and used by InteliSense in both VS 2022 and VS code.

As a shortcut for easy testing I modified the src/App template to be a valid app with layouts I could use for testing. This would obviously need to be removed before merging.

The current code generation is very rudimentary and needs a lot of work. The main focus was to ensure that compilation and IntelliSense worked, and to get a feel for the development process. Because the generator needs to run as part of VisualStudio/Omnisharp it is a lot harder to develop this kind of functionality than I imagined. Fully automatic testing would also be hard, as the errors are different when running in VS/VSCode/dotnet commandline, so there would need to be a manual routine to ensure that everything works everywhere before relasing new versions. The generator can be referenced as a normal .dll from a .Test project, so unit testing is pretty easy.

Notes

This PR includes a new project Altinn.App.ModelGenerator and a corresponding .Test project. The ModelGenerator will be referenced from App.csproj with some special attributes, and mapping the json files as AdditionalFiles so they become availible in the compilation.

  <ItemGroup>
    <!-- Use Model Generator -->
    <ProjectReference Include="..\Altinn.App.ModelGenerator\Altinn.App.ModelGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    <AdditionalFiles Include="config\**\*.json"></AdditionalFiles>
    <AdditionalFiles Include="ui\**\*.json"></AdditionalFiles>
  </ItemGroup>

Actual usage

After adding the reference to the package, you can just delete your [modelName].cs file, and all your references in DataProcessing and Instantiation will continue to work as the model is now autogenerated. When you add new dataModelBindings, they will automatically be part of the model.

Known remaining issues

  1. Missing annotations means serialization to Json and XML might be buggy
  2. Current code generation is awfull, and does not Pascal case Class Names, nor handle duplicate classes.
  3. Does not yet generate json schema for frontend validation (nor xsd, but I don't think that is actually used?)
  4. Uses a new concept that might be unfamiliar to many app developers, and make debugging confusing.

Transitive dependencies for the generator

The generator needs to parse Json, and I opted for System.Text.Json. It has a few dependencies, and for some unknown reason a Source generator needs to reference all transitive dependencies as in the following section.

 <!-- 
    Start referencing System.Text.Json (and all dependencies)
    This is a manual multistep process because it needs to run as part of the
    compillation process (in Visual Studio), so it can't use the normal dependency resolving
  -->
  <ItemGroup>
    <PackageReference Include="System.Text.Json" Version="6.0.1" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Buffers" Version="4.5.1" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Memory" Version="4.5.4" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" GeneratePathProperty="true" PrivateAssets="all" />
  </ItemGroup>

  <PropertyGroup>
    <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
  </PropertyGroup>

  <Target Name="GetDependencyTargetPaths">
    <ItemGroup>
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Json)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Bcl_AsyncInterfaces)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Runtime_CompilerServices_Unsafe)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Threading_Tasks_Extensions)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Buffers)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Memory)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Numerics_Vectors)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Encodings_Web)\lib\netstandard2.0\*.dll" IncludeRuntimeDependency="false" />
    </ItemGroup>
  </Target>
  <!-- End referencing System.Text.Json (and dependencies) -->

@nkylstad nkylstad added the external-contribution-❤️ Pull request from a developer outside the Altinn teams. label Jun 14, 2022
@RonnyB71
Copy link
Member

RonnyB71 commented Jul 6, 2022

@ivarne suggest we put this on hold until the work on #90 is done, ok by you?

@ivarne
Copy link
Member Author

ivarne commented Jul 6, 2022

Yes, That seems rather obvious to me.

@ivarne ivarne marked this pull request as draft July 6, 2022 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external-contribution-❤️ Pull request from a developer outside the Altinn teams.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants