(string message, Request request, SearchResult searchResult = null) where T : Response, new()
{
var response = new T() as Response;
- var culture = Culture;
-
- try
- {
- culture = new CultureInfo(request?.Header?.AcceptLanguage?.FirstOrDefault()?.ToLower());
- }
- catch
- {
- }
if (searchResult != null)
{
- var statusPage = ComponentManager.ResponseManager.CreateStatusPage
+ return WebEx.ComponentHub.StatusPageManager.CreateStatusResponse
(
- massage,
+ message,
response.Status,
- searchResult?.ModuleContext?.PluginContext ??
- searchResult?.ApplicationContext?.PluginContext
+ searchResult?.EndpointContext?.ApplicationContext,
+ request
);
-
- if (statusPage == null)
- {
- return response;
- }
-
- if (statusPage is II18N i18n)
- {
- i18n.Culture = culture;
- }
-
- if (statusPage is Resource resource)
- {
- resource.ApplicationContext = searchResult?.ApplicationContext ?? new ApplicationContext()
- {
- PluginContext = searchResult?.ModuleContext?.PluginContext ??
- searchResult?.ApplicationContext?.PluginContext,
- ApplicationId = "webex",
- ApplicationName = "WebExpress",
- ContextPath = new UriResource()
- };
-
- resource.ModuleContext = searchResult?.ModuleContext ?? new ModuleContext()
- {
- ApplicationContext = resource.ApplicationContext,
- PluginContext = searchResult?.ModuleContext?.PluginContext ??
- searchResult?.ApplicationContext?.PluginContext,
- ModuleId = "webex",
- ModuleName = "WebExpress",
- ContextPath = new UriResource()
- };
-
- resource.Initialization(new ResourceContext(resource.ModuleContext));
- }
-
- return statusPage.Process(request);
}
- var message = $"{response.Status}" +
- $"{massage}
" +
- $"";
+ message = $"
{response.Status}" +
+ $"{message}
" +
+ $"";
response.Content = message;
response.Header.ContentLength = message.Length;
@@ -538,7 +470,7 @@ public HttpContext CreateContext(IFeatureCollection contextFeatures)
{
try
{
- return new HttpContext(contextFeatures, this.HttpServerContext);
+ return new HttpContext(contextFeatures, HttpServerContext);
}
catch (Exception ex)
{
diff --git a/src/WebExpress.WebCore/HttpServerContext.cs b/src/WebExpress.WebCore/HttpServerContext.cs
index 1f94c11..76db1ee 100644
--- a/src/WebExpress.WebCore/HttpServerContext.cs
+++ b/src/WebExpress.WebCore/HttpServerContext.cs
@@ -2,7 +2,8 @@
using System.Globalization;
using System.Reflection;
using WebExpress.WebCore.Config;
-using WebExpress.WebCore.WebUri;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebLog;
namespace WebExpress.WebCore
{
@@ -12,9 +13,9 @@ namespace WebExpress.WebCore
public class HttpServerContext : IHttpServerContext
{
///
- /// Returns the uri of the web server.
+ /// Returns the route of the web server.
///
- public string Uri { get; protected set; }
+ public IRoute Route { get; protected set; }
///
/// Returns the endpoints to which the web server responds.
@@ -49,7 +50,7 @@ public class HttpServerContext : IHttpServerContext
///
/// Returns the basic context path.
///
- public UriResource ContextPath { get; protected set; }
+ public IRoute ContextPath { get; protected set; }
///
/// Returns the culture.
@@ -59,7 +60,7 @@ public class HttpServerContext : IHttpServerContext
///
/// Returns the log for writing status messages to the console and to a log file.
///
- public Log Log { get; protected set; }
+ public ILog Log { get; protected set; }
///
/// Returns the host.
@@ -67,9 +68,9 @@ public class HttpServerContext : IHttpServerContext
public IHost Host { get; protected set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
- /// The uri of the web server.
+ /// The uri of the route server.
/// The endpoints to which the web server responds.
/// The package home directory.chnis
/// The asset home directory.
@@ -81,22 +82,22 @@ public class HttpServerContext : IHttpServerContext
/// The host.
public HttpServerContext
(
- string uri,
+ IRoute route,
ICollection endpoints,
string packageBaseFolder,
string assetBaseFolder,
string dataBaseFolder,
string configBaseFolder,
- UriResource contextPath,
+ IRoute contextPath,
CultureInfo culture,
- Log log,
+ ILog log,
IHost host
)
{
var assembly = typeof(HttpServer).Assembly;
Version = assembly.GetCustomAttribute()?.InformationalVersion;
- Uri = uri;
+ Route = route;
Endpoints = endpoints;
PackagePath = packageBaseFolder;
AssetPath = assetBaseFolder;
diff --git a/src/WebExpress.WebCore/IHttpServerContext.cs b/src/WebExpress.WebCore/IHttpServerContext.cs
index 26261a9..1ef850b 100644
--- a/src/WebExpress.WebCore/IHttpServerContext.cs
+++ b/src/WebExpress.WebCore/IHttpServerContext.cs
@@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Globalization;
using WebExpress.WebCore.Config;
-using WebExpress.WebCore.WebUri;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebLog;
namespace WebExpress.WebCore
{
@@ -11,9 +12,9 @@ namespace WebExpress.WebCore
public interface IHttpServerContext
{
///
- /// Returns the uri of the web server.
+ /// Returns the route of the web server.
///
- string Uri { get; }
+ IRoute Route { get; }
///
/// Returns the endpoints to which the web server responds.
@@ -48,7 +49,7 @@ public interface IHttpServerContext
///
/// Returns the basic context path.
///
- UriResource ContextPath { get; }
+ IRoute ContextPath { get; }
///
/// Returns the culture.
@@ -58,7 +59,7 @@ public interface IHttpServerContext
///
/// Returns the log for writing status messages to the console and to a log file.
///
- Log Log { get; }
+ ILog Log { get; }
///
/// Returns the host.
diff --git a/src/WebExpress.WebCore/Internationalization/I18N.cs b/src/WebExpress.WebCore/Internationalization/I18N.cs
new file mode 100644
index 0000000..ec8a0f7
--- /dev/null
+++ b/src/WebExpress.WebCore/Internationalization/I18N.cs
@@ -0,0 +1,127 @@
+using System.Globalization;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebPage;
+
+namespace WebExpress.WebCore.Internationalization
+{
+ ///
+ /// Provides internationalization (i18n) functionalities.
+ ///
+ public static class I18N
+ {
+ ///
+ /// Translates a given key to the default language.
+ ///
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public static string Translate(string key)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(key) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the default language.
+ ///
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public static string Translate(string key, params object[] args)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(key, args) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The request with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public static string Translate(Request request, string key)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager.Translate(request, key) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The request with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public static string Translate(Request request, string key, params object[] args)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(request, key, args) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The render context with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public static string Translate(IRenderContext renderContext, string key)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(renderContext?.Request, key) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The render context with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public static string Translate(IRenderContext renderContext, string key, params object[] args)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(renderContext?.Request, key, args) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public static string Translate(CultureInfo culture, string key)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(culture, key) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public static string Translate(CultureInfo culture, string key, params object[] args)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(culture, key, args) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The plugin id.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public static string Translate(CultureInfo culture, string pluginId, string key)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(culture, pluginId, key) ?? key;
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The plugin id.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public static string Translate(CultureInfo culture, string pluginId, string key, params object[] args)
+ {
+ return WebEx.ComponentHub?.InternationalizationManager?.Translate(culture, pluginId, key, args) ?? key;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/Internationalization/II18N.cs b/src/WebExpress.WebCore/Internationalization/II18N.cs
deleted file mode 100644
index 1fbfa61..0000000
--- a/src/WebExpress.WebCore/Internationalization/II18N.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Globalization;
-
-namespace WebExpress.WebCore.Internationalization
-{
- public interface II18N
- {
- ///
- /// Returns or sets the culture.
- ///
- CultureInfo Culture { get; set; }
- }
-}
diff --git a/src/WebExpress.WebCore/Internationalization/IInternationalizationManager.cs b/src/WebExpress.WebCore/Internationalization/IInternationalizationManager.cs
new file mode 100644
index 0000000..cfed473
--- /dev/null
+++ b/src/WebExpress.WebCore/Internationalization/IInternationalizationManager.cs
@@ -0,0 +1,80 @@
+using System.Globalization;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.Internationalization
+{
+ ///
+ /// The interface of the internationalization manager.
+ ///
+ public interface IInternationalizationManager : IComponentManager
+ {
+ ///
+ /// Translates a given key to the default language.
+ ///
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public string Translate(string key);
+
+ ///
+ /// Translates a given key to the default language.
+ ///
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public string Translate(string key, params object[] args);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The request with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ string Translate(Request request, string key);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The request with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ string Translate(Request request, string key, params object[] args);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ string Translate(CultureInfo culture, string key);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ string Translate(CultureInfo culture, string key, params object[] args);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The plugin id.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ string Translate(CultureInfo culture, string pluginId, string key);
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The plugin id.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ string Translate(CultureInfo culture, string pluginId, string key, params object[] args);
+ }
+}
diff --git a/src/WebExpress.WebCore/Internationalization/InternationalizationExtensions.cs b/src/WebExpress.WebCore/Internationalization/InternationalizationExtensions.cs
deleted file mode 100644
index 6c02023..0000000
--- a/src/WebExpress.WebCore/Internationalization/InternationalizationExtensions.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using WebExpress.WebCore.WebApplication;
-
-namespace WebExpress.WebCore.Internationalization
-{
- public static class InternationalizationExtensions
- {
- ///
- /// Internationalization of a key.
- ///
- /// An internationalization object that is being extended.
- /// The internationalization key.
- /// The value of the key in the current language.
- public static string I18N(this II18N obj, string key)
- {
- return InternationalizationManager.I18N(obj, key);
- }
-
- ///
- /// Internationalization of a key.
- ///
- /// An internationalization object that is being extended.
- /// The plugin id.
- /// The internationalization key.
- /// The value of the key in the current language.
- public static string I18N(this II18N obj, string pluginId, string key)
- {
- return InternationalizationManager.I18N(obj.Culture, pluginId, key);
- }
-
- ///
- /// Internationalization of a key.
- ///
- /// An internationalization object that is being extended.
- /// The allication context.
- /// The internationalization key.
- /// The value of the key in the current language.
- public static string I18N(this II18N obj, IApplicationContext applicationContext, string key)
- {
- return InternationalizationManager.I18N(obj.Culture, applicationContext?.PluginContext?.PluginId, key);
- }
- }
-}
diff --git a/src/WebExpress.WebCore/Internationalization/InternationalizationManager.cs b/src/WebExpress.WebCore/Internationalization/InternationalizationManager.cs
index d582a8a..bc9ee28 100644
--- a/src/WebExpress.WebCore/Internationalization/InternationalizationManager.cs
+++ b/src/WebExpress.WebCore/Internationalization/InternationalizationManager.cs
@@ -3,8 +3,9 @@
using System.IO;
using System.Linq;
using System.Reflection;
-using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.Internationalization.Model;
using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebMessage;
using WebExpress.WebCore.WebPlugin;
namespace WebExpress.WebCore.Internationalization
@@ -12,8 +13,10 @@ namespace WebExpress.WebCore.Internationalization
///
/// Internationalization
///
- public sealed class InternationalizationManager : IComponentPlugin, ISystemComponent
+ public sealed class InternationalizationManager : IInternationalizationManager, IComponentManagerPlugin, ISystemComponent
{
+ private readonly IComponentHub _componentHub;
+
///
/// Returns the default language.
///
@@ -22,7 +25,7 @@ public sealed class InternationalizationManager : IComponentPlugin, ISystemCompo
///
/// Returns the directory by listing the internationalization key-value pairs.
///
- private static InternationalizationDictionary Dictionary { get; } = new InternationalizationDictionary();
+ private static InternationalizationDictionary Dictionary { get; } = [];
///
/// Returns or sets the reference to the context of the host.
@@ -30,33 +33,30 @@ public sealed class InternationalizationManager : IComponentPlugin, ISystemCompo
public IHttpServerContext HttpServerContext { get; private set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
- internal InternationalizationManager()
+ /// The component hub.
+ /// The reference to the context of the host.
+ private InternationalizationManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
{
- ComponentManager.PluginManager.AddPlugin += (sender, pluginContext) =>
+ _componentHub = componentHub;
+
+ _componentHub.PluginManager.AddPlugin += (sender, pluginContext) =>
{
Register(pluginContext);
};
- ComponentManager.PluginManager.RemovePlugin += (sender, pluginContext) =>
+ _componentHub.PluginManager.RemovePlugin += (sender, pluginContext) =>
{
Remove(pluginContext);
};
- }
- ///
- /// Initialization
- ///
- /// The reference to the context of the host.
- public void Initialization(IHttpServerContext context)
- {
- HttpServerContext = context;
+ HttpServerContext = httpServerContext;
DefaultCulture = HttpServerContext.Culture;
HttpServerContext.Log.Debug
(
- I18N("webexpress:internationalizationmanager.initialization")
+ Translate("webexpress.webcore:internationalizationmanager.initialization")
);
}
@@ -67,11 +67,11 @@ public void Initialization(IHttpServerContext context)
public void Register(IPluginContext pluginContext)
{
var pluginId = pluginContext.PluginId;
- Register(pluginContext.Assembly, pluginId);
+ Register(pluginContext.Assembly, pluginId.ToString());
HttpServerContext.Log.Debug
(
- I18N("webexpress:internationalizationmanager.register", pluginId)
+ Translate("webexpress.webcore:internationalizationmanager.register", pluginId)
);
}
@@ -92,22 +92,23 @@ public void Register(IEnumerable pluginContexts)
///
/// The assembly that contains the key-value pairs to insert.
/// The id of the plugin to which the internationalization data will be assigned.
- internal static void Register(Assembly assembly, string pluginId)
+ public void Register(Assembly assembly, string pluginId)
{
var assemblyName = assembly.GetName().Name.ToLower();
var name = assemblyName + ".internationalization.";
- var resources = assembly.GetManifestResourceNames().Where(x => x.ToLower().Contains(name));
+ var resources = assembly.GetManifestResourceNames().Where(x => x.Contains(name, System.StringComparison.CurrentCultureIgnoreCase));
foreach (var languageResource in resources)
{
var language = languageResource.Split('.').LastOrDefault()?.ToLower();
- if (!Dictionary.ContainsKey(language))
+ if (!Dictionary.TryGetValue(language, out InternationalizationItem value))
{
- Dictionary.Add(language, new InternationalizationItem());
+ value = ([]);
+ Dictionary.Add(language, value);
}
- var dictItem = Dictionary[language];
+ var dictItem = value;
using var stream = assembly.GetManifestResourceStream(languageResource);
using var streamReader = new StreamReader(stream);
@@ -126,6 +127,8 @@ internal static void Register(Assembly assembly, string pluginId)
}
}
}
+
+ Log();
}
///
@@ -134,50 +137,99 @@ internal static void Register(Assembly assembly, string pluginId)
/// The context of the plugin containing the key-value pairs to remove.
public void Remove(IPluginContext pluginContext)
{
+ if (pluginContext == null)
+ {
+ return;
+ }
+ foreach (var dictionary in Dictionary.Values)
+ {
+ var keysToRemove = dictionary.Keys.Where(k => k.StartsWith($"{pluginContext?.PluginId}:")).ToList();
+
+ foreach (var key in keysToRemove)
+ {
+ dictionary.Remove(key);
+ }
+ }
+
+ Log();
+ }
+
+ ///
+ /// Translates a given key to the default language.
+ ///
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public string Translate(string key)
+ {
+ return Translate(DefaultCulture, null, key);
}
///
- /// Internationalization of a key.
+ /// Translates a given key to the default language.
///
- /// An internationalization object that is being extended.
/// The internationalization key.
+ /// The formatting arguments.
/// The value of the key in the current language.
- public static string I18N(II18N obj, string key)
+ public string Translate(string key, params object[] args)
{
- return I18N(obj.Culture, key);
+ return string.Format(Translate(DefaultCulture, null, key), args);
}
///
- /// Internationalization of a key.
+ /// Translates a given key to the specified language.
///
/// The request with the language to use.
/// The internationalization key.
/// The value of the key in the current language.
- public static string I18N(Request request, string key)
+ public string Translate(Request request, string key)
{
- return I18N(request.Culture, null, key);
+ return Translate(request.Culture, null, key);
}
///
- /// Internationalization of a key.
+ /// Translates a given key to the specified language.
+ ///
+ /// The request with the language to use.
+ /// The internationalization key.
+ /// The formatting arguments.
+ /// The value of the key in the current language.
+ public string Translate(Request request, string key, params object[] args)
+ {
+ return string.Format(Translate(request, key), args);
+ }
+
+ ///
+ /// Translates a given key to the specified language.
+ ///
+ /// The culture with the language to use.
+ /// The internationalization key.
+ /// The value of the key in the current language.
+ public string Translate(CultureInfo culture, string key)
+ {
+ return Translate(culture, null, key);
+ }
+
+ ///
+ /// Translates a given key to the specified language.
///
/// The culture with the language to use.
/// The internationalization key.
+ /// The formatting arguments.
/// The value of the key in the current language.
- public static string I18N(CultureInfo culture, string key)
+ public string Translate(CultureInfo culture, string key, params object[] args)
{
- return I18N(culture, null, key);
+ return string.Format(Translate(culture, key), args);
}
///
- /// Internationalization of a key.
+ /// Translates a given key to the specified language.
///
/// The culture with the language to use.
/// The plugin id.
/// The internationalization key.
/// The value of the key in the current language.
- public static string I18N(CultureInfo culture, string pluginId, string key)
+ public string Translate(CultureInfo culture, string pluginId, string key)
{
var language = culture?.TwoLetterISOLanguageName;
var k = string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(pluginId) || key.StartsWith($"{pluginId?.ToLower()}:") ? key?.ToLower() : $"{pluginId?.ToLower()}:{key?.ToLower()}";
@@ -192,46 +244,48 @@ public static string I18N(CultureInfo culture, string pluginId, string key)
language = DefaultCulture?.TwoLetterISOLanguageName;
}
- var item = Dictionary[language];
+ if (string.IsNullOrWhiteSpace(language))
+ {
+ return key;
+ }
- if (item.ContainsKey(k))
+ if (Dictionary.TryGetValue(language, out InternationalizationItem item))
{
- return item[k];
+ if (item.TryGetValue(k, out string value))
+ {
+ return value;
+ }
}
return key;
}
///
- /// Internationalization of a key.
+ /// Translates a given key to the specified language.
///
+ /// The culture with the language to use.
+ /// The plugin id.
/// The internationalization key.
+ /// The formatting arguments.
/// The value of the key in the current language.
- public static string I18N(string key)
+ public string Translate(CultureInfo culture, string pluginId, string key, params object[] args)
{
- return I18N(DefaultCulture, null, key);
+ return string.Format(Translate(culture, pluginId, key), args);
}
///
- /// Internationalization of a key.
+ /// Information about the component is collected and prepared for output in the log.
///
- /// The internationalization key.
- /// The formatting arguments.
- /// The value of the key in the current language.
- public static string I18N(string key, params object[] args)
+ private void Log()
{
- return string.Format(I18N(DefaultCulture, null, key), args);
+
}
///
- /// Information about the component is collected and prepared for output in the log.
+ /// Release of unmanaged resources reserved during use.
///
- /// The context of the plugin.
- /// A list of log entries.
- /// The shaft deep.
- public void PrepareForLog(IPluginContext pluginContext, IList output, int deep)
+ public void Dispose()
{
-
}
}
}
diff --git a/src/WebExpress.WebCore/Internationalization/InternationalizationDictionary.cs b/src/WebExpress.WebCore/Internationalization/Model/InternationalizationDictionary.cs
similarity index 82%
rename from src/WebExpress.WebCore/Internationalization/InternationalizationDictionary.cs
rename to src/WebExpress.WebCore/Internationalization/Model/InternationalizationDictionary.cs
index de064ec..ac4087b 100644
--- a/src/WebExpress.WebCore/Internationalization/InternationalizationDictionary.cs
+++ b/src/WebExpress.WebCore/Internationalization/Model/InternationalizationDictionary.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace WebExpress.WebCore.Internationalization
+namespace WebExpress.WebCore.Internationalization.Model
{
///
/// key = language (ISO 639-1 two-letter)
diff --git a/src/WebExpress.WebCore/Internationalization/InternationalizationItem.cs b/src/WebExpress.WebCore/Internationalization/Model/InternationalizationItem.cs
similarity index 69%
rename from src/WebExpress.WebCore/Internationalization/InternationalizationItem.cs
rename to src/WebExpress.WebCore/Internationalization/Model/InternationalizationItem.cs
index 9aaa614..40ede17 100644
--- a/src/WebExpress.WebCore/Internationalization/InternationalizationItem.cs
+++ b/src/WebExpress.WebCore/Internationalization/Model/InternationalizationItem.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace WebExpress.WebCore.Internationalization
+namespace WebExpress.WebCore.Internationalization.Model
{
internal class InternationalizationItem : Dictionary
{
diff --git a/src/WebExpress.WebCore/Internationalization/de b/src/WebExpress.WebCore/Internationalization/de
index 8880cbc..8d5479e 100644
--- a/src/WebExpress.WebCore/Internationalization/de
+++ b/src/WebExpress.WebCore/Internationalization/de
@@ -39,10 +39,15 @@ componentmanager.wrongtype=Der Typ '{0}' implementiert die Schnittstelle '{1}' n
componentmanager.duplicate=Die Komponente '{0}' wurde bereits registriert.
componentmanager.remove=Die Komponente '{0}' wurde entfernt.
componentmanager.component=Komponenten:
+componentmanager.name=Komponente: '{0}'
+
+logmanager.initialization=Der Logmanager wurde initialisiert.
+logmanager.titel=Logmanager
internationalizationmanager.initialization=Der Internationalisierungsmanager wurde initialisiert.
internationalizationmanager.register=Das Plugin '{0}' wurde im Internationalizationmanager registriert.
+packagemanager.titel=Paketmanager:
packagemanager.initialization=Der Paketmanager wurde initialisiert.
packagemanager.existing=Das Paket '{0}' ist im Katalog registriert.
packagemanager.add=Das Paket '{0}' wird im Katalog neu aufgenommen.
@@ -51,23 +56,26 @@ packagemanager.scan=Das Verzeichnis '{0}' wird auf neue Pakete gescannt.
packagemanager.save=Der Katalog wird gespeichert.
packagemanager.packagenotfound=Das Paket '{0}' wurde nicht im Dateisystem gefunden.
packagemanager.boot.notfound=Das Plugin '{0}' ist nicht bekannt.
+packagemanager.package=Package: '{0}'
pluginmanager.initialization=Der Pluginmanager wurde initialisiert.
pluginmanager.load={0}.dll wird geladen. Version = '{1}'
pluginmanager.created=Das Plugin '{0}' wurde erstellt und im PluginManager registriert.
pluginmanager.duplicate=Das Plugin '{0}' wurde bereits im PluginManager registriert.
+pluginmanager.tomany=Es ist mehr als eine Pluginklasse vorhanden! Das Plugin '{0}' wird nicht geladen.
pluginmanager.notavailable=Das Plugin '{0}' ist im PluginManager nicht vorhanden.
pluginmanager.plugin=Plugin: '{0}'
pluginmanager.pluginmanager.label=Plugin Manager:
pluginmanager.pluginmanager.system=Systemplugin: '{0}'
pluginmanager.pluginmanager.custom=Benutzerdefiniertes Plugin: '{0}'
pluginmanager.pluginmanager.unfulfilleddependencies=Plugin mit unerfüllten Abhängigkeiten: '{0}'
-pluginmanager.plugin.initialization=Das Plugin '{0}' wurde initialisiert.
pluginmanager.plugin.processing.start=Das Plugin '{0}' wird ausgeführt.
pluginmanager.plugin.processing.end=Die Ausführung des Plugin '{0}' wurde beendet.
pluginmanager.fulfilleddependencies=Das Plugin '{0}' erfüllt alle Abhängigkeiten.
pluginmanager.unfulfilleddependencies=Das Plugin '{0}' erfüllt eine Abhängigkeit zu dem Plugin '{1}' nicht.
+pluginmanager.applicationless=Das Plugin '{0}' besitzt keine Angaben zur Anwendung.
+applicationmanager.titel=Anwendungsmanager:
applicationmanager.initialization=Der Anwendungsmanager wurde initialisiert.
applicationmanager.register=Die Anwendung '{0}' wurde erstellt und im Anwendungsmanager registriert.
applicationmanager.duplicate=Die Anwendung '{0}' wurde bereits im Anwendungsmanager registriert.
@@ -77,55 +85,90 @@ applicationmanager.application.processing.start=Die Anwendung '{0}' wird ausgef
applicationmanager.application.processing.end=Die Ausführung der Anwendung '{0}' wurde beendet.
applicationmanager.application.boot.notfound=Das Plugin '{0}' ist nicht bekannt.
-modulemanager.initialization=Der Modulmanager wurde initialisiert.
-modulemanager.register=Das Modul '{0}' wurde der Anwendung '{1}' zugewiesen und im Modulmanager registriert.
-modulemanager.duplicat=Das Modul '{0}' wurde bereits in der Anwendung '{1}' registriert.
-modulemanager.applicationless=Das Modul '{0}' besitzt keine Angaben zur Anwendung.
-modulemanager.module=Module: '{0}' für die Anwendung(n) '{1}'
-modulemanager.module.initialization=Das Modul '{1}' der Anwendung {0} wurde initialisiert.
-modulemanager.module.processing.start=Das Modul '{1}' der Anwendung {0} wird ausgeführt.
-modulemanager.module.processing.end=Die Ausführung des Modul '{1}' der Anwendung {0} wurde beendet.
-
resourcemanager.initialization=Der Ressourcenmanager wurde initialisiert.
-resourcemanager.register={0} Ressource(n) wurden dem Modul '{1}' zugewiesen.
-resourcemanager.modulenotfound=Das Modul '{1}' wurde nicht gefunden, welches in der Ressource '{0}' angegeben wurde.
-resourcemanager.moduleless=Die Ressource '{0}' besitzt keine Angaben zum Modul.
-resourcemanager.addresource=Die Ressource '{0}' wurde in dem Modul '{1}' registiert.
-resourcemanager.addresource.duplicate=Die Ressource '{0}' des Moduls '{1}' ist bereits hinzugefügt worden.
-resourcemanager.addresource.error=Die Ressource '{0}' des Moduls '{1}' konnte nicht hinzugefügt werden.
-resourcemanager.sitemap=Inhalt der Sitemap für das Modul '{0}':
+resourcemanager.register={0} Ressource(n) wurden der Anwendung '{1}' zugewiesen.
+resourcemanager.addresource=Die Ressource '{0}' wurde in der Anwendung '{1}' registiert.
+resourcemanager.addresource.duplicate=Die Ressource '{0}' der Anwendung '{1}' ist bereits hinzugefügt worden.
+resourcemanager.addresource.error=Die Ressource '{0}' der Anwendung '{1}' konnte nicht hinzugefügt werden.
+resourcemanager.sitemap=Inhalt der Sitemap für die Anwendung '{0}':
resourcemanager.wrongtype=Der Type '{0}' implementiert die Schnittstelle '{1}' nicht.
-resourcemanager.resource=Ressource: '{0}' für das Modul '{1}'
+resourcemanager.resource=Ressource: '{0}' für die Anwednung '{1}'
+
+assetmanager.initialization=Der Assetmanager wurde initialisiert.
+assetmanager.addresource=Das Asset '{0}' wurde in der Anwendung '{1}' registiert.
+
+pagemanager.initialization=Der Pagemanager wurde initialisiert.
+pagemanager.addpage=Die Seite '{0}' wurde in der Anwendung '{1}' registiert.
+pagemanager.page=Seite: '{0}' für die Anwendung '{1}'
-responsemanager.initialization=Der Responsemanagermanager wurde initialisiert.
-responsemanager.register=Status {0} wurde im Module '{1}' registriert und der Statusseite '{2}' zugewiesen.
-responsemanager.duplicat=Der Status {0} wurde bereits im Module '{1}' registriert registriert. Die Statusseite '{2}' wird daher nicht verwendet.
-responsemanager.statuscode=Ein Statuscode wurde der Ressource '{1}' für das Modul '{0}' nicht zugewiesen.
-responsemanager.statuspage=Statuscode: '{0}'
+restapimanager.initialization=Der RestApiManager wurde initialisiert.
+restapimanager.addrestapi=Die Seite '{0}' wurde in der Anwendung '{1}' registiert.
+restapimanager.resource=Seite: '{0}' für die Anwendung '{1}'
+restapimanager.methodnotsupported=Die Methode '{0}' wird nicht unterstützt.
+statuspagemanager.titel=Statuspagemanager:
+statuspagemanager.initialization=Der Statuspagemanager wurde initialisiert.
+statuspagemanager.register=Der Status '{0}' wurde registriert und der Statusseite '{1}' zugewiesen.
+statuspagemanager.duplicat=Der Status '{0}' wurde bereits registriert. Die Statusseite '{1}' wird daher nicht verwendet.
+statuspagemanager.statuscodeless=Ein Statuscode wurde der Ressource '{1}' für die Anwendung '{0}' nicht zugewiesen.
+statuspagemanager.statuspage=Statuscode: '{0}'
+
+sitemapmanager.titel=Sitemap:
sitemapmanager.initialization=Der Sitemap-Manager wurde initialisiert.
sitemapmanager.refresh=Die Sitemap wird neu aufgebaut.
sitemapmanager.alreadyassigned=Der Knoten der Sitemap '{0}' ist bereits zugewiesen. Die Ressource '{1}' wird nicht in die Sitemap aufgenommen.
sitemapmanager.addresource=Die Ressource '{0}' wurde in der Sitemap registriert.
sitemapmanager.addresource.error=Die Ressource '{0}' konnte nicht in der Sitemap hinzugefügt werden.
sitemapmanager.preorder={0} => {1}
-sitemapmanager.sitemap=Sitemap:
sitemapmanager.merge.error=Die beiden Sitemaps '{0}' und '{1}' konnten nicht gemerdged werden.
sessionmanager.initialization=Der Sessionmanager wurde initialisiert.
+settingpagemanager.initialization=Der Settingpagemanager wurde initialisiert.
+settingpagemanager.register.category=Die Einstellungskategorie '{0}' wurde der Anwendung '{1}' zugewiesen und im Settingpagemanager registriert.
+settingpagemanager.register.group=Die Einstellungsgruppe '{0}' wurde der Anwendung '{1}' zugewiesen und im Settingpagemanager registriert.
+settingpagemanager.register.page=Die Einstellungsseite '{0}' wurde der Anwendung '{1}' zugewiesen und im Settingpagemanager registriert.
+settingpagemanager.register.nocategory=Die Einstellungsseite '{0}' wurde keiner Einstellungskategorie zugewiesen.
+settingpagemanager.register.nogroup=Die Einstellungsseite '{0}' wurde keiner Einstellungsgruppe zugewiesen.
+settingpagemanager.category.general.name=Allgemeine Einstellungen
+settingpagemanager.category.general.description=Standardkategorie für allgemeine Anwendungseinstellungen.
+settingpagemanager.group.general.name=Allgemein
+settingpagemanager.group.general.description=Allgemeine Anwendungseinstellungen.
+
+eventmanager.titel=Eventmanager:
eventmanager.initialization=Der Eventmanager wurde initialisiert.
-
-jobmanager.initialization=Der Schedulemanager wurde initialisiert.
-jobmanager.register=Das Plugin '{0}' wurde im Schedulemanager registriert.
-jobmanager.job.register=Der Job '{1}' wurden dem Modul '{0}' zugewiesen.
-jobmanager.moduleless=Der Job '{0}' besitzt keine Angaben zum Modul.
-jobmanager.wrongmodule=Der Job '{1}' ist kein Teil des Moduls {0}.
-jobmanager.job=Job: '{0}' für Modul '{1}'
+eventmanager.register=Der Eventhandler '{0}' wurde der Anwendung '{1}' zugewiesen und im Eventmanager registriert.
+eventmanager.duplicate=Der Eventhandler '{0}' wurde bereits in der Anwendung '{1}' registriert.
+eventmanager.eventless=Der Eventhandler '{0}' besitzt keine Angaben zu einem Event.
+eventmanager.handler=Eventhandler: '{0}' für die Anwendung '{1}'.
+
+jobmanager.initialization=Der Jobmanager wurde initialisiert.
+jobmanager.register=Der Job '{0}' wurde der Anwendung '{1}' zugewiesen und im Jobmanager registriert.
+jobmanager.duplicate=Der Job '{0}' wurde bereits in der Anwendung '{1}' registriert.
+jobmanager.jobless=Der Job '{0}' besitzt keine Angaben zu einem Job.
+jobmanager.job=Job: '{0}' für Anwendung '{1}'
jobmanager.job.process=Der Job '{0}' wird ausgeführt.
jobmanager.cron.parseerror=Syntaxfehler in der Zeitangabe eines Jobs. Der Wert '{0}' kann nicht verarbeitet werden.
jobmanager.cron.range=Syntaxfehler in der Zeitangabe eines Jobs. Der Wert '{0}' ist außerhalb des gültigen Bereiches.
+fragmentmanager.initialization=Der Fragmentmanager wurde initialisiert.
+fragmentmanager.register=Das Fragment '{0}' wurde in der Sektion '{1}' der Anwendung '{2}' registriert.
+fragmentmanager.error.section=Die Angabe der Sektion ist fehlerhaft.
+fragmentmanager.wrongtype=Der Typ '{0}' implementiert die Schnittstelle '{1}' nicht.
+fragmentmanager.addfragment.duplicate=Das Fragment '{0}' aus dem Plugin '{1}' ist bereits hinzugefügt worden.
+fragmentmanager.titel=Fragmente:
+fragmentmanager.fragment=Fragment: '{0}' für die Anwendung '{1}'.
+
+identitymanager.initialization=Der Identitymanager wurde initialisiert.
+identitymanager.registerpermission=Die Berechtigung '{0}' wurde der Anwendung '{1}' zugewiesen und im Identitymanager registriert.
+identitymanager.duplicatepermission=Die Berechtigung '{0}' wurde bereits in der Anwendung '{1}' registriert.
+identitymanager.registerrole=Die Rolle '{0}' wurde der Anwendung '{1}' zugewiesen und im Identitymanager registriert.
+identitymanager.duplicaterole=Die Rolle '{0}' wurde bereits in der Anwendung '{1}' registriert.
+
+thememanager.initialization=Der Thememanager wurde initialisiert.
+thememanager.addtheme=Das Theme '{0}' wurde in der Anwendung '{1}' registiert.
+thememanager.titel=Designvorlagen:
+thememanager.theme=Designvorlage: '{0}' für die Anwendung '{1}'.
+
resource.variable.duplicate=Variable '{0}' bereits vorhanden!
resource.file={0}: Datei '{1}' wurde geladen.
-
diff --git a/src/WebExpress.WebCore/Internationalization/en b/src/WebExpress.WebCore/Internationalization/en
index 164d882..c2dcfb9 100644
--- a/src/WebExpress.WebCore/Internationalization/en
+++ b/src/WebExpress.WebCore/Internationalization/en
@@ -39,10 +39,15 @@ componentmanager.wrongtype=The type '{0}' does not implement the interface '{1}'
componentmanager.duplicate=The component '{0}' has already been registered.
componentmanager.remove=The component '{0}' has been removed.
componentmanager.component=Components:
+componentmanager.name=Component: '{0}'
+
+logmanager.initialization:The log manager has been initialized.
+logmanager.titel:Log manager
internationalizationmanager.initialization=The internationalization manager has been initialized.
internationalizationmanager.register=The plugin '{0}' is registered in the internationalization manager.
+packagemanager.titel=Package manager:
packagemanager.initialization=The package manager has been initialized.
packagemanager.existing=The package '{0}' is registered in the catalog.
packagemanager.add=Package '{0}' is added to the catalog.
@@ -51,23 +56,26 @@ packagemanager.scan=The directory '{0}' is scanned for new packages.
packagemanager.save=The catalog is saved.
packagemanager.packagenotfound=The package '{0}' was not found in the file system.
packagemanager.boot.notfound=The plugin '{0}' is unknown.
+packagemanager.package=Package: '{0}'
pluginmanager.initialization=The plugin manager has been initialized.
pluginmanager.load={0}.dll is loading. Version = '{1}'
pluginmanager.created=The plugin '{0}' was created and registered in the plugin manager.
pluginmanager.duplicate=The plugin '{0}' has already been registered in plugin manager.
+pluginmanager.tomany=There is more than one plugin class! The plugin '{0}' is not loading.
pluginmanager.notavailable=The plugin '{0}' does not exist in plugin manager.
pluginmanager.plugin=Plugin: '{0}'
pluginmanager.pluginmanager.label=Plugin manager:
pluginmanager.pluginmanager.system=System plugin: '{0}'
pluginmanager.pluginmanager.custom=custom plugin: '{0}'
pluginmanager.pluginmanager.unfulfilleddependencies=Plugin with unfulfilled dependencies: '{0}'
-pluginmanager.plugin.initialization=The plugin '{0}' has been initialized.
pluginmanager.plugin.processing.start=The plugin '{0}' is running.
pluginmanager.plugin.processing.end=The running of the plugin '{0}' has been stopped.
pluginmanager.fulfilleddependencies=The plugin '{0}' fulfills all dependencies.
pluginmanager.unfulfilleddependencies=The plugin '{0}' does not fulfill a dependency on the plugin '{1}'.
+pluginmanager.applicationless=The plugin '{0}' does not have any information about an application.
+applicationmanager.titel=Application manager:
applicationmanager.initialization=The application manager has been initialized.
applicationmanager.registerapplication=The application '{0}' has been created and registered in the application manager.
applicationmanager.duplicateapplication=The application '{0}' has already been registered in the application manager.
@@ -77,54 +85,90 @@ applicationmanager.application.processing.start=The application '{0}' is running
applicationmanager.application.processing.end=The running of the application '{0}' has been stopped.
applicationmanager.application.boot.notfound=The plugin '{0}' is unknown.
-modulemanager.initialization=The module manager has been initialized.
-modulemanager.register=The module '{0}' has been assigned to the application '{1}' and registered in the module manager.
-modulemanager.duplicate=The module '{0}' has already been registered in the application '{1}'.
-modulemanager.applicationless=The module '{0}' does not have any information about the application.
-modulemanager.module=Module: '{0}' for application(s) '{1}'
-pluginmanager.module.initialization=The module '{1}' of the application '{0}' has been initialized.
-pluginmanager.module.processing.start=The module '{1}' of the application '{0}' is running.
-pluginmanager.module.processing.end=The running of the module '{1}' of the application '{0}' has been stopped.
-
resourcemanager.initialization=The resource manager has been initialized.
-resourcemanager.register={0} resource(s) have been assigned to the module '{1}'.
-resourcemanager.modulenotfound=The module '{1}' could not be found, which was specified in the resource '{0}'.
-resourcemanager.moduleless=The resource '{0}' does not have any information about the module.
-resourcemanager.addresource=The resource '{0}' has been registered in the module '{1}'.
-resourcemanager.addresource.duplicate=The resource '{0}' of module '{1}' has already been added.
-resourcemanager.addresource.error=The resource '{0}' of the module '{1}' could not be added.
+resourcemanager.register={0} resource(s) have been assigned to the application '{1}'.
+resourcemanager.addresource=The resource '{0}' has been registered in the application '{1}'.
+resourcemanager.addresource.duplicate=The resource '{0}' of application '{1}' has already been added.
+resourcemanager.addresource.error=The resource '{0}' of the application '{1}' could not be added.
resourcemanager.sitemap=Sitemap content resource '{0}' application:
resourcemanager.wrongtype=The type '{0}' does not implement the interface '{1}'.
-resourcemanager.statuspage=Resource: '{0}' for module '{1}'
+resourcemanager.resource=Resource: '{0}' for application '{1}'
+
+assetmanager.initialization=The asset manager has been initialized.
+assetmanager.addresource=The asset '{0}' has been registered in the application '{1}'.
+
+pagemanager.initialization=The page manager has been initialized.
+pagemanager.addpage=The page '{0}' has been registered in the application '{1}'.
+pagemanager.page=Page: '{0}' for application '{1}'
+
+restapimanager.initialization=The REST API manager has been initialized.
+restapimanager.addrestapi=The REST API '{0}' has been registered in the application '{1}'.
+restapimanager.resource=REST API: '{0}' for application '{1}'
+restapimanager.methodnotsupported=The method '{0}' is not supported.
-responsemanager.initialization=The response manager has been initialized.
-responsemanager.register=Status {0} has been registered in the module '{1}' and assigned to the status page '{2}'.
-responsemanager.duplicat=The status {0} has already been registered in the module '{1}'. Therefore, the status page '{2}' is not used.
-responsemanager.statuscode=A status code has not been assigned to the resource '{1}' for the module '{0}'.
-responsemanager.resource=Status code: '{0}'
+statuspagemanager.titel=Status page manager:
+statuspagemanager.initialization=The status page manager has been initialized.
+statuspagemanager.register=The status '{0}' has been registered and assigned to the status page '{1}'.
+statuspagemanager.duplicat=The status '{0}' has already been registered. Therefore, the status page '{1}' is not used.
+statuspagemanager.statuscodeless=A status code has not been assigned to the resource '{1}' for the application '{0}'.
+statuspagemanager.resource=Status code: '{0}'
+sitemapmanager.titel=Sitemap:
sitemapmanager.initialization=The sitemap manager has been initialized.
sitemapmanager.refresh=The sitemap will be rebuilt.
sitemapmanager.alreadyassigned=The node of the sitemap '{0}' is already assigned. The resource '{1}' is not included in the sitemap.
sitemapmanager.addresource=The resource '{0}' has been registered in the sitemap.
sitemapmanager.addresource.error=Could not add resource '{0}' in the sitemap.
sitemapmanager.preorder={0} => {1}
-sitemapmanager.sitemap=Sitemap:
sitemapmanager.merge.error=The two sitemaps '{0}' and '{1}' could not be merged.
sessionmanager.initialization=The session manager has been initialized.
+settingpagemanager.initialization=The setting page manager has been initialized.
+settingpagemanager.register.category=The setting category '{0}' has been registered in the application '{1}'.
+settingpagemanager.register.group=The setting group '{0}' has been registered in the application '{1}'.
+settingpagemanager.register.page=The setting page '{0}' has been registered in the application '{1}'.
+settingpagemanager.register.nocategory=The setting page '{0}' has not been assigned to a setting category.
+settingpagemanager.register.nogroup=The setting page '{0}' has not been assigned to a setting group.
+settingpagemanager.category.general.name=General settings
+settingpagemanager.category.general.description=Default category for general application settings.
+settingpagemanager.group.general.name=General
+settingpagemanager.group.general.description=General application settings.
+
+eventmanager.titel=Event manager:
eventmanager.initialization=The event manager has been initialized.
+eventmanager.register=The event handler '{0}' has been registered in the application '{1}'.
+eventmanager.duplicate=The event handler '{0}' has already been registered. Therefore, the application '{1}' is not used.
+eventmanager.eventless=The event handler '{0}' does not have any information about the event.
+eventmanager.handler=Event handler: '{0}' for application '{1}'.
jobmanager.initialization=The schedule manager has been initialized.
-jobmanager.register=The plugin '{0}' is registered in the schedule manager manager.
-jobmanager.job.register=The job '{1}' have been assigned to the module '{0}'.
-jobmanager.moduleless=The job '{0}' does not have any information about the module.
-jobmanager.wrongmodule=The '{1}' job is not part of the module {0}.
-jobmanager.job=Job: '{0}' for module '{1}'
+jobmanager.register=The job '{0}' has been registered in the application '{1}'.
+jobmanager.duplicate=The job '{0}' has already been registered. Therefore, the application '{1}' is not used.
+jobmanager.jobless=The job '{0}' does not have any information about the job.
+jobmanager.job=Job: '{0}' for plugin '{1}'
jobmanager.job.process=The job '{0}' is executed.
jobmanager.cron.parseerror=Syntax error in the timing of a job. The value '{0}' cannot be processed.
jobmanager.cron.range=Syntax error in the timing of a job. The value '{0}' is outside the valid range.
+fragmentmanager.initialization=The fragment manager has been initialized.
+fragmentmanager.register=The fragment '{0}' has been registered in the '{1}' section of application '{2}'.
+fragmentmanager.error.section=The section is incorrect.
+fragmentmanager.wrongtype=The type '{0}' does not implement the interface '{1}'.
+fragmentmanager.addfragment.duplicate=The fragment '{0}' from the plugin '{1}' has already been added.
+fragmentmanager.titel=Fragments:
+fragmentmanager.fragment=Fragment: '{0}' for application '{1}'.
+
+identitymanager.initialization=The identity manager has been initialized.
+identitymanager.registerpermission=The permission '{0}' has been assigned to the application '{1}' and registered in the identity manager.
+identitymanager.duplicatepermission=The permission '{0}' has already been registered in the application '{1}'.
+identitymanager.registerrole=The role '{0}' has been assigned to the application '{1}' and registered in the identity manager.
+identitymanager.duplicaterole=The role '{0}' has already been registered in the application '{1}'.
+
+thememanager.initialization=The theme manager has been initialized.
+thememanager.addtheme=The theme '{0}' has been registered in the application '{1}'.
+thememanager.titel=Themes:
+thememanager.theme=Theme: '{0}' for application '{1}'.
+
resource.variable.duplicate=Variable '{0}' already exists!
-resource.file={0}: File '{1}' has been loaded.
\ No newline at end of file
+resource.file={0}: File '{1}' has been loaded.
diff --git a/src/WebExpress.WebCore/Setting/ISettingItem.cs b/src/WebExpress.WebCore/Setting/ISettingItem.cs
index 5a3ad8f..eb2fdd5 100644
--- a/src/WebExpress.WebCore/Setting/ISettingItem.cs
+++ b/src/WebExpress.WebCore/Setting/ISettingItem.cs
@@ -1,5 +1,8 @@
namespace WebExpress.WebCore.Setting
{
+ ///
+ /// Interface for a settings object.
+ ///
public interface ISettingItem
{
}
diff --git a/src/WebExpress.WebCore/Setting/SettingLogItem.cs b/src/WebExpress.WebCore/Setting/SettingLogItem.cs
index e72a49a..88c66ff 100644
--- a/src/WebExpress.WebCore/Setting/SettingLogItem.cs
+++ b/src/WebExpress.WebCore/Setting/SettingLogItem.cs
@@ -45,7 +45,7 @@ public class SettingLogItem : ISettingItem
public string Timepattern { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public SettingLogItem()
{
diff --git a/src/WebExpress.WebCore/WebApplication/Application.cs b/src/WebExpress.WebCore/WebApplication/Application.cs
new file mode 100644
index 0000000..98f63d6
--- /dev/null
+++ b/src/WebExpress.WebCore/WebApplication/Application.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace WebExpress.WebCore.WebApplication
+{
+ ///
+ /// This represents an application.
+ ///
+ public abstract class Application : IApplication
+ {
+ ///
+ /// Returns the context of the application.
+ ///
+ public IApplicationContext ApplicationContext { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Application()
+ {
+ }
+
+ ///
+ /// Initialization of the application. Here, for example, managed resources can be loaded.
+ ///
+ /// The context that applies to the execution of the application
+ public virtual void Initialization(IApplicationContext applicationContext)
+ {
+ ApplicationContext = applicationContext;
+ }
+
+ ///
+ /// Called when the application starts working. The call is concurrent.
+ ///
+ public virtual void Run()
+ {
+ }
+
+ ///
+ /// Release unmanaged resources that have been reserved during use.
+ ///
+ public virtual void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebApplication/ApplicationContext.cs b/src/WebExpress.WebCore/WebApplication/ApplicationContext.cs
index 9d58cda..14c97f1 100644
--- a/src/WebExpress.WebCore/WebApplication/ApplicationContext.cs
+++ b/src/WebExpress.WebCore/WebApplication/ApplicationContext.cs
@@ -1,9 +1,11 @@
-using System.Collections.Generic;
+using WebExpress.WebCore.WebEndpoint;
using WebExpress.WebCore.WebPlugin;
-using WebExpress.WebCore.WebUri;
namespace WebExpress.WebCore.WebApplication
{
+ ///
+ /// Represents the context of an application.
+ ///
public class ApplicationContext : IApplicationContext
{
///
@@ -26,11 +28,6 @@ public class ApplicationContext : IApplicationContext
///
public string Description { get; internal set; }
- ///
- /// Returns an enumeration of options. Options enable optional resources.
- ///
- public IEnumerable Options { get; internal set; }
-
///
/// Returns the asset directory. This is mounted in the asset directory of the server.
///
@@ -44,27 +41,27 @@ public class ApplicationContext : IApplicationContext
///
/// Returns the context path. This is mounted in the context path of the server.
///
- public UriResource ContextPath { get; internal set; }
+ public IRoute ContextPath { get; internal set; }
///
/// Returns the icon uri.
///
- public UriResource Icon { get; internal set; }
+ public IRoute Icon { get; internal set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public ApplicationContext()
{
}
///
- /// Conversion of the apllication context into its string representation.
+ /// Conversion of the application context into its string representation.
///
/// The string that uniquely represents the application.
public override string ToString()
{
- return $"Application {ApplicationId}";
+ return $"Application: {ApplicationId}";
}
}
}
diff --git a/src/WebExpress.WebCore/WebApplication/ApplicationDictionary.cs b/src/WebExpress.WebCore/WebApplication/ApplicationDictionary.cs
deleted file mode 100644
index b6d1622..0000000
--- a/src/WebExpress.WebCore/WebApplication/ApplicationDictionary.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Collections.Generic;
-using WebExpress.WebCore.WebPlugin;
-
-namespace WebExpress.WebCore.WebApplication
-{
- ///
- /// Key = Plugin context
- /// Value = { Key = application id, Value = application item }
- ///
- internal class ApplicationDictionary : Dictionary>
- {
- }
-}
diff --git a/src/WebExpress.WebCore/WebApplication/ApplicationManager.cs b/src/WebExpress.WebCore/WebApplication/ApplicationManager.cs
index ff23a8a..139ceb7 100644
--- a/src/WebExpress.WebCore/WebApplication/ApplicationManager.cs
+++ b/src/WebExpress.WebCore/WebApplication/ApplicationManager.cs
@@ -1,22 +1,29 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication.Model;
using WebExpress.WebCore.WebAttribute;
using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebLog;
using WebExpress.WebCore.WebPlugin;
-using WebExpress.WebCore.WebUri;
namespace WebExpress.WebCore.WebApplication
{
///
/// Management of WebExpress applications.
///
- public sealed class ApplicationManager : IComponentPlugin, IExecutableElements, ISystemComponent
+ public sealed class ApplicationManager : IApplicationManager, IExecutableElements, ISystemComponent
{
+ private readonly IComponentHub _componentHub;
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly ApplicationDictionary _dictionary = new();
+
///
/// An event that fires when an application is added.
///
@@ -27,48 +34,29 @@ public sealed class ApplicationManager : IComponentPlugin, IExecutableElements,
///
public event EventHandler RemoveApplication;
- ///
- /// Returns or sets the reference to the context of the host.
- ///
- public IHttpServerContext HttpServerContext { get; private set; }
-
- ///
- /// Returns or sets the directory where the applications are listed.
- ///
- private ApplicationDictionary Dictionary { get; } = new ApplicationDictionary();
-
///
/// Returns the stored applications.
///
- public IEnumerable Applications => Dictionary.Values.SelectMany(x => x.Values).Select(x => x.ApplicationContext);
+ public IEnumerable Applications => _dictionary.All;
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
- internal ApplicationManager()
+ /// The component hub.
+ /// The reference to the context of the host.
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used via Reflection.")]
+ private ApplicationManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
{
- ComponentManager.PluginManager.AddPlugin += (sender, pluginContext) =>
- {
- Register(pluginContext);
- };
+ _componentHub = componentHub;
- ComponentManager.PluginManager.RemovePlugin += (sender, pluginContext) =>
- {
- Remove(pluginContext);
- };
- }
+ _componentHub.PluginManager.AddPlugin += OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin += OnRemovePlugin;
- ///
- /// Initialization
- ///
- /// The reference to the context of the host.
- public void Initialization(IHttpServerContext context)
- {
- HttpServerContext = context;
+ _httpServerContext = httpServerContext;
- HttpServerContext.Log.Debug
+ _httpServerContext.Log.Debug
(
- InternationalizationManager.I18N("webexpress:applicationmanager.initialization")
+ I18N.Translate("webexpress.webcore:applicationmanager.initialization")
);
}
@@ -76,18 +64,15 @@ public void Initialization(IHttpServerContext context)
/// Discovers and registers applications from the specified plugin.
///
/// A context of a plugin whose applications are to be registered.
- public void Register(IPluginContext pluginContext)
+ private void Register(IPluginContext pluginContext)
{
// the plugin has already been registered
- if (Dictionary.ContainsKey(pluginContext))
+ if (_dictionary.Contains(pluginContext))
{
return;
}
- Dictionary.Add(pluginContext, new Dictionary());
-
var assembly = pluginContext.Assembly;
- var pluginDict = Dictionary[pluginContext];
foreach (var type in assembly.GetExportedTypes().Where
(
@@ -102,9 +87,8 @@ public void Register(IPluginContext pluginContext)
var icon = string.Empty;
var description = string.Empty;
var contextPath = string.Empty;
- var assetPath = Path.DirectorySeparatorChar.ToString();
- var dataPath = Path.DirectorySeparatorChar.ToString();
- var options = new List();
+ var assetPath = "/";
+ var dataPath = "/";
// determining attributes
foreach (var customAttribute in type.CustomAttributes
@@ -134,23 +118,6 @@ public void Register(IPluginContext pluginContext)
{
dataPath = customAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();
}
- else if (customAttribute.AttributeType == typeof(OptionAttribute))
- {
- var value = customAttribute.ConstructorArguments.FirstOrDefault().Value.ToString().ToLower().Trim();
- options.Add(value);
- }
- else if (customAttribute.AttributeType.Name == typeof(WebExOptionAttribute<>).Name && customAttribute.AttributeType.Namespace == typeof(WebExOptionAttribute<>).Namespace)
- {
- var value = customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault()?.FullName?.ToLower();
- options.Add(value);
- }
- else if (customAttribute.AttributeType.Name == typeof(WebExOptionAttribute<,>).Name && customAttribute.AttributeType.Namespace == typeof(WebExOptionAttribute<,>).Namespace)
- {
- var firstValue = customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault()?.FullName?.ToLower();
- var secoundValue = customAttribute.AttributeType.GenericTypeArguments.LastOrDefault()?.FullName?.ToLower();
-
- options.Add($"{firstValue}.{secoundValue}");
- }
}
// creating application context
@@ -160,27 +127,31 @@ public void Register(IPluginContext pluginContext)
ApplicationId = id,
ApplicationName = name,
Description = description,
- Options = options,
- AssetPath = Path.Combine(HttpServerContext.AssetPath, assetPath),
- DataPath = Path.Combine(HttpServerContext.DataPath, dataPath),
- Icon = UriResource.Combine(HttpServerContext.ContextPath, contextPath, icon),
- ContextPath = UriResource.Combine(HttpServerContext.ContextPath, contextPath)
+ AssetPath = Path.Combine(_httpServerContext.AssetPath, assetPath),
+ DataPath = Path.Combine(_httpServerContext.DataPath, dataPath),
+ Icon = RouteEndpoint.Combine(_httpServerContext.ContextPath, contextPath, icon),
+ ContextPath = RouteEndpoint.Combine(_httpServerContext.ContextPath, contextPath)
};
// create application
- var applicationInstance = Activator.CreateInstance(type) as IApplication;
+ var applicationInstance = ComponentActivator.CreateInstance
+ (
+ type,
+ applicationContext,
+ _httpServerContext,
+ _componentHub
+ );
- if (!pluginDict.ContainsKey(id))
+ if (_dictionary.AddApplication(pluginContext, new ApplicationItem()
{
- pluginDict.Add(id, new ApplicationItem()
- {
- ApplicationContext = applicationContext,
- Application = applicationInstance
- });
-
- HttpServerContext.Log.Debug
+ ApplicationClass = type,
+ ApplicationContext = applicationContext,
+ Application = applicationInstance
+ }))
+ {
+ _httpServerContext.Log.Debug
(
- InternationalizationManager.I18N("webexpress:applicationmanager.register", id)
+ I18N.Translate("webexpress.webcore:applicationmanager.register", id)
);
// raises the AddApplication event
@@ -188,54 +159,61 @@ public void Register(IPluginContext pluginContext)
}
else
{
- HttpServerContext.Log.Warning
+ _httpServerContext.Log.Warning
(
- InternationalizationManager.I18N("webexpress:applicationmanager.duplicate", id)
+ I18N.Translate("webexpress.webcore:applicationmanager.duplicate", id)
);
}
}
+
+ Log();
}
///
- /// Discovers and registers applications from the specified plugin.
+ /// Removes all applications associated with the specified plugin context.
///
- /// A list with plugin contexts that contain the applications.
- public void Register(IEnumerable pluginContexts)
+ /// The context of the plugin that contains the applications to remove.
+ internal void Remove(IPluginContext pluginContext)
{
- foreach (var pluginContext in pluginContexts)
+ if (pluginContext == null)
+ {
+ return;
+ }
+
+ foreach (var applicationContext in _dictionary.RemoveApplications(pluginContext))
{
- Register(pluginContext);
+ OnRemoveApplication(applicationContext);
}
+
+ Log();
}
///
- /// Determines the application contexts for a given application id.
+ /// Returns the application context for a given application id.
///
/// The application id.
- /// The context of the application or null.
- public IApplicationContext GetApplcation(string applicationId)
+ /// The context of the application or null if the application id is null, empty, or not found.
+ public IApplicationContext GetApplication(string applicationId)
{
- if (string.IsNullOrWhiteSpace(applicationId)) return null;
-
- var items = Dictionary.Values
- .Where(x => x.ContainsKey(applicationId.ToLower()))
- .Select(x => x[applicationId.ToLower()])
- .FirstOrDefault();
-
- if (items != null)
- {
- return items.ApplicationContext;
- }
+ return _dictionary.GetApplication(applicationId);
+ }
- return null;
+ ///
+ /// Returns the application contexts for a given application id.
+ ///
+ /// The application type.
+ /// The context of the application or null.
+ public IApplicationContext GetApplication()
+ {
+ return GetApplications(typeof(T)).FirstOrDefault();
}
///
- /// Determines the application contexts for the given application ids.
+ /// Returns the application contexts for the given application ids.
///
/// The applications ids. Can contain regular expressions or * for all.
/// The contexts of the applications as an enumeration.
- public IEnumerable GetApplcations(IEnumerable applicationIds)
+ public IEnumerable GetApplications(IEnumerable applicationIds)
{
var list = new List();
@@ -263,18 +241,23 @@ public IEnumerable GetApplcations(IEnumerable appli
}
///
- /// Determines the application contexts for the given plugin.
+ /// Returns the application contexts for the given plugin.
///
/// The context of the plugin.
/// The contexts of the applications as an enumeration.
- public IEnumerable GetApplcations(IPluginContext pluginContext)
+ public IEnumerable GetApplications(IPluginContext pluginContext)
{
- if (!Dictionary.ContainsKey(pluginContext))
- {
- return new List();
- }
+ return _dictionary.GetApplications(pluginContext);
+ }
- return Dictionary[pluginContext].Values.Select(x => x.ApplicationContext);
+ ///
+ /// Returns the application contexts for a given application type.
+ ///
+ /// The application type.
+ /// The contexts of the applications as an enumeration.
+ public IEnumerable GetApplications(Type application)
+ {
+ return _dictionary.GetApplications(application);
}
///
@@ -287,14 +270,13 @@ public void Boot(IPluginContext pluginContext)
{
return;
}
-
- if (!Dictionary.ContainsKey(pluginContext))
+ else if (!_dictionary.Contains(pluginContext))
{
- HttpServerContext.Log.Warning
+ _httpServerContext.Log.Warning
(
- InternationalizationManager.I18N
+ I18N.Translate
(
- "webexpress:applicationmanager.application.boot.notfound",
+ "webexpress.webcore:applicationmanager.application.boot.notfound",
pluginContext.PluginId
)
);
@@ -302,39 +284,28 @@ public void Boot(IPluginContext pluginContext)
return;
}
- foreach (var applicationItem in Dictionary[pluginContext]?.Values ?? Enumerable.Empty())
+ foreach (var applicationItem in _dictionary.GetApplicationItems(pluginContext))
{
var token = applicationItem.CancellationTokenSource.Token;
- // Initialize application
- applicationItem.Application.Initialization(applicationItem.ApplicationContext);
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N
- (
- "webexpress:applicationmanager.application.initialization",
- applicationItem.ApplicationContext.ApplicationId
- )
- );
-
// Run the application concurrently
Task.Run(() =>
{
- HttpServerContext.Log.Debug
+ _httpServerContext.Log.Debug
(
- InternationalizationManager.I18N
+ I18N.Translate
(
- "webexpress:applicationmanager.application.processing.start",
+ "webexpress.webcore:applicationmanager.application.processing.start",
applicationItem.ApplicationContext.ApplicationId)
);
applicationItem.Application.Run();
- HttpServerContext.Log.Debug
+ _httpServerContext.Log.Debug
(
- InternationalizationManager.I18N
+ I18N.Translate
(
- "webexpress:applicationmanager.application.processing.end",
+ "webexpress.webcore:applicationmanager.application.processing.end",
applicationItem.ApplicationContext.ApplicationId
)
);
@@ -350,31 +321,12 @@ public void Boot(IPluginContext pluginContext)
/// The context of the plugin that contains the applications.
public void ShutDown(IPluginContext pluginContext)
{
- foreach (var applicationItem in Dictionary[pluginContext]?.Values ?? Enumerable.Empty())
+ foreach (var applicationItem in _dictionary.GetApplicationItems(pluginContext))
{
applicationItem.CancellationTokenSource.Cancel();
}
}
- ///
- /// Removes all applications associated with the specified plugin context.
- ///
- /// The context of the plugin that contains the applications to remove.
- public void Remove(IPluginContext pluginContext)
- {
- if (!Dictionary.ContainsKey(pluginContext))
- {
- return;
- }
-
- foreach (var applicationContext in Dictionary[pluginContext])
- {
- OnRemoveApplication(applicationContext.Value.ApplicationContext);
- }
-
- Dictionary.Remove(pluginContext);
- }
-
///
/// Raises the AddApplication event.
///
@@ -393,22 +345,61 @@ private void OnRemoveApplication(IApplicationContext applicationContext)
RemoveApplication?.Invoke(this, applicationContext);
}
+ ///
+ /// Raises the event when an plugin is added.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being added.
+ private void OnAddPlugin(object sender, IPluginContext e)
+ {
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when a plugin is removed.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being removed.
+ private void OnRemovePlugin(object sender, IPluginContext e)
+ {
+ Remove(e);
+ }
+
///
/// Information about the component is collected and prepared for output in the log.
///
- /// The context of the plugin.
- /// A list of log entries.
- /// The shaft deep.
- public void PrepareForLog(IPluginContext pluginContext, IList output, int deep)
+ private void Log()
{
- foreach (var applicationContext in GetApplcations(pluginContext))
+ if (!Applications.Any())
+ {
+ return;
+ }
+
+ using var frame = new LogFrameSimple(_httpServerContext.Log);
+ var list = new List
+ {
+ I18N.Translate("webexpress.webcore:applicationmanager.titel")
+ };
+
+ foreach (var applicationContext in Applications)
{
- output.Add
+ list.Add
(
- string.Empty.PadRight(deep) +
- InternationalizationManager.I18N("webexpress:applicationmanager.application", applicationContext.ApplicationId)
+ string.Empty.PadRight(2) +
+ I18N.Translate("webexpress.webcore:applicationmanager.application", applicationContext.ApplicationId)
);
}
+
+ _httpServerContext.Log.Info(string.Join(Environment.NewLine, list));
+ }
+
+ ///
+ /// Release of unmanaged resources reserved during use.
+ ///
+ public void Dispose()
+ {
+ _componentHub.PluginManager.AddPlugin -= OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin -= OnRemovePlugin;
}
}
}
diff --git a/src/WebExpress.WebCore/WebApplication/IApplication.cs b/src/WebExpress.WebCore/WebApplication/IApplication.cs
index 18e2fd2..4ea4ddc 100644
--- a/src/WebExpress.WebCore/WebApplication/IApplication.cs
+++ b/src/WebExpress.WebCore/WebApplication/IApplication.cs
@@ -1,18 +1,12 @@
-using System;
+using WebExpress.WebCore.WebComponent;
namespace WebExpress.WebCore.WebApplication
{
///
/// This interface represents an application.
///
- public interface IApplication : IDisposable
+ public interface IApplication : IComponent
{
- ///
- /// Initialization of the application .
- ///
- /// The context.
- void Initialization(IApplicationContext context);
-
///
/// Called when the application starts working. The call is concurrent.
///
diff --git a/src/WebExpress.WebCore/WebApplication/IApplicationContext.cs b/src/WebExpress.WebCore/WebApplication/IApplicationContext.cs
index e4f50e9..23c2062 100644
--- a/src/WebExpress.WebCore/WebApplication/IApplicationContext.cs
+++ b/src/WebExpress.WebCore/WebApplication/IApplicationContext.cs
@@ -1,13 +1,13 @@
-using System.Collections.Generic;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebEndpoint;
using WebExpress.WebCore.WebPlugin;
-using WebExpress.WebCore.WebUri;
namespace WebExpress.WebCore.WebApplication
{
///
/// The application context.
///
- public interface IApplicationContext
+ public interface IApplicationContext : IContext
{
///
/// Provides the context of the associated plugin.
@@ -29,11 +29,6 @@ public interface IApplicationContext
///
string Description { get; }
- ///
- /// Returns an enumeration of options. Options enable optional resources.
- ///
- IEnumerable Options { get; }
-
///
/// Returns the asset directory. This is mounted in the asset directory of the server.
///
@@ -47,11 +42,11 @@ public interface IApplicationContext
///
/// Returns the context path. This is mounted in the context path of the server.
///
- UriResource ContextPath { get; }
+ IRoute ContextPath { get; }
///
/// Returns the icon uri.
///
- UriResource Icon { get; }
+ IRoute Icon { get; }
}
}
diff --git a/src/WebExpress.WebCore/WebApplication/IApplicationManager.cs b/src/WebExpress.WebCore/WebApplication/IApplicationManager.cs
new file mode 100644
index 0000000..ed01437
--- /dev/null
+++ b/src/WebExpress.WebCore/WebApplication/IApplicationManager.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebApplication
+{
+ ///
+ /// Interface of the management of WebExpress applications.
+ ///
+ public interface IApplicationManager : IComponentManager
+ {
+ ///
+ /// An event that fires when an application is added.
+ ///
+ event EventHandler AddApplication;
+
+ ///
+ /// An event that fires when an application is removed.
+ ///
+ event EventHandler RemoveApplication;
+
+ ///
+ /// Returns the stored applications.
+ ///
+ IEnumerable Applications { get; }
+
+ ///
+ /// Returns the application contexts for a given application id.
+ ///
+ /// The application id.
+ /// The context of the application or null.
+ IApplicationContext GetApplication(string applicationId);
+
+ ///
+ /// Returns the application contexts for a given application id.
+ ///
+ /// The application type.
+ /// The context of the application or null.
+ IApplicationContext GetApplication();
+
+ ///
+ /// Returns the application contexts for the given application ids.
+ ///
+ /// The applications ids. Can contain regular expressions or * for all.
+ /// The contexts of the applications as an enumeration.
+ IEnumerable GetApplications(IEnumerable applicationIds);
+
+ ///
+ /// Returns the application contexts for the given plugin.
+ ///
+ /// The context of the plugin.
+ /// The contexts of the applications as an enumeration.
+ IEnumerable GetApplications(IPluginContext pluginContext);
+
+ ///
+ /// Returns the application contexts for a given application type.
+ ///
+ /// The application type.
+ /// The contexts of the applications as an enumeration.
+ IEnumerable GetApplications(Type application);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebApplication/Model/ApplicationDictionary.cs b/src/WebExpress.WebCore/WebApplication/Model/ApplicationDictionary.cs
new file mode 100644
index 0000000..d1cff54
--- /dev/null
+++ b/src/WebExpress.WebCore/WebApplication/Model/ApplicationDictionary.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebApplication.Model
+{
+ ///
+ /// Represents a dictionary that maps plugin contexts to application items.
+ ///
+ internal class ApplicationDictionary
+ {
+ private readonly Dictionary> _dict = [];
+
+ ///
+ /// Returns all application contexts from the dictionary.
+ ///
+ public IEnumerable All => _dict
+ .Values.SelectMany(x => x.Values)
+ .Select(x => x.ApplicationContext);
+
+ ///
+ /// Adds a application item to the dictionary.
+ ///
+ /// The plugin context.
+ /// The application item.
+ /// True if the application item was added successfully, false if an element with the same status code already exists.
+ public bool AddApplication(IPluginContext pluginContext, ApplicationItem applicationItem)
+ {
+ if (!_dict.TryGetValue(pluginContext, out var applicationDict))
+ {
+ applicationDict = [];
+ _dict[pluginContext] = applicationDict;
+ }
+
+ if (applicationDict.TryAdd(applicationItem.ApplicationContext.ApplicationId, applicationItem))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Removes applications from the dictionary.
+ ///
+ /// The plugin context.
+ /// An IEnumerable of application contexts that were removed.
+ public IEnumerable RemoveApplications(IPluginContext pluginContext)
+ {
+ var applicationContexts = GetApplications(pluginContext);
+
+ _dict.Remove(pluginContext);
+
+ return applicationContexts;
+ }
+
+ ///
+ /// Returns the application contexts for a given plugin context.
+ ///
+ /// The plugin context.
+ /// An IEnumerable of application contexts associated with the given plugin context.
+ public IEnumerable GetApplicationItems(IPluginContext pluginContext)
+ {
+ var applicationItems = _dict
+ .Where(x => x.Key == pluginContext)
+ .Select(x => x.Value)
+ .Select(x => x.Values)
+ .SelectMany(x => x);
+
+ return applicationItems;
+ }
+
+ ///
+ /// Returns the application contexts for a given plugin context.
+ ///
+ /// The plugin context.
+ /// An IEnumerable of application contexts associated with the given plugin context.
+ public IEnumerable GetApplications(IPluginContext pluginContext)
+ {
+ var applicationContexts = GetApplicationItems(pluginContext)
+ .Select(x => x.ApplicationContext);
+
+ return applicationContexts;
+ }
+
+ ///
+ /// Returns the application context for a given application id.
+ ///
+ /// The application id.
+ /// The context of the application or null if the application id is null, empty, or not found.
+ public IApplicationContext GetApplication(string applicationId)
+ {
+ if (string.IsNullOrWhiteSpace(applicationId)) return null;
+
+ var items = _dict.Values
+ .Where(x => x.ContainsKey(applicationId.ToLower()))
+ .Select(x => x[applicationId.ToLower()])
+ .FirstOrDefault();
+
+ return items?.ApplicationContext;
+ }
+
+ ///
+ /// Returns the application contexts for a given application type.
+ ///
+ /// The application type.
+ /// The contexts of the applications as an enumeration.
+ public IEnumerable GetApplications(Type application)
+ {
+ if (application == null) return [];
+
+ var items = _dict.Values.SelectMany(x => x.Values)
+ .Where(x => x.ApplicationClass.Equals(application) || application.IsAssignableFrom(x.ApplicationClass))
+ .Select(x => x.ApplicationContext);
+
+ return items;
+ }
+
+ ///
+ /// Checks if the dictionary contains the specified plugin context.
+ ///
+ /// The plugin context to check for.
+ /// True if the plugin context exists in the dictionary, otherwise false.
+ public bool Contains(IPluginContext pluginContext)
+ {
+ return _dict.ContainsKey(pluginContext);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebApplication/ApplicationItem.cs b/src/WebExpress.WebCore/WebApplication/Model/ApplicationItem.cs
similarity index 72%
rename from src/WebExpress.WebCore/WebApplication/ApplicationItem.cs
rename to src/WebExpress.WebCore/WebApplication/Model/ApplicationItem.cs
index d6cca18..2ed8b64 100644
--- a/src/WebExpress.WebCore/WebApplication/ApplicationItem.cs
+++ b/src/WebExpress.WebCore/WebApplication/Model/ApplicationItem.cs
@@ -1,6 +1,7 @@
-using System.Threading;
+using System;
+using System.Threading;
-namespace WebExpress.WebCore.WebApplication
+namespace WebExpress.WebCore.WebApplication.Model
{
///
/// Represents an application entry in the application directory.
@@ -12,6 +13,11 @@ internal class ApplicationItem
///
public IApplicationContext ApplicationContext { get; set; }
+ ///
+ /// Returns the application class.
+ ///
+ public Type ApplicationClass { get; internal set; }
+
///
/// The application.
///
diff --git a/src/WebExpress.WebCore/WebAsset/Asset.cs b/src/WebExpress.WebCore/WebAsset/Asset.cs
new file mode 100644
index 0000000..e554e83
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/Asset.cs
@@ -0,0 +1,164 @@
+using System;
+using System.IO;
+using System.Reflection;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// Delivery of a resource embedded in the assembly.
+ ///
+ public class Asset : IAsset
+ {
+ private readonly IComponentHub _componentHub;
+ private readonly IAssetContext _assetContext;
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly string _embeddedResource;
+ private byte[] _data;
+
+ ///
+ /// Returns the root directory.
+ ///
+ public string AssetDirectory { get; protected set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The component hub.
+ /// The asset context.
+ /// The server context.
+ /// The embedded resource name.
+ public Asset(IComponentHub componentHub, IAssetContext assetContext, IHttpServerContext httpServerContext, string embeddedResource)
+ {
+ _componentHub = componentHub;
+ _assetContext = assetContext;
+ _httpServerContext = httpServerContext;
+ _embeddedResource = embeddedResource;
+
+ var assembly = _assetContext.PluginContext.Assembly;
+ _data = GetData(assembly);
+ }
+
+ ///
+ /// Processing of the resource.
+ ///
+ /// The request.
+ /// The response.
+ public Response Process(Request request)
+ {
+ if (_data == null)
+ {
+ return new ResponseNotFound();
+ }
+
+ var extension = Path.GetExtension(_assetContext.EndpointId.ToString())?.ToLower() ?? "";
+ var response = new ResponseOK();
+
+ response.Header.CacheControl = "public, max-age=31536000";
+ response.Header.ContentLength = _data.Length;
+ response.Content = _data;
+
+ switch (extension)
+ {
+ case ".pdf":
+ response.Header.ContentType = "application/pdf";
+ break;
+ case ".txt":
+ response.Header.ContentType = "text/plain";
+ break;
+ case ".css":
+ response.Header.ContentType = "text/css";
+ break;
+ case ".js":
+ response.Header.ContentType = "application/javascript";
+ break;
+ case ".xml":
+ response.Header.ContentType = "text/xml";
+ break;
+ case ".html":
+ case ".htm":
+ response.Header.ContentType = "text/html";
+ break;
+ case ".zip":
+ response.Header.ContentDisposition = "attatchment; filename=" + _assetContext.EndpointId + "; size=" + _data.LongLength;
+ response.Header.ContentType = "application/zip";
+ break;
+ case ".doc":
+ case ".docx":
+ response.Header.ContentType = "application/msword";
+ break;
+ case ".xls":
+ case ".xlx":
+ response.Header.ContentType = "application/vnd.ms-excel";
+ break;
+ case ".ppt":
+ response.Header.ContentType = "application/vnd.ms-powerpoint";
+ break;
+ case ".gif":
+ response.Header.ContentType = "image/gif";
+ break;
+ case ".png":
+ response.Header.ContentType = "image/png";
+ break;
+ case ".svg":
+ response.Header.ContentType = "image/svg+xml";
+ break;
+ case ".jpeg":
+ case ".jpg":
+ response.Header.ContentType = "image/jpg";
+ break;
+ case ".ico":
+ response.Header.ContentType = "image/x-icon";
+ break;
+ case ".mp3":
+ response.Header.ContentType = "audio/mpeg";
+ break;
+ case ".mp4":
+ response.Header.ContentType = "video/mp4";
+ break;
+ default:
+ response.Header.ContentType = "binary/octet-stream";
+ break;
+ }
+
+ _httpServerContext.Log.Debug(I18N.Translate
+ (
+ "webexpress.webcore:asset.file",
+ request.RemoteEndPoint, request.Uri
+ ));
+
+ return response;
+ }
+
+ ///
+ /// Reads the data of a specified resource.
+ ///
+ /// The assembly.
+ /// The data.
+ private byte[] GetData(Assembly assembly)
+ {
+ if (assembly == null || _embeddedResource == null)
+ {
+ return [];
+ }
+
+ using var stream = assembly.GetManifestResourceStream(_embeddedResource);
+ using var memoryStream = new MemoryStream();
+ stream.CopyTo(memoryStream);
+
+ return memoryStream.ToArray();
+ }
+
+ ///
+ /// Performs application-specific tasks related to sharing, returning, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ _data = null;
+
+ GC.SuppressFinalize(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WebExpress.WebCore/WebAsset/AssetContext.cs b/src/WebExpress.WebCore/WebAsset/AssetContext.cs
new file mode 100644
index 0000000..f8b15a0
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/AssetContext.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// Represents the context of a asset.
+ ///
+ public class AssetContext : IAssetContext
+ {
+ ///
+ /// Returns the associated plugin context.
+ ///
+ public IPluginContext PluginContext { get; internal set; }
+
+ ///
+ /// Returns the corresponding application context.
+ ///
+ public IApplicationContext ApplicationContext { get; internal set; }
+
+ ///
+ /// Returns the conditions that must be met for the resource to be active.
+ ///
+ public IEnumerable Conditions => [];
+
+ ///
+ /// Returns the resource id.
+ ///
+ public IComponentId EndpointId { get; internal set; }
+
+ ///
+ /// Returns whether the resource is created once and reused each time it is called.
+ ///
+ public bool Cache => true;
+
+ ///
+ /// Returns or sets whether all subpaths should be taken into sitemap.
+ ///
+ public bool IncludeSubPaths { get; internal set; }
+
+ ///
+ /// Returns the internal routing path for the endpoint.
+ ///
+ public IRoute Route { get; internal set; }
+
+ ///
+ /// Returns the attributes associated with the page.
+ ///
+ public IEnumerable Attributes => [];
+
+ ///
+ /// Initializes a new instance of the class with the specified endpoint manager, parent type, context path, and path segment.
+ ///
+ public AssetContext()
+ {
+ }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// A string that represents the current object.
+ public override string ToString()
+ {
+ return $"Asset: {EndpointId}";
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/AssetManager.cs b/src/WebExpress.WebCore/WebAsset/AssetManager.cs
new file mode 100644
index 0000000..44b7876
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/AssetManager.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAsset.Model;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebPlugin;
+using WebExpress.WebCore.WebUri;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// The asset manager manages WebExpress elements, which can be called with a URI (Uniform Resource Identifier).
+ ///
+ public sealed class AssetManager : IAssetManager, ISystemComponent
+ {
+ private readonly IComponentHub _componentHub;
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly AssetItemDictionary _itemDictionary = new();
+ private readonly AssetEndpointDictionary _endpointDictionary = [];
+
+ ///
+ /// An event that fires when an asset is added.
+ ///
+ public event EventHandler AddAsset;
+
+ ///
+ /// An event that fires when an asset is removed.
+ ///
+ public event EventHandler RemoveAsset;
+
+ ///
+ /// Returns all asset contexts.
+ ///
+ public IEnumerable Assets => _itemDictionary.All.Select(x => x.AssetContext);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The component hub.
+ /// The reference to the context of the host.
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used via Reflection.")]
+ private AssetManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
+ {
+ _componentHub = componentHub;
+
+ _componentHub.PluginManager.AddPlugin += OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin += OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication += OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication += OnRemoveApplication;
+
+ var endpointtRegistration = new EndpointRegistration()
+ {
+ EndpointResolver = (type, applicationContext) => _endpointDictionary
+ .Where(x => x.Key == applicationContext)
+ .Select(x => x.Value)
+ .Where(x => x.Item2.GetType() == type)
+ .Select(x => x.Item1),
+ EndpointsResolver = () => _endpointDictionary
+ .Select(x => x.Value)
+ .Select(x => x.Item1),
+ HandleRequest = (request, endpointContext) =>
+ {
+ var assetContext = endpointContext as IAssetContext;
+ var asset = _itemDictionary.All
+ .FirstOrDefault(x => request.Uri.ToString().ToLower().Replace('/', '.').EndsWith(x.AssetContext.EndpointId.ToString()));
+
+ if (asset != null)
+ {
+ return asset.Instance.Process(request);
+ }
+
+ return new ResponseNotFound();
+ }
+ };
+
+ AddAsset += (sender, e) => endpointtRegistration.AddEndpoint?.Invoke(sender, e);
+ RemoveAsset += (sender, e) => endpointtRegistration.RemoveEndpoint?.Invoke(sender, e);
+
+ _componentHub.EndpointManager.Register(endpointtRegistration);
+
+ _httpServerContext = httpServerContext;
+
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate("webexpress.webcore:assetmanager.initialization")
+ );
+ }
+
+ ///
+ /// Discovers and binds resources to an application.
+ ///
+ /// The context of the plugin whose resources are to be associated.
+ private void Register(IPluginContext pluginContext)
+ {
+ if (_itemDictionary.ContainsPlugin(pluginContext))
+ {
+ return;
+ }
+
+ Register(pluginContext, _componentHub.ApplicationManager.GetApplications(pluginContext));
+ }
+
+ ///
+ /// Discovers and binds resources to an application.
+ ///
+ /// The context of the application whose resources are to be associated.
+ private void Register(IApplicationContext applicationContext)
+ {
+ foreach (var pluginContext in _componentHub.PluginManager.GetPlugins(applicationContext))
+ {
+ if (_itemDictionary.ContainsApplication(pluginContext, applicationContext))
+ {
+ continue;
+ }
+
+ Register(pluginContext, [applicationContext]);
+ }
+ }
+
+ ///
+ /// Registers resources for a given plugin and application context.
+ ///
+ /// The plugin context.
+ /// The application context (optional).
+ private void Register(IPluginContext pluginContext, IEnumerable applicationContexts)
+ {
+ var assembly = pluginContext?.Assembly;
+ var assemblName = assembly.GetName().Name;
+ var embeddedResources = assembly.GetManifestResourceNames();
+
+ foreach (var resource in embeddedResources)
+ {
+ if (resource.StartsWith(assemblName + ".Assets.", StringComparison.OrdinalIgnoreCase))
+ {
+ var id = resource[(assemblName.Length + 8)..];
+
+ // assign the asset to existing applications
+ foreach (var applicationContext in applicationContexts)
+ {
+ var prefix = applicationContext.ContextPath
+ .Concat(new UriPathSegmentConstant("assets"))
+ .Concat
+ (
+ applicationContext.PluginContext != pluginContext
+ ? pluginContext.PluginName.ToLower()
+ : ""
+ );
+
+ var assetContext = new AssetContext()
+ {
+ EndpointId = new ComponentId(id),
+ PluginContext = pluginContext,
+ ApplicationContext = applicationContext,
+ Route = prefix.Concat(new UriPathSegmentConstant($"{id}")),
+ IncludeSubPaths = false
+ };
+
+ var assetItem = new AssetItem(_componentHub.AssetManager)
+ {
+ AssetClass = typeof(Asset),
+ AssetContext = assetContext,
+ Instance = ComponentActivator.CreateInstance
+ (
+ typeof(Asset),
+ assetContext,
+ _httpServerContext,
+ _componentHub,
+ resource
+ )
+ };
+
+ if (_itemDictionary.AddAssetItem(pluginContext, applicationContext, assetItem))
+ {
+ OnAddAsset(assetContext);
+ _httpServerContext?.Log.Debug(
+ I18N.Translate(
+ "webexpress.webcore:assetmanager.addresource",
+ id,
+ applicationContext.ApplicationId
+ )
+ );
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Removes all resources associated with the specified plugin context.
+ ///
+ /// The context of the plugin that contains the resources to remove.
+ internal void Remove(IPluginContext pluginContext)
+ {
+ foreach (var assetContext in _itemDictionary.Remove(pluginContext))
+ {
+ OnRemoveAsset(assetContext);
+ }
+ }
+
+ ///
+ /// Removes all assets associated with the specified application context.
+ ///
+ /// The context of the application that contains the resources to remove.
+ internal void Remove(IApplicationContext applicationContext)
+ {
+ foreach (var assetContext in _itemDictionary.Remove(applicationContext))
+ {
+ OnRemoveAsset(assetContext);
+ }
+ }
+
+ ///
+ /// Returns an enumeration of all containing asset contexts of a plugin.
+ ///
+ /// A context of a plugin whose asset are to be registered.
+ /// An enumeration of asset contexts.
+ public IEnumerable GetAssets(IPluginContext pluginContext)
+ {
+ return _itemDictionary.GetAssets(pluginContext);
+ }
+
+ ///
+ /// Returns an enumeration of asset contextes.
+ ///
+ /// The context of the application.
+ /// An enumeration of asset contextes.
+ public IEnumerable GetAssets(IApplicationContext applicationContext)
+ {
+ return _itemDictionary.GetAssets(applicationContext);
+ }
+
+ ///
+ /// Raises the AddAsset event.
+ ///
+ /// The asset context.
+ private void OnAddAsset(IAssetContext assetContext)
+ {
+ AddAsset?.Invoke(this, assetContext);
+ }
+
+ ///
+ /// Raises the RemoveAsset event.
+ ///
+ /// The asset context.
+ private void OnRemoveAsset(IAssetContext assetContext)
+ {
+ RemoveAsset?.Invoke(this, assetContext);
+ }
+
+ ///
+ /// Raises the event when an plugin is added.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being added.
+ private void OnAddPlugin(object sender, IPluginContext e)
+ {
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when a plugin is removed.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being removed.
+ private void OnRemovePlugin(object sender, IPluginContext e)
+ {
+ Remove(e);
+ }
+
+ ///
+ /// Raises the event when an application is added.
+ ///
+ /// The source of the event.
+ /// The context of the application being added.
+ private void OnAddApplication(object sender, IApplicationContext e)
+ {
+ Register(e);
+
+ var assembly = typeof(AssetManager).Assembly;
+ var assemblyName = assembly.GetName().Name.ToLower();
+
+ var context = new AssetContext()
+ {
+ ApplicationContext = e,
+ PluginContext = new PluginContext()
+ {
+ PluginId = new ComponentId(assemblyName),
+ Assembly = assembly
+ },
+ EndpointId = new ComponentId(assemblyName + ".asset"),
+ IncludeSubPaths = true,
+ Route = RouteEndpoint.Combine(e.ContextPath, "assets")
+ };
+
+ var asset = ComponentActivator.CreateInstance(typeof(Asset), context, _httpServerContext, _componentHub);
+
+ _endpointDictionary.TryAdd(e, (context, asset));
+ }
+
+ ///
+ /// Raises the event when an application is removed.
+ ///
+ /// The source of the event.
+ /// The context of the application being removed.
+ private void OnRemoveApplication(object sender, IApplicationContext e)
+ {
+ Remove(e);
+
+ _endpointDictionary.Remove(e);
+ }
+
+ ///
+ /// Information about the component is collected and prepared for output in the log.
+ ///
+ private void Log()
+ {
+ //foreach (var resourcenItem in GetResorceItems(pluginContext))
+ //{
+ // output.Add
+ // (
+ // string.Empty.PadRight(deep) +
+ // I18N.Translate
+ // (
+ // "webexpress.webcore:resourcemanager.resource",
+ // resourcenItem?.ResourceContext?.EndpointId,
+ // string.Join(",", resourcenItem.ResourceContext?.ApplicationContext?.ApplicationId)
+ // )
+ // );
+ //}
+ }
+
+ ///
+ /// Release of unmanaged resources reserved during use.
+ ///
+ public void Dispose()
+ {
+ _componentHub.PluginManager.AddPlugin -= OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin -= OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication -= OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication -= OnRemoveApplication;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/IAsset.cs b/src/WebExpress.WebCore/WebAsset/IAsset.cs
new file mode 100644
index 0000000..78d8e5c
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/IAsset.cs
@@ -0,0 +1,18 @@
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// Defines the contract for a asset component.
+ ///
+ public interface IAsset : IEndpoint
+ {
+ ///
+ /// Processing of the resource.
+ ///
+ /// The request.
+ /// The response.
+ Response Process(Request request);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/IAssetContext.cs b/src/WebExpress.WebCore/WebAsset/IAssetContext.cs
new file mode 100644
index 0000000..93ec6a8
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/IAssetContext.cs
@@ -0,0 +1,12 @@
+using WebExpress.WebCore.WebEndpoint;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// Defines the context for a asset, providing access to various related contexts and properties.
+ ///
+ public interface IAssetContext : IEndpointContext
+ {
+
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/IAssetManager.cs b/src/WebExpress.WebCore/WebAsset/IAssetManager.cs
new file mode 100644
index 0000000..d97cca3
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/IAssetManager.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebAsset
+{
+ ///
+ /// The asset manager manages resources elements, which can be called with a URI (Uniform Resource Identifier).
+ ///
+ public interface IAssetManager : IComponentManager
+ {
+ ///
+ /// An event that fires when an asset is added.
+ ///
+ event EventHandler AddAsset;
+
+ ///
+ /// An event that fires when an asset is removed.
+ ///
+ event EventHandler RemoveAsset;
+
+ ///
+ /// Returns all asset contexts.
+ ///
+ IEnumerable Assets { get; }
+
+ ///
+ /// Returns an enumeration of all containing asset contexts of a plugin.
+ ///
+ /// A context of a plugin whose resources are to be registered.
+ /// An enumeration of resource contexts.
+ IEnumerable GetAssets(IPluginContext pluginContext);
+
+ ///
+ /// Returns an enumeration of asset contextes.
+ ///
+ /// The context of the application.
+ /// An enumeration of asset contextes.
+ IEnumerable GetAssets(IApplicationContext applicationContext);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/Model/AssetEndpointDictionary.cs b/src/WebExpress.WebCore/WebAsset/Model/AssetEndpointDictionary.cs
new file mode 100644
index 0000000..5e9f39c
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/Model/AssetEndpointDictionary.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+
+namespace WebExpress.WebCore.WebAsset.Model
+{
+ ///
+ /// Represents a dictionary that maps plugin contexts to application contexts and assets.
+ /// key = plugin context
+ /// value = { key = application context, value = asset }
+ ///
+ internal class AssetEndpointDictionary : Dictionary
+ {
+
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/Model/AssetItem.cs b/src/WebExpress.WebCore/WebAsset/Model/AssetItem.cs
new file mode 100644
index 0000000..b0a04dd
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/Model/AssetItem.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace WebExpress.WebCore.WebAsset.Model
+{
+ ///
+ /// A assat element that contains meta information about a asset.
+ ///
+ internal class AssetItem : IDisposable
+ {
+ private readonly IAssetManager _assetManager;
+
+ ///
+ /// Returns or sets the type of asset.
+ ///
+ public Type AssetClass { get; set; }
+
+ ///
+ /// Returns or sets the instance of the asset, if the asset is cached, otherwise null.
+ ///
+ public IAsset Instance { get; set; }
+
+ ///
+ /// Returns the asset context.
+ ///
+ public IAssetContext AssetContext { get; internal set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The asset manager.
+ internal AssetItem(IAssetManager assetManager)
+ {
+ _assetManager = assetManager;
+ }
+
+ ///
+ /// Performs application-specific tasks related to sharing, returning, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+
+ }
+
+ ///
+ /// Convert the asset element to a string.
+ ///
+ /// The asset element in its string representation.
+ public override string ToString()
+ {
+ return $"Asset: '{AssetContext?.EndpointId}'";
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAsset/Model/AssetItemDictionary.cs b/src/WebExpress.WebCore/WebAsset/Model/AssetItemDictionary.cs
new file mode 100644
index 0000000..4924daa
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAsset/Model/AssetItemDictionary.cs
@@ -0,0 +1,203 @@
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebAsset.Model
+{
+ ///
+ /// Represents a dictionary that maps plugin contexts to application contexts and asset items.
+ /// key = plugin context
+ /// value = { key = resource type, value = ressource item }
+ ///
+ internal class AssetItemDictionary
+ {
+ private readonly Dictionary>> _dictionary = [];
+
+ ///
+ /// Returns all asset items.
+ ///
+ public IEnumerable All => _dictionary.Values
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x);
+
+ ///
+ /// Adds a asset item to the dictionary.
+ ///
+ /// The plugin context.
+ /// The application context.
+ /// The resource item.
+ /// True if the resource item was added successfully, false if an element with the same status code already exists.
+ public bool AddAssetItem(IPluginContext pluginContext, IApplicationContext applicationContext, AssetItem assetItem)
+ {
+ var type = assetItem.AssetClass;
+
+ if (!typeof(IAsset).IsAssignableFrom(type))
+ {
+ return false;
+ }
+
+ if (!_dictionary.ContainsKey(pluginContext))
+ {
+ _dictionary[pluginContext] = [];
+ }
+
+ var appContextDict = _dictionary[pluginContext];
+
+ if (!appContextDict.TryGetValue(applicationContext, out List value))
+ {
+ value = ([]);
+ appContextDict[applicationContext] = value;
+ }
+
+ var assetList = value;
+
+ assetList.RemoveAll(x => x.AssetContext?.EndpointId == assetItem.AssetContext.EndpointId);
+ assetList.Add(assetItem);
+
+ return true;
+ }
+
+ ///
+ /// Removes all resources associated with the specified plugin context.
+ ///
+ /// The context of the plugin that contains the resources to remove.
+ /// An enumeration of asset contexts that were removed.
+ public IEnumerable Remove(IPluginContext pluginContext)
+ {
+ if (pluginContext == null)
+ {
+ return [];
+ }
+
+ // the plugin has not been registered in the manager
+ if (_dictionary.TryGetValue(pluginContext, out var value))
+ {
+ var items = value.Values
+ .SelectMany(x => x)
+ .ToList();
+
+ foreach (var assetItem in items)
+ {
+ assetItem.Dispose();
+ }
+
+ _dictionary.Remove(pluginContext);
+
+ return items.Select(x => x.AssetContext);
+ }
+
+ return [];
+ }
+
+ ///
+ /// Removes all assets associated with the specified application context.
+ ///
+ /// The context of the application that contains the resources to remove.
+ /// An enumeration of asset contexts that were removed.
+ internal IEnumerable Remove(IApplicationContext applicationContext)
+ {
+ if (applicationContext == null)
+ {
+ return [];
+ }
+
+ var removedAssets = new List();
+
+ foreach (var pluginDict in _dictionary.Values)
+ {
+ foreach (var assetList in pluginDict.Where(x => x.Key == applicationContext).Select(x => x.Value))
+ {
+ foreach (var assetItem in assetList)
+ {
+ removedAssets.Add(assetItem.AssetContext);
+ assetItem.Dispose();
+ }
+ }
+
+ pluginDict.Remove(applicationContext);
+ }
+
+ return removedAssets;
+ }
+
+ ///
+ /// Checks if the dictionary contains the specified plugin context.
+ ///
+ /// The plugin context to check.
+ /// True if the plugin context exists in the dictionary, otherwise false.
+ public bool ContainsPlugin(IPluginContext pluginContext)
+ {
+ return _dictionary.ContainsKey(pluginContext);
+ }
+
+ ///
+ /// Checks if the dictionary contains the specified application context.
+ ///
+ /// The plugin context to check.
+ /// The application context to check.
+ /// True if the application context exists in the dictionary, otherwise false.
+ public bool ContainsApplication(IPluginContext pluginContext, IApplicationContext applicationContext)
+ {
+ if (_dictionary.TryGetValue(pluginContext, out var appDict) && appDict.ContainsKey(applicationContext))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns the asset items from the dictionary.
+ ///
+ /// The application context.
+ /// An IEnumerable of asset items
+ public IEnumerable GetAssetItems(IApplicationContext applicationContext)
+ {
+ if (_dictionary.ContainsKey(applicationContext?.PluginContext))
+ {
+ var appContextDict = _dictionary[applicationContext?.PluginContext];
+
+ if (appContextDict.TryGetValue(applicationContext, out List value))
+ {
+ var assetList = value;
+
+ return assetList;
+ }
+ }
+
+ return [];
+ }
+
+ ///
+ /// Returns an enumeration of all containing asset contexts of a plugin.
+ ///
+ /// A context of a plugin whose asset are to be registered.
+ /// An enumeration of asset contexts.
+ public IEnumerable GetAssets(IPluginContext pluginContext)
+ {
+ if (_dictionary.TryGetValue(pluginContext, out var pluginResources))
+ {
+ return pluginResources
+ .SelectMany(x => x.Value)
+ .Select(x => x.AssetContext);
+ }
+
+ return [];
+ }
+
+ ///
+ /// Returns an enumeration of asset contextes.
+ ///
+ /// The context of the application.
+ /// An enumeration of asset contextes.
+ public IEnumerable GetAssets(IApplicationContext applicationContext)
+ {
+ return _dictionary.Values
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x)
+ .Where(x => x.AssetContext.ApplicationContext.Equals(applicationContext))
+ .Select(x => x.AssetContext);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ApplicationAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ApplicationAttribute.cs
index 836a363..adb5ee8 100644
--- a/src/WebExpress.WebCore/WebAttribute/ApplicationAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/ApplicationAttribute.cs
@@ -3,28 +3,12 @@
namespace WebExpress.WebCore.WebAttribute
{
- ///
- /// Application assignment attribute of the application ID.
- ///
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class ApplicationAttribute : Attribute, IModuleAttribute
- {
- ///
- /// Constructor
- ///
- /// A specific ApplicationId, regular expression, or * for any application.
- public ApplicationAttribute(string applicationId)
- {
-
- }
- }
-
///
/// An application expression attribute, which is determined by the type.
///
- /// The type of the application.
+ /// The type of the application.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class ApplicationAttribute : Attribute, IModuleAttribute where T : class, IApplication
+ public class ApplicationAttribute : Attribute, IPluginAttribute where TApplication : class, IApplication
{
}
diff --git a/src/WebExpress.WebCore/WebAttribute/AssetPathAttribute.cs b/src/WebExpress.WebCore/WebAttribute/AssetPathAttribute.cs
index b535463..188e32f 100644
--- a/src/WebExpress.WebCore/WebAttribute/AssetPathAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/AssetPathAttribute.cs
@@ -1,9 +1,16 @@
-namespace WebExpress.WebCore.WebAttribute
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
{
- public class AssetPathAttribute : System.Attribute, IApplicationAttribute, IModuleAttribute
+
+ ///
+ /// Attribute to specify the path for assets in the application.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class AssetPathAttribute : Attribute, IApplicationAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The path for assets.
public AssetPathAttribute(string assetPath)
diff --git a/src/WebExpress.WebCore/WebAttribute/CacheAttribute.cs b/src/WebExpress.WebCore/WebAttribute/CacheAttribute.cs
index 968e73c..e90b6ab 100644
--- a/src/WebExpress.WebCore/WebAttribute/CacheAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/CacheAttribute.cs
@@ -5,11 +5,11 @@ namespace WebExpress.WebCore.WebAttribute
///
/// Indicates that a page or component can be reused
///
- [AttributeUsage(AttributeTargets.Class)]
- public class CacheAttribute : System.Attribute, IResourceAttribute
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class CacheAttribute : Attribute, IEndpointAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public CacheAttribute()
{
diff --git a/src/WebExpress.WebCore/WebAttribute/ConditionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ConditionAttribute.cs
index 4b32bb1..245d8ae 100644
--- a/src/WebExpress.WebCore/WebAttribute/ConditionAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/ConditionAttribute.cs
@@ -6,11 +6,11 @@ namespace WebExpress.WebCore.WebAttribute
///
/// Activation of options (e.g. WebEx.WebApp.Setting.SystemInformation for displaying system information).
///
- [AttributeUsage(AttributeTargets.Class)]
- public class ConditionAttribute : Attribute, IResourceAttribute where T : class, ICondition
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class ConditionAttribute : Attribute, IEndpointAttribute where T : class, ICondition
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public ConditionAttribute()
{
diff --git a/src/WebExpress.WebCore/WebAttribute/ContextPathAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ContextPathAttribute.cs
index 0fa43f5..d8554f2 100644
--- a/src/WebExpress.WebCore/WebAttribute/ContextPathAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/ContextPathAttribute.cs
@@ -2,11 +2,14 @@
namespace WebExpress.WebCore.WebAttribute
{
+ ///
+ /// Attribute to define the context path for an application or endpoint.
+ ///
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
- public class ContextPathAttribute : Attribute, IApplicationAttribute, IModuleAttribute, IResourceAttribute
+ public class ContextPathAttribute : Attribute, IApplicationAttribute, IEndpointAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The context path.
public ContextPathAttribute(string contetxPath)
diff --git a/src/WebExpress.WebCore/WebAttribute/DataPathAttribute.cs b/src/WebExpress.WebCore/WebAttribute/DataPathAttribute.cs
index 5cfe84c..40b5754 100644
--- a/src/WebExpress.WebCore/WebAttribute/DataPathAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/DataPathAttribute.cs
@@ -1,9 +1,15 @@
-namespace WebExpress.WebCore.WebAttribute
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
{
- public class DataPathAttribute : System.Attribute, IApplicationAttribute, IModuleAttribute
+ ///
+ /// Attribute to specify the data path for an application.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class DataPathAttribute : System.Attribute, IApplicationAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The path for the data.
public DataPathAttribute(string dataPath)
diff --git a/src/WebExpress.WebCore/WebAttribute/DefaultAttribute.cs b/src/WebExpress.WebCore/WebAttribute/DefaultAttribute.cs
index 7b45a50..d7fa97f 100644
--- a/src/WebExpress.WebCore/WebAttribute/DefaultAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/DefaultAttribute.cs
@@ -5,11 +5,11 @@ namespace WebExpress.WebCore.WebAttribute
///
/// Indicates that a status page ist default
///
- [AttributeUsage(AttributeTargets.Class)]
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DefaultAttribute : Attribute, IStatusPageAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public DefaultAttribute()
{
diff --git a/src/WebExpress.WebCore/WebAttribute/DependencyAttribute.cs b/src/WebExpress.WebCore/WebAttribute/DependencyAttribute.cs
index d1519d9..1668cc2 100644
--- a/src/WebExpress.WebCore/WebAttribute/DependencyAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/DependencyAttribute.cs
@@ -6,10 +6,10 @@ namespace WebExpress.WebCore.WebAttribute
/// Marks a plugin as dependent on another plugin.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class DependencyAttribute : System.Attribute, IPluginAttribute
+ public class DependencyAttribute : Attribute, IPluginAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The Id of the plugin to which there is a dependency.
public DependencyAttribute(string dependency)
diff --git a/src/WebExpress.WebCore/WebAttribute/DescriptionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/DescriptionAttribute.cs
index 414e31e..750f2a4 100644
--- a/src/WebExpress.WebCore/WebAttribute/DescriptionAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/DescriptionAttribute.cs
@@ -1,9 +1,16 @@
-namespace WebExpress.WebCore.WebAttribute
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
{
- public class DescriptionAttribute : System.Attribute, IPluginAttribute, IApplicationAttribute, IModuleAttribute
+ ///
+ /// Attribute to provide a description for a class.
+ /// Implements , , and .
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class DescriptionAttribute : Attribute, IPluginAttribute, IApplicationAttribute, ISettingCategoryAttribute, ISettingGroupAttribute, IThemeAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The description.
public DescriptionAttribute(string description)
diff --git a/src/WebExpress.WebCore/WebAttribute/EventAttribute.cs b/src/WebExpress.WebCore/WebAttribute/EventAttribute.cs
new file mode 100644
index 0000000..0e7991a
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/EventAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+using WebExpress.WebCore.WebEvent;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Specifying a event.
+ ///
+ /// The type of the event.
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class EventAttribute : Attribute, IEventAttribute where T : class, IEvent
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EventAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IResourceAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IEndpointAttribute.cs
similarity index 79%
rename from src/WebExpress.WebCore/WebAttribute/IResourceAttribute.cs
rename to src/WebExpress.WebCore/WebAttribute/IEndpointAttribute.cs
index e845ac5..7ce2128 100644
--- a/src/WebExpress.WebCore/WebAttribute/IResourceAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/IEndpointAttribute.cs
@@ -3,7 +3,7 @@
///
/// Interface of a resource assignment attribute.
///
- public interface IResourceAttribute
+ public interface IEndpointAttribute
{
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/IModuleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IEventAttribute.cs
similarity index 52%
rename from src/WebExpress.WebCore/WebAttribute/IModuleAttribute.cs
rename to src/WebExpress.WebCore/WebAttribute/IEventAttribute.cs
index 4ecba85..451ca33 100644
--- a/src/WebExpress.WebCore/WebAttribute/IModuleAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/IEventAttribute.cs
@@ -1,9 +1,9 @@
namespace WebExpress.WebCore.WebAttribute
{
///
- /// Interface of a module assignment attribute.
+ /// Interface of a event assignment attribute.
///
- public interface IModuleAttribute
+ public interface IEventAttribute
{
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/IFragmentAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IFragmentAttribute.cs
new file mode 100644
index 0000000..b8f1860
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IFragmentAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Marks a class as a fragment component.
+ ///
+ public interface IFragmentAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IPageAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IPageAttribute.cs
new file mode 100644
index 0000000..57ef491
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IPageAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a page assignment attribute.
+ ///
+ public interface IPageAttribute : IEndpointAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IPermissionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IPermissionAttribute.cs
new file mode 100644
index 0000000..6dc2788
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IPermissionAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a permission assignment attribute.
+ ///
+ public interface IPermissionAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IRestApiAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IRestApiAttribute.cs
new file mode 100644
index 0000000..976ecab
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IRestApiAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a rest api assignment attribute.
+ ///
+ public interface IRestApiAttribute : IEndpointAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IRoleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IRoleAttribute.cs
new file mode 100644
index 0000000..f868701
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IRoleAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a role assignment attribute.
+ ///
+ public interface IRoleAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ISegmentAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ISegmentAttribute.cs
index 9022a55..10ac119 100644
--- a/src/WebExpress.WebCore/WebAttribute/ISegmentAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/ISegmentAttribute.cs
@@ -2,6 +2,9 @@
namespace WebExpress.WebCore.WebAttribute
{
+ ///
+ /// Interface for converting an object to a URI path segment.
+ ///
public interface ISegmentAttribute
{
///
diff --git a/src/WebExpress.WebCore/WebAttribute/ISettingCategoryAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ISettingCategoryAttribute.cs
new file mode 100644
index 0000000..618eb8c
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ISettingCategoryAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a setting category assignment attribute.
+ ///
+ public interface ISettingCategoryAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ISettingGroupAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ISettingGroupAttribute.cs
new file mode 100644
index 0000000..695cd6f
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ISettingGroupAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a setting group assignment attribute.
+ ///
+ public interface ISettingGroupAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ISettingPageAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ISettingPageAttribute.cs
new file mode 100644
index 0000000..2ad2955
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ISettingPageAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a setting page assignment attribute.
+ ///
+ public interface ISettingPageAttribute : IEndpointAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IThemeAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IThemeAttribute.cs
new file mode 100644
index 0000000..f34e542
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IThemeAttribute.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Interface of a theme assignment attribute.
+ ///
+ public interface IThemeAttribute
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IconAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IconAttribute.cs
index 6257c6f..7f8643f 100644
--- a/src/WebExpress.WebCore/WebAttribute/IconAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/IconAttribute.cs
@@ -1,9 +1,15 @@
-namespace WebExpress.WebCore.WebAttribute
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
{
- public class IconAttribute : System.Attribute, IPluginAttribute, IApplicationAttribute, IModuleAttribute
+ ///
+ /// Attribute to specify an icon for a plugin, application, or status page.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class IconAttribute : Attribute, IPluginAttribute, IApplicationAttribute, IStatusPageAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The icon.
public IconAttribute(string icon)
diff --git a/src/WebExpress.WebCore/WebAttribute/IdAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IdAttribute.cs
new file mode 100644
index 0000000..2a0cb44
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/IdAttribute.cs
@@ -0,0 +1,18 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// The unique identification key.
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Class)]
+ public class IdAttribute : System.Attribute, IPluginAttribute, IApplicationAttribute, IEndpointAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The id.
+ public IdAttribute(string id)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ImageAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ImageAttribute.cs
new file mode 100644
index 0000000..0ed9d7a
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ImageAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to specify an image for a theme.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class ImageAttribute : Attribute, IThemeAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The image.
+ public ImageAttribute(string image)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/IncludeSubPathsAttribute.cs b/src/WebExpress.WebCore/WebAttribute/IncludeSubPathsAttribute.cs
index 6e596ec..f14ea97 100644
--- a/src/WebExpress.WebCore/WebAttribute/IncludeSubPathsAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/IncludeSubPathsAttribute.cs
@@ -3,10 +3,10 @@
///
/// Determines whether all resources below the specified path (including segment) are also processed.
///
- public class IncludeSubPathsAttribute : System.Attribute, IResourceAttribute
+ public class IncludeSubPathsAttribute : System.Attribute, IEndpointAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// All subpaths are included.
public IncludeSubPathsAttribute(bool includeSubPaths)
diff --git a/src/WebExpress.WebCore/WebAttribute/JobAttribute.cs b/src/WebExpress.WebCore/WebAttribute/JobAttribute.cs
index a1c431e..e6fbe3e 100644
--- a/src/WebExpress.WebCore/WebAttribute/JobAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/JobAttribute.cs
@@ -1,9 +1,13 @@
namespace WebExpress.WebCore.WebAttribute
{
+ ///
+ /// Represents an attribute to schedule jobs based on specified time intervals.
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Class)]
public class JobAttribute : System.Attribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The minute 0-59 or * for any. Comma-separated values or ranges (-) are also possible.
/// The hour 0-23 or * for arbitrary. Comma-separated values or ranges (-) are also possible.
diff --git a/src/WebExpress.WebCore/WebAttribute/MethodAttribute.cs b/src/WebExpress.WebCore/WebAttribute/MethodAttribute.cs
new file mode 100644
index 0000000..c78a190
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/MethodAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using WebExpress.WebCore.WebRestApi;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// The range in which the attribute is valid.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class MethodAttribute : Attribute, IEndpointAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MethodAttribute(CrudMethod crudMethod)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ModuleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ModuleAttribute.cs
deleted file mode 100644
index 6face4f..0000000
--- a/src/WebExpress.WebCore/WebAttribute/ModuleAttribute.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using WebExpress.WebCore.WebModule;
-
-namespace WebExpress.WebCore.WebAttribute
-{
- ///
- /// Specifying a module.
- ///
- /// The type of the module.
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class ModuleAttribute : Attribute, IResourceAttribute, IModuleAttribute where T : class, IModule
- {
- ///
- /// Constructor
- ///
- public ModuleAttribute()
- {
-
- }
- }
-}
diff --git a/src/WebExpress.WebCore/WebAttribute/NameAttribute.cs b/src/WebExpress.WebCore/WebAttribute/NameAttribute.cs
index 03e02a6..e9d30b4 100644
--- a/src/WebExpress.WebCore/WebAttribute/NameAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/NameAttribute.cs
@@ -1,11 +1,18 @@
-namespace WebExpress.WebCore.WebAttribute
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
{
- public class NameAttribute : System.Attribute, IPluginAttribute, IApplicationAttribute, IModuleAttribute
+ ///
+ /// Attribute to assign a name to a class.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class NameAttribute : Attribute, IPluginAttribute, IApplicationAttribute, ISettingCategoryAttribute, ISettingGroupAttribute, IThemeAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The name.
+
public NameAttribute(string name)
{
diff --git a/src/WebExpress.WebCore/WebAttribute/OptionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/OptionAttribute.cs
deleted file mode 100644
index 5fa300f..0000000
--- a/src/WebExpress.WebCore/WebAttribute/OptionAttribute.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using WebExpress.WebCore.WebModule;
-using WebExpress.WebCore.WebResource;
-
-namespace WebExpress.WebCore.WebAttribute
-{
- ///
- /// Activation of options (e.g. 'webexpress.webapp.settinglog' or 'webexpress.webapp.*').
- ///
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class OptionAttribute : Attribute, IApplicationAttribute
- {
- ///
- /// Constructor
- ///
- /// The option to activate.
- public OptionAttribute(string option)
- {
-
- }
- }
-
- ///
- /// Activation of options (e.g. 'webexpress.webapp.settinglog' or 'webexpress.webapp.*').
- ///
- /// The module or resource class.
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class WebExOptionAttribute : Attribute, IApplicationAttribute where M : class, IModule
- {
-
- }
-
- ///
- /// Activation of options (e.g. 'webexpress.webapp.settinglog' or 'webexpress.webapp.*').
- /// The module or resource class.
- /// The resource or resource class.
- ///
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
- public class WebExOptionAttribute : Attribute, IApplicationAttribute where M : class, IModule where R : class, IResource
- {
- }
-}
diff --git a/src/WebExpress.WebCore/WebAttribute/OptionalAttribute.cs b/src/WebExpress.WebCore/WebAttribute/OptionalAttribute.cs
deleted file mode 100644
index 792b663..0000000
--- a/src/WebExpress.WebCore/WebAttribute/OptionalAttribute.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-
-namespace WebExpress.WebCore.WebAttribute
-{
- ///
- /// Marks a ressorce as optional. This becomes active when the option is specified in the application.
- ///
- [AttributeUsage(AttributeTargets.Class)]
- public class OptionalAttribute : Attribute, IResourceAttribute
- {
- ///
- /// Constructor
- ///
- public OptionalAttribute()
- {
-
- }
- }
-}
diff --git a/src/WebExpress.WebCore/WebAttribute/OrderAttribute.cs b/src/WebExpress.WebCore/WebAttribute/OrderAttribute.cs
new file mode 100644
index 0000000..2a548c8
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/OrderAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute used to identify a class as a plugin component.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class OrderAttribute : System.Attribute, IFragmentAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The order within the section.
+ public OrderAttribute(int order)
+ {
+ }
+
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ParentAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ParentAttribute.cs
deleted file mode 100644
index ae0a043..0000000
--- a/src/WebExpress.WebCore/WebAttribute/ParentAttribute.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using WebExpress.WebCore.WebResource;
-
-namespace WebExpress.WebCore.WebAttribute
-{
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class ParentAttribute : Attribute, IResourceAttribute where T : class, IResource
- {
- ///
- /// Constructor
- ///
- public ParentAttribute()
- {
-
- }
- }
-}
diff --git a/src/WebExpress.WebCore/WebAttribute/PermissionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/PermissionAttribute.cs
new file mode 100644
index 0000000..704de81
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/PermissionAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using WebExpress.WebCore.WebIdentity;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Connects roles with permissions.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class PermissionAttribute : Attribute, IPermissionAttribute where T : class, IIdentityPermission
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PermissionAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/RoleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/RoleAttribute.cs
new file mode 100644
index 0000000..8970557
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/RoleAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using WebExpress.WebCore.WebIdentity;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Connects roles with permissions.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class RoleAttribute : Attribute, IRoleAttribute where T : class, IIdentityRole
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RoleAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ScopeAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ScopeAttribute.cs
index fdb024e..a2dd838 100644
--- a/src/WebExpress.WebCore/WebAttribute/ScopeAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/ScopeAttribute.cs
@@ -6,11 +6,11 @@ namespace WebExpress.WebCore.WebAttribute
///
/// The range in which the component is valid.
///
- [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
- public class ScopeAttribute : Attribute, IResourceAttribute where T : class, IScope
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class ScopeAttribute : Attribute, IPageAttribute, ISettingPageAttribute where T : class, IScope
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public ScopeAttribute()
{
diff --git a/src/WebExpress.WebCore/WebAttribute/SectionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SectionAttribute.cs
new file mode 100644
index 0000000..5445fd6
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/SectionAttribute.cs
@@ -0,0 +1,19 @@
+using System;
+using WebExpress.WebCore.WebSection;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to identify a section.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class SectionAttribute : Attribute, IFragmentAttribute, ISettingCategoryAttribute, ISettingGroupAttribute where T : class, ISection
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SectionAttribute()
+ {
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentAttribute.cs
index 8c7954d..6c4884d 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentAttribute.cs
@@ -7,7 +7,7 @@ namespace WebExpress.WebCore.WebAttribute
/// A static path segment.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class SegmentAttribute : Attribute, IResourceAttribute, ISegmentAttribute
+ public class SegmentAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
{
///
/// Returns or set the segment of the uri path.
@@ -20,7 +20,7 @@ public class SegmentAttribute : Attribute, IResourceAttribute, ISegmentAttribute
private string Display { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The segment of the uri path.
/// The display string.
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentDoubleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentDoubleAttribute.cs
index 96d700f..1c2a208 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentDoubleAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentDoubleAttribute.cs
@@ -3,7 +3,11 @@
namespace WebExpress.WebCore.WebAttribute
{
- public class SegmentDoubleAttribute : Attribute, IResourceAttribute, ISegmentAttribute
+ ///
+ /// Attribute to define a double segment in a URI path.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class SegmentDoubleAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
{
///
/// Returns or sets the name of the variable.
@@ -16,7 +20,7 @@ public class SegmentDoubleAttribute : Attribute, IResourceAttribute, ISegmentAtt
private string Display { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The name of the variable.
/// The display string.
@@ -32,18 +36,6 @@ public SegmentDoubleAttribute(string variableName, string display)
/// The path segment.
public IUriPathSegment ToPathSegment()
{
- //var expression = @"^[+-]?(\d*,\d+|\d+(,\d*)?)( +[eE][+-]?\d+)?$";
-
- //var callBackDisplay = new Func((segment, moduleId, culture) =>
- //{
- // return null;
- //});
-
- //var callBackValiables = new Func>(segment =>
- //{
- // return null;
- //});
-
return new UriPathSegmentVariableDouble(VariableName, Display);
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentGuidAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentGuidAttribute.cs
index 47538bd..57d1d7d 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentGuidAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentGuidAttribute.cs
@@ -8,7 +8,8 @@ namespace WebExpress.WebCore.WebAttribute
/// A dynamic path segment of type guid.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class SegmentGuidAttribute : Attribute, IResourceAttribute, ISegmentAttribute where T : Parameter
+ public class SegmentGuidAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
+ where TParameter : Parameter
{
///
/// Returns or sets the name of the variable.
@@ -26,14 +27,13 @@ public class SegmentGuidAttribute : Attribute, IResourceAttribute, ISegmentAt
private UriPathSegmentVariableGuid.Format DisplayFormat { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
- /// The type of the variable.
/// The display string.
/// The display format.
public SegmentGuidAttribute(string display, UriPathSegmentVariableGuid.Format displayFormat = UriPathSegmentVariableGuid.Format.Simple)
{
- VariableName = (Activator.CreateInstance(typeof(T)) as Parameter)?.Key?.ToLower();
+ VariableName = (Activator.CreateInstance() as Parameter)?.Key?.ToLower();
Display = display;
DisplayFormat = displayFormat;
}
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentIntAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentIntAttribute.cs
index 542535f..ed888a2 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentIntAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentIntAttribute.cs
@@ -3,7 +3,11 @@
namespace WebExpress.WebCore.WebAttribute
{
- public class SegmentIntAttribute : Attribute, IResourceAttribute, ISegmentAttribute
+ ///
+ /// Attribute to define an integer segment in a URI path.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class SegmentIntAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
{
///
/// Returns or sets the name of the variable.
@@ -16,7 +20,7 @@ public class SegmentIntAttribute : Attribute, IResourceAttribute, ISegmentAttrib
private string Display { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The name of the variable.
/// The display string.
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs
index 2d7c5a2..d125473 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs
@@ -3,7 +3,11 @@
namespace WebExpress.WebCore.WebAttribute
{
- public class SegmentStringAttribute : Attribute, IResourceAttribute, ISegmentAttribute
+ ///
+ /// Attribute to define a segment string in a URI path.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class SegmentStringAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
{
///
/// Returns or sets the name of the variable.
@@ -16,7 +20,7 @@ public class SegmentStringAttribute : Attribute, IResourceAttribute, ISegmentAtt
private string Display { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The name of the variable.
/// The display string.
@@ -32,18 +36,6 @@ public SegmentStringAttribute(string variableName, string display)
/// The path segment.
public IUriPathSegment ToPathSegment()
{
- //var expression = "^[^\"]*$";
-
- //var callBackDisplay = new Func((segment, moduleId, culture) =>
- //{
- // return null;
- //});
-
- //var callBackValiables = new Func>(segment =>
- //{
- // return null;
- //});
-
return new UriPathSegmentVariableString(VariableName, Display);
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs
index 408e1dc..fc6b841 100644
--- a/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs
@@ -3,7 +3,14 @@
namespace WebExpress.WebCore.WebAttribute
{
- public class SegmentUIntAttribute : Attribute, IResourceAttribute, ISegmentAttribute
+ ///
+ /// Attribute to define a segment with an unsigned integer variable in the URI path.
+ ///
+ ///
+ /// This attribute is used to specify a segment in the URI path that contains an unsigned integer variable.
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class SegmentUIntAttribute : Attribute, IEndpointAttribute, ISegmentAttribute
{
///
/// Returns or sets the name of the variable.
@@ -16,7 +23,7 @@ public class SegmentUIntAttribute : Attribute, IResourceAttribute, ISegmentAttri
private string Display { get; set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The name of the variable.
/// The display string.
@@ -32,23 +39,6 @@ public SegmentUIntAttribute(string variableName, string display)
/// The path segment.
public IUriPathSegment ToPathSegment()
{
- //var expression = @"^\d$";
-
- //var callBackDisplay = new Func((segment, moduleId, culture) =>
- //{
- // return Display;
- //});
-
- //var callBackValiables = new Func>(segment =>
- //{
- // var dict = new Dictionary
- // {
- // { VariableName, segment }
- // };
-
- // return dict;
- //});
-
return new UriPathSegmentVariableUInt(VariableName, Display);
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/SettingCategoryAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SettingCategoryAttribute.cs
new file mode 100644
index 0000000..ee798b9
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/SettingCategoryAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using WebExpress.WebCore.WebSettingPage;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to specify the category in which the settings page is associated.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class SettingCategoryAttribute : Attribute, ISettingGroupAttribute
+ where TCategory : class, ISettingCategory
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SettingCategoryAttribute()
+ {
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/SettingGroupAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SettingGroupAttribute.cs
new file mode 100644
index 0000000..5da22f1
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/SettingGroupAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+using WebExpress.WebCore.WebSettingPage;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to define a setting group in which the settings page is associated.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class SettingGroupAttribute : Attribute, IEndpointAttribute
+ where TGroup : class, ISettingGroup
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SettingGroupAttribute()
+ {
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/SettingHideAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SettingHideAttribute.cs
new file mode 100644
index 0000000..837fa1c
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/SettingHideAttribute.cs
@@ -0,0 +1,16 @@
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Represents an attribute that hides a setting in the web UI.
+ ///
+ public class SettingHideAttribute : System.Attribute, IEndpointAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SettingHideAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/SettingSectionAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SettingSectionAttribute.cs
new file mode 100644
index 0000000..7fc68fb
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/SettingSectionAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+using WebExpress.WebCore.WebSettingPage;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to specify the section where the settings page is listed.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class SettingSectionAttribute : Attribute, IEndpointAttribute, ISettingCategoryAttribute, ISettingGroupAttribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The section where the settings page is listed.
+ public SettingSectionAttribute(SettingSection section)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/StatusCodeAttribute.cs b/src/WebExpress.WebCore/WebAttribute/StatusCodeAttribute.cs
index 0543993..44e838b 100644
--- a/src/WebExpress.WebCore/WebAttribute/StatusCodeAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/StatusCodeAttribute.cs
@@ -1,17 +1,23 @@
-using System;
-
-namespace WebExpress.WebCore.WebAttribute
+namespace WebExpress.WebCore.WebAttribute
{
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
- public class StatusCodeAttribute : System.Attribute, IApplicationAttribute
+ ///
+ /// Specifies the status code for an HTTP response (see RFC 7231).
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]
+ public class StatusCodeAttribute : System.Attribute
{
///
- /// Constructor
+ /// Gets the status code.
///
- /// The status code.
- public StatusCodeAttribute(int status)
- {
+ public int StatusCode { get; }
+ ///
+ /// Initializes a new instance of the class with the specified status code.
+ ///
+ /// The status code.
+ public StatusCodeAttribute(int code)
+ {
+ StatusCode = code;
}
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/StatusResponseAttribute.cs b/src/WebExpress.WebCore/WebAttribute/StatusResponseAttribute.cs
new file mode 100644
index 0000000..27220cb
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/StatusResponseAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Specifies the status code for a starus page.
+ ///
+ /// The type of the response.
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class StatusResponseAttribute : Attribute, IStatusPageAttribute
+ where TResponse : Response, new()
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StatusResponseAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/SystemPluginAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SystemPluginAttribute.cs
index 4efd157..1962657 100644
--- a/src/WebExpress.WebCore/WebAttribute/SystemPluginAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/SystemPluginAttribute.cs
@@ -9,7 +9,7 @@ namespace WebExpress.WebCore.WebAttribute
public class SystemPluginAttribute : Attribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
public SystemPluginAttribute()
{
diff --git a/src/WebExpress.WebCore/WebAttribute/ThemeModeAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ThemeModeAttribute.cs
new file mode 100644
index 0000000..8baa04c
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ThemeModeAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+using WebExpress.WebCore.WebTheme;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to specify the theme mode.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class ThemeModeAttribute : Attribute, IThemeAttribute
+ {
+ ///
+ /// Initializes a new instance of the class with the specified theme mode.
+ ///
+ /// The theme mode to be applied.
+ public ThemeModeAttribute(ThemeMode mode)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/ThemeStyleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/ThemeStyleAttribute.cs
new file mode 100644
index 0000000..1235cb6
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/ThemeStyleAttribute.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Specifies the style for a theme.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class ThemeStyleAttribute : Attribute, IThemeAttribute
+ {
+ ///
+ /// Initializes a new instance of the class with the specified URI.
+ ///
+ /// The URI of the css theme style.
+ public ThemeStyleAttribute(string uri)
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebAttribute/TitleAttribute.cs b/src/WebExpress.WebCore/WebAttribute/TitleAttribute.cs
index 6fa9aeb..0fdf584 100644
--- a/src/WebExpress.WebCore/WebAttribute/TitleAttribute.cs
+++ b/src/WebExpress.WebCore/WebAttribute/TitleAttribute.cs
@@ -1,14 +1,17 @@
namespace WebExpress.WebCore.WebAttribute
{
- public class TitleAttribute : System.Attribute, IResourceAttribute
+ ///
+ /// Represents an attribute that assigns a title to a page, setting page, or status page.
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Class)]
+ public class TitleAttribute : System.Attribute, IPageAttribute, ISettingPageAttribute, IStatusPageAttribute
{
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
/// The display text.
public TitleAttribute(string display)
{
-
}
}
}
diff --git a/src/WebExpress.WebCore/WebAttribute/WebIconAttribute.cs b/src/WebExpress.WebCore/WebAttribute/WebIconAttribute.cs
new file mode 100644
index 0000000..a110a65
--- /dev/null
+++ b/src/WebExpress.WebCore/WebAttribute/WebIconAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using WebExpress.WebCore.WebIcon;
+
+namespace WebExpress.WebCore.WebAttribute
+{
+ ///
+ /// Attribute to specify an icon for a plugin, application, or status page.
+ ///
+ /// The type of the icon, which must implement the interface.
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class WebIconAttribute : Attribute, ISettingPageAttribute, ISettingCategoryAttribute, ISettingGroupAttribute
+ where TIcon : IIcon
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WebIconAttribute()
+ {
+
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentActivator.cs b/src/WebExpress.WebCore/WebComponent/ComponentActivator.cs
new file mode 100644
index 0000000..ed44dfd
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/ComponentActivator.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebStatusPage;
+
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Provides methods to create instances of components with dependency injection.
+ ///
+ public static class ComponentActivator
+ {
+ ///
+ /// Creates an instance of the specified response type with the component hub and advanced parameters.
+ ///
+ /// The type of the response.
+ /// The type of the response to create.
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// Additional parameter with a status message to pass to the response's constructor.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified response type.
+ public static T CreateInstance(Type responseType, IHttpServerContext httpServerContext, IComponentHub componentHub, StatusMessage statusMessage, params object[] advancedParameters) where T : Response
+ {
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = responseType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var properties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(StatusMessage) ? statusMessage :
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ properties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is T component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(responseType) as T;
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context, component hub advanced parameters.
+ ///
+ /// The type of the component manager, which must implement .
+ /// The reference to the context of the host.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static T CreateInstance(IHttpServerContext httpServerContext, params object[] advancedParameters) where T : class, IComponentHub
+ {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = typeof(T).GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+
+ advancedParameters.Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is T component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(typeof(T), advancedParameters) as T;
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context, component hub advanced parameters.
+ ///
+ /// The type of the component manager, which must implement .
+ /// The type of the component to create.
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static T CreateInstance(Type componentType, IHttpServerContext httpServerContext, IComponentHub componentHub, params object[] advancedParameters) where T : class, IComponentManager
+ {
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = componentType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var properties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ properties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is T component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(componentType) as T;
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context, component hub advanced parameters.
+ ///
+ /// The type of the component manager, which must implement .
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// The type of the component to create.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static T CreateInstance(IHttpServerContext httpServerContext, IComponentHub componentHub, Type componentType, params object[] advancedParameters) where T : IComponent
+ {
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = componentType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var properties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ properties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is T component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return (T)Activator.CreateInstance(componentType);
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context, component hub advanced parameters.
+ ///
+ /// The type of the component, which must implement .
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static T CreateInstance(IHttpServerContext httpServerContext, IComponentHub componentHub, params object[] advancedParameters) where T : class, IComponent
+ {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ var componentType = typeof(T);
+ var constructors = componentType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var properties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ properties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x => x != null)
+ .Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is T component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(componentType) as T;
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context and component hub and advanced parameters.
+ ///
+ /// The type of the component, which must implement .
+ /// The type of the context, which must implement .
+ /// The type of the component to create.
+ /// The context to pass to the component's constructor.
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static TComponent CreateInstance(Type componentType, TContext context, IHttpServerContext httpServerContext, IComponentHub componentHub, params object[] advancedParameters)
+ where TComponent : class, IComponent
+ where TContext : IContext
+ {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = componentType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var hubProperties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ var contextIdProperty = context.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Where(x => x.PropertyType == typeof(IComponentId))
+ .FirstOrDefault();
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ parameter.ParameterType == typeof(TContext) ? context :
+ parameter.ParameterType == typeof(IComponentId) ? contextIdProperty?.GetValue(context) :
+ hubProperties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x =>
+ x.GetType() == parameter.ParameterType ||
+ (
+ parameter.ParameterType == typeof(IApplicationContext) &&
+ x.GetType().GetInterfaces().Any(x => x == typeof(IApplicationContext))
+ )
+ )
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is TComponent component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(componentType) as TComponent;
+ }
+
+ ///
+ /// Creates an instance of the specified component type with the provided context and component hub and advanced parameters.
+ ///
+ /// The type of the context, which must implement .
+ /// The type of the component to create.
+ /// The context to pass to the component's constructor.
+ /// The reference to the context of the host.
+ /// The component hub to use for dependency injection.
+ /// Additional parameters to pass to the component's constructor.
+ /// An instance of the specified component type.
+ public static IComponent CreateInstance(Type componentType, TContext context, IHttpServerContext httpServerContext, IComponentHub componentHub, params object[] advancedParameters)
+ where TContext : IContext
+ {
+ var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ var constructors = componentType?.GetConstructors(flags);
+
+ if (constructors != null)
+ {
+ foreach (var constructor in constructors.OrderByDescending(x => x.GetParameters().Length))
+ {
+ // injection
+ var parameters = constructor.GetParameters();
+ var properties = componentHub.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ var contextIdProperty = context.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Where(x => x.PropertyType == typeof(IComponentId))
+ .FirstOrDefault();
+
+ var parameterValues = parameters.Select(parameter =>
+ parameter.ParameterType == typeof(IComponentHub) ? componentHub :
+ parameter.ParameterType == typeof(IHttpServerContext) ? httpServerContext :
+ parameter.ParameterType == typeof(TContext) ? context :
+ parameter.ParameterType == typeof(IComponentId) ? contextIdProperty?.GetValue(context) :
+ properties.Where(x => x.PropertyType == parameter.ParameterType)
+ .FirstOrDefault()?
+ .GetValue(componentHub) ??
+ advancedParameters.Where(x => x.GetType() == parameter.ParameterType)
+ .FirstOrDefault() ?? null
+ ).ToArray();
+
+ if (constructor.Invoke(parameterValues) is IComponent component)
+ {
+ return component;
+ }
+ }
+ }
+
+ return Activator.CreateInstance(componentType) as IComponent;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentHub.cs b/src/WebExpress.WebCore/WebComponent/ComponentHub.cs
new file mode 100644
index 0000000..cbbea77
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/ComponentHub.cs
@@ -0,0 +1,540 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAsset;
+using WebExpress.WebCore.WebComponent.Model;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebEvent;
+using WebExpress.WebCore.WebFragment;
+using WebExpress.WebCore.WebIdentity;
+using WebExpress.WebCore.WebJob;
+using WebExpress.WebCore.WebLog;
+using WebExpress.WebCore.WebPackage;
+using WebExpress.WebCore.WebPage;
+using WebExpress.WebCore.WebPlugin;
+using WebExpress.WebCore.WebResource;
+using WebExpress.WebCore.WebRestApi;
+using WebExpress.WebCore.WebSession;
+using WebExpress.WebCore.WebSettingPage;
+using WebExpress.WebCore.WebSitemap;
+using WebExpress.WebCore.WebStatusPage;
+using WebExpress.WebCore.WebTask;
+using WebExpress.WebCore.WebTheme;
+
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Central management of components.
+ ///
+ public class ComponentHub : IComponentHub
+ {
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly ComponentDictionary _dictionary = [];
+ private readonly LogManager _logManager;
+ private readonly PackageManager _packageManager;
+ private readonly InternationalizationManager _internationalizationManager;
+ private readonly PluginManager _pluginManager;
+ private readonly ApplicationManager _applicationManager;
+ private readonly EndpointManager _endpointManager;
+ private readonly AssetManager _assetManager;
+ private readonly ResourceManager _resourceManager;
+ private readonly PageManager _pageManager;
+ private readonly SettingPageManager _settingPageManager;
+ private readonly RestApiManager _restApiManager;
+ private readonly SitemapManager _sitemapManager;
+ private readonly FragmentManager _fragmentManager;
+ private readonly StatusPageManager _statusPageManager;
+ private readonly SessionManager _sessionManager;
+ private readonly EventManager _eventManager;
+ private readonly JobManager _jobManager;
+ private readonly TaskManager _taskManager;
+ private readonly IdentityManager _identityManager;
+ private readonly ThemeManager _themeManager;
+ private int _lastCounter = 0;
+
+ ///
+ /// An event that fires when an component is added.
+ ///
+ public event EventHandler AddComponent;
+
+ ///
+ /// An event that fires when an component is removed.
+ ///
+ public event EventHandler RemoveComponent;
+
+ ///
+ /// Returns all registered managers.
+ ///
+ public IEnumerable Managers => new IComponentManager[]
+ {
+ _logManager,
+ _packageManager,
+ _pluginManager,
+ _applicationManager,
+ _endpointManager,
+ _sitemapManager,
+ _fragmentManager,
+ _assetManager,
+ _resourceManager,
+ _pageManager,
+ _settingPageManager,
+ _restApiManager,
+ _eventManager,
+ _jobManager,
+ _statusPageManager,
+ _internationalizationManager,
+ _identityManager,
+ _sessionManager,
+ _taskManager,
+ _themeManager
+ }.Concat(_dictionary.Values.SelectMany(x => x).Select(x => x.ComponentInstance));
+
+ ///
+ /// Returns the log manager.
+ ///
+ /// The instance of the log manager.
+ public ILogManager LogManager => _logManager;
+
+ ///
+ /// Returns the package manager.
+ ///
+ /// The instance of the package manager.
+ public IPackageManager PackageManager => _packageManager;
+
+ ///
+ /// Returns the plugin manager.
+ ///
+ /// The instance of the plugin manager.
+ public IPluginManager PluginManager => _pluginManager;
+
+ ///
+ /// Returns the application manager.
+ ///
+ /// The instance of the application manager.
+ public IApplicationManager ApplicationManager => _applicationManager;
+
+ ///
+ /// Returns the event manager.
+ ///
+ /// The instance of the event manager.
+ public IEventManager EventManager => _eventManager;
+
+ ///
+ /// Returns the job manager.
+ ///
+ /// The instance of the job manager.
+ public IJobManager JobManager => _jobManager;
+
+ ///
+ /// Returns the task manager.
+ ///
+ /// The instance of the task manager.
+ public ITaskManager TaskManager => _taskManager;
+
+ ///
+ /// Returns the endpoint manager.
+ ///
+ /// The instance of the endpoint manager.
+ public IEndpointManager EndpointManager => _endpointManager;
+
+ ///
+ /// Returns the asset manager.
+ ///
+ /// The instance of the asset manager.
+ public IAssetManager AssetManager => _assetManager;
+
+ ///
+ /// Returns the resource manager.
+ ///
+ /// The instance of the resource manager.
+ public IResourceManager ResourceManager => _resourceManager;
+
+ ///
+ /// Returns the page manager.
+ ///
+ /// The instance of the page manager.
+ public IPageManager PageManager => _pageManager;
+
+ ///
+ /// Returns the setting page manager.
+ ///
+ /// The instance of the setting page manager.
+ public ISettingPageManager SettingPageManager => _settingPageManager;
+
+ ///
+ /// Returns the rest api manager.
+ ///
+ /// The instance of the rest api manager.
+ public IRestApiManager RestApiManager => _restApiManager;
+
+ ///
+ /// Returns the sitemap manager.
+ ///
+ /// The instance of the sitemap manager.
+ public ISitemapManager SitemapManager => _sitemapManager;
+
+ ///
+ /// Returns the fragment manager.
+ ///
+ /// The instance of the fragment manager.
+ public IFragmentManager FragmentManager => _fragmentManager;
+
+ ///
+ /// Returns the status page manager.
+ ///
+ /// The instance of the status page manager.
+ public IStatusPageManager StatusPageManager => _statusPageManager;
+
+ ///
+ /// Returns the internationalization manager.
+ ///
+ /// The instance of the internationalization manager.
+ public IInternationalizationManager InternationalizationManager => _internationalizationManager;
+
+ ///
+ /// Returns the identity manager.
+ ///
+ /// The instance of the identity manager.
+ public IIdentityManager IdentityManager => _identityManager;
+
+ ///
+ /// Returns the session manager.
+ ///
+ /// The instance of the session manager.
+ public ISessionManager SessionManager => _sessionManager;
+
+ ///
+ /// Returns the theme manager.
+ ///
+ /// The instance of the theme manager.
+ public IThemeManager ThemeManager => _themeManager;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The reference to the context of the host.
+ protected ComponentHub(IHttpServerContext httpServerContext)
+ {
+ _httpServerContext = httpServerContext;
+
+ // order is relevant
+ _pluginManager = CreateInstance(typeof(PluginManager)) as PluginManager;
+ _packageManager = CreateInstance(typeof(PackageManager)) as PackageManager;
+
+ _logManager = CreateInstance(typeof(LogManager)) as LogManager;
+ _internationalizationManager = CreateInstance(typeof(InternationalizationManager)) as InternationalizationManager;
+ _applicationManager = CreateInstance(typeof(ApplicationManager)) as ApplicationManager;
+ _sitemapManager = CreateInstance(typeof(SitemapManager)) as SitemapManager;
+ _fragmentManager = CreateInstance(typeof(FragmentManager)) as FragmentManager;
+ _endpointManager = CreateInstance(typeof(EndpointManager)) as EndpointManager;
+ _assetManager = CreateInstance(typeof(AssetManager)) as AssetManager;
+ _resourceManager = CreateInstance(typeof(ResourceManager)) as ResourceManager;
+ _pageManager = CreateInstance(typeof(PageManager)) as PageManager;
+ _settingPageManager = CreateInstance(typeof(SettingPageManager)) as SettingPageManager;
+ _restApiManager = CreateInstance(typeof(RestApiManager)) as RestApiManager;
+ _statusPageManager = CreateInstance(typeof(StatusPageManager)) as StatusPageManager;
+ _eventManager = CreateInstance(typeof(EventManager)) as EventManager;
+ _jobManager = CreateInstance(typeof(JobManager)) as JobManager;
+ _sessionManager = CreateInstance(typeof(SessionManager)) as SessionManager;
+ _taskManager = CreateInstance(typeof(TaskManager)) as TaskManager;
+ _identityManager = CreateInstance(typeof(IdentityManager)) as IdentityManager;
+ _themeManager = CreateInstance(typeof(ThemeManager)) as ThemeManager;
+
+ _internationalizationManager.Register(typeof(HttpServer).Assembly, typeof(HttpServer).Assembly.GetName().Name?.ToLower());
+
+ _httpServerContext.Log.Debug
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.initialization")
+ );
+
+ _pluginManager.AddPlugin += (sender, pluginContext) =>
+ {
+ Register(pluginContext);
+ };
+
+ PluginManager.RemovePlugin += (sender, pluginContext) =>
+ {
+ Remove(pluginContext);
+ };
+ }
+
+ ///
+ /// Creates and initializes a component.
+ ///
+ /// The component class.
+ /// The instance of the create and initialized component.
+ private IComponentManager CreateInstance(Type componentType)
+ {
+ if (componentType == null)
+ {
+ return null;
+ }
+ else if (!componentType.GetInterfaces().Where(x => x == typeof(IComponentManager)).Any())
+ {
+ _httpServerContext.Log.Warning
+ (
+ _internationalizationManager.Translate
+ (
+ "webexpress.webcore:componentmanager.wrongtype",
+ componentType?.FullName, typeof(IComponentManager).FullName
+ )
+ );
+
+ return null;
+ }
+
+ try
+ {
+ return ComponentActivator.CreateInstance(componentType, _httpServerContext, this);
+ }
+ catch (Exception ex)
+ {
+ _httpServerContext.Log.Exception(ex);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Returns a component based on its id.
+ ///
+ /// The id.
+ /// The instance of the component or null.
+ public IComponentManager GetComponentManager(string id)
+ {
+ return _dictionary.Values
+ .SelectMany(x => x)
+ .Where(x => x.ComponentId.Equals(id, StringComparison.OrdinalIgnoreCase))
+ .Select(x => x.ComponentInstance)
+ .FirstOrDefault();
+ }
+
+ ///
+ /// Returns a component based on its type.
+ ///
+ /// The component class.
+ /// The instance of the component or null.
+ public TComponentManager GetComponentManager()
+ where TComponentManager : IComponentManager
+ {
+ return (TComponentManager)_dictionary.Values
+ .SelectMany(x => x)
+ .Where(x => x.ComponentClass == typeof(TComponentManager))
+ .Select(x => x.ComponentInstance)
+ .FirstOrDefault();
+ }
+
+ ///
+ /// Discovers and registers the components from the specified plugin.
+ ///
+ /// A plugin context that contain the components.
+ internal void Register(IPluginContext pluginContext)
+ {
+ // the plugin has already been registered
+ if (_dictionary.ContainsKey(pluginContext))
+ {
+ return;
+ }
+
+ var assembly = pluginContext.Assembly;
+
+ _dictionary.Add(pluginContext, []);
+ var componentItems = _dictionary[pluginContext];
+
+ foreach (var type in assembly.GetExportedTypes().Where(x => x.IsClass && x.IsSealed && x.GetInterface(typeof(IComponentManager).Name) != null))
+ {
+ var id = type.FullName?.ToLower();
+
+ // determining attributes
+ var componentInstance = CreateInstance(type);
+
+ if (!componentItems.Where(x => x.ComponentId.Equals(id, StringComparison.OrdinalIgnoreCase)).Any())
+ {
+ _dictionary[pluginContext] = componentItems.Concat([ new ComponentItem()
+ {
+ ComponentClass = type,
+ ComponentId = id,
+ ComponentInstance = componentInstance
+ }]);
+
+ _httpServerContext.Log.Debug
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.register", id)
+ );
+
+ // raises the AddComponent event
+ OnAddComponent(componentInstance);
+ }
+ else
+ {
+ _httpServerContext.Log.Warning
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.duplicate", id)
+ );
+ }
+ }
+
+ Log();
+ }
+
+ ///
+ /// Boots the components.
+ ///
+ /// The plugin context.
+ internal void BootComponent(IPluginContext pluginContext)
+ {
+ _pluginManager.Boot(pluginContext);
+ _applicationManager.Boot(pluginContext);
+
+ foreach (var component in _dictionary.Values
+ .Where(x => x is IExecutableElements)
+ .Select(x => x as IExecutableElements))
+ {
+ component.Boot(pluginContext);
+ }
+ }
+
+ ///
+ /// Boots the components.
+ ///
+ /// A enumeration of plugin contexts.
+ internal void BootComponent(IEnumerable pluginContexts)
+ {
+ foreach (var pluginContext in pluginContexts)
+ {
+ BootComponent(pluginContext);
+ }
+ }
+
+ ///
+ /// Starts the component.
+ ///
+ public void Execute()
+ {
+ _httpServerContext.Log.Debug
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.execute")
+ );
+
+ _packageManager.Execute();
+ _jobManager.Execute();
+ }
+
+ ///
+ /// Shutting down the component manager.
+ ///
+ public void ShutDown()
+ {
+ _httpServerContext.Log.Debug
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.shutdown")
+ );
+ }
+
+ ///
+ /// Shutting down the component.
+ ///
+ /// The plugin context.
+ internal void ShutDownComponent(IPluginContext pluginContext)
+ {
+ _pluginManager.ShutDown(pluginContext);
+ _applicationManager.ShutDown(pluginContext);
+
+ foreach (var component in _dictionary.Values
+ .Where(x => x is IExecutableElements)
+ .Select(x => x as IExecutableElements))
+ {
+ component.ShutDown(pluginContext);
+ }
+ }
+
+ ///
+ /// Removes all components associated with the specified plugin context.
+ ///
+ /// The context of the plugin that contains the applications to remove.
+ public void Remove(IPluginContext pluginContext)
+ {
+ if (pluginContext == null)
+ {
+ return;
+ }
+
+ if (_dictionary.TryGetValue(pluginContext, out IEnumerable componentItems))
+ {
+ if (!componentItems.Any())
+ {
+ return;
+ }
+
+ foreach (var componentItem in componentItems)
+ {
+ OnRemoveComponent(componentItem.ComponentInstance);
+
+ _httpServerContext.Log.Debug
+ (
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.remove")
+ );
+ }
+ }
+
+ _dictionary.Remove(pluginContext);
+ }
+
+ ///
+ /// Raises the AddComponent event.
+ ///
+ /// The component.
+ private void OnAddComponent(IComponentManager component)
+ {
+ AddComponent?.Invoke(null, component);
+ }
+
+ ///
+ /// Raises the RemoveComponent event.
+ ///
+ /// The component.
+ private void OnRemoveComponent(IComponentManager component)
+ {
+ RemoveComponent?.Invoke(null, component);
+ }
+
+ ///
+ /// Output of the components to the log.
+ ///
+ private void Log()
+ {
+ if (_lastCounter == Managers.Count())
+ {
+ return;
+ }
+
+ using var frame = new LogFrameSimple(_httpServerContext.Log);
+ var output = new List
+ {
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.component")
+ };
+
+ foreach (var manager in Managers)
+ {
+ output.Add
+ (
+ string.Empty.PadRight(2) +
+ _internationalizationManager.Translate("webexpress.webcore:componentmanager.name", manager.GetType()?.Name.ToLower())
+ );
+ }
+
+ _httpServerContext.Log.Info(string.Join(Environment.NewLine, output));
+ _lastCounter = Managers.Count();
+ }
+
+ ///
+ /// Release of unmanaged resources reserved during use.
+ ///
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentId.cs b/src/WebExpress.WebCore/WebComponent/ComponentId.cs
new file mode 100644
index 0000000..65fb013
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/ComponentId.cs
@@ -0,0 +1,143 @@
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Represents a component identifier.
+ ///
+ public class ComponentId : IComponentId
+ {
+ private readonly string _id;
+
+ ///
+ /// Initializes a new instance of the class with the specified identifier.
+ ///
+ /// The identifier of the component.
+ public ComponentId(string id)
+ {
+ _id = id?.ToLower();
+ }
+
+ ///
+ /// Defines an implicit conversion of a string to a .
+ ///
+ /// The identifier of the component.
+ /// A new instance of initialized with the specified identifier.
+ public static implicit operator ComponentId(string id)
+ {
+ return new ComponentId(id);
+ }
+
+ ///
+ /// Defines an implicit conversion of a to a string.
+ ///
+ /// The to convert.
+ /// The identifier of the component as a string.
+ public static implicit operator string(ComponentId componentId)
+ {
+ return componentId._id;
+ }
+
+ ///
+ /// Determines whether two specified objects have the same value.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if the value of is the same as the value of ; otherwise, false.
+ public static bool operator ==(ComponentId lhs, IComponentId rhs)
+ {
+ if (ReferenceEquals(lhs, rhs))
+ {
+ return true;
+ }
+ if (lhs is null || rhs is null)
+ {
+ return false;
+ }
+
+ return lhs.ToString().Equals(rhs.ToString());
+ }
+
+ ///
+ /// Determines whether two specified objects have the same value.
+ ///
+ /// The first to compare.
+ /// The second string to compare.
+ /// true if the value of is the same as the value of ; otherwise, false.
+ public static bool operator ==(ComponentId lhs, string rhs)
+ {
+ if (ReferenceEquals(lhs, rhs))
+ {
+ return true;
+ }
+ if (lhs is null || rhs is null)
+ {
+ return false;
+ }
+
+ return lhs._id == rhs;
+ }
+
+ ///
+ /// Determines whether two specified objects have different values.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if the value of is different from the value of ; otherwise, false.
+ public static bool operator !=(ComponentId lhs, IComponentId rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ ///
+ /// Determines whether two specified objects have different values.
+ ///
+ /// The first to compare.
+ /// The second string to compare.
+ /// true if the value of is different from the value of ; otherwise, false.
+ public static bool operator !=(ComponentId lhs, string rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current .
+ ///
+ /// The object to compare with the current .
+ /// true if the specified object is equal to the current ; otherwise, false.
+ public bool Equals(string obj)
+ {
+ return _id.Equals(obj);
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current .
+ ///
+ /// The object to compare with the current .
+ /// true if the specified object is equal to the current ; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ if (obj is ComponentId other)
+ {
+ return _id == other._id;
+ }
+ return false;
+ }
+
+ ///
+ /// Serves as the default hash function.
+ ///
+ /// A hash code for the current .
+ public override int GetHashCode()
+ {
+ return _id.GetHashCode();
+ }
+
+ ///
+ /// Returns the string representation of the component identifier.
+ ///
+ /// The identifier of the component as a string.
+ public override string ToString()
+ {
+ return _id;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentManager.cs b/src/WebExpress.WebCore/WebComponent/ComponentManager.cs
deleted file mode 100644
index 4483349..0000000
--- a/src/WebExpress.WebCore/WebComponent/ComponentManager.cs
+++ /dev/null
@@ -1,488 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using WebExpress.WebCore.Internationalization;
-using WebExpress.WebCore.WebApplication;
-using WebExpress.WebCore.WebEvent;
-using WebExpress.WebCore.WebJob;
-using WebExpress.WebCore.WebModule;
-using WebExpress.WebCore.WebPackage;
-using WebExpress.WebCore.WebPlugin;
-using WebExpress.WebCore.WebResource;
-using WebExpress.WebCore.WebSession;
-using WebExpress.WebCore.WebSitemap;
-using WebExpress.WebCore.WebStatusPage;
-using WebExpress.WebCore.WebTask;
-
-namespace WebExpress.WebCore.WebComponent
-{
- ///
- /// Central management of components.
- ///
- public static class ComponentManager
- {
- ///
- /// An event that fires when an component is added.
- ///
- public static event EventHandler AddComponent;
-
- ///
- /// An event that fires when an component is removed.
- ///
- public static event EventHandler RemoveComponent;
-
- ///
- /// Returns the reference to the context of the host.
- ///
- public static IHttpServerContext HttpServerContext { get; private set; }
-
- ///
- /// Returns the directory where the components are listed.
- ///
- private static ComponentDictionary Dictionary { get; } = new ComponentDictionary();
-
- ///
- /// Returns all registered components.
- ///
- public static IEnumerable Components => new IComponent[]
- {
- PackageManager,
- PluginManager,
- ApplicationManager,
- ModuleManager,
- EventManager,
- JobManager,
- ResponseManager,
- SitemapManager,
- InternationalizationManager,
- SessionManager,
- TaskManager
- }.Concat(Dictionary.Values.SelectMany(x => x).Select(x => x.ComponentInstance));
-
- ///
- /// Returns the package manager.
- ///
- /// The instance of the package manager or null.
- public static PackageManager PackageManager { get; private set; }
-
- ///
- /// Returns the plugin manager.
- ///
- /// The instance of the plugin manager or null.
- public static PluginManager PluginManager { get; private set; }
-
- ///
- /// Returns the application manager.
- ///
- /// The instance of the application manager or null.
- public static ApplicationManager ApplicationManager { get; private set; }
-
- ///
- /// Returns the module manager.
- ///
- /// The instance of the module manager or null.
- public static ModuleManager ModuleManager { get; private set; }
-
- ///
- /// Returns the event manager.
- ///
- /// The instance of the event manager or null.
- public static EventManager EventManager { get; private set; }
-
- ///
- /// Returns the job manager.
- ///
- /// The instance of the job manager or null.
- public static JobManager JobManager { get; private set; }
-
- ///
- /// Returns the response manager.
- ///
- /// The instance of the response manager or null.
- public static ResponseManager ResponseManager { get; private set; }
-
- ///
- /// Returns the resource manager.
- ///
- /// The instance of the resource manager or null.
- public static ResourceManager ResourceManager { get; private set; }
-
- ///
- /// Returns the sitemap manager.
- ///
- /// The instance of the sitemap manager or null.
- public static SitemapManager SitemapManager { get; private set; }
-
- ///
- /// Returns the internationalization manager.
- ///
- /// The instance of the internationalization manager or null.
- public static InternationalizationManager InternationalizationManager { get; private set; }
-
- ///
- /// Returns the session manager.
- ///
- /// The instance of the session manager or null.
- public static SessionManager SessionManager { get; private set; }
-
- ///
- /// Returns the task manager.
- ///
- /// The instance of the task manager manager or null.
- public static TaskManager TaskManager { get; private set; }
-
- ///
- /// Initialization
- ///
- /// The reference to the context of the host.
- internal static void Initialization(IHttpServerContext httpServerContext)
- {
- HttpServerContext = httpServerContext;
-
- InternationalizationManager.Register(typeof(HttpServer).Assembly, "webexpress");
-
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N("webexpress:componentmanager.initialization")
- );
-
- // order is relevant
- PackageManager = CreateInstance(typeof(PackageManager)) as PackageManager;
- PluginManager = CreateInstance(typeof(PluginManager)) as PluginManager;
- InternationalizationManager = CreateInstance(typeof(InternationalizationManager)) as InternationalizationManager;
- ApplicationManager = CreateInstance(typeof(ApplicationManager)) as ApplicationManager;
- ModuleManager = CreateInstance(typeof(ModuleManager)) as ModuleManager;
- ResourceManager = CreateInstance(typeof(ResourceManager)) as ResourceManager;
- ResponseManager = CreateInstance(typeof(ResponseManager)) as ResponseManager;
- EventManager = CreateInstance(typeof(EventManager)) as EventManager;
- JobManager = CreateInstance(typeof(JobManager)) as JobManager;
- SitemapManager = CreateInstance(typeof(SitemapManager)) as SitemapManager;
- SessionManager = CreateInstance(typeof(SessionManager)) as SessionManager;
- TaskManager = CreateInstance(typeof(TaskManager)) as TaskManager;
-
- PluginManager.AddPlugin += (sender, pluginContext) =>
- {
- Register(pluginContext);
- };
-
- PluginManager.RemovePlugin += (sender, pluginContext) =>
- {
- Remove(pluginContext);
- };
- }
-
- ///
- /// Creates and initializes a component.
- ///
- /// The component class.
- /// The instance of the create and initialized component.
- private static IComponent CreateInstance(Type componentType)
- {
- if (componentType == null)
- {
- return null;
- }
- else if (!componentType.GetInterfaces().Where(x => x == typeof(IComponent)).Any())
- {
- HttpServerContext.Log.Warning
- (
- InternationalizationManager.I18N
- (
- "webexpress:componentmanager.wrongtype",
- componentType?.FullName, typeof(IComponent).FullName
- )
- );
-
- return null;
- }
-
- try
- {
- var flags = BindingFlags.NonPublic | BindingFlags.Instance;
- var component = componentType?.Assembly.CreateInstance
- (
- componentType?.FullName,
- false,
- flags,
- null,
- null,
- null,
- null
- ) as IComponent;
-
- //var component = Activator.CreateInstance(componentType, flags) as IComponent;
-
- component.Initialization(HttpServerContext);
-
- return component;
- }
- catch (Exception ex)
- {
- HttpServerContext.Log.Exception(ex);
- }
-
- return null;
- }
-
- ///
- /// Returns a component based on its id.
- ///
- /// The id.
- /// The instance of the component or null.
- public static IComponent GetComponent(string id)
- {
- return Dictionary.Values
- .SelectMany(x => x)
- .Where(x => x.ComponentId.Equals(id, StringComparison.OrdinalIgnoreCase))
- .Select(x => x.ComponentInstance)
- .FirstOrDefault();
- }
-
- ///
- /// Returns a component based on its type.
- ///
- /// The component class.
- /// The instance of the component or null.
- public static T GetComponent() where T : IComponent
- {
- return (T)Dictionary.Values
- .SelectMany(x => x)
- .Where(x => x.ComponentClass == typeof(T))
- .Select(x => x.ComponentInstance)
- .FirstOrDefault();
- }
-
- ///
- /// Discovers and registers the components from the specified plugin.
- ///
- /// A plugin context that contain the components.
- public static void Register(IPluginContext pluginContext)
- {
- // the plugin has already been registered
- if (Dictionary.ContainsKey(pluginContext))
- {
- return;
- }
-
- var assembly = pluginContext.Assembly;
-
- Dictionary.Add(pluginContext, new List());
- var componentItems = Dictionary[pluginContext];
-
- foreach (var type in assembly.GetExportedTypes().Where(x => x.IsClass && x.IsSealed && x.GetInterface(typeof(IComponent).Name) != null))
- {
- var id = type.FullName?.ToLower();
-
- // determining attributes
- var componentInstance = CreateInstance(type);
-
- if (!componentItems.Where(x => x.ComponentId.Equals(id, StringComparison.OrdinalIgnoreCase)).Any())
- {
- componentItems.Add(new ComponentItem()
- {
- ComponentClass = type,
- ComponentId = id,
- ComponentInstance = componentInstance
- });
-
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N("webexpress:componentmanager.register", id)
- );
-
- // raises the AddComponent event
- OnAddComponent(componentInstance);
- }
- else
- {
- HttpServerContext.Log.Warning
- (
- InternationalizationManager.I18N("webexpress:componentmanager.duplicate", id)
- );
- }
- }
- }
-
- ///
- /// Discovers and registers the components from the specified plugins.
- ///
- /// A list with plugin contexts that contain the components.
- public static void Register(IEnumerable pluginContexts)
- {
- foreach (var pluinContext in pluginContexts)
- {
- Register(pluinContext);
- }
- }
-
- ///
- /// Boots the components.
- ///
- /// The plugin context.
- internal static void BootComponent(IPluginContext pluginContext)
- {
- PluginManager.Boot(pluginContext);
- ApplicationManager.Boot(pluginContext);
- ModuleManager.Boot(pluginContext);
-
- foreach (var component in Dictionary.Values
- .Where(x => x is IExecutableElements)
- .Select(x => x as IExecutableElements))
- {
- component.Boot(pluginContext);
- }
- }
-
- ///
- /// Boots the components.
- ///
- /// A enumeration of plugin contexts.
- internal static void BootComponent(IEnumerable pluginContexts)
- {
- foreach (var pluginContext in pluginContexts)
- {
- BootComponent(pluginContext);
- }
- }
-
- ///
- /// Starts the component.
- ///
- internal static void Execute()
- {
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N("webexpress:componentmanager.execute")
- );
-
- PackageManager.Execute();
- JobManager.Execute();
- }
-
- ///
- /// Shutting down the component manager.
- ///
- public static void ShutDown()
- {
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N("webexpress:componentmanager.shutdown")
- );
- }
-
- ///
- /// Shutting down the component.
- ///
- /// The plugin context.
- public static void ShutDownComponent(IPluginContext pluginContext)
- {
- PluginManager.ShutDown(pluginContext);
- ApplicationManager.ShutDown(pluginContext);
- ModuleManager.ShutDown(pluginContext);
-
- foreach (var component in Dictionary.Values
- .Where(x => x is IExecutableElements)
- .Select(x => x as IExecutableElements))
- {
- component.ShutDown(pluginContext);
- }
- }
-
- ///
- /// Removes all components associated with the specified plugin context.
- ///
- /// The context of the plugin that contains the applications to remove.
- public static void Remove(IPluginContext pluginContext)
- {
- if (Dictionary.ContainsKey(pluginContext))
- {
- return;
- }
-
- var componentItems = Dictionary[pluginContext];
-
- if (!componentItems.Any())
- {
- return;
- }
-
- foreach (var componentItem in componentItems)
- {
- OnRemoveComponent(componentItem.ComponentInstance);
-
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N("webexpress:componentmanager.remove")
- );
- }
-
- ModuleManager.Remove(pluginContext);
- ApplicationManager.Remove(pluginContext);
- PluginManager.Remove(pluginContext);
-
- Dictionary.Remove(pluginContext);
- }
-
- ///
- /// Raises the AddComponent event.
- ///
- /// The component.
- private static void OnAddComponent(IComponent component)
- {
- AddComponent?.Invoke(null, component);
- }
-
- ///
- /// Raises the RemoveComponent event.
- ///
- /// The component.
- private static void OnRemoveComponent(IComponent component)
- {
- RemoveComponent?.Invoke(null, component);
- }
-
- ///
- /// Output of the components to the log.
- ///
- public static void LogStatus()
- {
- using var frame = new LogFrameSimple(HttpServerContext.Log);
- var output = new List
- {
- InternationalizationManager.I18N("webexpress:componentmanager.component")
- };
-
- foreach (var pluginContext in PluginManager.Plugins)
- {
- output.Add
- (
- string.Empty.PadRight(2) +
- InternationalizationManager.I18N("webexpress:pluginmanager.plugin", pluginContext.PluginId)
- );
-
- ApplicationManager.PrepareForLog(pluginContext, output, 4);
- ModuleManager.PrepareForLog(pluginContext, output, 4);
- ResourceManager.PrepareForLog(pluginContext, output, 4);
- ResponseManager.PrepareForLog(pluginContext, output, 4);
- JobManager.PrepareForLog(pluginContext, output, 4);
- }
-
- foreach (var item in Dictionary)
- {
- foreach (var component in item.Value)
- {
- output.Add
- (
- string.Empty.PadRight(2) +
- InternationalizationManager.I18N("webexpress:pluginmanager.plugin", item.Key.PluginId)
- );
-
- component.ComponentInstance?.PrepareForLog(item.Key, output, 4);
- }
- }
-
- HttpServerContext.Log.Info(string.Join(Environment.NewLine, output));
- }
- }
-}
diff --git a/src/WebExpress.WebCore/WebComponent/IComponent.cs b/src/WebExpress.WebCore/WebComponent/IComponent.cs
index f4228c8..7954ea8 100644
--- a/src/WebExpress.WebCore/WebComponent/IComponent.cs
+++ b/src/WebExpress.WebCore/WebComponent/IComponent.cs
@@ -1,30 +1,10 @@
-using System.Collections.Generic;
-using WebExpress.WebCore.WebPlugin;
-
-namespace WebExpress.WebCore.WebComponent
+namespace WebExpress.WebCore.WebComponent
{
///
- /// Interface of the manager classes.
+ /// Interface of a component.
///
public interface IComponent
{
- ///
- /// Returns the reference to the context of the host.
- ///
- static IHttpServerContext HttpServerContext { get; }
-
- ///
- /// Initialization
- ///
- /// The reference to the context of the host.
- void Initialization(IHttpServerContext context);
- ///
- /// Information about the component is collected and prepared for output in the log.
- ///
- /// The context of the plugin.
- /// A list of log entries.
- /// The shaft deep.
- void PrepareForLog(IPluginContext pluginContext, IList output, int deep);
}
}
diff --git a/src/WebExpress.WebCore/WebComponent/IComponentHub.cs b/src/WebExpress.WebCore/WebComponent/IComponentHub.cs
new file mode 100644
index 0000000..13ac642
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/IComponentHub.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAsset;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebEvent;
+using WebExpress.WebCore.WebFragment;
+using WebExpress.WebCore.WebIdentity;
+using WebExpress.WebCore.WebJob;
+using WebExpress.WebCore.WebLog;
+using WebExpress.WebCore.WebPackage;
+using WebExpress.WebCore.WebPage;
+using WebExpress.WebCore.WebPlugin;
+using WebExpress.WebCore.WebResource;
+using WebExpress.WebCore.WebRestApi;
+using WebExpress.WebCore.WebSession;
+using WebExpress.WebCore.WebSettingPage;
+using WebExpress.WebCore.WebSitemap;
+using WebExpress.WebCore.WebStatusPage;
+using WebExpress.WebCore.WebTask;
+using WebExpress.WebCore.WebTheme;
+
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Interface of the central management of manager components.
+ ///
+ public interface IComponentHub : IComponentManager
+ {
+ ///
+ /// An event that fires when an component is added.
+ ///
+ event EventHandler AddComponent;
+
+ ///
+ /// An event that fires when an component is removed.
+ ///
+ event EventHandler RemoveComponent;
+
+ ///
+ /// Returns all registered components.
+ ///
+ IEnumerable Managers { get; }
+
+ ///
+ /// Returns the log manager.
+ ///
+ /// The instance of the log manager.
+ ILogManager LogManager { get; }
+
+ ///
+ /// Returns the package manager.
+ ///
+ /// The instance of the package manager.
+ IPackageManager PackageManager { get; }
+
+ ///
+ /// Returns the plugin manager.
+ ///
+ /// The instance of the plugin manager.
+ public IPluginManager PluginManager { get; }
+
+ ///
+ /// Returns the application manager.
+ ///
+ /// The instance of the application manager.
+ IApplicationManager ApplicationManager { get; }
+
+ ///
+ /// Returns the event manager.
+ ///
+ /// The instance of the event manager.
+ IEventManager EventManager { get; }
+
+ ///
+ /// Returns the job manager.
+ ///
+ /// The instance of the job manager.
+ IJobManager JobManager { get; }
+
+ ///
+ /// Returns the task manager.
+ ///
+ /// The instance of the task manager.
+ ITaskManager TaskManager { get; }
+
+ ///
+ /// Returns the endpoint manager.
+ ///
+ /// The instance of the endpoint manager.
+ IEndpointManager EndpointManager { get; }
+
+ ///
+ /// Returns the asset manager.
+ ///
+ /// The instance of the asset manager.
+ public IAssetManager AssetManager { get; }
+
+ ///
+ /// Returns the resource manager.
+ ///
+ /// The instance of the resource manager.
+ IResourceManager ResourceManager { get; }
+
+ ///
+ /// Returns the page manager.
+ ///
+ /// The instance of the page manager.
+ IPageManager PageManager { get; }
+
+ ///
+ /// Returns the setting page manager.
+ ///
+ /// The instance of the setting page manager.
+ ISettingPageManager SettingPageManager { get; }
+
+ ///
+ /// Returns the rest api manager.
+ ///
+ /// The instance of the rest api manager.
+ IRestApiManager RestApiManager { get; }
+
+ ///
+ /// Returns the sitemap manager.
+ ///
+ /// The instance of the sitemap manager.
+ ISitemapManager SitemapManager { get; }
+
+ ///
+ /// Returns the fragment manager.
+ ///
+ /// The instance of the fragment manager.
+ IFragmentManager FragmentManager { get; }
+
+ ///
+ /// Returns the status page manager.
+ ///
+ /// The instance of the status page manager.
+ IStatusPageManager StatusPageManager { get; }
+
+ ///
+ /// Returns the internationalization manager.
+ ///
+ /// The instance of the internationalization manager.
+ IInternationalizationManager InternationalizationManager { get; }
+
+ ///
+ /// Returns the identity manager.
+ ///
+ /// The instance of the identity manager.
+ IIdentityManager IdentityManager { get; }
+
+ ///
+ /// Returns the session manager.
+ ///
+ /// The instance of the session manager.
+ ISessionManager SessionManager { get; }
+
+ ///
+ /// Returns the theme manager.
+ ///
+ /// The instance of the theme manager.
+ IThemeManager ThemeManager { get; }
+
+ ///
+ /// Returns a component based on its id.
+ ///
+ /// The id.
+ /// The instance of the component.
+ IComponentManager GetComponentManager(string id);
+
+ ///
+ /// Returns a component based on its type.
+ ///
+ /// The component class.
+ /// The instance of the component.
+ TComponentManager GetComponentManager()
+ where TComponentManager : IComponentManager;
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/IComponentId.cs b/src/WebExpress.WebCore/WebComponent/IComponentId.cs
new file mode 100644
index 0000000..e4229d0
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/IComponentId.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Represents an interface for component identifiers.
+ ///
+ public interface IComponentId
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/IComponentManager.cs b/src/WebExpress.WebCore/WebComponent/IComponentManager.cs
new file mode 100644
index 0000000..e4555e5
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/IComponentManager.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Interface of the manager classes.
+ ///
+ public interface IComponentManager : IDisposable
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/IComponentPlugin.cs b/src/WebExpress.WebCore/WebComponent/IComponentManagerPlugin.cs
similarity index 94%
rename from src/WebExpress.WebCore/WebComponent/IComponentPlugin.cs
rename to src/WebExpress.WebCore/WebComponent/IComponentManagerPlugin.cs
index 46981bc..9366404 100644
--- a/src/WebExpress.WebCore/WebComponent/IComponentPlugin.cs
+++ b/src/WebExpress.WebCore/WebComponent/IComponentManagerPlugin.cs
@@ -6,7 +6,7 @@ namespace WebExpress.WebCore.WebComponent
///
/// Interface of the manager classes.
///
- public interface IComponentPlugin : IComponent
+ public interface IComponentManagerPlugin : IComponentManager
{
///
/// Discovers and registers entries from the specified plugin.
diff --git a/src/WebExpress.WebCore/WebComponent/IContext.cs b/src/WebExpress.WebCore/WebComponent/IContext.cs
new file mode 100644
index 0000000..cb0ac42
--- /dev/null
+++ b/src/WebExpress.WebCore/WebComponent/IContext.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebComponent
+{
+ ///
+ /// Represents the interface for all web contexts.
+ ///
+ public interface IContext
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentDictionary.cs b/src/WebExpress.WebCore/WebComponent/Model/ComponentDictionary.cs
similarity index 60%
rename from src/WebExpress.WebCore/WebComponent/ComponentDictionary.cs
rename to src/WebExpress.WebCore/WebComponent/Model/ComponentDictionary.cs
index 57ff804..d49fc29 100644
--- a/src/WebExpress.WebCore/WebComponent/ComponentDictionary.cs
+++ b/src/WebExpress.WebCore/WebComponent/Model/ComponentDictionary.cs
@@ -1,14 +1,14 @@
using System.Collections.Generic;
using WebExpress.WebCore.WebPlugin;
-namespace WebExpress.WebCore.WebComponent
+namespace WebExpress.WebCore.WebComponent.Model
{
///
/// Internal management of components.
/// key = plugin
/// value = component item
///
- public class ComponentDictionary : Dictionary>
+ internal class ComponentDictionary : Dictionary>
{
}
diff --git a/src/WebExpress.WebCore/WebComponent/ComponentItem.cs b/src/WebExpress.WebCore/WebComponent/Model/ComponentItem.cs
similarity index 66%
rename from src/WebExpress.WebCore/WebComponent/ComponentItem.cs
rename to src/WebExpress.WebCore/WebComponent/Model/ComponentItem.cs
index d46af63..a3df3b5 100644
--- a/src/WebExpress.WebCore/WebComponent/ComponentItem.cs
+++ b/src/WebExpress.WebCore/WebComponent/Model/ComponentItem.cs
@@ -1,7 +1,10 @@
using System;
-namespace WebExpress.WebCore.WebComponent
+namespace WebExpress.WebCore.WebComponent.Model
{
+ ///
+ /// Represents an item of a web component, including its class type, ID, and instance.
+ ///
public class ComponentItem
{
///
@@ -17,10 +20,10 @@ public class ComponentItem
///
/// Returns the component instance or null if not already created.
///
- public IComponent ComponentInstance { get; internal set; }
+ public IComponentManager ComponentInstance { get; internal set; }
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
internal ComponentItem()
{
diff --git a/src/WebExpress.WebCore/WebEndpoint/EndpointManager.cs b/src/WebExpress.WebCore/WebEndpoint/EndpointManager.cs
new file mode 100644
index 0000000..a87b971
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/EndpointManager.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAttribute;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebIcon;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebUri;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// The endpoint manager manages WebExpress elements, which can be called with a URI (Uniform Resource Identifier).
+ ///
+ public sealed class EndpointManager : IEndpointManager, ISystemComponent
+ {
+ private static readonly string[] _namespacePrefixes = ["page", "pages", "webpage", "webpages", "website", "www", "web"];
+ private static readonly string _indexPrefix = "index";
+ private static readonly string[] _classSuffixes = ["page"];
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly Dictionary _registrations = [];
+
+ ///
+ /// An event that fires when an endpoint is added.
+ ///
+ public event EventHandler AddEndpoint;
+
+ ///
+ /// An event that fires when an endpoint is removed.
+ ///
+ public event EventHandler RemoveEndpoint;
+
+ ///
+ /// Returns all endpoints contexts.
+ ///
+ public IEnumerable Endpoints => _registrations.Values.SelectMany(x => x.EndpointsResolver());
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The component hub.
+ /// The reference to the context of the host.
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used via Reflection.")]
+ private EndpointManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
+ {
+ //_componentHub = componentHub;
+
+ _httpServerContext = httpServerContext;
+
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate("webexpress.webcore:endpointmanager.initialization")
+ );
+ }
+
+ ///
+ /// Registers an endpoint context type.
+ ///
+ /// The type of the endpoint context.
+ /// The registration details containing the callback functions.
+ public void Register(EndpointRegistration endpointRegistration) where TEndpointContext : IEndpointContext
+ {
+ var type = typeof(TEndpointContext);
+ if (!_registrations.ContainsKey(type))
+ {
+ _registrations[type] = endpointRegistration;
+
+ endpointRegistration.AddEndpoint += OnAddEndpoint;
+ endpointRegistration.RemoveEndpoint += OnRemoveEndpoint;
+ }
+ }
+
+ ///
+ /// Removes the registration for a specific endpoint context type.
+ ///
+ /// The type of the endpoint context.
+ public void Remove() where TEndpointContext : IEndpointContext
+ {
+ var type = typeof(TEndpointContext);
+ _registrations.Remove(type, out var endpointRegistration);
+
+ endpointRegistration.AddEndpoint -= OnAddEndpoint;
+ endpointRegistration.RemoveEndpoint -= OnRemoveEndpoint;
+ }
+
+ ///
+ /// Returns an enumeration of endpoint contexts.
+ ///
+ /// The endpoint type.
+ /// The application context.
+ /// An enumeration of endpoint contexts.
+ public IEnumerable GetEndpoints(Type endpointType, IApplicationContext applicationContext = null)
+ {
+ if (endpointType == null)
+ {
+ return [];
+ }
+
+ return _registrations.SelectMany(x => x.Value.EndpointResolver(endpointType, applicationContext));
+ }
+
+ ///
+ /// Handles a request and returns a response.
+ ///
+ /// The request to handle.
+ /// The context of the endpoint handling the request.
+ /// The response generated by the endpoint.
+ public Response HandleRequest(Request request, IEndpointContext endpointContext)
+ {
+ var registration = _registrations
+ .Where(x => x.Key == endpointContext?.GetType())
+ .Select(x => x.Value)
+ .FirstOrDefault();
+
+ return registration?.HandleRequest(request, endpointContext);
+ }
+
+ ///
+ /// Raises the event when an endpoint is added.
+ ///
+ /// The source of the event.
+ /// The context of the endpoint being added.
+ private void OnAddEndpoint(object sender, IEndpointContext endpointContext)
+ {
+ AddEndpoint?.Invoke(sender, endpointContext);
+ }
+
+ ///
+ /// Raises the event when an endpoint is removed.
+ ///
+ /// The source of the event.
+ /// The context of the endpoint being removed.
+ private void OnRemoveEndpoint(object sender, IEndpointContext endpointContext)
+ {
+ RemoveEndpoint?.Invoke(sender, endpointContext);
+ }
+
+ ///
+ /// Release of unmanaged resources reserved during use.
+ ///
+ public void Dispose()
+ {
+ }
+
+ ///
+ /// Returns the route of an endpoint based on the class type, application context and segment attributes.
+ ///
+ /// The type of the class.
+ /// The application context route.
+ /// The segment attribute.
+ /// The intermediate segments.
+ /// The namespace prefixes.
+ /// The route of the endpoint.
+ public static IRoute CreateEndpointRoute
+ (
+ Type classType,
+ IRoute contextRoute,
+ ISegmentAttribute segment,
+ IEnumerable intermediateSegments = null,
+ string[] namespacePrefixes = null
+ )
+ {
+ var assemblyName = classType.Assembly.GetName().Name;
+ var fullClassName = classType.FullName;
+ var className = _classSuffixes?.FirstOrDefault(s => classType.Name.ToLowerInvariant().EndsWith(s, StringComparison.OrdinalIgnoreCase)) is string suffix
+ ? classType.Name.ToLowerInvariant()[..^suffix.Length]
+ : classType.Name.ToLowerInvariant();
+ var segments = (fullClassName.Length - classType.Name.Length - 1 > assemblyName.Length)
+ ? fullClassName[(assemblyName.Length + 1)..^(classType.Name.Length + 1)].ToLowerInvariant().Split('.', StringSplitOptions.RemoveEmptyEntries)
+ : [];
+
+ var segmentMapping = segments.Select((segment, index) => new
+ {
+ FullNamespace = $"{assemblyName}.{string.Join(".", segments.Take(index + 1))}",
+ Segment = segment
+ });
+
+ var segmentAttributesMapping = segmentMapping.Select(s =>
+ {
+ var segmentResult = default(IUriPathSegment);
+ var name = default(string);
+ var description = default(string);
+ var icon = default(IIcon);
+
+ var typeName = $"{s.FullNamespace}.Index";
+ var segmentInfoType = classType.Assembly.GetType(typeName, throwOnError: false, ignoreCase: true);
+
+ if (segmentInfoType != null)
+ {
+ var segAttrType = segmentInfoType.CustomAttributes
+ .Where(x => x.AttributeType.GetInterfaces().Contains(typeof(ISegmentAttribute)))
+ .Select(x => x.AttributeType)
+ .FirstOrDefault();
+
+ var segInstance = segAttrType != null
+ ? segmentInfoType.GetCustomAttribute(segAttrType, false) as ISegmentAttribute
+ : null;
+ var nameAttr = segmentInfoType.CustomAttributes
+ .FirstOrDefault(x => x.AttributeType == typeof(TitleAttribute));
+ var descAttr = segmentInfoType.CustomAttributes
+ .FirstOrDefault(x => x.AttributeType == typeof(DescriptionAttribute));
+ var iconAttr = segmentInfoType.CustomAttributes
+ .FirstOrDefault(x => x.AttributeType.IsGenericType &&
+ x.AttributeType.GetGenericTypeDefinition() == typeof(WebIconAttribute<>));
+
+ segmentResult = segInstance?.ToPathSegment();
+ name = nameAttr?.ConstructorArguments.FirstOrDefault().Value?.ToString();
+ description = descAttr?.ConstructorArguments.FirstOrDefault().Value?.ToString();
+ icon = iconAttr != null
+ ? Activator.CreateInstance(iconAttr.AttributeType.GenericTypeArguments.FirstOrDefault()) as IIcon
+ : null;
+ }
+
+ return new
+ {
+ Segment = segmentResult ?? new UriPathSegmentConstant(s.Segment),
+ Name = name,
+ Description = description,
+ Icon = icon
+ };
+ });
+
+ segmentAttributesMapping = segmentAttributesMapping.Any() && _namespacePrefixes
+ .Contains(segmentAttributesMapping
+ .First().Segment
+ .ToString())
+ ? segmentAttributesMapping.Skip(1)
+ : segmentAttributesMapping;
+
+ segmentAttributesMapping = segmentAttributesMapping.Any() && (namespacePrefixes ?? [])
+ .Contains(segmentAttributesMapping
+ .First().Segment
+ .ToString())
+ ? segmentAttributesMapping.Skip(1)
+ : segmentAttributesMapping;
+
+ var endpointRoute = (intermediateSegments ?? [])
+ .Concat(segmentAttributesMapping.Where(x => !x.Segment.IsEmpty).Select(x => x.Segment));
+
+ var classSegment = !className.StartsWith(_indexPrefix)
+ ? segment?.ToPathSegment() ?? new UriPathSegmentConstant(className)
+ : null;
+ var uri = RouteEndpoint.Combine(contextRoute, endpointRoute)
+ .Concat(classSegment);
+
+ return uri;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/EndpointRegistration.cs b/src/WebExpress.WebCore/WebEndpoint/EndpointRegistration.cs
new file mode 100644
index 0000000..72b82b6
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/EndpointRegistration.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// Contains the registration details for an endpoint, including factory and resolver functions.
+ ///
+ public class EndpointRegistration
+ {
+ ///
+ /// Stores the event handler for adding an endpoint.
+ ///
+ public EventHandler AddEndpoint { get; set; }
+
+ ///
+ /// Stores the event handler for removing an endpoint.
+ ///
+ public EventHandler RemoveEndpoint { get; set; }
+
+ ///
+ /// Returns or sets the context resolver function to resolve the corresponding endpoint contexts.
+ ///
+ public Func> EndpointResolver { get; set; }
+
+ ///
+ /// Returns or sets the endpoint resolver function to resolve additional endpoint contexts.
+ ///
+ public Func> EndpointsResolver { get; set; }
+
+ ///
+ /// Returns or sets the function to handle requests.
+ ///
+ public Func HandleRequest { get; set; }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/IEndpoint.cs b/src/WebExpress.WebCore/WebEndpoint/IEndpoint.cs
new file mode 100644
index 0000000..8db24c3
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/IEndpoint.cs
@@ -0,0 +1,11 @@
+using WebExpress.WebCore.WebComponent;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// Defines the base contract for resources of all kinds, such as REST APIs or Pages.
+ ///
+ public interface IEndpoint : IComponent
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/IEndpointContext.cs b/src/WebExpress.WebCore/WebEndpoint/IEndpointContext.cs
new file mode 100644
index 0000000..0a37b8f
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/IEndpointContext.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// Represents the context of a endpoint.
+ ///
+ public interface IEndpointContext : IContext
+ {
+ ///
+ /// Returns the endpoint id.
+ ///
+ IComponentId EndpointId { get; }
+
+ ///
+ /// Returns the associated plugin context.
+ ///
+ IPluginContext PluginContext { get; }
+
+ ///
+ /// Returns the corresponding application context.
+ ///
+ IApplicationContext ApplicationContext { get; }
+
+ ///
+ /// Provides the conditions that must be met for the resource to be active.
+ ///
+ IEnumerable Conditions { get; }
+
+ ///
+ /// Determines whether the resource is created once and reused each time it is called.
+ ///
+ bool Cache { get; }
+
+ ///
+ /// Returns or sets whether all subpaths should be taken into sitemap.
+ ///
+ bool IncludeSubPaths { get; }
+
+ ///
+ /// Returns the internal routing path for the endpoint.
+ ///
+ IRoute Route { get; }
+
+ ///
+ /// Returns the attributes associated with the page.
+ ///
+ IEnumerable Attributes { get; }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/IEndpointManager.cs b/src/WebExpress.WebCore/WebEndpoint/IEndpointManager.cs
new file mode 100644
index 0000000..bf11c67
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/IEndpointManager.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// Represents a endpoint manager.
+ ///
+ public interface IEndpointManager : IComponentManager
+ {
+ ///
+ /// Returns all endpoints contexts.
+ ///
+ IEnumerable Endpoints { get; }
+
+ ///
+ /// Registers an endpoint context type.
+ ///
+ /// The type of the endpoint context.
+ /// The registration details containing the callback functions.
+ void Register(EndpointRegistration registration) where T : IEndpointContext;
+
+ ///
+ /// Removes the registration for a specific endpoint context type.
+ ///
+ /// The type of the endpoint context.
+ void Remove() where T : IEndpointContext;
+
+ ///
+ /// Returns an enumeration of endpoint contexts.
+ ///
+ /// The endpoint type.
+ /// The application context.
+ /// An enumeration of endpoint contexts.
+ IEnumerable GetEndpoints(Type endpointType, IApplicationContext applicationContext = null);
+
+ /////
+ ///// Creates a new instance or if caching is active, a possibly existing instance is returned.
+ /////
+ ///// The endpoint context.
+ ///// The uri.
+ ///// The search context.
+ ///// The created endpoint.
+ //IEndpoint CreateEndpoint(IEndpointContext endpointContext, UriResource uri, SearchContext searchContext);
+
+ ///
+ /// Handles a request and returns a response.
+ ///
+ /// The request to handle.
+ /// The context of the endpoint handling the request.
+ /// The response generated by the endpoint.
+ Response HandleRequest(Request request, IEndpointContext endpointContext);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/IRoute.cs b/src/WebExpress.WebCore/WebEndpoint/IRoute.cs
new file mode 100644
index 0000000..39f8929
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/IRoute.cs
@@ -0,0 +1,63 @@
+using System.Collections.Generic;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebUri;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// A route in WebExpress represents a logical internal path or pattern used to map endpoints within the sitemap.
+ ///
+ /// While a URI (Uniform Resource Identifier) defines the complete, standardized external identifier of a resource
+ /// (e.g., http://example.com/path?query=value#fragment) and thus represents the external address of an endpoint,
+ /// a route represents the internal address of an endpoint that is used exclusively for internal purposes such as routing
+ /// and request processing.
+ ///
+ /// A route contains neither a scheme, nor an authority, nor other external components. Furthermore, it may include
+ /// placeholders for dynamic segments (e.g., /users/{id}).
+ ///
+ public interface IRoute
+ {
+ ///
+ /// The segments of the route (e.g., /over/there).
+ ///
+ IEnumerable PathSegments { get; }
+
+ ///
+ /// Returns a string representation of the route.
+ ///
+ string Display { get; }
+
+ ///
+ /// Determines if the route is the root.
+ ///
+ bool IsRoot { get; }
+
+ ///
+ /// Concatenates the given path segment to the current route and returns a new instance of IRoute with the updated path.
+ ///
+ /// The path segment to be concatenated with the existing route.
+ /// A new IRoute instance representing the route after concatenation.
+ IRoute Concat(string segment);
+
+ ///
+ /// Concatenates the given path segment to the current route and returns a new instance of IRoute with the updated path.
+ ///
+ /// An array of path segments to be concatenated to the existing route.
+ /// A new IRoute instance representing the route after concatenation.
+ IRoute Concat(params IUriPathSegment[] segments);
+
+ ///
+ /// Removes a specified segment from the route and returns a new instance of IRoute with the updated path.
+ ///
+ /// The path segment to be removed from the existing route.
+ /// A new IRoute instance representing the route after the segment removal.
+ IRoute RemoveSegment(string segments);
+
+ ///
+ /// Converts the route to a URI.
+ ///
+ /// The parameters to be included in the URI.
+ /// An instance of IUri representing the route as a URI.
+ IUri ToUri(params Parameter[] parameters);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEndpoint/RouteEndpoint.cs b/src/WebExpress.WebCore/WebEndpoint/RouteEndpoint.cs
new file mode 100644
index 0000000..9666f69
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEndpoint/RouteEndpoint.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.WebMessage;
+using WebExpress.WebCore.WebUri;
+
+namespace WebExpress.WebCore.WebEndpoint
+{
+ ///
+ /// A route in WebExpress represents a logical internal path or pattern used to map endpoints within the sitemap.
+ ///
+ /// While a URI (Uniform Resource Identifier) defines the complete, standardized external identifier of a resource
+ /// (e.g., http://example.com/path?query=value#fragment) and thus represents the external address of an endpoint,
+ /// a route represents the internal address of an endpoint that is used exclusively for internal purposes such as routing
+ /// and request processing.
+ ///
+ /// A route contains neither a scheme, nor an authority, nor other external components. Furthermore, it may include
+ /// placeholders for dynamic segments (e.g., /users/{id}).
+ ///
+ public partial class RouteEndpoint : IRoute
+ {
+ ///
+ /// The segments of the route (e.g., /over/there).
+ ///
+ public IEnumerable PathSegments { get; private set; } = [new UriPathSegmentRoot()];
+
+ ///
+ /// Returns a string representation of the route.
+ ///
+ public string Display { get; set; }
+
+ ///
+ /// Determines if the route is the root.
+ ///
+ public bool IsRoot => PathSegments.Count() == 1;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RouteEndpoint()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The scheme (e.g. Http, FTP).
+ /// The authority (e.g. user@example.com:8080).
+ /// The uri.
+ public RouteEndpoint(UriScheme scheme, UriAuthority authority, string uri)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The route.
+ public RouteEndpoint(string route)
+ {
+ if (string.IsNullOrWhiteSpace(route) || route == "/") return;
+
+ PathSegments = PathSegments
+ .Concat(route.Split('/', StringSplitOptions.RemoveEmptyEntries)
+ .Select(x => new UriPathSegmentConstant(x)));
+ }
+
+ ///
+ /// Copy constructor
+ ///
+ /// The route.
+ public RouteEndpoint(IRoute route)
+ {
+ PathSegments = route?.PathSegments.Select(x => x.Copy()) ?? [];
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The path segments.
+ public RouteEndpoint(params IUriPathSegment[] segments)
+ {
+ if (segments.Length > 0)
+ {
+ PathSegments = PathSegments
+ .Concat(segments.Where(x => !x.IsEmpty).Select(x => x.Copy()));
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The base route.
+ /// The path segments.
+ public RouteEndpoint(IRoute route, params string[] segments)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The base route.
+ /// The path segments.
+ public RouteEndpoint(IRoute route, params IUriPathSegment[] segments)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The route.
+ /// The path segments.
+ /// Other segments.
+ public RouteEndpoint(IRoute route, IEnumerable segments, IEnumerable extendedSegments)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The scheme (e.g. Http, FTP).
+ /// The authority (e.g. user@example.com:8080).
+ /// References a position within a resource (e.g. #Anchor).
+ /// The query part (e.g. ?title=Uniform_Resource_Identifier).
+ /// The path segments.
+ public RouteEndpoint(UriScheme scheme, UriAuthority authority, string fragment, IEnumerable query, IEnumerable segments)
+ {
+ }
+
+ ///
+ /// Concatenates the given path segment to the current route and returns a new instance of IRoute with the updated path.
+ ///
+ /// The path segment to be concatenated with the existing route.
+ /// A new IRoute instance representing the route after concatenation.
+ public IRoute Concat(string segment)
+ {
+ if (string.IsNullOrWhiteSpace(segment))
+ {
+ return this;
+ }
+
+ var copy = new RouteEndpoint((IRoute)this);
+ copy.PathSegments = copy.PathSegments
+ .Concat(segment.Split('/', StringSplitOptions.RemoveEmptyEntries)
+ .Select(x => new UriPathSegmentConstant(x)));
+
+ return copy;
+ }
+
+ ///
+ /// Concatenates the given path segment to the current route and returns a new instance of IRoute with the updated path.
+ ///
+ /// An array of path segments to be concatenated to the existing route.
+ /// A new IRoute instance representing the route after concatenation.
+ public virtual IRoute Concat(params IUriPathSegment[] segments)
+ {
+ if (segments == null || segments.Length == 0)
+ {
+ return this;
+ }
+
+ var copy = new RouteEndpoint((IRoute)this);
+ copy.PathSegments = copy.PathSegments
+ .Select(x => x.Copy())
+ .Concat(segments.Where(x => x != null).Where(x => !x.IsEmpty));
+
+ return copy;
+ }
+
+ ///
+ /// Removes a specified segment from the route and returns a new instance of IRoute with the updated path.
+ ///
+ /// The path segment to be removed from the existing route.
+ /// A new IRoute instance representing the route after the segment removal.
+ public virtual IRoute RemoveSegment(string segments)
+ {
+ if (string.IsNullOrWhiteSpace(segments) || !ToString().Contains(segments))
+ {
+ return this;
+ }
+
+ var segmentParts = segments.Split('/', StringSplitOptions.RemoveEmptyEntries);
+ var copy = new RouteEndpoint((IRoute)this);
+
+ copy.PathSegments = copy.PathSegments
+ .Where(x => !segmentParts.Contains(x.Value))
+ .Select(x => x.Copy());
+
+ return copy;
+ }
+
+ ///
+ /// Converts the route to a URI.
+ ///
+ /// The parameters to be included in the URI.
+ /// An instance of IUri representing the route as a URI.
+ public IUri ToUri(params Parameter[] parameters)
+ {
+ return new UriEndpoint(this).SetParameters(parameters);
+ }
+
+ ///
+ /// Combines the specified routes into a compound route.
+ ///
+ /// The routes to be combine.
+ /// A combined route.
+ public static RouteEndpoint Combine(params IRoute[] routes)
+ {
+ var r = routes.Skip(1).Where(x => !x.IsRoot).SelectMany(x => x.PathSegments.Skip(1));
+ var copy = new RouteEndpoint(routes.FirstOrDefault());
+ copy.PathSegments = copy.PathSegments
+ .Concat(r);
+
+ return copy;
+ }
+
+ ///
+ /// Combines the specified routes into a compound uri.
+ ///
+ /// The base route to be used as the starting point.
+ /// The routes to be combine.
+ /// A combined route.
+ public static RouteEndpoint Combine(IRoute baseRoute, params string[] routes)
+ {
+ var copy = new RouteEndpoint(baseRoute);
+ copy.PathSegments = copy.PathSegments
+ .Concat(routes.Where
+ (
+ x => !string.IsNullOrWhiteSpace(x))
+ .SelectMany(x => x.Split('/', StringSplitOptions.RemoveEmptyEntries)
+ )
+ .Select(x => new UriPathSegmentConstant(x) as IUriPathSegment));
+
+ return copy;
+ }
+
+ ///
+ /// Combines the specified base route, intermediate route, and enumerable segments into a compound route.
+ ///
+ /// The base route serving as the starting point.
+ /// The enumerable collection of path segments to be added.
+ /// A new compound route combining all specified components.
+ public static RouteEndpoint Combine(IRoute baseRoute, IEnumerable segments)
+ {
+ var copy = new RouteEndpoint(baseRoute);
+ copy.PathSegments = copy.PathSegments
+ .Concat(segments);
+
+ return copy;
+ }
+
+ ///
+ /// Combines the specified base route, intermediate route, and enumerable segments into a compound route.
+ ///
+ /// The base route serving as the starting point.
+ /// The path segment(s) to be added.
+ /// A new compound route combining all specified components.
+ public static RouteEndpoint Combine(IRoute baseRoute, string segments)
+ {
+ var copy = new RouteEndpoint(baseRoute);
+ copy.PathSegments = copy.PathSegments
+ .Concat
+ (
+ segments?.Split('/', StringSplitOptions.RemoveEmptyEntries)
+ ?.Select(x => new UriPathSegmentConstant(x)) ?? []
+ );
+
+ return copy;
+ }
+
+ ///
+ /// Converts a route to a string.
+ ///
+ /// The uri to convert.
+ public static implicit operator string(RouteEndpoint route)
+ {
+ return route?.ToString();
+ }
+
+ ///
+ /// Converts the route to a string.
+ ///
+ /// A string that represents the current route.
+ public override string ToString()
+ {
+ var path = "/" + string.Join
+ (
+ "/",
+ PathSegments.Where(x => x is not UriPathSegmentRoot)
+ .Select(x => x.ToString().TrimStart('/'))
+ );
+
+ return path?.TrimEnd('/');
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WebExpress.WebCore/WebEvent/EventDictionary.cs b/src/WebExpress.WebCore/WebEvent/EventDictionary.cs
deleted file mode 100644
index a6bf724..0000000
--- a/src/WebExpress.WebCore/WebEvent/EventDictionary.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Collections.Generic;
-using WebExpress.WebCore.WebEvent;
-using WebExpress.WebCore.WebPlugin;
-
-namespace WebExpress.WebCore.WebJob
-{
- ///
- /// key = plugin context
- /// value = ressource items
- ///
- internal class EventDictionary : Dictionary>
- {
- }
-}
diff --git a/src/WebExpress.WebCore/WebEvent/EventHandlerContext.cs b/src/WebExpress.WebCore/WebEvent/EventHandlerContext.cs
new file mode 100644
index 0000000..9191a50
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/EventHandlerContext.cs
@@ -0,0 +1,41 @@
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebEvent
+{
+ ///
+ /// Represents the context of an event.
+ ///
+ public class EventHandlerContext : IEventHandlerContext
+ {
+ ///
+ /// Returns the event id.
+ ///
+ public IComponentId EventId { get; internal set; }
+
+ ///
+ /// Returns the event handler id.
+ ///
+ public string EventHandlerId { get; internal set; }
+
+ ///
+ /// Returns the associated plugin context.
+ ///
+ public IPluginContext PluginContext { get; internal set; }
+
+ ///
+ /// Returns the corresponding application context.
+ ///
+ public IApplicationContext ApplicationContext { get; internal set; }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// A string that represents the current object.
+ public override string ToString()
+ {
+ return $"Event: {EventId}";
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEvent/EventManager.cs b/src/WebExpress.WebCore/WebEvent/EventManager.cs
index 80a0965..04d6b87 100644
--- a/src/WebExpress.WebCore/WebEvent/EventManager.cs
+++ b/src/WebExpress.WebCore/WebEvent/EventManager.cs
@@ -1,9 +1,13 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAttribute;
using WebExpress.WebCore.WebComponent;
-using WebExpress.WebCore.WebJob;
-using WebExpress.WebCore.WebModule;
+using WebExpress.WebCore.WebEvent.Model;
+using WebExpress.WebCore.WebLog;
using WebExpress.WebCore.WebPlugin;
namespace WebExpress.WebCore.WebEvent
@@ -11,66 +15,137 @@ namespace WebExpress.WebCore.WebEvent
///
/// The event manager.
///
- public sealed class EventManager : IComponentPlugin, ISystemComponent
+ public sealed class EventManager : IEventManager, ISystemComponent
{
+ private readonly IComponentHub _componentHub;
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly EventDictionary _dictionary = [];
+
+ ///
+ /// An event that fires when an event handler is added.
+ ///
+ public event EventHandler AddEventHandler;
+
///
- /// Returns or sets the reference to the context of the host.
+ /// An event that fires when an event handler is removed.
///
- public IHttpServerContext HttpServerContext { get; private set; }
+ public event EventHandler RemoveEventHandler;
///
- /// Returns the directory where the events are listed.
+ /// Returns the collection of events.
///
- private EventDictionary Dictionary { get; } = new EventDictionary();
+ public IEnumerable EventHandlers => _dictionary.Values
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x)
+ .Select(x => x.EventHandlerContext);
///
- /// Constructor
+ /// Initializes a new instance of the class.
///
- internal EventManager()
+ /// The component hub.
+ /// The reference to the context of the host.
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used via Reflection.")]
+ private EventManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
{
- ComponentManager.PluginManager.AddPlugin += (sender, pluginContext) =>
- {
- Register(pluginContext);
- };
+ _componentHub = componentHub;
- ComponentManager.PluginManager.RemovePlugin += (sender, pluginContext) =>
- {
- Remove(pluginContext);
- };
+ _componentHub.PluginManager.AddPlugin += OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin += OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication += OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication += OnRemoveApplication;
+
+ _httpServerContext = httpServerContext;
- ComponentManager.ModuleManager.AddModule += (sender, moduleContext) =>
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate
+ (
+ "webexpress.webcore:eventmanager.initialization"
+ )
+ );
+ }
+
+ ///
+ /// Returns the event handler contexts.
+ ///
+ /// The type of event.
+ /// The application context.
+ /// An IEnumerable of event handler contexts.
+ public IEnumerable GetEventHandlers(IApplicationContext applicationContext)
+ where TEvent : IEvent
+ {
+ return _dictionary.GetEventHandlerItems(applicationContext)
+ .Select(x => x.EventHandlerContext);
+ }
+
+ ///
+ /// Returns the event handler contexts.
+ ///
+ /// The application context.
+ /// The type of event.
+ /// An IEnumerable of event handler contexts.
+ public IEnumerable GetEventHandlers(IApplicationContext applicationContext, Type eventType)
+ {
+ return _dictionary.GetEventHandlerItems(applicationContext, eventType)
+ .Select(x => x.EventHandlerContext);
+ }
+
+ ///
+ /// Raises the specified event.
+ ///
+ /// The type of event.
+ /// The application context.
+ /// The sender object.
+ /// The event argument.
+ public void RaiseEvent(IApplicationContext applicationContext, object sender, IEventArgument argument)
+ where TEvent : IEvent
+ {
+ var eventHandlers = _dictionary.GetEventHandlerItems(applicationContext);
+
+ foreach (var eventHandler in eventHandlers)
{
- AssignToModule(moduleContext);
- };
+ eventHandler?.Process(sender, argument);
+ }
+ }
- ComponentManager.ModuleManager.RemoveModule += (sender, moduleContext) =>
+ ///
+ /// Discovers and binds jobs to an application.
+ ///
+ /// The context of the plugin whose jobs are to be associated.
+ private void Register(IPluginContext pluginContext)
+ {
+ if (_dictionary.ContainsKey(pluginContext))
{
- DetachFromModule(moduleContext);
- };
+ return;
+ }
+
+ Register(pluginContext, _componentHub.ApplicationManager.GetApplications(pluginContext));
}
///
- /// Initialization
+ /// Discovers and binds jobs to an application.
///
- /// The reference to the context of the host.
- public void Initialization(IHttpServerContext context)
+ /// The context of the application whose jobs are to be associated.
+ private void Register(IApplicationContext applicationContext)
{
- HttpServerContext = context;
+ foreach (var pluginContext in _componentHub.PluginManager.GetPlugins(applicationContext))
+ {
+ if (_dictionary.TryGetValue(pluginContext, out var appDict) && appDict.ContainsKey(applicationContext))
+ {
+ continue;
+ }
- HttpServerContext.Log.Debug
- (
- InternationalizationManager.I18N
- (
- "webexpress:eventmanager.initialization"
- )
- );
+ Register(pluginContext, [applicationContext]);
+ }
}
///
- /// Discovers and registers event handlers from the specified plugin.
+ /// Registers resources for a given plugin and application context.
///
- /// A context of a plugin whose event handlers are to be registered.
- public void Register(IPluginContext pluginContext)
+ /// The plugin context.
+ /// The application context (optional).
+ private void Register(IPluginContext pluginContext, IEnumerable applicationContexts)
{
var assembly = pluginContext?.Assembly;
@@ -79,96 +154,228 @@ public void Register(IPluginContext pluginContext)
x => x.IsClass == true &&
x.IsSealed &&
x.IsPublic &&
- x.GetInterface(typeof(IEventHandler).Name) != null
+ (
+ x.GetInterface(typeof(IEventHandler).Name) != null ||
+ x.GetInterface(typeof(IEventHandler<>).Name) != null
+ )
))
{
+ var id = eventHandlerType.FullName?.ToLower();
+ var eventType = default(Type);
+
+ foreach (var customAttribute in eventHandlerType.CustomAttributes
+ .Where(x => x.AttributeType.GetInterfaces().Contains(typeof(IEventAttribute))))
+ {
+ if (customAttribute.AttributeType.Name == typeof(EventAttribute<>).Name && customAttribute.AttributeType.Namespace == typeof(EventAttribute<>).Namespace)
+ {
+ eventType = customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault();
+ }
+ }
+ if (eventType == default)
+ {
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate
+ (
+ "webexpress.webcore:eventmanager.eventless",
+ id
+ )
+ );
+
+ break;
+ }
+
+ // assign the event to existing applications
+ foreach (var applicationContext in applicationContexts)
+ {
+ var eventHandlerContext = new EventHandlerContext()
+ {
+ EventId = new ComponentId(eventType.FullName),
+ EventHandlerId = id,
+ PluginContext = pluginContext,
+ ApplicationContext = applicationContext
+ };
+
+ if (_dictionary.AddEventItem
+ (
+ pluginContext,
+ applicationContext,
+ new EventItem(_componentHub, _httpServerContext, pluginContext, applicationContext, eventHandlerContext, eventHandlerType, eventType)
+ ))
+ {
+ OnAddEventHandler(eventHandlerContext);
+
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate
+ (
+ "webexpress.webcore:eventmanager.register",
+ id,
+ applicationContext.ApplicationId
+ )
+ );
+ }
+ else
+ {
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate
+ (
+ "webexpress.webcore:eventmanager.duplicate",
+ id,
+ applicationContext.ApplicationId
+ )
+ );
+ }
+ }
+ }
+
+ Log();
+ }
+
+ ///
+ /// Removes all events associated with the specified plugin context.
+ ///
+ /// The context of the plugin that contains the events to remove.
+ internal void Remove(IPluginContext pluginContext)
+ {
+ // the plugin has not been registered in the manager
+ if (_dictionary.TryGetValue(pluginContext, out var value))
+ {
+ foreach (var eventHandlerItem in value
+ .SelectMany(x => x.Value)
+ .SelectMany(x => x.Value))
+ {
+ eventHandlerItem.Dispose();
+ }
+
+ _dictionary.Remove(pluginContext);
}
}
///
- /// Discovers and registers entries from the specified plugin.
+ /// Removes all events associated with the specified application context.
///
- /// A list with plugin contexts that contain the jobs.
- public void Register(IEnumerable pluginContexts)
+ /// The context of the application that contains the events to remove.
+ internal void Remove(IApplicationContext applicationContext)
{
- foreach (var pluginContext in pluginContexts)
+ if (applicationContext == null)
+ {
+ return;
+ }
+
+ foreach (var pluginDict in _dictionary.Values)
{
- Register(pluginContext);
+ foreach (var appDict in pluginDict.Where(x => x.Key == applicationContext).Select(x => x.Value))
+ {
+ foreach (var eventHandlerItem in appDict.Values.SelectMany(x => x))
+ {
+ OnRemoveEventHandler(eventHandlerItem.EventHandlerContext);
+ eventHandlerItem.Dispose();
+ }
+ }
+
+ pluginDict.Remove(applicationContext);
}
}
///
- /// Assign existing event to the module.
+ /// Raises the AddEventHandler event.
+ ///
+ /// The event handler context.
+ private void OnAddEventHandler(IEventHandlerContext eventHandlerContext)
+ {
+ AddEventHandler?.Invoke(this, eventHandlerContext);
+ }
+
+ ///
+ /// Raises the RemoveEventHandler event.
///
- /// The context of the module.
- private void AssignToModule(IModuleContext moduleContext)
+ /// The event handler context.
+ private void OnRemoveEventHandler(IEventHandlerContext eventHandlerContext)
{
- //foreach (var scheduleItem in Dictionary.Values.SelectMany(x => x))
- //{
- // if (scheduleItem.moduleId.Equals(moduleContext?.ModuleId))
- // {
- // scheduleItem.AddModule(moduleContext);
- // }
- //}
+ RemoveEventHandler?.Invoke(this, eventHandlerContext);
}
///
- /// Remove an existing modules to the event.
+ /// Raises the event when an plugin is added.
///
- /// The context of the module.
- private void DetachFromModule(IModuleContext moduleContext)
+ /// The source of the event.
+ /// The context of the plugin being added.
+ private void OnAddPlugin(object sender, IPluginContext e)
{
- //foreach (var scheduleItem in Dictionary.Values.SelectMany(x => x))
- //{
- // if (scheduleItem.moduleId.Equals(moduleContext?.ModuleId))
- // {
- // scheduleItem.DetachModule(moduleContext);
- // }
- //}
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when a plugin is removed.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being removed.
+ private void OnRemovePlugin(object sender, IPluginContext e)
+ {
+ Remove(e);
+ }
+
+ ///
+ /// Raises the event when an application is added.
+ ///
+ /// The source of the event.
+ /// The context of the application being added.
+ private void OnAddApplication(object sender, IApplicationContext e)
+ {
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when an application is removed.
+ ///
+ /// The source of the event.
+ /// The context of the application being removed.
+ private void OnRemoveApplication(object sender, IApplicationContext e)
+ {
+ Remove(e);
}
///
- /// Removes all jobs associated with the specified plugin context.
+ /// Information about the component is collected and prepared for output in the log.
///
- /// The context of the plugin that contains the event to remove.
- public void Remove(IPluginContext pluginContext)
+ private void Log()
{
- //// the plugin has not been registered in the manager
- //if (!Dictionary.ContainsKey(pluginContext))
- //{
- // return;
- //}
+ if (!EventHandlers.Any())
+ {
+ return;
+ }
- //foreach (var scheduleItem in Dictionary[pluginContext])
- //{
- // scheduleItem.Dispose();
- //}
+ using var frame = new LogFrameSimple(_httpServerContext.Log);
+ var list = new List
+ {
+ I18N.Translate("webexpress.webcore:eventmanager.titel")
+ };
- //Dictionary.Remove(pluginContext);
+ foreach (var eventHandlerContext in EventHandlers)
+ {
+ list.Add
+ (
+ I18N.Translate("webexpress.webcore:eventmanager.handler", eventHandlerContext.EventId, eventHandlerContext.ApplicationContext?.ApplicationId)
+ );
+ }
+
+ _httpServerContext.Log.Info(string.Join(Environment.NewLine, list));
}
///
- /// Information about the component is collected and prepared for output in the event.
+ /// Release of unmanaged resources reserved during use.
///
- /// The context of the plugin.
- /// A list of log entries.
- /// The shaft deep.
- public void PrepareForLog(IPluginContext pluginContext, IList output, int deep)
+ public void Dispose()
{
- //foreach (var scheduleItem in GetScheduleItems(pluginContext))
- //{
- // output.Add
- // (
- // string.Empty.PadRight(deep) +
- // InternationalizationManager.I18N
- // (
- // "webexpress:eventmanager.job",
- // scheduleItem.JobId,
- // scheduleItem.ModuleContext
- // )
- // );
- //}
+ _componentHub.PluginManager.AddPlugin -= OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin -= OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication -= OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication -= OnRemoveApplication;
+
+ GC.SuppressFinalize(this);
}
}
}
diff --git a/src/WebExpress.WebCore/WebEvent/IEvent.cs b/src/WebExpress.WebCore/WebEvent/IEvent.cs
new file mode 100644
index 0000000..26c48e4
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/IEvent.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebEvent
+{
+ ///
+ /// Represents an event.
+ ///
+ public interface IEvent
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEvent/IEventArgument.cs b/src/WebExpress.WebCore/WebEvent/IEventArgument.cs
new file mode 100644
index 0000000..bebc6a5
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/IEventArgument.cs
@@ -0,0 +1,9 @@
+namespace WebExpress.WebCore.WebEvent
+{
+ ///
+ /// Represents an argument for an event.
+ ///
+ public interface IEventArgument
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/WebExpress.WebCore/WebEvent/IEventContext.cs b/src/WebExpress.WebCore/WebEvent/IEventContext.cs
deleted file mode 100644
index 72f9f67..0000000
--- a/src/WebExpress.WebCore/WebEvent/IEventContext.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using WebExpress.WebCore.WebModule;
-using WebExpress.WebCore.WebPlugin;
-
-namespace WebExpress.WebCore.WebEvent
-{
- public interface IEventContext
- {
- ///
- /// Returns the associated plugin context.
- ///
- IPluginContext PluginContext { get; }
-
- ///
- /// Returns the corresponding module context.
- ///
- IModuleContext ModuleContext { get; }
- }
-}
diff --git a/src/WebExpress.WebCore/WebEvent/IEventHandler.cs b/src/WebExpress.WebCore/WebEvent/IEventHandler.cs
index 8dd298f..11b51ad 100644
--- a/src/WebExpress.WebCore/WebEvent/IEventHandler.cs
+++ b/src/WebExpress.WebCore/WebEvent/IEventHandler.cs
@@ -1,6 +1,30 @@
-namespace WebExpress.WebCore.WebEvent
+using WebExpress.WebCore.WebComponent;
+
+namespace WebExpress.WebCore.WebEvent
{
- public interface IEventHandler
+ ///
+ /// Represents an event handler.
+ ///
+ public interface IEventHandler : IComponent
{
+ ///
+ /// Process the event.
+ ///
+ /// The object that triggered the event.
+ /// The argument for the event.
+ void Process(object sender, IEventArgument eventArgument);
+ }
+
+ ///
+ /// Represents an event handler.
+ ///
+ public interface IEventHandler : IComponent where T : class, IEventArgument
+ {
+ ///
+ /// Process the event.
+ ///
+ /// The object that triggered the event.
+ /// The argument for the event.
+ void Process(object sender, T eventArgument);
}
}
diff --git a/src/WebExpress.WebCore/WebEvent/IEventHandlerContext.cs b/src/WebExpress.WebCore/WebEvent/IEventHandlerContext.cs
new file mode 100644
index 0000000..8f86628
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/IEventHandlerContext.cs
@@ -0,0 +1,32 @@
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebEvent
+{
+ ///
+ /// Represents the context of an event.
+ ///
+ public interface IEventHandlerContext : IContext
+ {
+ ///
+ /// Returns the event id.
+ ///
+ IComponentId EventId { get; }
+
+ ///
+ /// Returns the event handler id.
+ ///
+ string EventHandlerId { get; }
+
+ ///
+ /// Returns the associated plugin context.
+ ///
+ IPluginContext PluginContext { get; }
+
+ ///
+ /// Returns the corresponding application context.
+ ///
+ IApplicationContext ApplicationContext { get; }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEvent/IEventManager.cs b/src/WebExpress.WebCore/WebEvent/IEventManager.cs
new file mode 100644
index 0000000..d725df2
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/IEventManager.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+
+namespace WebExpress.WebCore.WebEvent
+{
+ ///
+ /// Represents the interface for managing web events.
+ ///
+ public interface IEventManager : IComponentManager
+ {
+ ///
+ /// Returns the collection of events.
+ ///
+ IEnumerable EventHandlers { get; }
+
+ ///
+ /// Returns the event handler contexts.
+ ///
+ /// The type of event.
+ /// The application context.
+ /// An IEnumerable of event handler contexts.
+ IEnumerable GetEventHandlers(IApplicationContext applicationContext)
+ where TEvent : IEvent;
+
+ ///
+ /// Returns the event handler contexts.
+ ///
+ /// The application context.
+ /// The type of event.
+ /// An IEnumerable of event handler contexts.
+ IEnumerable GetEventHandlers(IApplicationContext applicationContext, Type eventType);
+
+ ///
+ /// Raises the specified event.
+ ///
+ /// The type of event.
+ /// The application context.
+ /// The sender object.
+ /// The event argument.
+ void RaiseEvent(IApplicationContext applicationContext, object sender, IEventArgument argument)
+ where TEvent : IEvent;
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEvent/Model/EventDictionary.cs b/src/WebExpress.WebCore/WebEvent/Model/EventDictionary.cs
new file mode 100644
index 0000000..49c2412
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/Model/EventDictionary.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebEvent.Model
+{
+ ///
+ /// Represents a dictionary that provides a mapping from plugin contexts to dictionaries of application contexts and event handler.
+ ///
+ internal class EventDictionary : Dictionary>>>
+ {
+ ///
+ /// Adds a event item to the dictionary.
+ ///
+ /// The plugin context.
+ /// The application context.
+ /// The event item.
+ /// True if the event handler item was added successfully, false if an element with the same status code already exists.
+ public bool AddEventItem(IPluginContext pluginContext, IApplicationContext applicationContext, EventItem eventItem)
+ {
+ var type = eventItem.EventClass;
+
+ if (!typeof(IEvent).IsAssignableFrom(type))
+ {
+ return false;
+ }
+
+ if (!TryGetValue(pluginContext, out var appContextDict))
+ {
+ appContextDict = [];
+ this[pluginContext] = appContextDict;
+ }
+
+ if (!appContextDict.TryGetValue(applicationContext, out var eventDict))
+ {
+ eventDict = [];
+ appContextDict[applicationContext] = eventDict;
+ }
+
+ if (!eventDict.TryGetValue(type, out var eventList))
+ {
+ eventList = [];
+ eventDict[type] = eventList;
+ }
+
+ if (eventList.Any(x => x.EventClass == type))
+ {
+ return false; // item with the same event handler already exists
+ }
+
+ eventList.Add(eventItem);
+
+ return true;
+ }
+
+ ///
+ /// Removes a event from the dictionary.
+ ///
+ /// The plugin context.
+ /// The application context.
+ public void RemoveEventHandler(IPluginContext pluginContext, IApplicationContext applicationContext)
+ where TEvent : IEvent
+ {
+ var type = typeof(TEvent);
+
+ if (ContainsKey(pluginContext))
+ {
+ var appContextDict = this[pluginContext];
+
+ if (appContextDict.ContainsKey(applicationContext))
+ {
+ var eventDict = appContextDict[applicationContext];
+
+ if (eventDict.ContainsKey(type))
+ {
+ eventDict.Remove(type);
+
+ if (eventDict.Count == 0)
+ {
+ appContextDict.Remove(applicationContext);
+
+ if (appContextDict.Count == 0)
+ {
+ Remove(pluginContext);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Returns the event handler from the dictionary.
+ ///
+ /// The type of event.
+ /// The application context.
+ /// An IEnumerable of event items
+ public IEnumerable GetEventHandlerItems(IApplicationContext applicationContext)
+ where TEvent : IEvent
+ {
+ return GetEventHandlerItems(applicationContext, typeof(TEvent));
+ }
+
+ ///
+ /// Returns the event handler from the dictionary.
+ ///
+ /// The application context.
+ /// The type of event.
+ /// An IEnumerable of event items
+ public IEnumerable GetEventHandlerItems(IApplicationContext applicationContext, Type eventType)
+ {
+ if (!typeof(IEvent).IsAssignableFrom(eventType))
+ {
+ return [];
+ }
+
+ if (ContainsKey(applicationContext?.PluginContext))
+ {
+ var appContextDict = this[applicationContext?.PluginContext];
+
+ if (appContextDict.ContainsKey(applicationContext))
+ {
+ var eventDict = appContextDict[applicationContext];
+
+ if (eventDict.ContainsKey(eventType))
+ {
+ return eventDict[eventType];
+ }
+ }
+ }
+
+ return [];
+ }
+
+ ///
+ /// Returns all event handler contexts for a given plugin context.
+ ///
+ /// The plugin context.
+ /// An IEnumerable of event handler contexts.
+ public IEnumerable GetEventHandlers(IPluginContext pluginContext)
+ {
+ return this.Where(entry => entry.Key == pluginContext)
+ .SelectMany(entry => entry.Value.Values)
+ .SelectMany(dict => dict.Values)
+ .SelectMany(x => x)
+ .Select(x => x.EventHandlerContext);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEvent/Model/EventItem.cs b/src/WebExpress.WebCore/WebEvent/Model/EventItem.cs
new file mode 100644
index 0000000..16c78f1
--- /dev/null
+++ b/src/WebExpress.WebCore/WebEvent/Model/EventItem.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Linq;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebEvent.Model
+{
+ ///
+ /// Represents an event item.
+ /// This class is intended for internal use only.
+ ///
+ internal class EventItem : IDisposable
+ {
+ private readonly IComponentHub _componentHub;
+ private readonly IComponent _instance;
+
+ ///
+ /// Returns the associated plugin context.
+ ///
+ public IPluginContext PluginContext { get; private set; }
+
+ ///
+ /// Returns the corresponding application context.
+ ///
+ public IApplicationContext ApplicationContext { get; private set; }
+
+ ///
+ /// Returns or sets the event handler context.
+ ///
+ public IEventHandlerContext EventHandlerContext { get; private set; }
+
+ ///
+ /// Returns or sets the event class.
+ ///
+ public Type EventClass { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The associated component hub.
+ /// The reference to the context of the host.
+ /// The associated plugin context.
+ /// The corresponding application context.
+ /// The event handler context.
+ /// The event handler type.
+ /// The event class.
+ public EventItem(IComponentHub componentHub, IHttpServerContext httpServerContext, IPluginContext pluginContext, IApplicationContext applicationContext, IEventHandlerContext eventHandlerContext, Type eventHandlerType, Type eventClass)
+ {
+ _componentHub = componentHub;
+ PluginContext = pluginContext;
+ ApplicationContext = applicationContext;
+ EventHandlerContext = eventHandlerContext;
+ EventClass = eventClass;
+
+ if (typeof(IEventHandler).IsAssignableFrom(eventHandlerType))
+ {
+ _instance = ComponentActivator.CreateInstance
+ (
+ eventHandlerType,
+ eventHandlerContext,
+ httpServerContext,
+ _componentHub,
+ pluginContext,
+ applicationContext
+ );
+
+ return;
+ }
+
+ _instance = ComponentActivator.CreateInstance
+ (
+ eventHandlerType,
+ eventHandlerContext,
+ httpServerContext,
+ _componentHub,
+ pluginContext,
+ applicationContext
+ );
+ }
+
+ ///
+ /// Process the event.
+ ///
+ /// The object that triggered the event.
+ /// The argument for the event.
+ public void Process(object sender, IEventArgument eventArgument)
+ {
+ if (_instance is IEventHandler handler)
+ {
+ handler.Process(sender, eventArgument);
+
+ return;
+ }
+
+ var handlerType = _instance.GetType()
+ .GetInterfaces()
+ .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEventHandler<>));
+
+ if (handlerType != null)
+ {
+ var genericArgument = handlerType.GetGenericArguments().First();
+ var method = handlerType.GetMethod("Process");
+ method.Invoke(_instance, [sender, eventArgument]);
+ }
+ }
+
+ ///
+ /// Performs application-specific tasks related to sharing, returning, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ if (_instance is IDisposable disposable)
+ {
+ disposable.Dispose();
+ }
+ }
+
+ ///
+ /// Convert the resource element to a string.
+ ///
+ /// The event element in its string representation.
+ public override string ToString()
+ {
+ return $"Event: '{EventClass.FullName.ToLower()}'";
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebEx.cs b/src/WebExpress.WebCore/WebEx.cs
index cbf3106..5a7f82c 100644
--- a/src/WebExpress.WebCore/WebEx.cs
+++ b/src/WebExpress.WebCore/WebEx.cs
@@ -8,43 +8,36 @@
using WebExpress.WebCore.Config;
using WebExpress.WebCore.Internationalization;
using WebExpress.WebCore.WebComponent;
-using WebExpress.WebCore.WebUri;
+using WebExpress.WebCore.WebEndpoint;
+using WebExpress.WebCore.WebLog;
+using WebExpress.WebCore.WebPackage;
[assembly: InternalsVisibleTo("WebExpress.WebCore.Test")]
namespace WebExpress.WebCore
{
- public class WebEx
+ ///
+ /// The class provides a web server application for WebExpress.
+ ///
+ public sealed class WebEx
{
+ private static IComponentHub _componentHub;
+ private HttpServer _httpServer;
+
///
/// Returns or sets the name of the web server.
///
public string Name { get; set; } = "WebExpress";
- ///
- /// The http(s) server.
- ///
- private HttpServer HttpServer { get; set; }
-
///
/// Returns the program version.
///
public static string Version => Assembly.GetExecutingAssembly().GetName().Version.ToString();
///
- /// Entry point of application.
+ /// Returns the component hub.
///
- /// Call arguments.
- /// The return code. 0 on success. A number greater than 0 for errors.
- public static int Main(string[] args)
- {
- var app = new WebEx()
- {
- Name = Assembly.GetExecutingAssembly().GetName().Name
- };
-
- return app.Execution(args);
- }
+ public static IComponentHub ComponentHub => _componentHub;
///
/// Running the application.
@@ -103,7 +96,7 @@ public int Execution(string[] args)
return 1;
}
- WebPackage.PackageBuilder.Create(argumentDict["spec"], argumentDict["config"], argumentDict["target"], argumentDict["output"]);
+ PackageBuilder.Create(argumentDict["spec"], argumentDict["config"], argumentDict["target"], argumentDict["output"]);
return 0;
}
@@ -126,7 +119,7 @@ public int Execution(string[] args)
Initialization(ArgumentParser.Current.GetValidArguments(args), Path.Combine(Path.Combine(Environment.CurrentDirectory, "config"), argumentDict["config"]));
// start the manager
- ComponentManager.Execute();
+ (_componentHub as ComponentHub).Execute();
// starting the web server
Start();
@@ -151,7 +144,7 @@ private void OnCancel(object sender, ConsoleCancelEventArgs e)
/// Initialization
///
/// The valid arguments.
- /// The configuration file.
+ /// The configuration file.
private void Initialization(string args, string configFile)
{
// Config laden
@@ -190,46 +183,48 @@ private void Initialization(string args, string configFile)
var context = new HttpServerContext
(
- config.Uri,
+ new RouteEndpoint(config.Route),
config.Endpoints,
Path.GetFullPath(packageBase),
Path.GetFullPath(assetBase),
Path.GetFullPath(dataBase),
Path.GetDirectoryName(configFile),
- new UriResource(config.ContextPath),
+ new RouteEndpoint(config.ContextPath),
culture,
log,
null
);
- HttpServer = new HttpServer(context)
+ _httpServer = new HttpServer(context)
{
Config = config
};
+ _componentHub = ComponentActivator.CreateInstance(_httpServer.HttpServerContext);
+
// start logging
- HttpServer.HttpServerContext.Log.Begin(config.Log);
+ _httpServer.HttpServerContext.Log.Begin(config.Log);
// log program start
- HttpServer.HttpServerContext.Log.Seperator('/');
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.startup"));
- HttpServer.HttpServerContext.Log.Info(message: "".PadRight(80, '-'));
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.version"), args: Version);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.arguments"), args: args);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.workingdirectory"), args: Environment.CurrentDirectory);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.packagebase"), args: config.PackageBase);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.assetbase"), args: config.AssetBase);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.database"), args: config.DataBase);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.configurationdirectory"), args: Path.GetDirectoryName(configFile));
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.configuration"), args: Path.GetFileName(configFile));
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.logdirectory"), args: Path.GetDirectoryName(HttpServer.HttpServerContext.Log.Filename));
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.log"), args: Path.GetFileName(HttpServer.HttpServerContext.Log.Filename));
+ _httpServer.HttpServerContext.Log.Seperator('/');
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.startup"));
+ _httpServer.HttpServerContext.Log.Info(message: "".PadRight(80, '-'));
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.version"), args: Version);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.arguments"), args: args);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.workingdirectory"), args: Environment.CurrentDirectory);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.packagebase"), args: config.PackageBase);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.assetbase"), args: config.AssetBase);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.database"), args: config.DataBase);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.configurationdirectory"), args: Path.GetDirectoryName(configFile));
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.configuration"), args: Path.GetFileName(configFile));
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.logdirectory"), args: Path.GetDirectoryName(_httpServer.HttpServerContext.Log.Filename));
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.log"), args: Path.GetFileName(_httpServer.HttpServerContext.Log.Filename));
foreach (var v in config.Endpoints)
{
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.uri"), args: v.Uri);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.uri"), args: v.Uri);
}
- HttpServer.HttpServerContext.Log.Seperator('=');
+ _httpServer.HttpServerContext.Log.Seperator('=');
if (!Directory.Exists(config.PackageBase))
{
@@ -254,7 +249,7 @@ private void Initialization(string args, string configFile)
///
private void Start()
{
- HttpServer.Start();
+ _httpServer.Start();
Thread.CurrentThread.Join();
}
@@ -264,17 +259,40 @@ private void Start()
///
private void Exit()
{
- HttpServer.Stop();
+ _httpServer.Stop();
// end of program log
- HttpServer.HttpServerContext.Log.Seperator('=');
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.errors"), args: HttpServer.HttpServerContext.Log.ErrorCount);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.warnings"), args: HttpServer.HttpServerContext.Log.WarningCount);
- HttpServer.HttpServerContext.Log.Info(message: InternationalizationManager.I18N("webexpress:app.done"));
- HttpServer.HttpServerContext.Log.Seperator('/');
+ _httpServer.HttpServerContext.Log.Seperator('=');
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.errors"), args: _httpServer.HttpServerContext.Log.ErrorCount);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.warnings"), args: _httpServer.HttpServerContext.Log.WarningCount);
+ _httpServer.HttpServerContext.Log.Info(message: I18N.Translate("webexpress.webcore:app.done"));
+ _httpServer.HttpServerContext.Log.Seperator('/');
+
+ // Stop running
+ (_componentHub as ComponentHub).ShutDown();
// stop logging
- HttpServer.HttpServerContext.Log.Close();
+ _httpServer.HttpServerContext.Log.Close();
+ }
+
+ ///
+ /// Returns a component based on its id.
+ ///
+ /// The id.
+ /// The instance of the component or null.
+ public static IComponentManager GetComponent(string id)
+ {
+ return _componentHub.GetComponentManager(id);
+ }
+
+ ///
+ /// Returns a component based on its type.
+ ///
+ /// The component class.
+ /// The instance of the component or null.
+ public static T GetComponent() where T : IComponentManager
+ {
+ return _componentHub.GetComponentManager();
}
}
}
diff --git a/src/WebExpress.WebCore/WebExpress.WebCore.csproj b/src/WebExpress.WebCore/WebExpress.WebCore.csproj
index 52fc48c..95844d4 100644
--- a/src/WebExpress.WebCore/WebExpress.WebCore.csproj
+++ b/src/WebExpress.WebCore/WebExpress.WebCore.csproj
@@ -3,9 +3,9 @@
Library
WebExpress.WebCore
- 0.0.7.0
- 0.0.7.0
- net8.0
+ 0.0.8.0
+ 0.0.8.0
+ net9.0
any
https://github.com/ReneSchwarzer/WebExpress.git
Rene_Schwarzer@hotmail.de
@@ -14,7 +14,7 @@
true
True
Core library of the WebExpress web server.
- 0.0.7-alpha
+ 0.0.8-alpha
https://github.com/ReneSchwarzer/WebExpress
icon.png
README.md
@@ -22,6 +22,7 @@
webexpress
True
true
+ true
@@ -36,6 +37,7 @@
+
diff --git a/src/WebExpress.WebCore/WebFragment/FragmentComparer.cs b/src/WebExpress.WebCore/WebFragment/FragmentComparer.cs
new file mode 100644
index 0000000..2d627ff
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/FragmentComparer.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Provides a method to compare two objects of type T for equality.
+ ///
+ /// The type of objects to compare.
+ [Obsolete("FragmentComparer is obsolete. Use a different comparer implementation.")]
+ public class FragmentComparer : IEqualityComparer
+ {
+ ///
+ /// Tests for equality.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ /// True if both objects are similar; false otherwise.
+ public bool Equals(T x, T y)
+ {
+ if (x == null && y == null)
+ {
+ return true;
+ }
+ else if (x.GetType() == y.GetType())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Returns a hash code for the specified object.
+ ///
+ /// The object for which to return a hash code.
+ /// The hash code.
+ public int GetHashCode([DisallowNull] T obj)
+ {
+ return obj.GetType().GetHashCode();
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/FragmentConditionExtentsion.cs b/src/WebExpress.WebCore/WebFragment/FragmentConditionExtentsion.cs
new file mode 100644
index 0000000..e8085db
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/FragmentConditionExtentsion.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebMessage;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Provides extension methods for checking conditions.
+ ///
+ public static class FragmentConditionExtentsion
+ {
+ ///
+ /// Checks if all conditions in the collection are fulfilled for the given request.
+ ///
+ /// The collection of conditions to check.
+ /// The request to evaluate the conditions against.
+ /// True if all conditions are fulfilled; otherwise, false.
+ public static bool Check(this IEnumerable conditions, Request request)
+ {
+ foreach (var condition in conditions)
+ {
+ if (!condition.Fulfillment(request))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/FragmentContext.cs b/src/WebExpress.WebCore/WebFragment/FragmentContext.cs
new file mode 100644
index 0000000..9994ff5
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/FragmentContext.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Represents the context for a web fragment, including plugin context, application context,
+ /// conditions for activation, culture information, and caching behavior.
+ ///
+ public class FragmentContext : IFragmentContext
+ {
+ ///
+ /// Returns the context of the associated plugin.
+ ///
+ public IPluginContext PluginContext { get; internal set; }
+
+ ///
+ /// Returns the application context.
+ ///
+ public IApplicationContext ApplicationContext { get; internal set; }
+
+ ///
+ /// Gets the unique identifier for the fragment.
+ ///
+ public IComponentId FragmentId { get; internal set; }
+
+ ///
+ /// Returns the conditions that must be met for the component to be active.
+ ///
+ public IEnumerable Conditions { get; internal set; } = [];
+
+ ///
+ /// Determines whether the component is created once and reused on each execution.
+ ///
+ public bool Cache { get; internal set; }
+
+ ///
+ /// Returns the section.
+ ///
+ public Type Section { get; internal set; }
+
+ ///
+ /// Returns the scope.
+ ///
+ public Type Scope { get; internal set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public FragmentContext()
+ {
+ }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ /// A string that represents the current object.
+ public override string ToString()
+ {
+ return $"Fragment: {FragmentId}";
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/FragmentManager.cs b/src/WebExpress.WebCore/WebFragment/FragmentManager.cs
new file mode 100644
index 0000000..e509279
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/FragmentManager.cs
@@ -0,0 +1,498 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using WebExpress.WebCore.Internationalization;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebAttribute;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebFragment.Model;
+using WebExpress.WebCore.WebHtml;
+using WebExpress.WebCore.WebLog;
+using WebExpress.WebCore.WebPage;
+using WebExpress.WebCore.WebPlugin;
+using WebExpress.WebCore.WebScope;
+using WebExpress.WebCore.WebSection;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// The fragment manager. Fragments are independent parts of a page.
+ ///
+ public sealed class FragmentManager : IFragmentManager
+ {
+ private readonly IComponentHub _componentHub;
+ private readonly IHttpServerContext _httpServerContext;
+ private readonly FragmentDictionary _dictionary = new();
+
+ ///
+ /// An event that fires when an fragment is added.
+ ///
+ public event EventHandler AddFragment;
+
+ ///
+ /// An event that fires when an fragment is removed.
+ ///
+ public event EventHandler RemoveFragment;
+
+ ///
+ /// Returns the collection of fragment contexts.
+ ///
+ public IEnumerable Fragments => _dictionary.All;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The component hub.
+ /// The reference to the context of the host.
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Used via Reflection.")]
+ private FragmentManager(IComponentHub componentHub, IHttpServerContext httpServerContext)
+ {
+ _componentHub = componentHub;
+ _httpServerContext = httpServerContext;
+
+ _componentHub.PluginManager.AddPlugin += OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin += OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication += OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication += OnRemoveApplication;
+
+ _httpServerContext.Log.Debug
+ (
+ I18N.Translate("webexpress.webcore:fragmentmanager.initialization")
+ );
+ }
+
+ ///
+ /// Discovers and binds fragments to an application.
+ ///
+ /// The context of the plugin whose fragments are to be associated.
+ private void Register(IPluginContext pluginContext)
+ {
+ if (_dictionary.Contains(pluginContext))
+ {
+ return;
+ }
+
+ Register(pluginContext, _componentHub.ApplicationManager.GetApplications(pluginContext));
+ }
+
+ ///
+ /// Discovers and binds fragments to an application.
+ ///
+ /// The context of the application whose fragments are to be associated.
+ private void Register(IApplicationContext applicationContext)
+ {
+ foreach (var pluginContext in _componentHub.PluginManager.GetPlugins(applicationContext))
+ {
+ if (_dictionary.Contains(pluginContext, applicationContext))
+ {
+ continue;
+ }
+
+ Register(pluginContext, [applicationContext]);
+ }
+ }
+
+ ///
+ /// Registers pages for a given plugin and application context.
+ ///
+ /// The plugin context.
+ /// The application context (optional).
+ private void Register(IPluginContext pluginContext, IEnumerable applicationContexts)
+ {
+ var assembly = pluginContext.Assembly;
+
+ foreach (var fragmentType in assembly.GetTypes()
+ .Where(x => x.IsClass == true && x.IsSealed && x.IsPublic)
+ .Where(x => x.GetInterface(typeof(IFragment<,>).Name) != null))
+ {
+ var id = fragmentType.FullName?.ToLower();
+ var scopes = new List();
+ var sections = new List();
+ var conditions = new List();
+ var cache = false;
+ var order = 0;
+
+ // determining attributes
+ foreach (var customAttribute in fragmentType.CustomAttributes.Where
+ (
+ x => x.AttributeType.GetInterfaces()
+ .Contains(typeof(IEndpointAttribute))
+ ))
+ {
+ if (customAttribute.AttributeType.Name == typeof(ScopeAttribute<>).Name && customAttribute.AttributeType.Namespace == typeof(ScopeAttribute<>).Namespace)
+ {
+ scopes.Add(customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault());
+ }
+ else if (customAttribute.AttributeType.Name == typeof(ConditionAttribute<>).Name && customAttribute.AttributeType.Namespace == typeof(ConditionAttribute<>).Namespace)
+ {
+ var condition = customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault();
+ conditions.Add(Activator.CreateInstance(condition) as ICondition);
+ }
+ else if (customAttribute.AttributeType == typeof(CacheAttribute))
+ {
+ cache = true;
+ }
+ }
+
+ foreach (var customAttribute in fragmentType.CustomAttributes.Where
+ (
+ x => x.AttributeType.GetInterfaces().Contains(typeof(IFragmentAttribute))
+ ))
+ {
+ if (customAttribute.AttributeType.Name == typeof(SectionAttribute<>).Name && customAttribute.AttributeType.Namespace == typeof(SectionAttribute<>).Namespace)
+ {
+ sections.Add(customAttribute.AttributeType.GenericTypeArguments.FirstOrDefault());
+ }
+ else if (customAttribute.AttributeType == typeof(OrderAttribute))
+ {
+ try
+ {
+ order = Convert.ToInt32(customAttribute.ConstructorArguments.FirstOrDefault().Value);
+ }
+ catch
+ {
+ }
+ }
+ }
+
+ // check section
+ if (sections.Count == 0)
+ {
+ _httpServerContext.Log.Warning(I18N.Translate
+ (
+ "webexpress.webcore:fragmentmanager.error.section"
+ ));
+
+ continue;
+ }
+
+ // check scope
+ if (scopes.Count == 0)
+ {
+ scopes.Add(typeof(IScope));
+ }
+
+ // assign the fragment to existing applications
+ foreach (var applicationContext in _componentHub.ApplicationManager.GetApplications(pluginContext))
+ {
+ // assign section
+ foreach (var section in sections)
+ {
+ // assign scope
+ foreach (var scope in scopes)
+ {
+ var fragmentContext = new FragmentContext()
+ {
+ PluginContext = pluginContext,
+ ApplicationContext = applicationContext,
+ FragmentId = new ComponentId(id),
+ Cache = cache,
+ Section = section,
+ Scope = scope,
+ Conditions = conditions
+ };
+
+ var fragmentItem = new FragmentItem(_componentHub, _httpServerContext)
+ {
+ PluginContext = pluginContext,
+ ApplicationContext = applicationContext,
+ FragmentContext = fragmentContext,
+ FragmentClass = fragmentType,
+ Order = order,
+ Cache = cache,
+ Conditions = conditions,
+ Section = section,
+ Scope = scope
+ };
+
+ if (_dictionary.AddFragmentItem(pluginContext, applicationContext, fragmentItem))
+ {
+ OnAddFragment(fragmentContext);
+
+ _httpServerContext?.Log.Debug
+ (
+ I18N.Translate
+ (
+ "webexpress.webcore:fragmentmanager.register",
+ id,
+ section,
+ applicationContext.ApplicationId
+ )
+ );
+ }
+ }
+ }
+ }
+ }
+
+ Log();
+ }
+
+ ///
+ /// Removes all components associated with the specified plugin context.
+ ///
+ /// The context of the plugin that contains the components to remove.
+ internal void Remove(IPluginContext pluginContext)
+ {
+ if (pluginContext == null)
+ {
+ return;
+ }
+
+ var fragments = _dictionary.RemoveFragments(pluginContext);
+
+ foreach (var fragment in fragments)
+ {
+ OnRemoveFragment(fragment);
+ }
+ }
+
+ ///
+ /// Removes all fragments associated with the specified application context.
+ ///
+ /// The context of the application that contains the fragments to remove.
+ internal void Remove(IApplicationContext applicationContext)
+ {
+ if (applicationContext == null)
+ {
+ return;
+ }
+
+ var fragments = _dictionary.RemoveFragments(applicationContext);
+
+ foreach (var fragment in fragments)
+ {
+ OnRemoveFragment(fragment);
+ }
+ }
+
+ ///
+ /// Raises the AddFragment event.
+ ///
+ /// The fragment context.
+ private void OnAddFragment(IFragmentContext fragmentContext)
+ {
+ AddFragment?.Invoke(this, fragmentContext);
+ }
+
+ ///
+ /// Raises the RemoveFragment event.
+ ///
+ /// The fragment context.
+ private void OnRemoveFragment(IFragmentContext fragmentContext)
+ {
+ RemoveFragment?.Invoke(this, fragmentContext);
+ }
+
+ ///
+ /// Raises the event when an plugin is added.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being added.
+ private void OnAddPlugin(object sender, IPluginContext e)
+ {
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when a plugin is removed.
+ ///
+ /// The source of the event.
+ /// The context of the plugin being removed.
+ private void OnRemovePlugin(object sender, IPluginContext e)
+ {
+ Remove(e);
+ }
+
+ ///
+ /// Raises the event when an application is added.
+ ///
+ /// The source of the event.
+ /// The context of the application being added.
+ private void OnAddApplication(object sender, IApplicationContext e)
+ {
+ Register(e);
+ }
+
+ ///
+ /// Raises the event when an application is removed.
+ ///
+ /// The source of the event.
+ /// The context of the application being removed.
+ private void OnRemoveApplication(object sender, IApplicationContext e)
+ {
+ Remove(e);
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments() where T : IFragmentBase
+ {
+ return GetFragments(typeof(T));
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(Type fragmentType)
+ {
+ return _dictionary.GetFragments(fragmentType);
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type.
+ /// The application context.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(IApplicationContext applicationContext) where TFragment : IFragmentBase
+ {
+ return GetFragments(applicationContext, typeof(TFragment));
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The application context.
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(IApplicationContext applicationContext, Type fragmentType)
+ {
+ return _dictionary.GetFragments(applicationContext, fragmentType);
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The section where the fragment is embedded.
+ /// The scope where the fragment is embedded.
+ /// The application context.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(IApplicationContext applicationContext)
+ where TSection : ISection
+ where TScope : IScope
+ {
+ return GetFragments(applicationContext, typeof(TSection), typeof(TScope));
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The application context.
+ /// The section where the fragment is embedded.
+ /// The scope where the fragment is embedded.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(IApplicationContext applicationContext, Type section, Type scope)
+ {
+ return _dictionary.GetFragments(applicationContext, section, scope);
+ }
+
+ ///
+ /// Returns all fragments that belong to a given application.
+ ///
+ /// The fragment type.
+ /// The section where the fragment is embedded.
+ /// The application context.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragments.
+ public IEnumerable GetFragments(IApplicationContext applicationContext, IEnumerable scopes)
+ where TFragment : IFragmentBase
+ where TSection : ISection
+ {
+ var effectiveScopes = (scopes?.Any() == true) ? scopes : [typeof(IScope)];
+
+ foreach (var item in _dictionary.GetFragmentItems(applicationContext, typeof(TFragment), typeof(TSection), effectiveScopes))
+ {
+ yield return item.CreateInstance();
+ }
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The application context.
+ /// The section where the fragment is embedded.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragments(IApplicationContext applicationContext, Type section, IEnumerable scopes)
+ {
+ var effectiveScopes = (scopes?.Any() == true) ? scopes : [typeof(IScope)];
+
+ foreach (var scope in effectiveScopes)
+ {
+ foreach (var item in GetFragments(applicationContext, section, effectiveScopes))
+ {
+ yield return item;
+ }
+ }
+ }
+
+ ///
+ /// Converts the fragments to HTML for a given section within the specified render context.
+ ///
+ /// The type of the render context.
+ /// The type of the visual tree.
+ /// The context in which rendering occurs.
+ /// The visual tree used for rendering.
+ /// The section where the fragment is embedded.
+ /// An enumeration of HTML nodes representing the rendered fragments.
+ public IEnumerable Render(TRenderContext renderContext, TVisualTree visualTree, Type section)
+ where TRenderContext : IRenderContext
+ where TVisualTree : IVisualTree
+ {
+ var applicationContext = renderContext?.PageContext?.ApplicationContext;
+ var scopes = renderContext?.PageContext?.Scopes ?? [typeof(IScope)];
+ var items = _dictionary.GetFragmentItems(applicationContext, section, scopes);
+
+ return items.Select(x => x.Render(renderContext, visualTree));
+ }
+
+ ///
+ /// Information about the component is collected and prepared for output in the log.
+ ///
+ private void Log()
+ {
+ if (!Fragments.Any())
+ {
+ return;
+ }
+
+ using var frame = new LogFrameSimple(_httpServerContext.Log);
+ var list = new List
+ {
+ I18N.Translate("webexpress.webcore:fragmentmanager.titel")
+ };
+
+ foreach (var fragment in Fragments.Distinct())
+ {
+ list.Add
+ (
+ string.Empty.PadRight(2) +
+ I18N.Translate("webexpress.webcore:fragmentmanager.fragment", fragment.FragmentId.ToString(), fragment.ApplicationContext?.ApplicationId)
+ );
+ }
+
+ _httpServerContext.Log.Info(string.Join(Environment.NewLine, list));
+ }
+
+ ///
+ /// Release of unmanaged resources reserved during use.
+ ///
+ public void Dispose()
+ {
+ _componentHub.PluginManager.AddPlugin -= OnAddPlugin;
+ _componentHub.PluginManager.RemovePlugin -= OnRemovePlugin;
+ _componentHub.ApplicationManager.AddApplication -= OnAddApplication;
+ _componentHub.ApplicationManager.RemoveApplication -= OnRemoveApplication;
+
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/IFragment.cs b/src/WebExpress.WebCore/WebFragment/IFragment.cs
new file mode 100644
index 0000000..8bd90a4
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/IFragment.cs
@@ -0,0 +1,29 @@
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebHtml;
+using WebExpress.WebCore.WebPage;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Represents a fragment that is a part of a web component.
+ ///
+ public interface IFragment : IFragment
+ {
+ }
+
+ ///
+ /// Represents a fragment that is a part of a web component.
+ ///
+ public interface IFragment : IComponent, IFragmentBase
+ where TRenderContext : IRenderContext
+ where TVisualTree : IVisualTree
+ {
+ ///
+ /// Converts the fragment to an HTML representation.
+ ///
+ /// The context in which the fragment is rendered.
+ /// The visual tree used for rendering the fragment.
+ /// An HTML node representing the rendered fragments. Can be null if no nodes are present.
+ IHtmlNode Render(TRenderContext renderContext, TVisualTree visualTree);
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/IFragmentBase.cs b/src/WebExpress.WebCore/WebFragment/IFragmentBase.cs
new file mode 100644
index 0000000..99e4524
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/IFragmentBase.cs
@@ -0,0 +1,11 @@
+using WebExpress.WebCore.WebComponent;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Defines the base interface for all fragments in the WebExpress framework.
+ ///
+ public interface IFragmentBase : IComponent
+ {
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/IFragmentContext.cs b/src/WebExpress.WebCore/WebFragment/IFragmentContext.cs
new file mode 100644
index 0000000..fcbc476
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/IFragmentContext.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebCondition;
+using WebExpress.WebCore.WebPlugin;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Interface representing the context of a web fragment.
+ /// Provides access to plugin context, application context, conditions for activation, and caching behavior.
+ ///
+ public interface IFragmentContext : IContext
+ {
+ ///
+ /// Returns the context of the associated plugin.
+ ///
+ IPluginContext PluginContext { get; }
+
+ ///
+ /// Returns the application context.
+ ///
+ IApplicationContext ApplicationContext { get; }
+
+ ///
+ /// Gets the unique identifier for the fragment.
+ ///
+ IComponentId FragmentId { get; }
+
+ ///
+ /// Returns the conditions that must be met for the component to be active.
+ ///
+ IEnumerable Conditions { get; }
+
+ ///
+ /// Returns the section.
+ ///
+ Type Section { get; }
+
+ ///
+ /// Returns the scope.
+ ///
+ Type Scope { get; }
+
+ ///
+ /// Determines whether the component is created once and reused on each execution.
+ ///
+ bool Cache { get; }
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/IFragmentDynamic.cs b/src/WebExpress.WebCore/WebFragment/IFragmentDynamic.cs
new file mode 100644
index 0000000..6a16ce4
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/IFragmentDynamic.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebPage;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Interface representing a dynamic fragment.
+ /// Provides methods for initialization and creation of fragments.
+ ///
+ public interface IFragmentDynamic
+ {
+ ///
+ /// Returns the context of the fragment.
+ ///
+ IFragmentContext Context { get; }
+
+ ///
+ /// Initialization
+ ///
+ /// The context.
+ /// The page where the fragment is active.
+ void Initialization(IFragmentContext context, IPage page);
+
+ ///
+ /// Creates fragments of a common type T.
+ ///
+ /// The created instances of the fragments.
+ IEnumerable Create()
+ where TComponent : IComponent;
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/IFragmentManager.cs b/src/WebExpress.WebCore/WebFragment/IFragmentManager.cs
new file mode 100644
index 0000000..540524b
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/IFragmentManager.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebComponent;
+using WebExpress.WebCore.WebHtml;
+using WebExpress.WebCore.WebPage;
+using WebExpress.WebCore.WebScope;
+using WebExpress.WebCore.WebSection;
+
+namespace WebExpress.WebCore.WebFragment
+{
+ ///
+ /// Interface for managing web fragments.
+ ///
+ public interface IFragmentManager : IComponentManager
+ {
+ ///
+ /// An event that fires when a fragment is added.
+ ///
+ event EventHandler AddFragment;
+
+ ///
+ /// An event that fires when a fragment is removed.
+ ///
+ event EventHandler RemoveFragment;
+
+ ///
+ /// Returns the collection of fragment contexts.
+ ///
+ IEnumerable Fragments { get; }
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments() where TFragment : IFragmentBase;
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(Type fragmentType);
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The fragment type..
+ /// The application context.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(IApplicationContext applicationContext)
+ where TFragment : IFragmentBase;
+
+ ///
+ /// Returns all fragment contexts that belong to a given fragment type.
+ ///
+ /// The application context.
+ /// The fragment type.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(IApplicationContext applicationContext, Type fragmentType);
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The section where the fragment is embedded.
+ /// The scope where the fragment is embedded.
+ /// The application context.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(IApplicationContext applicationContext)
+ where TSection : ISection
+ where TScope : IScope;
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The application context.
+ /// The section where the fragment is embedded.
+ /// The scope where the fragment is embedded.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(IApplicationContext applicationContext, Type section, Type scope);
+
+ ///
+ /// Returns all fragments that belong to a given application.
+ ///
+ /// The fragment type.
+ /// The section where the fragment is embedded.
+ /// The application context.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragments.
+ public IEnumerable GetFragments(IApplicationContext applicationContext, IEnumerable scopes)
+ where TFragment : IFragmentBase
+ where TSection : ISection;
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The application context.
+ /// The section where the fragment is embedded.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragment contexts.
+ IEnumerable GetFragments(IApplicationContext applicationContext, Type section, IEnumerable scopes);
+
+ ///
+ /// Converts the fragments to HTML for a given section within the specified render context.
+ ///
+ /// The type of the render context.
+ /// The type of the visual tree.
+ /// The context in which rendering occurs.
+ /// The visual tree used for rendering.
+ /// The section where the fragment is embedded.
+ /// An enumeration of HTML nodes representing the rendered fragments.
+ IEnumerable Render(TRenderContext renderContext, TVisualTree visualTree, Type section)
+ where TRenderContext : IRenderContext
+ where TVisualTree : IVisualTree;
+ }
+}
diff --git a/src/WebExpress.WebCore/WebFragment/Model/FragmentDictionary.cs b/src/WebExpress.WebCore/WebFragment/Model/FragmentDictionary.cs
new file mode 100644
index 0000000..1213440
--- /dev/null
+++ b/src/WebExpress.WebCore/WebFragment/Model/FragmentDictionary.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WebExpress.WebCore.WebApplication;
+using WebExpress.WebCore.WebPlugin;
+using WebExpress.WebCore.WebScope;
+
+namespace WebExpress.WebCore.WebFragment.Model
+{
+ ///
+ /// Represents a dictionary that maps plugin contexts to application contexts,
+ /// which in turn maps to a dictionary of section types and inner maps of scope types and lists of FragmentItem objects.
+ /// Plugin -> Application -> Section -> Scope -> FragmentItem
+ ///
+ internal class FragmentDictionary
+ {
+ private readonly Dictionary>>>> _dict = [];
+
+ ///
+ /// Returns all fragment contexts from the dictionary.
+ ///
+ public IEnumerable All => _dict.Values
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x)
+ .Select(x => x.FragmentContext);
+
+ ///
+ /// Adds a fragment item to the dictionary.
+ ///
+ /// The plugin context.
+ /// The application context.
+ /// The fragment item.
+ /// True if the fragment item was added successfully, false if an element with the same status code already exists.
+ public bool AddFragmentItem(IPluginContext pluginContext, IApplicationContext applicationContext, FragmentItem fragmentItem)
+ {
+ var type = fragmentItem.FragmentClass;
+
+ if (type.GetInterface(typeof(IFragment<,>).Name) == null)
+ {
+ return false;
+ }
+
+ if (!_dict.TryGetValue(pluginContext, out var applicationDict))
+ {
+ applicationDict = [];
+ _dict[pluginContext] = applicationDict;
+ }
+
+ if (!applicationDict.TryGetValue(applicationContext, out var sectionDict))
+ {
+ sectionDict = [];
+ applicationDict[applicationContext] = sectionDict;
+ }
+
+ if (!sectionDict.TryGetValue(fragmentItem.Section, out var scopeDict))
+ {
+ scopeDict = [];
+ sectionDict[fragmentItem.Section] = scopeDict;
+ }
+
+ if (!scopeDict.TryGetValue(fragmentItem.Scope, out var itemList))
+ {
+ itemList = [];
+ scopeDict[fragmentItem.Scope] = itemList;
+ }
+
+ if (!itemList.Any(x => x.FragmentClass == fragmentItem.FragmentClass))
+ {
+ itemList.Add(fragmentItem);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Removes fragments from the dictionary.
+ ///
+ /// The plugin context.
+ /// An IEnumerable of fragment contexts that were removed.
+ public IEnumerable RemoveFragments(IPluginContext pluginContext)
+ {
+ var fragments = GetFragments(pluginContext);
+
+ _dict.Remove(pluginContext);
+
+ return fragments;
+ }
+
+ ///
+ /// Removes fragments from the dictionary.
+ ///
+ /// The application context.
+ /// An IEnumerable of fragment contexts that were removed.
+ public IEnumerable RemoveFragments(IApplicationContext applicationContext)
+ {
+ foreach (var pluginKeyValue in _dict)
+ {
+ if (pluginKeyValue.Value.TryGetValue(applicationContext, out var sectionDict))
+ {
+ pluginKeyValue.Value.Remove(applicationContext);
+
+ if (pluginKeyValue.Value.Count == 0)
+ {
+ _dict.Remove(pluginKeyValue.Key);
+ }
+
+ foreach (var item in sectionDict.Values
+ .SelectMany(x => x.Values)
+ .SelectMany(x => x)
+ .Select(x => x.FragmentContext))
+ {
+ yield return item;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Returns all fragment contexts that belong to a given application.
+ ///
+ /// The application context.
+ /// The section where the fragment is embedded.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragment contexts.
+ public IEnumerable GetFragmentItems(IApplicationContext applicationContext, Type section, IEnumerable scopes)
+ {
+ return _dict.Values
+ .SelectMany(x => x)
+ .Where(x => x.Key == applicationContext)
+ .SelectMany(x => x.Value)
+ .Where(x => x.Key == section || section.IsAssignableFrom(x.Key))
+ .SelectMany(x => x.Value)
+ .Where(x => scopes.Any(y => x.Key == y))
+ .SelectMany(x => x.Value)
+ .OrderBy(x => x.Order);
+ }
+
+ ///
+ /// Returns all fragment items that belong to a given application context, fragment type, section, and scopes.
+ ///
+ /// The application context.
+ /// The type of fragment.
+ /// The section where the fragment is embedded.
+ /// The scopes where the fragment is embedded.
+ /// An enumeration of the filtered fragment items.
+ public IEnumerable GetFragmentItems(IApplicationContext applicationContext, Type fragment, Type section, IEnumerable