Skip to content

Commit

Permalink
Improved assembly loader
Browse files Browse the repository at this point in the history
  • Loading branch information
RicoSuter committed Feb 7, 2018
1 parent 2812149 commit 04576e4
Show file tree
Hide file tree
Showing 29 changed files with 8,169 additions and 287 deletions.
130 changes: 82 additions & 48 deletions src/NSwag.AssemblyLoader/AssemblyLoader.cs
Expand Up @@ -27,11 +27,13 @@ public class AssemblyLoader : MarshalByRefObject
#else
public class AssemblyLoader
{
private readonly HashSet<string> _assembliesLoadedByAssemblyName = new HashSet<string>();

public AssemblyLoadContext Context { get; }

public AssemblyLoader()
{
Context = AssemblyLoadContext.Default; // TODO: Switch back to new CustomAssemblyLoadContext(); ?
Context = new CustomAssemblyLoadContext(); // TODO: Switch back to new CustomAssemblyLoadContext(); ?
}

#endif
Expand Down Expand Up @@ -94,14 +96,14 @@ protected void RegisterReferencePaths(IEnumerable<string> referencePaths)
#if FullNet
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
#else
var assembliesLoadedByName = new HashSet<string>(); // used to avoid recursions
Context.Resolving += (context, args) =>
#endif
{
var separatorIndex = args.Name.IndexOf(",", StringComparison.Ordinal);
var assemblyName = separatorIndex > 0 ? args.Name.Substring(0, separatorIndex) : args.Name;
string assemblyVersion = null;
#if FullNet
Version version = null;
if (separatorIndex > 0)
{
separatorIndex = args.Name.IndexOf("=", separatorIndex, StringComparison.Ordinal);
Expand All @@ -110,55 +112,56 @@ protected void RegisterReferencePaths(IEnumerable<string> referencePaths)
var endIndex = args.Name.IndexOf(",", separatorIndex, StringComparison.Ordinal);
if (endIndex > 0)
{
assemblyVersion = string.Join(".", args.Name
var parts = args.Name
.Substring(separatorIndex + 1, endIndex - separatorIndex - 1)
.Split('.').Take(3)) + ".";
.Split('.');
version = new Version(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
}
}
}
#if FullNet
var existingAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == assemblyName);
if (existingAssembly != null)
return existingAssembly;
#else
var version = args.Version;
#endif
// search for exact version
if (assemblyVersion != null)
if (version != null)
{
foreach (var path in allReferencePaths)
{
var files = Directory.GetFiles(path, assemblyName + ".dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
try
{
var info = FileVersionInfo.GetVersionInfo(file);
if (info.FileVersion.StartsWith(assemblyVersion))
{
#if FullNet
return Assembly.LoadFrom(file);
#else
var currentDirectory = DynamicApis.DirectoryGetCurrentDirectoryAsync().GetAwaiter().GetResult();
return Context.LoadFromAssemblyPath(PathUtilities.MakeAbsolutePath(file, currentDirectory));
#endif
}
}
catch (Exception exception)
{
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by file '" + file + "': \n" + exception.ToString());
}
}
}
var assemblyByVersion = TryLoadByVersion(allReferencePaths, assemblyName, version.Major + "." + version.Minor + "." + version.Build + ".");
if (assemblyByVersion != null)
return assemblyByVersion;
assemblyByVersion = TryLoadByVersion(allReferencePaths, assemblyName, version.Major + "." + version.Minor + ".");
if (assemblyByVersion != null)
return assemblyByVersion;
assemblyByVersion = TryLoadByVersion(allReferencePaths, assemblyName, version.Major + ".");
if (assemblyByVersion != null)
return assemblyByVersion;
}
// search only for assembly name
foreach (var path in allReferencePaths)
var assembly = TryLoadByName(allReferencePaths, assemblyName);
if (assembly != null)
return assembly;
return TryLoadByAssemblyName(assemblyName);
};
}

private Assembly TryLoadByVersion(List<string> allReferencePaths, string assemblyName, string assemblyVersion)
{
foreach (var path in allReferencePaths)
{
var files = Directory.GetFiles(path, assemblyName + ".dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
var files = Directory.GetFiles(path, assemblyName + ".dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
try
{
try
var info = FileVersionInfo.GetVersionInfo(file);
if (info.FileVersion.StartsWith(assemblyVersion))
{
#if FullNet
return Assembly.LoadFrom(file);
Expand All @@ -167,30 +170,61 @@ protected void RegisterReferencePaths(IEnumerable<string> referencePaths)
return Context.LoadFromAssemblyPath(PathUtilities.MakeAbsolutePath(file, currentDirectory));
#endif
}
catch (Exception exception)
{
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by file '" + file + "': \n" + exception.ToString());
}
}
catch (Exception exception)
{
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by file '" + file + "': \n" + exception);
}
}
}

#if !FullNet
if (!assembliesLoadedByName.Contains(assemblyName))
return null;
}

private Assembly TryLoadByName(List<string> allReferencePaths, string assemblyName)
{
foreach (var path in allReferencePaths)
{
var files = Directory.GetFiles(path, assemblyName + ".dll", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
try
{
assembliesLoadedByName.Add(assemblyName);
return Context.LoadFromAssemblyName(new AssemblyName(assemblyName));
#if FullNet
return Assembly.LoadFrom(file);
#else
var currentDirectory = DynamicApis.DirectoryGetCurrentDirectoryAsync().GetAwaiter().GetResult();
return Context.LoadFromAssemblyPath(PathUtilities.MakeAbsolutePath(file, currentDirectory));
#endif
}
catch (Exception exception)
{
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by name '" + assemblyName + "': \n" + exception.ToString());
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by file '" + file + "': \n" + exception);
}
}
}

return null;
}

private Assembly TryLoadByAssemblyName(string assemblyName)
{
#if !FullNet
if (!_assembliesLoadedByAssemblyName.Contains(assemblyName))
{
try
{
_assembliesLoadedByAssemblyName.Add(assemblyName);
return Context.LoadFromAssemblyName(new AssemblyName(assemblyName));
}
catch (Exception exception)
{
Debug.WriteLine("NSwag: AssemblyLoader exception when loading assembly by name '" + assemblyName + "': \n" + exception);
}
}
#endif

return null;
};
return null;
}

private string[] GetAllDirectories(string rootDirectory)
Expand Down
3 changes: 2 additions & 1 deletion src/NSwag.ConsoleCore/Properties/launchSettings.json
@@ -1,7 +1,8 @@
{
"profiles": {
"NSwag.ConsoleCore": {
"commandName": "Project"
"commandName": "Project",
"commandLineArgs": "run \"C:\\Data\\Projects\\NSwag\\src\\NSwag.Sample.NETCore20\\nswag.json\""
}
}
}
@@ -1,7 +1,7 @@
/* tslint:disable */
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v11.13.2.0 (NJsonSchema v9.10.21.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org)
// Generated using the NSwag toolchain v11.13.3.0 (NJsonSchema v9.10.22.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
// ReSharper disable InconsistentNaming
Expand Down Expand Up @@ -1155,6 +1155,7 @@ export class GeoPoint implements IGeoPoint {
}

static fromJS(data: any, _mappings?: any): GeoPoint {
data = typeof data === 'object' ? data : {};
return createInstance<GeoPoint>(data, _mappings, GeoPoint);
}

Expand Down Expand Up @@ -1192,6 +1193,7 @@ export class GenericRequestOfAddressAndPerson implements IGenericRequestOfAddres
}

static fromJS(data: any, _mappings?: any): GenericRequestOfAddressAndPerson {
data = typeof data === 'object' ? data : {};
return createInstance<GenericRequestOfAddressAndPerson>(data, _mappings, GenericRequestOfAddressAndPerson);
}

Expand Down Expand Up @@ -1229,6 +1231,7 @@ export class Address implements IAddress {
}

static fromJS(data: any, _mappings?: any): Address {
data = typeof data === 'object' ? data : {};
return createInstance<Address>(data, _mappings, Address);
}

Expand Down Expand Up @@ -1301,6 +1304,7 @@ export class Person implements IPerson {
}

static fromJS(data: any, _mappings?: any): Person {
data = typeof data === 'object' ? data : {};
if (data["discriminator"] === "Teacher")
return createInstance<Teacher>(data, _mappings, Teacher);
return createInstance<Person>(data, _mappings, Person);
Expand Down Expand Up @@ -1381,6 +1385,7 @@ export class Teacher extends Person implements ITeacher {
}

static fromJS(data: any, _mappings?: any): Teacher {
data = typeof data === 'object' ? data : {};
return createInstance<Teacher>(data, _mappings, Teacher);
}

Expand Down Expand Up @@ -1423,6 +1428,7 @@ export class Exception implements IException {
}

static fromJS(data: any, _mappings?: any): Exception {
data = typeof data === 'object' ? data : {};
return createInstance<Exception>(data, _mappings, Exception);
}

Expand Down Expand Up @@ -1458,6 +1464,7 @@ export class PersonNotFoundException extends Exception implements IPersonNotFoun
}

static fromJS(data: any, _mappings?: any): PersonNotFoundException {
data = typeof data === 'object' ? data : {};
return createInstance<PersonNotFoundException>(data, _mappings, PersonNotFoundException);
}

Expand Down
28 changes: 28 additions & 0 deletions src/NSwag.Sample.NETCore11/nswag.json
@@ -0,0 +1,28 @@
{
"runtime": "NetCore11",
"swaggerGenerator": {
"webApiToSwagger": {
"controllerNames": [
"NSwag.Sample.NETCore11.Controllers.PetController"
],
"isAspNetCore": true,
"defaultUrlTemplate": "api/{controller}/{id?}",
"defaultPropertyNameHandling": "Default",
"defaultReferenceTypeNullHandling": "Null",
"defaultEnumHandling": "Integer",
"flattenInheritanceHierarchy": false,
"generateKnownTypes": true,
"generateXmlObjects": false,
"generateAbstractProperties": false,
"addMissingPathParameters": false,
"ignoreObsoleteProperties": false,
"allowReferencesWithProperties": false,
"output": "swagger.json",
"assemblyPaths": [
"bin/Debug/netcoreapp1.1/NSwag.Sample.NETCore11.dll"
],
"referencePaths": []
}
},
"codeGenerators": {}
}

0 comments on commit 04576e4

Please sign in to comment.