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

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

获取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引发的警示的更多相关文章

  1. 由一个bug引发的SQLite缓存一致性探索

    问题 我们在生产环境中使用SQLite时中发现建表报“table xxx already exists”错误,但DB文件中并没有该表.后面才发现这个是SQLite在实现过程中的一个bug,而这个bug ...

  2. z-index失效原因分析——由一个bug引发的对层叠上下文和z-index属性的深度思考

    新年刚开工就被一个bug虐得整个人都不好了,特地记录下. (一)bug描述 在一个fixed-data-table(一个React组件)制作的表格中,需要给表头的字段提示的特效,所以做了一个提示层,但 ...

  3. MyBatis 学习记录7 一个Bug引发的思考

    主题 这次学习MyBatis的主题我想记录一个使用起来可能会遇到,但是没有经验的话很不好解决的BUG,在特定情况下很容易发生. 异常 java.lang.IllegalArgumentExceptio ...

  4. MySQL 5.6的一个bug引发的故障

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

  5. Hexo next博客的pjax一个Bug引发的关于pjax用法的小技巧-----pjax后图片点击放大的js失效

    文章目录 广告: 背景 发现 解决 get技能 广告: 本人博客地址:https://mmmmmm.me 源码:https://github.com/dataiyangu/dataiyangu.git ...

  6. .Net remoting, Webservice,WCF,Socket区别

    传统上,我们把计算机后台程序(Daemon)提供的功能,称为"服务"(service).比如,让一个杀毒软件在后台运行,它会自动监控系统,那么这种自动监控就是一个"服务& ...

  7. 大比速:remoting、WCF(http)、WCF(tcp)、WCF(RESTful)、asp.net core(RESTful)

    近来在考虑一个服务选型,dotnet提供了众多的远程服务形式.在只考虑dotnet到dotnet的情形下,我们可以选择remoting.WCF(http).WCF(tcp).WCF(RESTful). ...

  8. 关于通信的关键词UDP/(TCP/IP)/IPC/RPC/.NET Remoting/WebService/WCF/Http 系列

    OSI七层和TCP/IP四层的关系 1.1 OSI引入了服务.接口.协议.分层的概念,TCP/IP借鉴了OSI的这些概念建立TCP/IP模型. 1.2 OSI先有模型,后有协议,先有标准,后进行实践: ...

  9. 大比速: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. 生于MVP,死于PMF

    本文的主要内容会按照是什么.为什么以及如何做的逻辑展开,主要包括以下几部分: 什么是MVP与PMF: 为什么要有MVP与PMF: 如何创建MVP: 如何验证PMF. 什么是MVP与PMF MVP(Mi ...

  2. $《第一行代码:Android》读书笔记——第10章 Android网络编程

    (一)WebView的用法 1.WebView也是一个普通的控件. 2.常用用法: WebView webView = (WebView)findViewById(R.id.web_view); we ...

  3. 多个网络请求成功返回再执行另外任务的思路分析(iOS)

    前言 今天我们来讨论一个经常出现的需求场景,也是一个老话题.在开发中我们往往会遇到需要进行多个网络请求,并且需要多个网络请求成功返回后再做其他事的场景.比如同一个界面显示的内容需要用到两个网络接口,而 ...

  4. vue项目的webpack设置请求模拟数据的接口方法

    最近在跟着视频写饿了吗vue项目,其中模拟数据由于webpack版本变化,跟视频中不一致,下方博客有解决方案,其实视频里面的还能看懂,现在webpack的服务都在插件包里了,好难找. 请参考:http ...

  5. 模型融合之blending和stacking

    1. blending 需要得到各个模型结果集的权重,然后再线性组合. """Kaggle competition: Predicting a Biological Re ...

  6. ASP.NET5 MVC6 利用Middleware 创建可访问HttpContext 的业务类工厂。(代替HttpContext.Current)

    我们的目标是在后台业务处理类中,能够很容易的取得用户信息或者其它HTTP请求相关的信息. 所以,首先我们需要一个存储这些信息的类: public class RequestData { public ...

  7. Oralce查询后修改数据,弹窗报提示these query result are not updateable,include the ROWID to get updateable

    select t.*, (select a.ANNEXNAME from base_annex a where a.id = t.closeFile) closeFileName, (select a ...

  8. SQl查询基础

    SQL语言是一门简单易学却又功能强大的语言,他让你快速上手并写出比较复杂的查询语句,但对于大多数开发者来书,使用SQL查询数据库并没有一个抽象的过程和一个合理的步骤,这很可能会是在写一些特定的查询语句 ...

  9. JavaScript -- 练习,Dom 获取节点

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. QT QFtp使用实例 从FTP下载一个文件

    1. ftp://ftp.denx.de/pub/u-boot/lowboot-1.0.0.patch.gz  下载文件 FtpGet.h #ifndef FTPGET_H #define FTPGE ...