Closed Seuleuzeuh closed 3 days ago
Maybe it's a duclicate of #19 ? But reading this, i don't understand how @JanK-Qics make it work.
@Seuleuzeuh as explained in #19, dotnet-codegencs does not allow directives like #r <assembly>
in the templates. My suggestion there (and here) is to create a regular CSPROJ where you can add the references that you need (including Microsoft.Data.SqlClient or whatever else you need), and use CodegenCS nuget.
You have two options here:
Main()
(you write the whole program).dotnet-codegencs template run <yourdll> [model]
. It can be useful because there are some smart defaults: you don't need to explicitly save the output files, the command-line tool can be used to define output folders, input models, etc. Code gets much shorter.Thanks @Drizin.
I've tried the second one, but it does not work. I've made a small repro project. I've try the command line with the .cs and the .dll, both not working.
Maybe it's a duclicate of #19 ? But reading this, i don't understand how @JanK-Qics make it work.
In main I load all assemblies (Assembly.LoadFrom) which I need and then I go over all the types which are compatible. Some of our assemblies are in Framework 4.8, so some types cannot be properly loaded to the .NET 7 CodegenCS project this is in, that's why I filter them out and work only with what doesn't fail.
public static void LoadAssembliesWithDocumentations()
{
foreach (var path in AssembliesPaths)
{
var assembly = Assembly.LoadFrom(path);
Assemblies.Add(assembly);
var xmlPath = path.Replace(".dll", ".xml", StringComparison.InvariantCulture);
var xml = XDocument.Load(xmlPath);
AssembliesDocumentations.Add(assembly, xml);
}
LoadAssemblyTypes();
}
/// <summary>
/// Loads types from assemblies which provide safe access to their CustomAttributes
/// </summary>
private static void LoadAssemblyTypes()
{
foreach (var assembly in Assemblies)
{
IEnumerable<Type> types = Array.Empty<Type>();
// load all loadable types
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types
.Where(t => t != null && !string.IsNullOrEmpty(t.FullName) && t.FullName.StartsWith("QicsUnity", StringComparison.InvariantCulture))
.Select(t => t!);
}
finally
{
// filter out types which don't provide safe access to CustomAttributes
foreach (var t in types)
{
try
{
// get only types on which the GetCustomAttributes call does not fail
t.GetCustomAttributes(false);
AssemblyTypes.Add(t);
}
catch (FileNotFoundException)
{
}
}
}
}
}
Here's Main() - here I trigger CodegenCS template runs, which are basically .WriteLine($$""" XY""") calls over the ICodegenContext created as new CodegenContext(). Each template finishes with .SaveToFolder on the context.
public static void Main()
{
// display login prompt if user is not authenticated yet
TfsUtility.Authenticate().GetAwaiter().GetResult();
// load the assemblies before generation starts
AssembliesUtility.LoadAssembliesWithDocumentations();
Console.WriteLine($"{"Generator",-40}{"Status",20}");
Console.WriteLine(new string('-', 55));
// Setup template runs
var templates = new CodegenCSTemplate[]
{
new ConstantsTemplate(),
new CqrsServicesTemplate(),
new DatePropertiesTemplate(),
new EnumsTemplate(),
new LocalizationTemplate(),
new ModelsTemplate(),
new ObjectsToInstancesTemplate(),
new ResourceStringsClassTemplate(),
new ResourceStringsJsonTemplate(),
new ResourceStringsResxTemplate()
};
...
}
@Seuleuzeuh I'm sorry for the delay - I finally found some time to check your repository.
I could make it work by making TemplateLauncher.cs
pre-load all DLLs in the same folder as the entrypoint type:
var baseFolder = new FileInfo(_entryPointClass.Assembly.Location).Directory;
var dlls = baseFolder.GetFiles("*.dll");
foreach (var dll in dlls)
{
try
{
Assembly.LoadFrom(dll.FullName);
}
catch (Exception ex) { }
}
Not the best solution, and probably we should make that parametrizable (dynamically pass the assembly references to load), but I'm open to other suggestions.
Then I was getting PlatformNotSupportedException: Microsoft.Data.SqlClient is not supported on this platform.
, which I could fix by adding <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
to your csproj.
Please let me know your thoughts, and if this works.
Issue https://github.com/Drizin/CodegenCS/issues/30 is about the same problem, so let me recap/resume this topic:
The underlying problem here (feature gap) is that during compilation we're passing a small number of DLL references but currently there is no way to add more references (the using namespaces
doesn't help with that), so basically System.Xml.dll
is not available.
Ideally, we would want some way of specifying references during the compilation phase (TemplateBuilder/RoslynCompiler) - that can also be used during execution (TemplateLauncher, when we invoke the built "template.dll").
In order to specify references in the command-line we could use something like -r:somepath.dll
, and that could also be used during execution (or maybe we can just save the references paths during build and load them automatically during execution - not sure if paths are already inside dll or if we can somehow store them as metadata).
But for people using VS Extension instead of CLI ideally we want to read some directives directly from source code (something like #r "somepath.dll"
, which is used for CSX scripts).
I'll try to draft it on this weekend. Feel free to share your thoughts and suggestions.
I've just republished new dotnet-codegencs 3.5.0
and VSExtension 3.7.2
.
CLI now has the option to specify -r:assembly.dll
, and both CLI/VSExtension allow the use of #r "assembly.dll"
in the templates.
Please check changes new unit tests and/or documentation updates. Looks like it's working fine for framework assemblies, but probably need some runtime adjustments to make it work with third-party assemblies.
Let me know how it goes.
Hi @Drizin !
I've try to replace an old T4 template by a CodegenCS generation. Our previous T4 query the database to generate some files. I've try do to the same with CodegenCS but this crash on run command. Is it possible to do that with CodegenCS ? I'm missing something ?
Have a great day !