• 基于AppDomain的插件开发WCF+HttpServer分布式部署(六)


    前面实现了单机程序中使用的插件框架,但如果插件以服务形式存在,并且分布在多个服务器上, 更新一次插件需要到每个服务器上进行更新,这样很不方便。这次我们在此原框架基础上,利用WCF在进程中Host一个WebService,然后管理端引用该服务后,就可以指的对被管理运算服务器进行插件更新了。

    插件管理服务:

    /// <summary>

    ///插件管理接口

    /// </summary>

    [ServiceContract]

    public interface IPluginServiceContract

    {

    [OperationContract]

    PluginItem[] List();

    [OperationContract]

    void Add(string assemblyName, string pluginUri);

    [OperationContract]

    void Remove(string assemblyName);

    }

    /// <summary>

    ///数据类

    /// </summary>

    [DataContract]

    public class PluginItem

    {

    /// <summary>

    ///程序集名称

    /// </summary>

    [DataMember]

    public string AssemblyName { get; set; }

    /// <summary>

    ///更新日期

    /// </summary>

    [DataMember]

    public DateTime UpdateTime { get; set; }

    }

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false)]

    public class PluginServiceImpl : IPluginServiceContract

    {

    private DirectoryInfo pluginPath;

    public PluginServiceImpl(string pluginPath)

    {

    this.pluginPath = new DirectoryInfo(pluginPath);

    }

    /// <summary>

    ///枚举当前所有插件

    /// </summary>

    /// <returns></returns>

    public PluginItem[] List()

    {

    var ret = this.pluginPath.GetFiles("*.dll").ToList().ConvertAll(d =>

    new PluginItem() { AssemblyName = Path.GetFileNameWithoutExtension(d.Name), UpdateTime = d.LastWriteTime });

    return ret.ToArray();

    }

    /// <summary>

    ///添加或者更新一个插件

    /// </summary>

    /// <param name="assemblyName">程序集名称</param>

    /// <param name="pluginUri">下载最新插件程序集的URI地址 eg:http://remote.com/plugins/plugins.hello.dll </param>

    public void Add(string assemblyName, string pluginUri)

    {

    byte[] pluginContent = new System.Net.WebClient().DownloadData(pluginUri);

    if(!assemblyName.ToLower().EndsWith(".dll"))

    {

    assemblyName = string.Concat(assemblyName, ".dll");

    }

    File.WriteAllBytes(Path.Combine(pluginPath.FullName, assemblyName), pluginContent);

    }

    /// <summary>

    ///依程序集删除一个插件

    /// </summary>

    /// <param name="assemblyName">程序集名称</param>

    public void Remove(string assemblyName)

    {

    if (!assemblyName.ToLower().EndsWith(".dll"))

    {

    assemblyName = string.Concat(assemblyName, ".dll");

    }

    File.Delete(Path.Combine(pluginPath.FullName, assemblyName));

    }

    }

    /// <summary>

    ///插件WCF启动、停止类

    /// </summary>

    public class PluginService

    {

    private ServiceHost host;

    /// <summary>

    ///开始服务

    /// </summary>

    /// <param name="hostName">主机名</param>

    /// <param name="port">端口</param>

    /// <param name="pluginPath">插件目录,一定要和插件加载类配置成一样的目录</param>

    public void Start(string hostName, int port, string pluginPath = "plugins")

    {

    IPluginServiceContract serviceContract = new PluginServiceImpl(pluginPath);

    this.host = new ServiceHost(serviceContract, new UriBuilder("http", hostName, port, "pluginservice").Uri);

    var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();

    if (smb == null)

    {

    smb = new ServiceMetadataBehavior();

    host.Description.Behaviors.Add(smb);

    }

    smb.HttpGetEnabled = true;

    smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy12;

    host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding()

    , "mex");

    host.AddServiceEndpoint(typeof(IPluginServiceContract), new BasicHttpBinding()

    , "");

    host.Open();

    }

    /// <summary>

    ///停止服务

    /// </summary>

    public void Stop()

    {

    this.host.Close();

    }

    }

    最后是管理客户端调用:

    static void Main(string[] args)

    {

    using (WebReferences.PluginServiceImpl ps = new WebReferences.PluginServiceImpl())

    {

    var list = ps.List();

    foreach (var i in list)

    {

    Console.Write("{0}, {1}", i.AssemblyName, i.UpdateTime);

    }

    Console.WriteLine("开始删除");

    Console.ReadLine();

    if (list.Length > 0)

    {

    ps.Remove(list[0].AssemblyName);

    list = ps.List();

    foreach (var i in list)

    {

    Console.Write("{0}, {1}", i.AssemblyName, i.UpdateTime);

    }

    }

    Console.WriteLine("开始部署");

    Console.ReadLine();

    System.IO.Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(),"plugins"), "Plugins.*.dll").ToList().ForEach(d =>

    {

    //http://localhost/plugins/Plugins.HelloWorld.dll

    ps.Add(Path.GetFileNameWithoutExtension(d), "http://localhost/plugins/" + Path.GetFileName(d));

    });

    list = ps.List();

    foreach (var i in list)

    {

    Console.Write("{0}, {1}", i.AssemblyName, i.UpdateTime);

    }

    }

    Console.ReadLine();

    }

  • 相关阅读:
    读书笔记4瞬时相应网站的高性能架构
    读书笔记3大型网站的架构要素
    读书笔记2大型网站的架构模式
    可用的rtmp卫视直播地址
    html中的特殊符号表示法
    深入理解JS原型链与继承
    css3 media媒体查询器用法总结
    HTML条件注释用法诠释
    jQuery中$符号冲突问题 (转载)
    JS 输出对象的属性以及方法[转载]
  • 原文地址:https://www.cnblogs.com/evlon/p/wcfplugin.html
Copyright © 2020-2023  润新知