From 64d594cc0cfbfb747468dc9ce219028fcf846ce5 Mon Sep 17 00:00:00 2001 From: Ogoun Date: Wed, 18 Dec 2019 16:32:22 +0300 Subject: [PATCH] Fixes --- ZeroLevel/Services/Config/Configuration.cs | 13 +++- ZeroLevel/Services/Network/BaseSocket.cs | 2 +- .../Reflection/EntryAssebmlyAttribute.cs | 71 +++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 ZeroLevel/Services/Reflection/EntryAssebmlyAttribute.cs diff --git a/ZeroLevel/Services/Config/Configuration.cs b/ZeroLevel/Services/Config/Configuration.cs index 385b3b0..efb4e54 100644 --- a/ZeroLevel/Services/Config/Configuration.cs +++ b/ZeroLevel/Services/Config/Configuration.cs @@ -2,9 +2,11 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using ZeroLevel.Services.Config; using ZeroLevel.Services.Config.Implementation; +using ZeroLevel.Services.Reflection; using ZeroLevel.Services.Serialization; namespace ZeroLevel @@ -14,14 +16,13 @@ namespace ZeroLevel /// /// Application folder path /// - public static string BaseDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + public static readonly string BaseDirectory; - public static string AppLocation = Assembly.GetEntryAssembly()?.Location; + public static readonly string AppLocation; public const string DEFAULT_SECTION_NAME = "_defaultsection"; #region Ctor - static Configuration() { _empty = new BaseConfiguration(); @@ -29,6 +30,12 @@ namespace ZeroLevel _empty.Freeze(true); _emptySet.FreezeConfiguration(true); DefaultSet = Configuration.CreateSet(); + var assembly = EntryAssemblyAttribute.GetEntryAssembly(); + if (assembly != null) + { + BaseDirectory = Path.GetDirectoryName(assembly.Location); + AppLocation = assembly.Location; + } } #endregion Ctor diff --git a/ZeroLevel/Services/Network/BaseSocket.cs b/ZeroLevel/Services/Network/BaseSocket.cs index de24b00..e1f04b2 100644 --- a/ZeroLevel/Services/Network/BaseSocket.cs +++ b/ZeroLevel/Services/Network/BaseSocket.cs @@ -6,7 +6,7 @@ namespace ZeroLevel.Network { static BaseSocket() { - MAX_FRAME_PAYLOAD_SIZE = Configuration.Default.FirstOrDefault("MAX_FRAME_PAYLOAD_SIZE", DEFAULT_MAX_FRAME_PAYLOAD_SIZE); + MAX_FRAME_PAYLOAD_SIZE = Configuration.Default?.FirstOrDefault("MAX_FRAME_PAYLOAD_SIZE", DEFAULT_MAX_FRAME_PAYLOAD_SIZE) ?? DEFAULT_MAX_FRAME_PAYLOAD_SIZE; } public static readonly IRouter NullRouter = new NullRouter(); diff --git a/ZeroLevel/Services/Reflection/EntryAssebmlyAttribute.cs b/ZeroLevel/Services/Reflection/EntryAssebmlyAttribute.cs new file mode 100644 index 0000000..372b4b4 --- /dev/null +++ b/ZeroLevel/Services/Reflection/EntryAssebmlyAttribute.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace ZeroLevel.Services.Reflection +{ + /// + /// For certain types of apps, such as web apps, + /// returns null. With the , we can designate + /// an assembly as the entry assembly by creating an instance of this attribute, + /// typically in the AssemblyInfo.cs file. + /// + /// [assembly: EntryAssembly] + /// + /// + [AttributeUsage(AttributeTargets.Assembly)] + public sealed class EntryAssemblyAttribute : Attribute + { + /// + /// Lazily find the entry assembly. + /// + private static readonly Lazy EntryAssemblyLazy = new Lazy(GetEntryAssemblyLazily); + + /// + /// Gets the entry assembly. + /// + /// The entry assembly. + public static Assembly GetEntryAssembly() + { + return EntryAssemblyLazy.Value; + } + + /// + /// Invoked lazily to find the entry assembly. We want to cache this value as it may + /// be expensive to find. + /// + /// The entry assembly. + private static Assembly GetEntryAssemblyLazily() + { + return Assembly.GetEntryAssembly() ?? FindEntryAssemblyInCurrentAppDomain(); + } + + /// + /// Finds the entry assembly in the current app domain. + /// + /// The entry assembly. + private static Assembly FindEntryAssemblyInCurrentAppDomain() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var entryAssemblies = new List(); + foreach (var assembly in assemblies) + { + // Note the usage of LINQ SingleOrDefault. The EntryAssemblyAttribute's AttrinuteUsage + // only allows it to occur once per assembly; declaring it more than once results in + // a compiler error. + var attribute = + assembly.GetCustomAttributes().OfType().SingleOrDefault(); + if (attribute != null) + { + entryAssemblies.Add(assembly); + } + } + + // Note that we use LINQ Single to ensure we found one and only one assembly with the + // EntryAssemblyAttribute. The EntryAssemblyAttribute should only be put on one assembly + // per application. + return entryAssemblies.SingleOrDefault(); + } + } +}