Initial Commit
commit
fd109766a8
|
@ -0,0 +1,41 @@
|
|||
# Autosave files
|
||||
*~
|
||||
|
||||
# build
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
packages/
|
||||
TestResults/
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.DS_Store
|
||||
*.sln.cache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.log
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.user
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
Thumbs.db
|
||||
.vs/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# resharper
|
||||
*_Resharper.*
|
||||
*.Resharper
|
||||
|
||||
# dotCover
|
||||
*.dotCover
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using ln.http;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using ln.logging;
|
||||
using ln.types;
|
||||
using System.Net;
|
||||
using ln.application.service;
|
||||
using ln.http.resources;
|
||||
|
||||
namespace ln.application
|
||||
{
|
||||
public class Application : IApplicationInterface
|
||||
{
|
||||
public ArgumentContainer Arguments { get; protected set; }
|
||||
public HTTPServer HttpServer { get; private set; }
|
||||
|
||||
public ServiceContainer ServiceContainer { get; }
|
||||
public ResourceApplication HTTPApplication { get; private set; }
|
||||
|
||||
public MemoryLogger MemoryLogger { get; }
|
||||
|
||||
public Application()
|
||||
{
|
||||
MemoryLogger = new MemoryLogger(8192);
|
||||
Logger.Default.Backends.Add(MemoryLogger);
|
||||
|
||||
Arguments = new ArgumentContainer()
|
||||
.Add((char)0, "log-level", "INFO")
|
||||
.Add('l', "http-listen","0.0.0.0")
|
||||
.Add('p', "http-port", "8080");
|
||||
|
||||
ServiceContainer = new ServiceContainer(this);
|
||||
}
|
||||
|
||||
public virtual void PrepareStart()
|
||||
{
|
||||
}
|
||||
|
||||
public void Start(String[] arguments)
|
||||
{
|
||||
Arguments.Parse(arguments);
|
||||
Logger.ConsoleLogger.MaxLogLevel = (LogLevel)Enum.Parse(typeof(LogLevel), Arguments["log-level"].Value);
|
||||
|
||||
/* Startup Sequence */
|
||||
|
||||
Logging.Log(LogLevel.INFO, "Calling PrepareStart()");
|
||||
PrepareStart();
|
||||
|
||||
/* HTTP Server */
|
||||
Logging.Log(LogLevel.INFO, "Start: HTTPServer on {0}:{1}", Arguments['l'].Value, Arguments['p'].IntegerValue);
|
||||
HttpServer = new HTTPServer();
|
||||
HttpServer.AddEndpoint(new System.Net.IPEndPoint(
|
||||
IPAddress.Parse(Arguments['l'].Value),
|
||||
Arguments['p'].IntegerValue
|
||||
));
|
||||
|
||||
HttpServer.Start();
|
||||
HTTPApplication = new ResourceApplication();
|
||||
HttpServer.DefaultApplication = HTTPApplication;
|
||||
|
||||
|
||||
/* Application Services */
|
||||
foreach (ServiceDefinition serviceDefinition in ServiceContainer)
|
||||
{
|
||||
if (serviceDefinition.AutoStart)
|
||||
ServiceContainer.Start(serviceDefinition);
|
||||
}
|
||||
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
Logging.Log(LogLevel.INFO, "Application shutdown requested");
|
||||
|
||||
/* Application Services */
|
||||
foreach (ServiceDefinition serviceDefinition in ServiceContainer)
|
||||
{
|
||||
if (serviceDefinition.IsAlive)
|
||||
{
|
||||
ServiceContainer.Stop(serviceDefinition);
|
||||
if (serviceDefinition.IsAlive)
|
||||
throw new Exception("application service could not be stopped");
|
||||
}
|
||||
}
|
||||
|
||||
/* HTTP Server */
|
||||
Logging.Log(LogLevel.INFO, "Stopping HTTP server");
|
||||
HttpServer.Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Plugin Classes
|
||||
*/
|
||||
Dictionary<Type, List<object>> pluginInstances = new Dictionary<Type, List<object>>();
|
||||
|
||||
public void RegisterPluginInstance<PC>(PC pluginInstance) => RegisterPluginInstance(typeof(PC),pluginInstance);
|
||||
public void RegisterPluginInstance(Type type,object pluginInstance)
|
||||
{
|
||||
if (!pluginInstances.ContainsKey(type))
|
||||
pluginInstances.Add(type, new List<object>());
|
||||
|
||||
if (!pluginInstances[type].Contains(pluginInstance))
|
||||
pluginInstances[type].Add(pluginInstance);
|
||||
}
|
||||
|
||||
public IEnumerable<PC> GetPluginInstances<PC>()
|
||||
{
|
||||
Type pluginType = typeof(PC);
|
||||
if (!pluginInstances.ContainsKey(pluginType))
|
||||
return new PC[0];
|
||||
|
||||
return pluginInstances[pluginType].Select((ut) => (PC)ut);
|
||||
}
|
||||
public IEnumerable GetPluginInstances(Type pluginType)
|
||||
{
|
||||
if (!pluginInstances.ContainsKey(pluginType))
|
||||
return new object[0];
|
||||
|
||||
return pluginInstances[pluginType];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ln.application.service;
|
||||
using ln.http.resources;
|
||||
using ln.http;
|
||||
using ln.types;
|
||||
namespace ln.application
|
||||
{
|
||||
public interface IApplicationInterface
|
||||
{
|
||||
ArgumentContainer Arguments { get; }
|
||||
|
||||
HTTPServer HttpServer { get; }
|
||||
ResourceApplication HTTPApplication { get; }
|
||||
ServiceContainer ServiceContainer { get; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("ln.application")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{44AA3A50-7214-47F2-9D60-6FF34C0FE6D3}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>ln.application</RootNamespace>
|
||||
<AssemblyName>ln.application</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Application.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="IApplicationInterface.cs" />
|
||||
<Compile Include="service\ServiceDefinition.cs" />
|
||||
<Compile Include="service\ServiceContainer.cs" />
|
||||
<Compile Include="service\ApplicationServiceBase.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ln.types\ln.types.csproj">
|
||||
<Project>{8D9AB9A5-E513-4BA7-A450-534F6456BF28}</Project>
|
||||
<Name>ln.types</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
|
||||
<Name>ln.logging</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ln.http.resources\ln.http.resources.csproj">
|
||||
<Project>{F9086FE4-8925-42FF-A59C-607341604293}</Project>
|
||||
<Name>ln.http.resources</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ln.http\ln.http.csproj">
|
||||
<Project>{CEEEEB41-3059-46A2-A871-2ADE22C013D9}</Project>
|
||||
<Name>ln.http</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="service\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using ln.logging;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ln.application.service
|
||||
{
|
||||
public abstract class ApplicationServiceBase : IDisposable
|
||||
{
|
||||
public int TimeOut { get; set; } = 10000;
|
||||
|
||||
public String ServiceName { get; protected set; }
|
||||
public virtual bool IsAlive => ((ServiceThread != null) && ServiceThread.IsAlive);
|
||||
|
||||
public bool StopRequested { get; protected set; }
|
||||
public Thread ServiceThread { get; protected set; }
|
||||
|
||||
public string ServiceStateText { get; protected set; }
|
||||
|
||||
public IApplicationInterface CurrentApplicationInterface { get; protected set; }
|
||||
|
||||
public Type[] DependingServiceTypes => dependingServiceTypes.ToArray();
|
||||
HashSet<Type> dependingServiceTypes = new HashSet<Type>();
|
||||
|
||||
public ApplicationServiceBase(String serviceName)
|
||||
{
|
||||
ServiceName = serviceName;
|
||||
ServiceStateText = "Initialized";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ServiceStateText = "Disposed";
|
||||
}
|
||||
|
||||
protected void DependOnService<S>() => dependingServiceTypes.Add(typeof(S));
|
||||
|
||||
public T Dependency<T>() where T : ApplicationServiceBase
|
||||
{
|
||||
T serviceBase = (T)CurrentApplicationInterface.ServiceContainer[typeof(T)].ServiceBase;
|
||||
if (serviceBase == null)
|
||||
throw new EntryPointNotFoundException(String.Format("depending service not found: {0}",typeof(T).ToString()));
|
||||
|
||||
return serviceBase;
|
||||
}
|
||||
|
||||
public virtual void ServiceMain(IApplicationInterface applicationInterface) => throw new NotImplementedException();
|
||||
|
||||
public virtual bool Start(IApplicationInterface applicationInterface, String[] arguments)
|
||||
{
|
||||
if (IsAlive)
|
||||
throw new NotSupportedException("Service is already alive");
|
||||
|
||||
CurrentApplicationInterface = applicationInterface;
|
||||
|
||||
foreach (Type dep in dependingServiceTypes)
|
||||
{
|
||||
ServiceDefinition depService = CurrentApplicationInterface.ServiceContainer[dep];
|
||||
if (!depService.IsAlive)
|
||||
{
|
||||
CurrentApplicationInterface.ServiceContainer.Start(depService);
|
||||
if (!depService.IsAlive)
|
||||
{
|
||||
Logging.Log(LogLevel.ERROR, "service {0} could not start depending service {1}", ServiceName, depService.ServiceClassName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StopRequested = false;
|
||||
ServiceThread = new Thread(() => ServiceMain(applicationInterface));
|
||||
ServiceThread.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Stop() => Stop(false);
|
||||
public virtual bool Stop(bool force)
|
||||
{
|
||||
if (IsAlive)
|
||||
{
|
||||
StopRequested = true;
|
||||
lock (ServiceThread)
|
||||
{
|
||||
Monitor.PulseAll(ServiceThread);
|
||||
}
|
||||
ServiceThread.Join(TimeOut);
|
||||
if (IsAlive && force)
|
||||
{
|
||||
Logging.Log(LogLevel.INFO, "Service did not shutdown, enforcing {0}",ServiceName);
|
||||
ServiceThread.Abort();
|
||||
ServiceThread.Join(TimeOut);
|
||||
}
|
||||
|
||||
if (!ServiceThread.IsAlive)
|
||||
CurrentApplicationInterface = null;
|
||||
|
||||
return !ServiceThread.IsAlive;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
namespace ln.application.service
|
||||
{
|
||||
public class ServiceContainer : IEnumerable<ServiceDefinition>
|
||||
{
|
||||
public Application Application { get; }
|
||||
|
||||
HashSet<ServiceDefinition> serviceDefinitions = new HashSet<ServiceDefinition>();
|
||||
|
||||
public ServiceContainer(Application application)
|
||||
{
|
||||
Application = application;
|
||||
}
|
||||
|
||||
public void Add(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
serviceDefinitions.Add(serviceDefinition);
|
||||
}
|
||||
public void Remove(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
serviceDefinitions.Remove(serviceDefinition);
|
||||
}
|
||||
|
||||
public ServiceDefinition this[string serviceClassName]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ServiceDefinition serviceDefinition in serviceDefinitions)
|
||||
{
|
||||
if (serviceDefinition.ServiceClassName.Equals(serviceClassName))
|
||||
return serviceDefinition;
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
public ServiceDefinition this[string assemblyName,string serviceClassName]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (ServiceDefinition serviceDefinition in serviceDefinitions)
|
||||
{
|
||||
if (serviceDefinition.ServiceClassName.Equals(serviceClassName) && Object.Equals(serviceDefinition.AssemblyName,assemblyName))
|
||||
return serviceDefinition;
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
public ServiceDefinition this[Type serviceType]
|
||||
{
|
||||
get
|
||||
{
|
||||
return this[serviceType.Assembly.FullName,serviceType.FullName];
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||
|
||||
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||
sd.Start(this.Application);
|
||||
}
|
||||
public void Stop(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||
|
||||
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||
sd.Stop();
|
||||
}
|
||||
public void Load(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||
|
||||
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||
sd.Load();
|
||||
}
|
||||
public void Unload(ServiceDefinition serviceDefinition)
|
||||
{
|
||||
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||
|
||||
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||
sd.Unload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public IEnumerator<ServiceDefinition> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<ServiceDefinition>)serviceDefinitions).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<ServiceDefinition>)serviceDefinitions).GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using ln.logging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
namespace ln.application.service
|
||||
{
|
||||
public class ServiceDefinition
|
||||
{
|
||||
public String AssemblyName { get; }
|
||||
public String ServiceClassName { get; }
|
||||
public bool AutoStart { get; set; }
|
||||
|
||||
public ApplicationServiceBase ServiceBase { get; private set; }
|
||||
|
||||
public bool IsLoaded => ServiceBase != null;
|
||||
public bool IsAlive => IsLoaded && ServiceBase.IsAlive;
|
||||
|
||||
Assembly serviceAssembly;
|
||||
Type serviceType;
|
||||
|
||||
public ServiceDefinition(String assemblyName, string serviceClassName)
|
||||
{
|
||||
AssemblyName = assemblyName;
|
||||
ServiceClassName = serviceClassName;
|
||||
}
|
||||
public ServiceDefinition(string serviceClassName)
|
||||
{
|
||||
AssemblyName = null;
|
||||
ServiceClassName = serviceClassName;
|
||||
}
|
||||
public static ServiceDefinition From<S>() => From<S>(true);
|
||||
public static ServiceDefinition From<S>(bool autoStart)
|
||||
{
|
||||
Type st = typeof(S);
|
||||
ServiceDefinition sd = new ServiceDefinition(
|
||||
st.Assembly.FullName,
|
||||
st.FullName
|
||||
);
|
||||
sd.AutoStart = autoStart;
|
||||
return sd;
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
if (IsLoaded)
|
||||
throw new NotSupportedException(String.Format("Service {0} [{1}] is already loaded",ServiceClassName,AssemblyName));
|
||||
|
||||
if (AssemblyName != null)
|
||||
serviceAssembly = Assembly.Load(AssemblyName);
|
||||
|
||||
serviceType = FinalAssembly.GetType(ServiceClassName);
|
||||
if (serviceType == null)
|
||||
throw new EntryPointNotFoundException(String.Format("could not get type {0}",ServiceClassName));
|
||||
|
||||
if (!serviceType.IsSubclassOf(typeof(ApplicationServiceBase)))
|
||||
throw new NotSupportedException(String.Format("application service type must derive from ApplicationServiceBase"));
|
||||
|
||||
ServiceBase = (ApplicationServiceBase)Activator.CreateInstance(serviceType);
|
||||
}
|
||||
public void Unload() => Unload(false);
|
||||
public void Unload(bool force)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
throw new NotSupportedException(String.Format("Service {0} [{1}] is not loaded", ServiceClassName, AssemblyName));
|
||||
|
||||
if (!force && IsAlive)
|
||||
throw new NotSupportedException(String.Format("Service {0} [{1}] still alive", ServiceClassName, AssemblyName));
|
||||
|
||||
ServiceBase.Dispose();
|
||||
|
||||
ServiceBase = null;
|
||||
serviceType = null;
|
||||
serviceAssembly = null;
|
||||
}
|
||||
public void Start(IApplicationInterface applicationInterface)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
Load();
|
||||
|
||||
Logging.Log(LogLevel.INFO, "service: starting {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
|
||||
if (ServiceBase.Start(applicationInterface,new string[0]))
|
||||
Logging.Log(LogLevel.INFO, "service: started {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
else
|
||||
Logging.Log(LogLevel.ERROR, "service: failed {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
if (IsAlive)
|
||||
{
|
||||
Logging.Log(LogLevel.INFO, "service: stopping {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
|
||||
if (ServiceBase.Stop())
|
||||
Logging.Log(LogLevel.INFO, "service: stopped {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
else
|
||||
Logging.Log(LogLevel.ERROR, "service: stopfail {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private Assembly FinalAssembly => serviceAssembly != null ? serviceAssembly : Assembly.GetEntryAssembly();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (AssemblyName != null ? AssemblyName.GetHashCode() : 0) ^ ServiceClassName.GetHashCode();
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is ServiceDefinition)
|
||||
{
|
||||
ServiceDefinition other = obj as ServiceDefinition;
|
||||
return Object.Equals(AssemblyName, other.AssemblyName) && ServiceClassName.Equals(other.ServiceClassName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue