C# Azure Functions code generator using autorest
Перейти к файлу
Pavel Krymets 0bacd527e6
Untangle constructor generation a bit (#716)
2020-04-30 10:03:02 -07:00
.github/ISSUE_TEMPLATE
eng
samples
src
test
.editorconfig
.gitattributes
.gitignore
AutoRest.CSharp.V3.sln
Directory.Build.props
Directory.Build.targets
global.json
package-lock.json
package.json
readme.md

readme.md

C# code generator for AutoRest V3

Setup

Build

  • dotnet build (at root)
  • ./eng/Generate.ps1 (at root in PowerShell Core)

Test

  • dotnet test (at root)

Customizing the generated code

Make a model internal

Define a class with the same namespace and name as generated model and use the desired accessibility.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model { }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    internal partial class Model { }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
-    public partial class Model { }
+    internal partial class Model { }
}

Rename a model class

Define a class with a desired name and mark it with [CodeGenModel("OriginalName")]

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model { }
}

Add customized model (NewModelClassName.cs)

namespace Azure.Service.Models
{
    [CodeGenModel("Model")]
    public partial class NewModelClassName { }
}

Generated code after (Generated/Models/NewModelClassName.cs):

namespace Azure.Service.Models
{
-    public partial class Model { }
+    public partial class NewModelClassName { }
}

Make model property internal

Define a class with a property matching a generated property name but with desired accessibility.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        public string Property { get; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    public partial class Model
    {
        internal string Property { get; } 
    }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        public string Property { get; }
    }
}

Rename a model property

Define a partial class with a new property name and mark it with [CodeGenMember("OriginalName")] attribute.

NOTE: you can also change a property to a field using this mapping.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        public string Property { get; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    public partial class Model
    {
        [CodeGenMember("Property")]
        public string RenamedProperty { get; } 
    }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        public string Property { get; }
+        // All original Property usages would reference a RenamedProperty
    }
}

Change a model property type

⚠️

NOTE: This is supported for a narrow set of cases where the underlying serialized type doesn't change

Scenarios that would work:

  1. String <-> TimeSpan (both represented as string in JSON)
  2. Float <-> Int (both are numbers)
  3. String <-> Enums (both strings)

Won't work:

  1. String <-> Bool (different json type)
  2. Changing model kinds

If you think you have a valid re-mapping scenario that's not supported file an issue.

⚠️

Define a property with different type than the generated one.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        public string Property { get; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    public partial class Model
    {
        public DateTime Property { get; }
    }
}

Generated code after (Generated/Models/Model.Serializer.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        public string Property { get; }
+        // Serialization code now reads and writes DateTime value instead of string  
    }
}

Changing member doc comment

Redefine a member in partial class with a new doc comment.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        /// Subpar doc comment
        public string Property { get; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    public partial class Model
    {
        /// Great doc comment
        public string Property { get; }
    }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        /// Subpar doc comment
-        public string Property { get; }  
    }
}

Customize serialization/deserialization methods

Use the Replace any generated member approach to replace Serialize/Deserialize method with a custom implementation.

Generated code before (Generated/Models/Cat.Serialization.cs):

namespace Azure.Service.Models
{
  public partial class Cat
  {
      internal static Cat DeserializeCat(JsonElement element)
      {
          string color = default;
          string name = default;
          foreach (var property in element.EnumerateObject())
          {
              if (property.NameEquals("color"))
              {
                  if (property.Value.ValueKind == JsonValueKind.Null)
                  {
                      continue;
                  }
                  color = property.Value.GetString();
                  continue;
              }
              if (property.NameEquals("name"))
              {
                  if (property.Value.ValueKind == JsonValueKind.Null)
                  {
                      continue;
                  }
                  name = property.Value.GetString();
                  continue;
              }
          }
          return new Cat(id, name);
      }
  }
}

Add customized model (Cat.cs)

namespace Azure.Service.Models
{
  public partial class Cat
  {
      internal static Cat DeserializeCat(JsonElement element)
      {
          string color = default;
          string name = default;
          foreach (var property in element.EnumerateObject())
          {
              if (property.NameEquals("name"))
              {
                  if (property.Value.ValueKind == JsonValueKind.Null)
                  {
                      continue;
                  }
                  name = property.Value.GetString();
                  continue;
              }
          }
          // WORKAROUND: server never sends color, default to black
          color = "black";
          return new Cat(name, color);
      }
  }
}

Generated code after (Generated/Models/Model.cs):

Generated code won't contain the DeserializeCat method and the custom one would be used for deserialization.

Renaming an enum

Redefine an enum with a new name and all the members mark it with [CodeGenModel("OriginEnumName")].

NOTE: because enums can't be partial all values have to be copied

Generated code before (Generated/Models/Colors.cs):

namespace Azure.Service.Models
{
    public enum Colors
    {
        Red,
        Green,
        Blue
    }
}

Add customized model (WallColors.cs)

namespace Azure.Service.Models
{
    [CodeGenModel("Colors")]
    public enum WallColors
    {
        Red,
        Green,
        Blue
    }
}

Generated code after (Generated/Models/Model.cs):

-namespace Azure.Service.Models
-{
-    public enum Colors
-    {
-        Red,
-        Green,
-        Blue
-    }
-}
+// Serialization code uses the new WallColors type name

Renaming an enum member

Redefine an enum with the same name and all the members, mark renamed member with [CodeGenMember("OriginEnumMemberName")].

NOTE: because enums can't be partial all values have to be copied but only the ones being renamed should be marked with an attributes

Generated code before (Generated/Models/Colors.cs):

namespace Azure.Service.Models
{
    public enum Colors
    {
        Red,
        Green,
        Blue
    }
}

Add customized model (Colors.cs)

namespace Azure.Service.Models
{
    public enum Colors
    {
        Red,
        Green,
        [CodeGenMember("Blue")]
        SkyBlue
    }
}

Generated code after (Generated/Models/Model.cs):

-namespace Azure.Service.Models
-{
-    public enum Colors
-    {
-        Red,
-        Green,
-        Blue
-    }
-}
+// Serialization code uses the new SkyBlue member name

Make a client internal

Define a class with the same namespace and name as generated client and use the desired accessibility.

Generated code before (Generated/Operations/ServiceClient.cs):

namespace Azure.Service.Operations
{
    public partial class ServiceClient { }
}

Add customized model (Model.cs)

namespace Azure.Service.Operations
{
    internal partial class ServiceClient { }
}

Generated code after (Generated/Operations/ServiceClient.cs):

namespace Azure.Service.Operations
{
-    public partial class ServiceClient { }
+    internal partial class ServiceClient { }
}

Rename a client

Define a partial client class with a new name and mark it with [CodeGenClient("OriginalName")]

Generated code before (Generated/Operations/ServiceClient.cs):

namespace Azure.Service.Operations
{
    public partial class ServiceClient {}
}

Add customized model (Model.cs)

namespace Azure.Service.Operations
{
    [CodeGenClient("ServiceClient")]
    public partial class TableClient { }
}

Generated code after (Generated/Operations/ServiceClient.cs):

namespace Azure.Service.Operations
{
-    public partial class ServiceClient { }
+    public partial class TableClient { }
}

Replace any generated member

Works for model and client properties, methods, constructors etc.

Define a partial class with member with the same name and for methods same parameters.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        public Model()
        {  
            Property = "a";
        }

        public string Property { get; set; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    public partial class Model
    {
        internal Model()
        {
            Property = "b";
        }
    }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        public Model()
-        {  
-            Property = "a";
-        }
    }
}

Remove any generated member

Works for model and client properties, methods, constructors etc.

Define a partial class with [CodeGenSuppress("NameOfMember", typeof(Parameter1Type), typeof(Parameter2Type))] attribute.

Generated code before (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
        public Model()
        {  
            Property = "a";
        }

        public Model(string property)
        {  
            Property = property;
        }

        public string Property { get; set; }
    }
}

Add customized model (Model.cs)

namespace Azure.Service.Models
{
    [CodeGenSuppress("Model", typeof(string))]
    public partial class Model
    {
    }
}

Generated code after (Generated/Models/Model.cs):

namespace Azure.Service.Models
{
    public partial class Model
    {
-        public Model(string property)
-        {  
-            Property = property;
-        }
    }
}

Configuration

# autorest-core version
version: 3.0.6282
shared-source-folder: $(this-folder)/src/assets
save-inputs: true
use: $(this-folder)/artifacts/bin/AutoRest.CSharp.V3/Debug/netcoreapp3.0/
clear-output-folder: false

pipeline:
  csharpproj:
    input: modelerfour/identity
  csharpproj/emitter:
    input: csharpproj
    scope: output-scope