Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
  • Loading branch information
buyaa-n and gewarren authored May 14, 2024
1 parent 6aadd3a commit 56029a0
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 12 deletions.
4 changes: 2 additions & 2 deletions docs/core/porting/net-framework-tech-unavailable.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ Windows Workflow Foundation (WF) is not supported in .NET 6+. For an alternative
- <xref:System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave>
- <xref:System.Reflection.Emit.AssemblyBuilderAccess.Save>

In .NET 9, a `PersistedAssemblyBuilder` was implemented and the <xref:System.Reflection.Emit.AssemblyBuilder.Save%2A?displayProperty=nameWithType> method was added back to the reflection emit library. To learn more about how to use this API, see [System.Reflection.Emit.PersistedAssemblyBuilder class doc](../../fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md).
In .NET 9, a `PersistedAssemblyBuilder` was implemented and the <xref:System.Reflection.Emit.AssemblyBuilder.Save%2A?displayProperty=nameWithType> method was added back to the reflection emit library. To learn more about how to use this API, see [System.Reflection.Emit.PersistedAssemblyBuilder class](../../fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md).

For more information about the different AssemblyBuilder implementations in .NET check [System.Reflection.Emit.AssemblyBuilder class doc](../../fundamentals/runtime-libraries/system-reflection-emit-assemblybuilder.md)
For more information about the different AssemblyBuilder implementations in .NET, see [System.Reflection.Emit.AssemblyBuilder class](../../fundamentals/runtime-libraries/system-reflection-emit-assemblybuilder.md)

## Loading multi-module assemblies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ ms.date: 05/10/2024

[!INCLUDE [context](includes/context.md)]

The <xref:System.Reflection.Emit.AssemblyBuilder.Save%2A?displayProperty=nameWithType> API wasn't originally ported to .NET (Core) because the implementation depended heavily on Windows-specific native code that also wasn't ported. In .NET 9 we added a fully managed `Reflection.Emit` implementation that supports saving. This implementation has no dependency on the pre-existing, runtime-specific `Reflection.Emit` implementation. That is, now there are two different implementations in .NET, runnable and persisted. To run the persisted assembly, first save it into a memory stream or a file, then load it back. Before `PersistedAssemblyBuilder`, because you could only run a generated assembly and not save it, it was difficult to debug these in-memory assemblies. Advantages of saving a dynamic assembly to a file are:
The <xref:System.Reflection.Emit.AssemblyBuilder.Save%2A?displayProperty=nameWithType> API wasn't originally ported to .NET (Core) because the implementation depended heavily on Windows-specific native code that also wasn't ported. New in .NET 9, the <xref:System.Reflection.Emit.PersistedAssemblyBuilder> class adds a fully managed `Reflection.Emit` implementation that supports saving. This implementation has no dependency on the pre-existing, runtime-specific `Reflection.Emit` implementation. That is, now there are two different implementations in .NET, runnable and persisted. To run the persisted assembly, first save it into a memory stream or a file, then load it back.

Before `PersistedAssemblyBuilder`, you could only run a generated assembly and not save it. Since the assembly was in-memory only, it was difficult to debug. Advantages of saving a dynamic assembly to a file are:

- You can verify the generated assembly with tools such as ILVerify, or decompile and manually examine it with tools such as ILSpy.
- The saved assembly can be loaded directly, no need to compile again, which can decrease application startup time.

To create a `PersistedAssemblyBuilder` instance, use the `public PersistedAssemblyBuilder(AssemblyName name, Assembly coreAssembly, IEnumerable<CustomAttributeBuilder>? assemblyAttributes = null)` constructor. The `coreAssembly` parameter is used to resolve base runtime types and can be used for resolving reference assembly versioning:
To create a `PersistedAssemblyBuilder` instance, use the <xref:System.Reflection.Emit.PersistedAssemblyBuilder.%23ctor(System.Reflection.AssemblyName,System.Reflection.Assembly,System.Collections.Generic.IEnumerable{System.Reflection.Emit.CustomAttributeBuilder})> constructor. The `coreAssembly` parameter is used to resolve base runtime types and can be used for resolving reference assembly versioning:

- If `Reflection.Emit` is used to generate an assembly that will only be executed on the same runtime version as the runtime version that the compiler is running on (typically in-proc), the core assembly can be simply `typeof(object).Assembly`. The following example demonstrates how to create and save an assembly to a stream and run it with the current runtime assembly:

Expand All @@ -30,13 +32,13 @@ To set the entry point for an executable or to set other options for the assembl

## Emit symbols and generate PDB

The symbols metadata is populated into the `pdbBuilder` out parameter when you call the `GenerateMetadata(out BlobBuilder ilStream, out BlobBuilder mappedFieldData, out MetadataBuilder pdbBuilder)` method on a `PersistedAssemblyBuilder` instance. To create an assembly with a portable PDB:
The symbols metadata is populated into the `pdbBuilder` out parameter when you call the <xref:System.Reflection.Emit.PersistedAssemblyBuilder.GenerateMetadata(System.Reflection.Metadata.BlobBuilder@,System.Reflection.Metadata.BlobBuilder@)> method on a `PersistedAssemblyBuilder` instance. To create an assembly with a portable PDB:

1. Create `ISymbolDocumentWriter` instances with the `ModuleBuilder.DefineDocument(...)` method. While emitting the method's IL, also emit the corresponding symbol info.
2. Create a `PortablePdbBuilder` instance using the `pdbBuilder` instance produced by the `GenerateMetadata(...)` method.
3. Serialize the `PortablePdbBuilder` into a `Blob`, and write the `Blob` into a PDB file stream (only if you're generating a standalone PDB).
4. Create a `DebugDirectoryBuilder` instance and add a `CodeViewEntry` (standalone PDB) or `EmbeddedPortablePdbEntry`.
5. Set the optional `debugDirectoryBuilder` argument when creating the `PEBuilder` instance.
1. Create <xref:System.Diagnostics.SymbolStore.ISymbolDocumentWriter> instances with the <xref:System.Reflection.Emit.ModuleBuilder.DefineDocument(System.String,System.Guid,System.Guid,System.Guid)?displayProperty=nameWithType> method. While emitting the method's IL, also emit the corresponding symbol info.
2. Create a <xref:System.Reflection.Metadata.Ecma335.PortablePdbBuilder> instance using the `pdbBuilder` instance produced by the <xref:System.Reflection.Emit.PersistedAssemblyBuilder.GenerateMetadata(System.Reflection.Metadata.BlobBuilder@,System.Reflection.Metadata.BlobBuilder@)> method.
3. Serialize the `PortablePdbBuilder` into a <xref:System.Reflection.Metadata.Blob>, and write the `Blob` into a PDB file stream (only if you're generating a standalone PDB).
4. Create a <xref:System.Reflection.PortableExecutable.DebugDirectoryBuilder> instance and add a <xref:System.Reflection.PortableExecutable.DebugDirectoryBuilder.CodeViewEntry%2A?displayProperty=nameWithType> (standalone PDB) or <xref:System.Reflection.PortableExecutable.DebugDirectoryBuilder.EmbeddedPortablePdbEntry%2A?displayProperty=nameWithType>.

Check failure on line 40 in docs/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.md

View workflow job for this annotation

GitHub Actions / lint

Trailing spaces [Expected: 0 or 2; Actual: 1]
5. Set the optional `debugDirectoryBuilder` argument when creating the <xref:System.Reflection.PortableExecutable.PEBuilder> instance.

The following example shows how to emit symbol info and generate a PDB file.

Expand Down Expand Up @@ -98,7 +100,7 @@ static DebugDirectoryBuilder GeneratePdb(MetadataBuilder pdbBuilder, ImmutableAr
}
```

Further you could add `CustomDebugInformation` by calling the `AddCustomDebugInformation` method from the `pdbBuilder` instance to add source embedding and source indexing etc. advanced PDB info.
Further, you can add <xref:System.Reflection.Metadata.CustomDebugInformation> by calling the <xref:System.Reflection.Metadata.Ecma335.MetadataBuilder.AddCustomDebugInformation(System.Reflection.Metadata.EntityHandle,System.Reflection.Metadata.GuidHandle,System.Reflection.Metadata.BlobHandle)?displayProperty=nameWithType> method from the `pdbBuilder` instance to add source embedding and source indexing advanced PDB information.

```csharp
private static void EmbedSource(MetadataBuilder pdbBuilder)
Expand All @@ -113,7 +115,7 @@ private static void EmbedSource(MetadataBuilder pdbBuilder)

## Add resources with PersistedAssemblyBuilder

You can call `MetadataBuilder.AddManifestResource(...)` to add as many resources as needed. Streams must be concatenated into one `BlobBuilder` that you pass into the `ManagedPEBuilder` argument.
You can call <xref:System.Reflection.Metadata.Ecma335.MetadataBuilder.AddManifestResource(System.Reflection.ManifestResourceAttributes,System.Reflection.Metadata.StringHandle,System.Reflection.Metadata.EntityHandle,System.UInt32)?displayProperty=nameWithType> to add as many resources as needed. Streams must be concatenated into one <xref:System.Reflection.Metadata.BlobBuilder> that you pass into the <xref:System.Reflection.PortableExecutable.ManagedPEBuilder> argument.
The following example shows how to create resources and attach it to the assembly that's created.

:::code language="csharp" source="./snippets/System.Reflection.Emit/PersistedAssemblyBuilder/Overview/csharp/GenerateMetadataSnippets.cs" id="Snippet2":::
Expand Down

0 comments on commit 56029a0

Please sign in to comment.