.net remoting和wcf自托管——一个bug引发的警示
一、解决问题,需要深入,并从细节入手,多从代码找原因,不能认为代码是死的,不会出错:
之前代码都运行良好,突然某一天,在我电脑上出问题了。出了问题,那就应该找出原因。其实这个问题,本身并不难,好歹给你报出了个错:
获取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();
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 = ;
while (true)
{
try
{
socket.Bind(new IPEndPoint(IPAddress.Any, result)); socket.Listen(); 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,即远程对象的代理,我们就可以调用接口中的方法了。
注意:实际代码中,需要考虑通道的释放等问题。
.net remoting和wcf自托管——一个bug引发的警示的更多相关文章
- 由一个bug引发的SQLite缓存一致性探索
问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug ...
- z-index失效原因分析——由一个bug引发的对层叠上下文和z-index属性的深度思考
新年刚开工就被一个bug虐得整个人都不好了,特地记录下. (一)bug描述 在一个fixed-data-table(一个React组件)制作的表格中,需要给表头的字段提示的特效,所以做了一个提示层,但 ...
- MyBatis 学习记录7 一个Bug引发的思考
主题 这次学习MyBatis的主题我想记录一个使用起来可能会遇到,但是没有经验的话很不好解决的BUG,在特定情况下很容易发生. 异常 java.lang.IllegalArgumentExceptio ...
- MySQL 5.6的一个bug引发的故障
突然收到告警,提示mysql宕机了,该服务器是从库.于是尝试登录服务器看看能否登录,发现可以登录,查看mysql进程也存在,尝试登录提示 ERROR (HY000): Too many connect ...
- Hexo next博客的pjax一个Bug引发的关于pjax用法的小技巧-----pjax后图片点击放大的js失效
文章目录 广告: 背景 发现 解决 get技能 广告: 本人博客地址:https://mmmmmm.me 源码:https://github.com/dataiyangu/dataiyangu.git ...
- .Net remoting, Webservice,WCF,Socket区别
传统上,我们把计算机后台程序(Daemon)提供的功能,称为"服务"(service).比如,让一个杀毒软件在后台运行,它会自动监控系统,那么这种自动监控就是一个"服务& ...
- 大比速:remoting、WCF(http)、WCF(tcp)、WCF(RESTful)、asp.net core(RESTful)
近来在考虑一个服务选型,dotnet提供了众多的远程服务形式.在只考虑dotnet到dotnet的情形下,我们可以选择remoting.WCF(http).WCF(tcp).WCF(RESTful). ...
- 关于通信的关键词UDP/(TCP/IP)/IPC/RPC/.NET Remoting/WebService/WCF/Http 系列
OSI七层和TCP/IP四层的关系 1.1 OSI引入了服务.接口.协议.分层的概念,TCP/IP借鉴了OSI的这些概念建立TCP/IP模型. 1.2 OSI先有模型,后有协议,先有标准,后进行实践: ...
- 大比速:remoting、WCF(http)、WCF(tcp)、WCF(RESTful)、asp.net core(RESTful) .net core 控制台程序使用依赖注入(Autofac)
大比速:remoting.WCF(http).WCF(tcp).WCF(RESTful).asp.net core(RESTful) 近来在考虑一个服务选型,dotnet提供了众多的远程服务形式.在只 ...
随机推荐
- 深度学习1--ubuntu14.04+win10双系统
相当多的内容参考的百度经验https://jingyan.baidu.com/article/eb9f7b6d79a7b4869364e885.html?qq-pf-to=pcqq.group 还可以 ...
- ajax使用formdata 提交excel文件表单到rails解析
.modal-body .container-fluid .row .col-md-12 1.下载模板文件 = link_to '模板文件' .row .col-md-12 = form_tag '' ...
- IM协议
四种协议英文全称与简称 1->IMPP(Instant Messaging And PresenceProtocol):即时信息和空间协议 2->PRIM(Presence and Ins ...
- Spring_HelloWord
环境:IntelliJ 14 : jdk1.8 Spring操作步骤 1.新建项目---Spring Batch 2.IntelliJ会自动加载jar包 3.现在就可以在src目录下写Java类文 ...
- 定制AIX操作系统的shell环境
操作系统与外部最主要的接口就叫做shell.shell是操作系统最外面的一层.shell管理你与操作系统之间的交互:等待你输入,向操作系统解释你的输入,并且处理各种各样的操作系统的输出结果. shel ...
- 快乐学习 Ionic Framework+PhoneGap 手册1-3 {面板切换}
编程的快乐和乐趣,来自于能成功运行程序并运用到项目中,会在后面案例,实际运用到项目当中与数据更新一起说明 从面板切换开始,请看效果图和代码,这只是一个面板切换的效果 Index HTML Code & ...
- PHP 最大化资源配置 Resource Limits 错误两则
报错信息1:PHP Fatal error: Allowed memory size of 25165824 bytes exhausted (tried to allocate 67108888 b ...
- Cocos2d-x项目移植到WP8系列之六:C#工程使用C++的DLL
原文链接: http://www.cnblogs.com/zouzf/p/3984510.html 此时,一些大问题都被解决后,整个工程基本能跑起来了,最后一个大问题是:业务层是用Lua开发的,底层的 ...
- Java public class 与 class 区别
在编写类的时候可以使用两种定义方式: public class 定义类 class 定义类 1.public class 定义类 如果一个类声明的时候使用了public class,则类名必须与文件名 ...
- [算法]在单链表和双链表中删除倒数第k个结点
题目: 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 要求: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1). 解答: 让链表从头 ...