一、解决问题,需要深入,并从细节入手,多从代码找原因,不能认为代码是死的,不会出错:

之前代码都运行良好,突然某一天,在我电脑上出问题了。出了问题,那就应该找出原因。其实这个问题,本身并不难,好歹给你报出了个错:

获取Word远程代理服务失败:无法加载类型“clr:NoteFirst.KMS.Clients.RomoteInterface.IOfficeService, NoteFirst.KMS.Clients.RomoteInterface”。,
Server stack trace: 在 System.Runtime.Remoting.Messaging.MethodCall.ResolveMethod(Boolean bThrowIfNotResolved)在 System.Runtime.Remoting.Messaging.MethodCall.HeaderHandler(Header[] h)在 System.Runtime.Serialization.Formatters.Soap.ObjectReader.ParseObject(ParseRecord pr)在 System.Runtime.Serialization.Formatters.Soap.SoapHandler.StartChildren()在 System.Runtime.Serialization.Formatters.Soap.SoapParser.ParseXml()在 System.Runtime.Serialization.Formatters.Soap.SoapParser.Run()在 System.Runtime.Serialization.Formatters.Soap.ObjectReader.Deserialize(HeaderHandler handler, ISerParser serParser)在 System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize(Stream serializationStream, HeaderHandler handler)在 System.Runtime.Remoting.Channels.CoreChannel.DeserializeSoapRequestMessage(Stream inputStream, Header[] h, Boolean bStrictBinding, TypeFilterLevel securityLevel)在 System.Runtime.Remoting.Channels.SoapServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg,   ITransportHeaders& responseHeaders, Stream& responseStream)

net remoting在调用定义的接口时报错,无法加载类型,这错误是个什么样的错误,怎么就不能加载了,之前都好好的。为了解决这个问题,我花了一天多的时间。从系统运行环境,到office重新安装,折腾了个遍,就差装系统了。都说出了问题,从内部找原因,可是同事机器上的代码运行良好,我们的代码绝对一致。于是,我把目光就聚焦到外部环境上了。不过话说回来,外部环境也是有点问题的,比如安装了多个版本的office。在安装和卸载的频繁操作之下,很难知道注册表会不会出问题。

到了第二天,我就去改改代码,试着用另外一种方法解决问题。结果改着改着,就发现了代码原来是有bug的。前辈的代码,看似高深,调用了c++的很多方法。

TcpChannel tcpChannel = new TcpChannel(9998);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(OfficeServiceImplement), CHANNEL_NAME, WellKnownObjectMode.SingleCall);EventLog.WriteEntry("NoteFirst", "注册tcp remote服务成功");

之前remoting采用的是http通道,我给改成tcp通道,结果问题就解决了。我就想,仅仅是通道不同,就会解决问题吗,所以想着http通道肯定是可以的。

  channel = new HttpServerChannel(CHANNEL_NAME, GetEnablePort(), Provider);RemotingConfiguration.RegisterWellKnownServiceType(typeof(OfficeServiceImplement), OBJECT_URI, WellKnownObjectMode.Singleton);

看下GetEnablePort的定义:

        private static int GetEnablePort(){Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);int result = 4211;while (true){try{socket.Bind(new IPEndPoint(IPAddress.Any, result));socket.Listen(100);socket.Close();ShareDataRW.OfficeAddinServicesPort = result;break;}catch{++result;}}return result;}

动态获取了端口,并有赋值操作:ShareDataRW.OfficeAddinServicesPort = result;

 service = Activator.GetObject(typeof(IOfficeService), string.Format(OfficeService.ServiceUrl, ShareDataRW.OfficeAddinServicesPort)) as IOfficeService;

这个是客户端调用remoting的代码,看看 ShareDataRW.OfficeAddinServicesPort 端口是怎么获取的:

       public static int OfficeAddinServicesPort{get{return ReadShareDataStruct().OfficeAddinServicesPort;}set{ShareData sd = ReadShareDataStruct();sd.OfficeAddinServicesPort = value;WriteReadShareDataStruct(sd);}}

这里又引入了几个方法:

        //将数据从非托管内存块封送到新分配的指定类型的托管对象        private static ShareData ReadShareDataStruct(){return (ShareData)Marshal.PtrToStructure(ShareDataMemoryPoint, ShareDataType);}
        //将数据从托管对象封送到非托管内存块中private static void WriteReadShareDataStruct(ShareData data){Marshal.StructureToPtr(data, ShareDataMemoryPoint, false);}

ShareData是个结构体:

      [StructLayout(LayoutKind.Sequential)]private struct ShareData{public int ClientServicesPort;public int OfficeAddinServicesPort;public int WpsAddinServicesPort;public int MainWindowsHandle;}

Type ShareDataType = typeof(ShareData);  

ShareDataMemoryPoint因为牵扯到c++里面的东西,不过从字面上看,共享内存地址,我猜的。看了这么多代码,我们大致理解,它是通过共享内存实现的端口存放,那为什么服务器端存进去的端口和客户端取出来的端口就不一样呢?这是我的疑惑点。为什么之前的代码就没有发生过这样的事情,请不要老提过去好不好,代码是动态运行的,内存当中的活动也是动态的。有一种可能性,就是发布服务的端口在代码执行到那句的时候已经定好了,并把它写到内存中了。等客户端再去拿的时候,在这之前值被动了手脚。至于谁修改了它,什么时候修改的,这将是一个秘密,等待探寻。

二、WCF实现:

在这漫长的解决问题当中,我无意间看到微软的建议:把.net remoting迁移到wcf中。微软给出了具体的迁移步骤,特别详细,于是我就改写了代码,用wcf去实现:

定义协议
   [ServiceContract]public interface IOfficeService{[OperationContract]void InsertTo(Bibliography[] bibliographies);[OperationContract]IntPtr GetActiveDocumentWindowHandle();[OperationContract]void Insert(string stream);/// <summary>/// 获取文档的初始化时间/// </summary>/// <returns></returns>
        [OperationContract]DateTime GetDateTimeOfActivedDocument();}  

注意:方法不能同名

怎么实现并不重要,想怎么实现就怎么实现,我只管定义接口,这是发布服务,自托管服务:

  NetTcpBinding binding = new NetTcpBinding();Uri baseAddress = new Uri("net.tcp://localhost:8099/wcfserver");ServiceHost serviceHost = new ServiceHost(typeof(OfficeServiceImplement), baseAddress);serviceHost.AddServiceEndpoint(typeof(IOfficeService), binding, baseAddress);serviceHost.Open();EventLog.WriteEntry("NoteFirst", string.Format("The WCF server is ready at {0}", baseAddress));

再来看看客户端的调用:

  NetTcpBinding binding = new NetTcpBinding();String url = "net.tcp://localhost:8099/wcfserver";EndpointAddress address = new EndpointAddress(url);ChannelFactory<IOfficeService> channelFactory = new ChannelFactory<IOfficeService>(binding, address);service = channelFactory.CreateChannel();

拿到service,即远程对象的代理,我们就可以调用接口中的方法了。

注意:实际代码中,需要考虑通道的释放等问题。

转载于:https://www.cnblogs.com/wangqiang3311/p/9373483.html

.net remoting和wcf自托管——一个bug引发的警示相关推荐

  1. 『转』度百死去飞秋一个BUG引发的血案

    作了一篇文章度百死去飞秋一个BUG引发的血案,昨天,度百死去的美国客户发邮件给我,说我的软件出问题了,我查来查去,发现居然是服务器上一个目录无法删除,一删除就报 cannot read from th ...

  2. 一个bug引发的人生感悟

    文章目录 问题现象 原因分析 节目id和节目路径映射关系 uuid数据 流程分析 发包机 解决办法 感悟 问题现象 发包机 结果csv文件,不同progid指向同一视频路径问题 原因分析 节目id和节 ...

  3. std::uniform_real_distribution的一个bug引发的服务器崩溃

    文章目录 前言 崩溃问题 std::uniform_real_distribution<> 的bug bug 重现方法 总结 前言 近日发生一次线上游戏服务器宕机问题,通过日志和core文 ...

  4. 一个bug引发的血案(大爆炸)

    据传,在冷战时期,CIA曾成功向前苏联"输出"一个有设计缺陷的控制软件,该软件用来控制天然气主管道.(KGB从一家加拿大公司窃取该软件.)那个植入的Bug最终引发了1982年的西伯 ...

  5. 查看redis缓存大小_一个 bug 引发了服务器崩溃,对应 redis 的 key 回收原理你清楚了吗?...

    1 背景 项目中使用了 redis 做旁路缓存.读请求到来时,有以下操作:1.检查缓存,有则返回2.没有则读取数据库,将结果回写到缓存中. 写请求到来时,有以下操作:1.更新数据库 2.更新缓存(实际 ...

  6. mysql 5.6 bug_MySQL 5.6的一个bug引发的故障

    突然收到告警,提示mysql宕机了,该服务器是从库.于是尝试登录服务器看看能否登录,发现可以登录,查看mysql进程也存在,尝试登录提示 ERROR 1040 (HY000): Too many co ...

  7. 一个BUG引发的灾难:ORA-00600 [kjmchkiseq:!seq]

    对于打工人可能最痛苦的就是被告知的故障,数据库有监控.告警.每天巡检,自己做了一系列数据库的"安保"工作,本以为可以万无一失,中午在安心的睡觉中,被人告知数据库crash了.当时的 ...

  8. 学习笔记---Web服务、Remoting、WCF (上) --- Web服务

    自从程序设计诞生起, 如何最大限度的重用代码, 减小编码的重复劳动就是程序员永恒不变的课题. 我们从学习面向对象开始, 先后引入了很多种共享代码的手段, 随着学习的不断深入就越发觉得程序设计的发展过程 ...

  9. 软件测试培训分享:做软件测试工作如何清楚的描述一个bug

    一名合格的软件测试工程师是需要清楚的交代自己的工作任务的,必须要清楚的告诉技术员出现的bug,那么做软件测试工作如何清楚的描述一个bug呢?来看看下面的详细介绍. 软件测试培训分享:做软件测试工作如何 ...

  10. EnterLib PIAB又一个BUG?

    在<这是EnterLib PIAB的BUG吗?>一文中我们讨论了PIAB关于抽象基类的BUG,今天又发现了一个新的问题.问题的起因源于<IoC+AOP的简单实现>这篇文章,因为 ...

最新文章

  1. Java线程6个状态详解
  2. 一道浅浅的山脊 —— 游戏3D造型艺术的工业化进程
  3. 孩子学python用什么教材比较好-python大学里用哪本教材比较好?
  4. 你能打动客户的C++理由,一定要先说服自己相信
  5. 教你七招提高.NET网站性能
  6. sillyGirl拉库部署+oicq+screen稳定运行完整教程。
  7. python爬取某鱼的直播间信息
  8. ROS1 noetic + depthai_ros教程
  9. 欧标语言等级划分 C1,小语种欧标等级的要求
  10. 君正X1000芯片软件开发手册
  11. 简单的回显客户端/服务器应用
  12. Microsoft Edge浏览器使用时过滤网页广告弹窗等插件推荐---电脑初始维护
  13. IceCTF - All your Base are belong to us
  14. 机器学习极简入门教程(一)
  15. 清除一个挖矿程序、步骤!!!
  16. 第三方在线地图源有哪些?
  17. Xutils中网络请求
  18. 网站收录前期如何优化
  19. hyperledger cello 0.9.0 项目部署总结
  20. 基于参数化模型(MANO)的手势姿态估计---全面剖析

热门文章

  1. HTML常见标签学习
  2. WebRTC回声消除(1)
  3. 超级大富翁主题团建活动
  4. windows audio错误0x80070005
  5. 基于osgEarth的空间态势三维场景视点控制与卫星轨道绘制
  6. 复制命令(COPY)
  7. 技术分享 | Hulu视频广告系统中的算法应用
  8. Sentinel控制台 1.8.0实时监控空白
  9. windows和ubuntu双系统之双硬盘安装
  10. establish connection