最近实现了一个管理本地服务和WCF服务的管理器:
1.用户控制服务的一组基础结构
namespace Practices.Services.Core
{
[DataContract]
public enum ServiceStatus
{
Available,
Running,
Pause,
Stoped
}
}
namespace Practices.Services.Core
{
[ServiceContract]
public interface IServiceControler
{
[OperationContract]
ServiceStatus GetServiceStatus();
[OperationContract]
void SetServiceStatus(ServiceStatus serviceStatus);
}
}
namespace Practices.Services.Core
{
[ServiceContract]
public interface ICacheControler
{
bool Cacheable
{
get;
}
string PoolName
{
get;
set;
}
[OperationContract]
void Cache();
EventHandler Cacheing
{
get;
set;
}
}
}
2.一个实现了基础结构的服务基类
namespace Practices.Services.Core
{
public class BaseServiceControler : MarshalByRefObject,IServiceControler,ICacheControler
{
#region Private Members
private string m_PoolName;
private EventHandler m_Cacheing;
private static Dictionary<Type, ServiceStatus> s_ServiceStatus = new Dictionary<Type, ServiceStatus>();
#endregion
public BaseServiceControler()
{
lock (s_ServiceStatus)
{
if (!s_ServiceStatus.ContainsKey(this.GetType()))
{
s_ServiceStatus.Add(this.GetType(),ServiceStatus.Running);
}
}
}
#region IServiceControler Members
public ServiceStatus GetServiceStatus()
{
return s_ServiceStatus[this.GetType()];
}
public void SetServiceStatus(ServiceStatus serviceStatus)
{
s_ServiceStatus[this.GetType()] = serviceStatus;
}
#endregion
#region ICacheControler Members
public bool Cacheable
{
get
{
return true;
}
}
public string PoolName
{
get
{
return m_PoolName;
}
set
{
m_PoolName = value;
}
}
public void Cache()
{
if (Cacheable)
{
if (m_Cacheing != null)
{
m_Cacheing(this, EventArgs.Empty);
}
}
}
public EventHandler Cacheing
{
get
{
return m_Cacheing;
}
set
{
m_Cacheing = value;
}
}
#endregion
}
}
Helper:
namespace Practices.Services.Core
{
public static class TypeResolver
{
public static Type ResolveType(string path, string typeString, AppDomain workerDomain)
{
Logger.WriteLog("TypeResolver",
string.Format("ResolveType in {0}",
workerDomain == null
? "Current"
: workerDomain.Id + ", " + workerDomain.FriendlyName));
string[] types = typeString.Split(',');
try
{
if (workerDomain == null)
{
if (string.IsNullOrEmpty(path))
{
return Assembly.Load(types[1]).GetType(types[0]);
}
return
Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, types[1])).GetType(
types[0]);
}
return workerDomain.Load(types[1]).GetType(types[0]);
}
catch (FileNotFoundException fileEx)
{
throw new TypeResolverException(String.Format("Can not find Assembly file[{0}].", types[1]), fileEx);
}
catch (FileLoadException fileEx)
{
throw new TypeResolverException(String.Format("Can not load Assembly file[{0}].", types[1]), fileEx);
}
}
public static object CreateInstance(string path, string typeString, AppDomain workerDomain, object[] args)
{
Logger.WriteLog("TypeResolver",
string.Format("CreateInstance in {0}",
workerDomain == null
? "Current"
: workerDomain.Id + ", " + workerDomain.FriendlyName));
string[] types = typeString.Split(',');
try
{
if (workerDomain == null)
{
if (string.IsNullOrEmpty(path))
{
return Assembly.Load(types[1]).CreateInstance(types[0], true, BindingFlags.Default, null, args,
null, null);
}
return
Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, types[1])).
CreateInstance(types[0], true, BindingFlags.Default, null, args, null, null);
}
return workerDomain.CreateInstanceAndUnwrap(types[1], types[0], true, BindingFlags.Default, null, args,
null, null, null);
}
catch (FileNotFoundException fileEx)
{
throw new TypeResolverException(String.Format("Can not find Assembly file[{0}].", types[1]), fileEx);
}
catch (FileLoadException fileEx)
{
throw new TypeResolverException(String.Format("Can not load Assembly file[{0}].", types[1]), fileEx);
}
}
}
}
namespace Practices.Services.Core
{
public static class Logger
{
public static void WriteLog(string service,string eventName)
{
Console.WriteLine(DateTime.Now.ToString("MM/dd HH:mm:ss ") + string.Format("T: [{2}], D: [{1}], S: [{0}] E: [{3}]",
service, AppDomain.CurrentDomain.Id + ", " + AppDomain.CurrentDomain.FriendlyName,
Thread.CurrentThread.ManagedThreadId, eventName));
}
}
}
namespace Practices.Services.Core
{
public class TypeResolverException : ApplicationException
{
public TypeResolverException()
{
}
public TypeResolverException(string message)
: base(message)
{
}
public TypeResolverException(string message, Exception innerException)
: base(message, innerException)
{
}
public TypeResolverException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
3.一个用于管理服务的服务(可以管理本地服务或WCF远程服务,可以实现Cache,更进一步也可以实现负载均衡)
接口定义:
namespace Practices.Services.ServiceManagers.Contracts
{
[ServiceContract]
public interface IServiceManager
{
#region Info Getting
[OperationContract]
List<string> GetServiceGroups();
[OperationContract]
List<ServiceInfo> GetServiceInfos(string groupName);
#endregion
#region ServiceNanagement
[OperationContract]
Object GetService(string groupName, string serviceName, Dictionary<string, Object> parameters, AppDomain workerDomain);
#endregion
#region Chache Management
[OperationContract]
void ClearChache();
[OperationContract]
void ClearChache(string poolName);
#endregion
}
}
namespace Practices.Services.ServiceManagers.Contracts
{
public interface IServiceFactory
{
Object CreateService(IServiceManager serviceManager, Dictionary<string, Object> parameters, AppDomain workerDomain);
}
}
namespace Practices.Services.ServiceManagers.Contracts
{
public class ServiceInfo
{
public string Name
{ get; set; }
public string Factory
{ get; set; }
public string Pooling
{ get; set; }
public string Singleton
{ get; set; }
public Dictionary<string, Object> Parameters
{ get; set; }
}
}
namespace Practices.Services.ServiceManagers.Contracts
{
public class ServiceManagerException:ApplicationException
{
public ServiceManagerException()
{
}
public ServiceManagerException(string message)
: base(message)
{
}
public ServiceManagerException(string message,Exception innerException)
: base(message, innerException)
{
}
public ServiceManagerException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
本地实现:
<?xml version="1.0" encoding="utf-8" ?>
<ServiceModel>
<ServiceGroups>
<ServiceGroup name ="Dispacher">
<Services>
<Service name="OCREntryDispacher" factory ="OCREntryDispacherFactory" pooling="false" singleton="false" >
<Parameters>
<Parameter name ="path" value ="Test.OCREntry"/>
<Parameter name ="type" value ="Test.OCREntryDispacher,Test"/>
<Parameter name ="GroupName" value ="OCREntry"/>
<Parameter name ="BatchSize" value="100"/>
<Parameter name ="ThreadCount" value="1" />
</Parameters>
</Service>
</Services>
</ServiceGroup>
<ServiceGroup name ="OCREntry">
<Services>
<Service name="1.00.00" factory ="OCREntryFactory" pooling="false" singleton="false" >
<Parameters>
<Parameter name ="path" value ="Test.OCREntry\1.00.00"/>
<Parameter name ="processor" value="Test.OCREntry,Test"/>
<Parameter name ="processorUser" value="XXX" />
</Parameters>
</Service>
</Services>
</ServiceGroup>
</ServiceGroups>
<Factories>
<Factory name="ParameterObjectFactory" type="Practices.Service.ServiceManager.LocalServiceManager.ParameterObjectFactory,Practices.Service.ServiceManager.LocalServiceManager"/>
<Factory name="CommonObjectFactory" type="Practices.Service.ServiceManager.LocalServiceManager.CommonObjectFactory,Practices.Service.ServiceManager.LocalServiceManager" />
<Factory name="WCFClientFactory" type="Practices.Service.ServiceManager.LocalServiceManager.WCFClientFactory,Practices.Service.ServiceManager.LocalServiceManager" />
</Factories>
</ServiceModel>
namespace Practices.Services.ServiceManagers.Local
{
public class LocalServiceManager : ServiceBase, IServiceManager
{
#region Private Property
private static ServiceGroupDictionary ServiceGroups
{
get { return ServiceModelRepository.GetServiceModel().ServiceGroups; }
}
private static FactoryDictionary ServiceFactories
{
get { return ServiceModelRepository.GetServiceModel().Factories; }
}
#endregion
#region IServiceManager Members
public List<string> GetServiceGroups()
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
return ServiceGroups.Select(group => group.Name).ToList();
}
public List<ServiceInfo> GetServiceInfos(string groupName)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
if (!ServiceGroups.Contains(groupName))
throw new ServiceManagerException(String.Format("Get Service Names[[{0}]]: Can not find group .",
groupName));
return
ServiceGroups[groupName].Services.Select(service => CreateServiceInfo(service)).ToList();
}
public object GetService(string groupName, string serviceName, Dictionary<string, object> parameters,
AppDomain workerDomain)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
if (!ServiceGroups.Contains(groupName))
throw new ServiceManagerException(String.Format("Get Group[[{0}]]: Can not find group .", groupName));
ServiceGroup serviceGroup = ServiceGroups[groupName];
if (!serviceGroup.Services.Contains(serviceName))
throw new ServiceManagerException(String.Format("Get Service[[{0}]]: Can not find service .",
serviceName));
Service service = serviceGroup.Services[serviceName];
if (!ServiceFactories.Contains(service.Factory))
throw new ServiceManagerException(String.Format("Get Factory[[{0}]]: Can not find factory .",
service.Factory));
Factory factory = ServiceFactories[service.Factory];
return GetService(service, parameters, factory, workerDomain);
}
public void ClearChache()
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
ObjectCacheManager.ClearChache();
}
public void ClearChache(string poolName)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
ObjectCacheManager.ClearChache(poolName);
}
#endregion
#region Helper Method
private Object GetService(Service service, Dictionary<string, object> parameters, Factory factory,
AppDomain workerDomain)
{
if (service.SingleTon
|| service.Pooling)
{
object obj = ObjectCacheManager.GetObject(service.Name, service.SingleTon);
if (obj != null) return obj;
}
var serviceFactory = (IServiceFactory) TypeResolver.CreateInstance(string.Empty, factory.Type, null, null);
parameters = service.Parameters.ToDictionary(parameters);
object result = serviceFactory.CreateService(this, parameters, workerDomain);
if (service.SingleTon
|| service.Pooling)
{
ObjectCacheManager.PutObject(service.Name, service.SingleTon, result);
}
return result;
}
private static ServiceInfo CreateServiceInfo(Service service)
{
return new ServiceInfo
{
Name = service.Name,
Factory = service.Factory,
Pooling = service.Pooling,
Singleton = service.Singleton,
Parameters = service.Parameters.ToDictionary(new Dictionary<string, Object>())
};
}
#endregion
}
}
HELPER:
namespace Practices.Services.ServiceManagers.Local
{
internal static class ObjectCacheManager
{
#region Private Fields
private static readonly Dictionary<string, List<Object>> s_ObjectCachePools =
new Dictionary<string, List<Object>>();
#endregion
#region Public Methods
public static object GetObject(string poolName, bool singleTon)
{
object result = null;
if (singleTon)
{
lock (s_ObjectCachePools)
{
if (s_ObjectCachePools.ContainsKey(poolName)
&& s_ObjectCachePools[poolName].Count > 0)
{
result = s_ObjectCachePools[poolName][0];
}
}
}
else
{
lock (s_ObjectCachePools)
{
if (s_ObjectCachePools.ContainsKey(poolName)
&& s_ObjectCachePools[poolName].Count > 0)
{
result = s_ObjectCachePools[poolName][0];
s_ObjectCachePools[poolName].RemoveAt(0);
}
}
}
return result;
}
public static void PutObject(string poolName, bool singleTon, object result)
{
if (singleTon)
{
lock (s_ObjectCachePools)
{
if (!s_ObjectCachePools.ContainsKey(poolName))
{
s_ObjectCachePools.Add(poolName, new List<Object>());
}
s_ObjectCachePools[poolName].Add(result);
}
}
var cacheControler = result as ICacheControler;
if (cacheControler != null
&& cacheControler.Cacheable)
{
cacheControler.PoolName = poolName;
cacheControler.Cacheing += Service_Cacheing;
}
}
public static void ClearChache()
{
lock (s_ObjectCachePools)
{
s_ObjectCachePools.Clear();
}
}
public static void ClearChache(string poolName)
{
lock (s_ObjectCachePools)
{
if (s_ObjectCachePools.ContainsKey(poolName))
{
s_ObjectCachePools.Remove(poolName);
}
}
}
#endregion
#region Event Handler
private static void Service_Cacheing(object sender, EventArgs e)
{
var cacheControler = sender as ICacheControler;
if (cacheControler != null && cacheControler.PoolName != "")
{
lock (s_ObjectCachePools)
{
if (!s_ObjectCachePools.ContainsKey(cacheControler.PoolName))
{
s_ObjectCachePools.Add(cacheControler.PoolName, new List<Object>());
}
s_ObjectCachePools[cacheControler.PoolName].Add(sender);
}
}
}
#endregion
}
}
MODEL:
namespace Practices.Services.ServiceManagers.Local.Model
{
[Serializable]
public class FactoryDictionary : KeyedCollection<string, Factory>
{
#region Override Member
protected override string GetKeyForItem(Factory item)
{
return item.Name;
}
#endregion
#region Constructor Member
public FactoryDictionary()
{
}
public FactoryDictionary(IEnumerable<Factory> factoryDictionary)
{
foreach (Factory factory in factoryDictionary)
{
Items.Add(new Factory(factory));
}
}
#endregion
}
[Serializable]
public class Factory
{
#region Constructor Member
public Factory()
{
}
public Factory(Factory factory)
{
Name = factory.Name;
Type = factory.Type;
}
#endregion
#region Public Property
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("type")]
public string Type { get; set; }
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local.Model
{
[Serializable]
public class ParameterDictionary : KeyedCollection<string, Parameter>
{
#region Override Member
protected override string GetKeyForItem(Parameter item)
{
return item.Name;
}
#endregion
#region Constructor Member
public ParameterDictionary()
{
}
public ParameterDictionary(IEnumerable<Parameter> parameterDictionary)
{
foreach (Parameter parameter in parameterDictionary)
{
Items.Add(new Parameter(parameter));
}
}
#endregion
#region Public Member
public Dictionary<string,Object> ToDictionary(Dictionary<string,Object> parameters)
{
Dictionary<string, Object> returnParameter = parameters ?? new Dictionary<string, object>();
foreach (Parameter item in Items)
{
if (!returnParameter.ContainsKey(item.Name))
{
returnParameter[item.Name] = item.Value;
}
}
return returnParameter;
}
#endregion
}
[Serializable]
public class Parameter
{
#region Constructor Member
public Parameter()
{
}
public Parameter(Parameter parameter)
{
Name = parameter.Name;
Value = parameter.Value;
}
#endregion
#region Public Property
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local.Model
{
[Serializable]
public class ServiceDictionary : KeyedCollection<string, Service>
{
#region Override Member
protected override string GetKeyForItem(Service item)
{
return item.Name;
}
#endregion
#region Constructor Member
public ServiceDictionary()
{
}
public ServiceDictionary(IEnumerable<Service> serviceDictionary)
{
foreach (Service service in serviceDictionary)
{
Items.Add(new Service(service));
}
}
#endregion
}
[Serializable]
public class Service
{
#region Constructor Member
public Service()
{
Parameters = new ParameterDictionary();
}
public Service(Service service)
{
Name = service.Name;
Factory = service.Factory;
Pooling = service.Pooling;
SingleTon = service.SingleTon;
Parameters = new ParameterDictionary(service.Parameters);
}
#endregion
#region Public Property
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("factory")]
public string Factory { get; set; }
[XmlAttribute("pooling")]
public bool Pooling { get; set; }
[XmlAttribute("singleton")]
public bool SingleTon { get; set; }
[XmlArray("Parameters")]
[XmlArrayItem("Parameter")]
public ParameterDictionary Parameters { get; set; }
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local.Model
{
[Serializable]
public class ServiceGroupDictionary : KeyedCollection<string, ServiceGroup>
{
#region Override Member
protected override string GetKeyForItem(ServiceGroup item)
{
return item.Name;
}
#endregion
#region Constructor Member
public ServiceGroupDictionary()
{
}
public ServiceGroupDictionary(IEnumerable<ServiceGroup> serviceGroupDictionary)
{
foreach (ServiceGroup serviceGroup in serviceGroupDictionary)
{
Items.Add(new ServiceGroup(serviceGroup));
}
}
#endregion
}
[Serializable]
public class ServiceGroup
{
#region Constructor Member
public ServiceGroup()
{
Services = new ServiceDictionary();
}
public ServiceGroup(ServiceGroup serviceGroup)
{
Name = serviceGroup.Name;
Services = new ServiceDictionary(serviceGroup.Services);
}
#endregion
#region Public Property
[XmlAttribute("name")]
public string Name { get; set; }
public ServiceDictionary Services
{ get; set; }
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local.Model
{
[Serializable]
public class ServiceModel
{
#region Constructor Member
public ServiceModel()
{
ServiceGroups = new ServiceGroupDictionary();
Factories = new FactoryDictionary();
}
public ServiceModel(ServiceModel serviceModel)
{
ServiceGroups = new ServiceGroupDictionary(serviceModel.ServiceGroups);
Factories = new FactoryDictionary(serviceModel.Factories);
}
#endregion
#region Public Property
[XmlArray("ServiceGroups")]
[XmlArrayItem("ServiceGroup")]
public ServiceGroupDictionary ServiceGroups
{ get; set; }
[XmlArray("Factories")]
[XmlArrayItem("Factory")]
public FactoryDictionary Factories
{ get; set; }
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local.Model
{
public static class ServiceModelRepository
{
#region Static Members
private static readonly ServiceModel s_ServiceModel;
#endregion
#region Static Constructor
static ServiceModelRepository()
{
s_ServiceModel = Load(GetConfigFilePath());
}
#endregion
#region Public Methods
public static ServiceModel GetServiceModel()
{
return s_ServiceModel;
}
public static void SaveServiceModel()
{
return Save(s_ServiceModel,GetConfigFilePath());
}
#endregion
#region Private Static Methods
private static ServiceModel Load(string fileName)
{
if (!File.Exists(fileName))
{
throw new ApplicationException("Load ServiceModel:Can not find the file " + fileName);
}
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ServiceModel));
using (XmlTextReader reader = new XmlTextReader(fileName))
{
return serializer.Deserialize(reader) as ServiceModel;
}
}
catch (Exception ex)
{
throw new ServiceManagerException("Load ServiceModel:" + ex.Message);
}
}
private static void Save(ServiceModel serviceModel, String fileName)
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ServiceModel));
using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.UTF8))
{
serializer.Serialize(writer, serviceModel);
}
}
catch (Exception ex)
{
throw new ServiceManagerException("Save ServiceModel:" + ex.Message);
}
}
private static string GetConfigFilePath()
{
Uri url = new Uri(Path.GetDirectoryName(typeof(ServiceModelRepository).Assembly.CodeBase));
return Path.Combine(url.LocalPath, "LocalServiceManager.config");
}
#endregion
}
}
FACTORY:
namespace Practices.Services.ServiceManagers.Local
{
public class CommonObjectFactory : IServiceFactory
{
#region IServiceFactory Members
public object CreateService(IServiceManager serviceManager, Dictionary<string, Object> parameters, AppDomain workerDomain)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
string path = parameters["path"].ToString();
string typeString = parameters["type"].ToString();
return TypeResolver.CreateInstance(path, typeString, workerDomain, null);
}
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local
{
public class WCFClientFactory:IServiceFactory
{
#region IServiceFactory Members
public object CreateService(IServiceManager serviceManager, Dictionary<string, Object> parameters, AppDomain workerDomain)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
string url = parameters["url"].ToString();
string path = parameters["path"].ToString();
string typeString = parameters["contracttype"].ToString();
Type contractType = TypeResolver.ResolveType(path, typeString, null);
return CreateWCFClient(contractType,url);
}
private object CreateWCFClient(Type contractType, string url)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
Type channelFactoryGenericType = typeof (ChannelFactory<>).MakeGenericType(new[] {contractType});
MethodInfo method = channelFactoryGenericType.GetMethod("CreateChannel",
new[]
{
typeof (System.ServiceModel.Channels.Binding
),
typeof (EndpointAddress)
});
return method.Invoke(null, new Object[] {new NetTcpBinding(), new EndpointAddress(url)});
}
#endregion
}
}
namespace Practices.Services.ServiceManagers.Local
{
public class ParameterObjectFactory : IServiceFactory
{
#region IServiceFactory Members
public object CreateService(IServiceManager serviceManager, Dictionary<string, Object> parameters, AppDomain workerDomain)
{
Logger.WriteLog(GetType().Name, new StackFrame().GetMethod().Name);
string path = parameters["path"].ToString();
string typeString = parameters["type"].ToString();
return TypeResolver.CreateInstance(path, typeString, workerDomain, new object[] { parameters });
}
#endregion
}
}