• 关于silverlight的xap包与dll分离的一些事儿


    好久没写东西了,最近搞了下silverlight方面的东西,有一需求要求应用程序的模块和xap包分离,实现按需加载,模块化的更新,怎么做呢?

    在没思路的情况下,百度,google是最好的方法了,虽然能搜到得东西不多,不过也让我有了头绪,也就有了下面的文章。

    1.用WebClient从服务端下载

    这是一个用来接收和发送数据的类,这里我们用它来从服务端加载dll模块

         public void DownloadAssembly()
            {
                var webClient = new WebClient();
                webClient.OpenReadCompleted += webClient_OpenReadCompleted;
                // //这个方法是异步的,线程池会自动分配一个线程给它
                webClient.OpenReadAsync(new Uri("GridModule.dll", UriKind.Relative));
            }
    
            void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                AssemblyPart part=new AssemblyPart();
    
                //将读取的流转化为当前应用程序域中的程序集
                var asm=part.Load(e.Result );
                //创建一个实例
                object o = asm.CreateInstance("GridModule.GridPage");
                Page p = o as Page;
                this.MainFrame.Content = o;
            }

    上面的方法很好的实现了客户端按需加载,如果话题到了这里就结束,倒也是皆大欢喜,一切都很简单,可惜问题往往不是这样。下面有个纠结的地方

    AssemblyPart这个类的load方法MSDN上给了这么一句话

    You cannot load multiple versions of the same assembly into the current application domain.

    当前应用程序域中,你是无法加载同一程序集的多个版本的,这真让人抓狂啊,你不能加载,为什么就不能更新呢?

    这也导致了你一旦有新的程序集更新,那么必须得关掉浏览器,重新打开加载。

    2.WebClient与IE缓存

    运行在IE上的东西,貌似总能与IE缓存扯上关系,这东西真是让人又爱又恨。那么这里又和sliverlight有什么联系呢?我们知道,silverlight通常是将程序集资源编译成xap包放在服务器端,客户端打开浏览器将xap包下载到本地进行解析运行的,那么既然是在浏览器中打开的,有请求,有响应,IE缓存也势必会出来露个脸。

    说IE缓存是好东西,那的确是好东西,第一次打开过后,以后可以很快捷的再次打开。说IE缓存是坏东西,每当我想更新,客户端须得清理掉IE缓存,才能看到更新效果,或者说我服务端做一些URL处理,不过这些个IE内部的处理机制,谁知道哪天会来点莫名其妙的事情呢。

    想知道IE是怎么更新缓存的话,那么就去查下ETAG这个东西,你就知道了。

    3.1xap与dll分离,使用IE缓存做存储介质

    刚有点扯远了,现在扯回来点,看这小标题,该如何着手做呢?

    有以下几点需要做到的

    1.从服务端获取dll的方式

    2.本地存储、加载dll的方式

    3.实例化dll,或者说创建dll的对象,总之到了客户端,你得用它

    1.从服务端获取dll的方式

    说道这个,相信你肯定会想到一开始提到的webclient了吧,的确用它非常不错,都是现成的,而且它会将下载的东西存储在IE缓存中,连第二点要做的存储都帮你做了,实在是非常好啊。

    2.本地存储、加载dll的方式

    存储上面已经提到,那么怎么加载呢?其实你也已经看到了,就是AssemblyPart,有个load方法,会将stream转换成将要加载到应用程序域中程序集assembly。

    3.实例化DLL

    so easy 了。。。用了下小反射而已

    3.2 xap与dll分离,使用独立缓存做存储介质

    用独立缓存的原因是什么呢?是不想受IE缓存的控制,可以完全掌控在自己的手中,这感觉还是比较踏实的,话说100M的空间一般的应用的都可以了,要做到的还是上面提到的几点,只是怎么做变了

    1.从服务端获取dll的方式

    这次直接贴代码了,呵呵

    服务端

        [ServiceContract]
        public interface IGetAssembly
        {
            [OperationContract]
            Dictionary<string, string> GetAssembliesDic();
    
            [OperationContract]
            RemoteFileInfo GetAssemblyStream(DownloadRequest request);
    
        }
        [DataContract]
        public class DownloadRequest
        {
            [DataMember]
            public string FileName;
        }
    
        [DataContract]
        public class RemoteFileInfo
        {
            [DataMember]
            public string FileName;
    
            [DataMember]
            public long Length;
    
            [DataMember]
            public string Version;
    
            [DataMember]
            public byte[] FileByte;
        }

    实现方法

       public class GetAssembly : IGetAssembly
        {
    
            public Dictionary<string, string> GetAssembliesDic()
            {
                Dictionary<string, string> datas = new Dictionary<string, string>();
                foreach (string item in ConfigurationManager.AppSettings.AllKeys)
                {
                    datas.Add(item,
                       ConfigurationManager.AppSettings[item].ToString());
                }
    
                //if (datas.Count == 0)
                //{
                //    throw new Exception("应用程序dll配置获取失败");
                //}
    
                return datas;
            }
    
    
            public RemoteFileInfo GetAssemblyStream(DownloadRequest assembly)
            {
                RemoteFileInfo result = new RemoteFileInfo();
                try
                {
                    string filePath = System.IO.Path.Combine(@"E:\wwwroot\session\bin\dll", assembly.FileName);
                    System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath);
    
                    // check if exists
                    if (!fileInfo.Exists)
                        throw new System.IO.FileNotFoundException("File not found",
                                                                 assembly.FileName );
    
                    // open stream
                    System.IO.FileStream stream = new System.IO.FileStream(filePath,
                              System.IO.FileMode.Open, System.IO.FileAccess.Read);
    
                 
                    byte[] bs = new byte[stream.Length];
                    stream.Read(bs, 0, bs.Length);
                    System.Reflection.Assembly asm = System.Reflection.Assembly.Load(bs);
                   
                    // return result 
                    result.FileName = assembly.FileName ;
                    result.Length = fileInfo.Length;
                    result.FileByte = bs;
                    result.Version = asm.GetName().Version.ToString(); 
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return result;
            }
        }

    服务端很简单,提供2方法,获取版本信息,以及下载指定dll

    客户端

         /// <summary>
            /// 从服务器端加载dll
            /// </summary>
            /// <param name="dllName"></param>
            /// <param name="call"></param>
            /// <param name="errCall"></param>
            public void GetDllFromServer(string dllName,Action<RemoteFileInfo > call, Action<string,Exception> errCall)
            {
    
                RemoteFileInfo result;
                System.ServiceModel.BasicHttpBinding basic = new System.ServiceModel.BasicHttpBinding();
                basic.MaxReceivedMessageSize = 2147483647;
                basic.MaxBufferSize = 2147483647;
                basic.ReceiveTimeout = TimeSpan.FromMinutes(5);
                basic.TransferMode = System.ServiceModel.TransferMode.StreamedResponse;
                basic.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.None;
    
                IGetAssembly service = ClientService.ClientService<IGetAssembly>.GetServiceChannel(basic,
                new System.ServiceModel.EndpointAddress("http://192.168.104.47/wcf2nd/GetAssembly.svc"));
    
                try
                {
                    service.BeginGetAssemblyStream(new DownloadRequest
                    {
                        FileName = dllName
                    }, (res) =>
                    {
                        try
                        {
                            result = service.EndGetAssemblyStream(res);
    
                            if (!System.Windows.Deployment.Current.Dispatcher.CheckAccess())
                            {
                                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                                {
                                    if (call != null)
                                        call(result);
                                });
                            }
                            else
                            {
                                if (call != null)
                                    call(result);
                            }
                        }
                        catch (Exception ex)
                        {
                            System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                if (errCall != null)
                                    errCall(dllName,ex);
                            });
                        }
    
                    }, null);
                }
                catch (Exception ex)
                {
                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        if (errCall != null)
                            errCall(dllName,ex);
                    });
                }
    
            }

    这是主要的加载方法了,方法应该比较明了了。

    2.本地存储、加载dll的方式

    存储读取dll的方法

            /// <summary>
            /// 将程序集以二进制方式存入独立缓存
            /// </summary>
            /// <param name="path">路径</param>
            /// <param name="assemblyName">程序集名</param>
            /// <param name="stream">要写入的流</param>
            public void SaveIntoIsolatedStorage(string path, string assemblyName, Stream stream)
            {
    
                IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream assembly = null;
                try
                {
                    stream.Seek(0, SeekOrigin.Begin);
                    assembly = store.OpenFile(assemblyName, System.IO.FileMode.Create);
    
                    byte[] res = StreamToBytes(stream);
                    assembly.Write(res, 0, res.Length);
    
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    assembly.Close();
                }
            }
    
            /// <summary>
            /// 从独立缓存中读取程序集流
            /// </summary>
            /// <param name="path">路径</param>
            /// <param name="assemblyName">程序集名</param>
            /// <returns></returns>
            public Stream ReadFromIsolatedStorage(string path, string assemblyName)
            {
                IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream assembly = null;
                if (store.FileExists(assemblyName))
                {
                    assembly = store.OpenFile(assemblyName, System.IO.FileMode.Open);
                }
    
    
                return assembly;
            }    

    存储读取dll版本信息

            /// <summary>
            /// 获取独立缓存中存储的程序集版本集合
            /// </summary>
            /// <returns></returns>
            public  Dictionary<string, string> GetDllVersion()
            {
                Dictionary<string, string> dic = new Dictionary<string, string>();
                IsolatedStorageSettings appSetting = IsolatedStorageSettings.ApplicationSettings;
                foreach (string item in appSetting.Keys)
                {
                    if (item.IndexOf("dll") != -1)
                    {
                        dic.Add(item, appSetting[item].ToString());
                    }
                }
                return dic;
    
            }
    
            /// <summary>
            /// 将dll名称与版本号的键值对存入独立缓存,如果存在该键值则更新
            /// </summary>
            public void SetDllVersion(string dllName, string version)
            {
                IsolatedStorageSettings appSetting = IsolatedStorageSettings.ApplicationSettings;
                try
                {
                    if (!appSetting.Contains(dllName))
                    {
                        appSetting.Add(dllName, version);
                    }
                    else
                    {
                        appSetting[dllName] = version;
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

    3.实例化dll

    这里就和上面的一样了,都是用assemblypart里的load方法将stream转化为assembly

    匆匆忙忙的写完了,程序也没有经过过多优化,不过思想已经比较清楚的表达了,欢迎讨论,拍砖

  • 相关阅读:
    SQL统计
    数据库中GETDATE()函数格式化时间
    C#中Math类的计算整数的三种方法
    Excel 导入到Datatable 中,再使用常规方法写入数据库
    C#实现二维码功能,winform 以及 asp.net均可以用
    JPEG、PNG、GIF三者的区别与联系
    javaScript基础知识--变量提升和闭包
    js基础
    js基础知识
    js基础知识
  • 原文地址:https://www.cnblogs.com/whosedream/p/2778928.html
Copyright © 2020-2023  润新知