Hallo Leute!
Visual Studio 2019, 16.9.4
Microsoft.CodeAnalysis.CSharp 3.9.0
Ich möchte Dapper ORM-Mappings dynamisch erstellen und verwende dazu folgenden Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using DFM = Dapper.FluentMap.Mapping;
namespace Fips.ORM.Dapper
{
public class MappersCreator
{
private Type CreateType(Type type, string name, Dictionary<string,string> mappings)
{
var assemblyName = type.Assembly.FullName;
var nspace = type.Namespace;
var sb = new StringBuilder();
foreach (var kv in mappings) {
sb.Append($" Map(m => m.{kv.Key}).ToColumn(\"{kv.Value}\");\n");
}
var code = $@"using Dapper.FluentMap.Mapping;
namespace {nspace}
{{
public class {name}Mapper : EntityMap<{name}>
{{
public {name}Mapper()
{{
{sb.ToString()}
}}
}}
}}";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
new[] { syntaxTree },
new MetadataReference[] {
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(type.Assembly.Location),
MetadataReference.CreateFromFile(typeof(DFM.EntityMap<Type>).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Expression<Type>).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
},
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
using (var memoryStream = new MemoryStream()) {
EmitResult result = compilation.Emit(memoryStream);
if (result.Success) {
memoryStream.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(memoryStream.ToArray());
Type ret = assembly.GetType($"{nspace}.{name}");
return ret;
} else {
foreach (var diagnostic in result.Diagnostics) {
Console.WriteLine(diagnostic);
}
return null;
}
}
}
}
}
Leider kriege ich nur folgende Fehler bei compilation.Emit(memoryStream) auf Zeile 51:> Fehlermeldung:
(5,32): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,30): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,33): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
Das ist mein CSPROJ-File:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="Dapper.FluentMap" Version="2.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Linq" />
<Reference Include="System.Linq.Expressions" />
<Reference Include="netstandard" />
</ItemGroup>
</Project>
Warum werden meine Referenzenangaben auf den Zeilen 42 und 45 (scheinbar) einfach ignoriert? Oder was ist sonst der Fehler?
Liebe Grüsse,
Fabiano
Klingt für mich eher nach einem Fall für ein eigenes Snippet.
Warum machst du es dir hier schwer und willst mit Roslyn was generieren lassen, was Code Snippets in VS schon erledigen können?
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Vielen Dank für deine schnelle Antwort!
Der Typ soll natürlich zur Laufzeit generiert werden, generierter Source oder gar eine Installation von VS kann ich nicht voraussetzen.
Im Prinzip hätt ich auch per System.Reflection.Emit.GetILGenerator direkt Bytecode erzeugen können, aber das ist mir zu hoch! 😉
Hallo Fabiano,
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
Hat mich auch schon ein paar Nerven gekostet, aber es geht (momentan) nur mit .NET Standard 2.0 als TFM.
Edit: dazu gibt es eine Issue Don't limit Source Generators to "netstandard2.0" target framework · Issue #45162 · dotnet/roslyn
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Vielen Dank für deine Antwort!
Leider hat das auch keinen Einfluss. Das CLI ist (natürlich) netcoreapp3.1, aber der ganze Rest netstandard2.0.
Könntest du dir das kurz anschauen? So wie ich mich kenne, liegt es an was ganz Blödem...🙁
Gruss,
Fabiano
Hallo Fabiano,
die Solution kompiliert bei mir wenn ich in Fipscode.CodeGenerator.csproj
diie Referenzen hinzufüge:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.CodeDom" Version="5.0.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
</Project>
BTW: ich dachte es ist ein Roslyn Source Generator. Sind dir diese bekannt? Damit kann zur Entwurfszeit Code erstellt werden und verweidet dies zur Laufzeit -- sofern möglich.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Ich denke mein problem war ähnlich. Vlt. hilgft der Issue dazu weiter: https://github.com/dotnet/roslyn/issues/50612
cSharp Projekte : https://github.com/jogibear9988
Hallo gfoidl
Vielen Dank für deine Unterstützung!
Es geht mir nicht um das CodeGenerator-Projekt, sondern um ORM.Test.
Die Solution kompiliert bei mir auch, aber wenn ich das ORM.Test-Projekt ausführe, kommen diese Fehler:> Fehlermeldung:
(5,32): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(9,30): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,13): error CS0012: The type 'Expression<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
(10,33): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
Klappt das bei dir?
Ich möchte wie gesagt auch keinen Source generieren, sondern fertige Typen.
Gruss,
Fabiano
Hallo jogibear9988
Diese 2 Zeilen von dir haben meinen Tag gerettet! Ach was, die ganze Woche! 🙂
MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location),
MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location)
Nochmals vielen Dank euch beiden, dass ihr euch gekümmert habt! Einen wunderschönen Abend!
Gruss,
Fabiano
Ich stecke wieder fest, und zwar erhalte ich beim Compiliern der Mapper folgende Fehler (Projekt Fipscode.ORM.Test):> Fehlermeldung:
(9,49): error CS0234: The type or namespace name 'SloganMapper' does not exist in the namespace 'Fipscode.ORM.Dapper.Fipscode.Entities.Test' (are you missing an assembly reference?)
(10,13): error CS0012: The type 'User' is defined in an assembly that is not referenced. You must add a reference to assembly 'Fipscode.Entities.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Könntet ihr euch das vielleicht nochmal ansehen? 😉
Der zu kompilierende Sourcecode wird auch ausgegeben, zum besseren Verständnis.