none
.net Remoting 的问题 RRS feed

  • 问题

  • 现在的结构是这样的
    表A,B,C
    接口IA,IB,IC分别是对表A,B,C的操作
    对应的实现有Aimpl,Bimpl,Cimpl
    宿主是IIS,在配置文件中

    <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Aimpl.rem"/>

    <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Bimpl.rem"/>

    <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Cimpl.rem"/>

    这样每加一个实现就要加一个配 置,目前已经有60左右了.

    现在突然说这样不好维护,要把所 有的结口改成一个,放到一个接口里.

    IA,IB,IC,有一些接口是 一统一的比如添加,修改等接口名称是一样的.

    如果要改,60个类,是很恐怖 的.而且系统可能会改出新的问题.

    主要问题是这个配置文件,每次有增加都要改,领导怕麻烦.


    2010年5月28日 9:48

答案

全部回复

  • 的确很可怕,不知道你们当初咋想的,粒度够细.

    2010年5月28日 9:53
  • 当初呀个基类,每个表一个类,继承一下基类.基本的添加,修改删除,就不用写方法了.

    因为另一个项目里是写在一起的,一大堆接口,方法.

    所以在这个项目里我一个表对应了一个文件(一个类),当时我想这样更清晰呀.

    问题是现在怎么解决呀.


    2010年5月29日 1:43
  • 我给你提个方法,我的理解是每个接口有自己的impl,那么可以这样来,

    把接口都放到一个assembly(dll)中,而对这些接口的实现可以放到一个或多个assembly(dll)中。

    当需要实例化某个接口时,通过LoadAssembly加载包含实现类的assembly(dll),然后从中查找直接继承

    该接口的class,查找成功后,使用Activator.Create创建对象,查找不到则转错误处理。

     

    2010年5月29日 1:54
  • 现在是Remoting不是直接创建的
    2010年5月29日 2:20
  • remoting 不是有两种方式吗?一种是通过配置文件,另一种是通过编码,使用工厂模式创建。
    • 已标记为答案 male110 2010年5月29日 6:11
    • 取消答案标记 male110 2010年5月29日 6:43
    2010年5月29日 2:49
  • 也是,我是想问,有没有其它的工具可以用的.我试试哈
    2010年5月29日 3:38
  • Assembly asb = Assembly.LoadFile(strPath);
                HttpChannel channel = new HttpChannel();
                ChannelServices.RegisterChannel(channel,false);
                //反射获取类型
                Type[]tps=asb.GetExportedTypes();
                foreach (Type t in tps)
                {
                    if (t.Name.Length <= 4 && t.Name.Substring(t.Name.Length - 4) != "Impl")
                        continue;
                    RemotingConfiguration.RegisterWellKnownServiceType(t,t.Name + ".rem", WellKnownObjectMode.SingleCall);
                }

    改成这样不行,现在的客户端是通过,http://localhost/service/a.rem这样的路径来获取远程对象的,这是测试时的客户端.

    正式的又有版本问题http://xxxx/service1_0/a.rem   1.0版本

    http://xxxx/service1_3/a.rem    1.3版本

    有没有更好的办法?


    2010年5月29日 6:48
  • 可能你的修改你的服务端,使用工厂模式激活,相关的实现,这里有:

    http://www.cnblogs.com/wayfarer/archive/2004/07/30/28723.html

    你可以仔细读下。

    2010年5月29日 7:34
  • Assembly asb = Assembly.LoadFile(strPath);
                HttpChannel channel = new HttpChannel();
                ChannelServices.RegisterChannel(channel,false);
                //反射获取类型
                Type[]tps=asb.GetExportedTypes();
                foreach (Type t in tps)
                {
                    if (t.Name.Length <= 4 && t.Name.Substring(t.Name.Length - 4) != "Impl")
                        continue;
                    RemotingConfiguration.RegisterWellKnownServiceType(t,t.Name + ".rem", WellKnownObjectMode.SingleCall);
                }

    改了,不行,改成代码了,跟原来的地址对不上.

    IIS宿主的.且不家版本问题,不知道怎么改了.


    2010年5月29日 8:35
  • 根据下面这个地址,你的服务可以按版本号和表名归类:

    http://localhost/service1-0/a.rem

    匹配规则: 基址 + 版本号 + 表名 + “.rem”;

    RemotingConfiguration.RegisterWellKnownServiceType(t,t.Name + ".rem", WellKnownObjectMode.SingleCall);
    下划线部分要加前置 "http://localhost/service1_0/"+t.Name+".rem".

    http://localhost/service1_0/ 放到配置文件中 <AppSetting name="BaseUri" value="http://localhost/service1_0/"/>

    • 已标记为答案 male110 2010年5月31日 0:43
    2010年5月29日 14:18
  • 怎么设置他的格式是binary,不是soap?
    2010年5月31日 1:32
  • 怎么设置他的格式是binary,不是soap?

    我确实没写过一行.net Remoting代码,这个问题,就交给懂 .net Remoting 的人来回答吧.
    2010年5月31日 1:42
  • string strBaseUri = ConfigurationManager.AppSettings["baseUri"];

    strBaseUri=strBaseUri.Replace("{version}",Constants.Version.Replace(".","_"));
                Assembly asb = Assembly.LoadFile(strPath);
                HttpChannel channel = new HttpChannel();
                ChannelServices.RegisterChannel(channel, false);
                //反射获取类型
                Type[] tps = asb.GetExportedTypes();
                foreach (Type t in tps)
                {
                    if (t.Name.Length <= 4 && t.Name.Substring(t.Name.Length - 4) != "Impl")
                        continue;
                    RemotingConfiguration.RegisterWellKnownServiceType(t,strBaseUri+ t.Name + ".rem", WellKnownObjectMode.SingleCall);
                }

     

     protected void Application_Start(object sender, EventArgs e)
     {

    RegisterService();

    }

    通过查看日志发现

    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/FaqQuestionImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/EmailTemplateImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/RolesImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/RoleFaqCategoryImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/RelativeProductTagImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/ProductsTagFilterImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/GenerateHomePageImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/ForumTagImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - http://localhost/TinydealWinRemote/AddressBookImpl.rem, 已注册成功
    2010-05-31 10:06:03,515 [8] WARN  Log - 服务已注册

    服务是注册的,但是在创建的时候就是出错,创建时的URL跟注册的一样.


    2010年5月31日 2:21
  • 出啥错?
    2010年5月31日 2:25
  •  public UserInfosServiceHelper()
            {
                String strUrl = Path.Combine(LogicBaseInfo.WebserviceUrl, "UserInfosImpl.rem").Replace("\\", "/");
                _Service = (IUserInfos)Activator.GetObject(typeof(IUserInfos), strUrl);
            }

    这里是创建远程对象,这里的strurl跟注册的一模一样.这个是在构造函数里

    然后用这个类的实例调用方法时就会出错.

    System.Runtime.Remoting.RemotingException: ???????????????????????????????????????System.Runtime.Remoting.RemotingException: ?????????http???????????????
       ??? System.Runtime.Remoting.Channels.ChannelServices.RegisterChannelInternal(IChannel chnl, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(IChannel chnl, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.RemotingConfigHandler.ConfigureChannels(RemotingXmlConfigFileData configData, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting(RemotingXmlConfigFileData configData, Boolean ensureSecurity)??????
       ??? System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting(RemotingXmlConfigFileData configData, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.RemotingConfigHandler.DoConfiguration(String filename, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.RemotingConfiguration.Configure(String filename, Boolean ensureSecurity)
       ??? System.Runtime.Remoting.Channels.Http.HttpRemotingHandler.InternalProcessRequest(HttpContext context)

    Server stack trace:


    Exception rethrown at [0]:
       在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       在 TinydealWin.Interfaces.IUserInfos.Exists(UserIdentity user, Int32 id)
       在 TinydealWin.Logic.UserInfosServiceHelper.Exists(Int32 id) 位置 E:\projects\TinydealWin\Projects\TinydealWin.Logic\UserInfosServiceHelper.cs:行号 21
       在 TinydealWin.Program.Main() 位置 E:\projects\TinydealWin\Projects\TinydealWin\Program.cs:行号 66


    2010年5月31日 2:51
  • 我有个问题,在下面这段代码中:

    public UserInfosServiceHelper()
            {
                String strUrl = Path.Combine(LogicBaseInfo.WebserviceUrl, "UserInfosImpl.rem").Replace("\\", "/");
                _Service = (IUserInfos)Activator.GetObject(typeof(IUserInfos), strUrl);
            }

    你给 strUrl 显示赋一个什么样的字符串, Activator.GetObject 能够成功?

    2010年5月31日 3:29
  • http://localhost/TinydealWinRemote/UserInfosImpl.rem最初时是这样的字符.改后也是这样的字符串,差别只是,如果用

    <wellknown mode="SingleCall" type="TinydealWin.Impl.UserInfosImpl,TinydealWin.Impl" objectUri="UserInfosImpl.rem"/>

    配置文件就能成功,一切正常

    改成代友注册就出错了


    2010年5月31日 3:57
  • 注册时的URL,跟创建时的一样的.我看了,跟日志中记录的完全一至,但就是不成功
    2010年5月31日 3:58
  • <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Aimpl.rem"/>

    <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Bimpl.rem"/>

    <wellknown mode="SingleCall" type="MySystem.impl" objectUri="Cimpl.rem"/>

    这个配置项目在客户端和服务器都有吧~ 是一样的吗?

    我的思路就是,既然能够通过读取配置项来运行程序,那么这些配置项也可以通过硬编码来提供,而不一定非要从文件读取.

    那么服务器和客户端都可以通过硬编码激活,而不用从配置项文件读取.

    2010年5月31日 5:07
  • 服务器端不需要 http://localhost.... 这些东西 只有客户端调用的时候,需要 http://localhost... 这些东西.
    2010年5月31日 5:17
  • http://www.soft000.com/down/remotingtest.rar

    这个是我做的测试,要不要http://localhost在服务端,都是一样的不行.

    如果改用配置文件就可以.

    帮看一下.怎么回事,要怎么改


    2010年5月31日 7:50
  • // 服务器端改动
    void Application_Start(object sender, EventArgs e) 
      {
        //在应用程序启动时运行的代码
      
        HttpChannel channel = new HttpChannel(9090);
        ChannelServices.RegisterChannel(channel, false);
    
        //RegisterWellKnownServiceType中第一个参数使用实现类的类型。
        string strUrl = "service1_0/test.rem";
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(impl.TestImpl), strUrl, WellKnownObjectMode.SingleCall);      
      }
    
    // 客户端改动
    static void Main(string[] args)
        {
          string strUrl = "http://localhost:9090/service1_0/test.rem";
    
          // Activator 第一个参数也需要使用实现类的类型。
          ITest service = (ITest)Activator.GetObject(typeof(TestImpl), strUrl);
          int x = service.Add(10, 20);
          Console.WriteLine(x);
          Console.ReadKey();
        }
    2010年5月31日 8:16
  • 你虚拟目录是怎么建的?


    2010年5月31日 8:24
  • 我试了,不行
    2010年5月31日 8:28
  • 我用 HttpChannel channel = new HttpChannel(9090); 指定了 9090 端口,也就是基址是 http://localhost:9090

    然后我注册的相对地址是 string strUrl = "service1_0/test.rem";

    客户端调用时,要访问的地址是:http://localhost:9090/service1_0/test.rem;

    和配置虚拟目录无关.

    我在VS中调试通过,先启动Web项目,然后启动客户端.

     

    2010年5月31日 8:39
  • 项目是IIS宿主的.

    我复制你的也没有成功呀,提示:无法连接到远程服务器

    区别就是在客户端是不引用IMPL的,只是通过接口来调用.只引用接口层,不引用实现层,我是下面的写法

     

     string strUrl = "http://localhost:9090/service1_0/test.rem";

                // Activator 第一个参数也需要使用实现类的类型。
                ITest service = (ITest)Activator.GetObject(typeof(ITest), strUrl);//这里是ITest,你是TestImpl
                int x = service.Add(10, 20);
                Console.WriteLine(x);
                Console.ReadKey();


    2010年5月31日 8:57
  • 你复制我的代码,按 F5 运行网站项目,然后在IE 中输入 http://localhost:9090/service1_0/test.rem?wsdl

     

    2010年5月31日 9:07
  • <definitions name="TestImpl" targetNamespace="http://schemas.microsoft.com/clr/nsassem/impl/impl%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">

    <message name="TestImpl.AddInput">
    <part name="a" type="xsd:int"/>
    <part name="b" type="xsd:int"/>
    </message>

    <message name="TestImpl.AddOutput">
    <part name="return" type="xsd:int"/>
    </message>

    <portType name="TestImplPortType">

    <operation name="Add" parameterOrder="a b">
    <input name="AddRequest" message="tns:TestImpl.AddInput"/>
    <output name="AddResponse" message="tns:TestImpl.AddOutput"/>
    </operation>
    </portType>

    <binding name="TestImplBinding" type="tns:TestImplPortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

    <suds:class type="ns0:TestImpl" rootType="MarshalByRefObject">
    <suds:implements type="ns2:ITest"/>
    </suds:class>

    <operation name="Add">
    <soap:operation soapAction="http://schemas.microsoft.com/clr/nsassem/impl.TestImpl/impl#Add"/>
    <suds:method attributes="public virtual"/>

    <input name="AddRequest">
    <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://schemas.microsoft.com/clr/nsassem/impl.TestImpl/impl"/>
    </input>

    <output name="AddResponse">
    <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://schemas.microsoft.com/clr/nsassem/impl.TestImpl/impl"/>
    </output>
    </operation>
    </binding>

    <message name="ITest.AddInput">
    <part name="a" type="xsd:int"/>
    <part name="b" type="xsd:int"/>
    </message>

    <message name="ITest.AddOutput">
    <part name="return" type="xsd:int"/>
    </message>

    <portType name="ITestPortType">

    <operation name="Add" parameterOrder="a b">
    <input name="AddRequest" message="tns:ITest.AddInput"/>
    <output name="AddResponse" message="tns:ITest.AddOutput"/>
    </operation>
    </portType>

    <binding name="ITestBinding" type="tns:ITestPortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <suds:interface type="ns2:ITest">
            </suds:interface>

    <operation name="Add">
    <soap:operation soapAction="http://schemas.microsoft.com/clr/nsassem/Interface.ITest/Interface#Add"/>

    <input name="AddRequest">
    <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://schemas.microsoft.com/clr/nsassem/Interface.ITest/Interface"/>
    </input>

    <output name="AddResponse">
    <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://schemas.microsoft.com/clr/nsassem/Interface.ITest/Interface"/>
    </output>
    </operation>
    </binding>

    <service name="TestImplService">

    <port name="TestImplPort" binding="tns:TestImplBinding">
    <soap:address location="http://localhost:9090/service1_0/test.rem"/>
    </port>
    </service>
    </definitions>
    2010年5月31日 9:14
  • 应该是正常的吧.

    你看那个客户端的我的代码

    string strUrl = "http://localhost:9090/service1_0/test.rem";

                // Activator 第一个参数也需要使用实现类的类型。
                ITest service = (ITest)Activator.GetObject(typeof(ITest), strUrl);
                int x = service.Add(10, 20);
                Console.WriteLine(x);
                Console.ReadKey();

    也正常吧,就是不行.

    不会真是人品问题吧


    2010年5月31日 9:18
  • 可以了,可能是我没启动服务端.

    运行时没有启动WEB项目.好奇怪.


    2010年5月31日 9:19
  • 可是我设了IIS目录指向到了这个虚拟目录呀?

    在实际项目中,没有服务程序,也是用的IIS宿主的.会有问题吗?


    2010年5月31日 9:20
  • 现在是我要先启动WEB端,再启动客户端.

    建了虚拟目录,也要打开里面的一个页面后才可以运行.

    配置文件里的不用,直接运行就可以.

    还有配置文件里是

    <serverProviders>
                        <formatter href="binary"/>
                    </serverProviders>

    指定了二进制格式.

    代码里要怎么指定?跟原来的一样,在配置文件里吗?


    2010年5月31日 9:26
  • 我上面给出的做法是支持服务宿主为window进程,,而非支持IIS的.

    我还得查下如何通过编码在IIS中宿主.net remoting服务.

    2010年5月31日 9:26
  • 必须指定端口号,不指定就不行.
    2010年5月31日 9:42
  • 在解决方案中,把网站的虚拟路径设置为:/service1_0,端口号设置为:1678

    服务器端只注册:

    void Application_Start(object sender, EventArgs e)
      {
        string strUrl = "test.rem";
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(impl.TestImpl), strUrl, WellKnownObjectMode.SingleCall);
      }

    启动调试,在IE输入:http://localhost:1678/service1_0/test.rem?wsdl

    这下可以符合IIS的模式.

    2010年5月31日 9:47
  • http://localhost/service1_0/test.rem?wsdl

    IIS不指定端口,这样是不行的.

    System.Runtime.Remoting.RemotingException: 找不到请求的服务

    改了也一样

    2010年5月31日 9:54
  • 大哥,麻烦你告诉我,你是在VS中调试测试的结果,还是在IIS中测试的结果?

    http://localhost/service1_0/test.rem?wsdl

    该路径等价于:

    http://localhost:80/service1_0/test.rem?wsdl

    如果在VS中调试的话,把网站的虚拟路径设置为:/service1_0,端口号设置为:80,

    然后你就可以用这个地址访问了 http://localhost/service1_0/test.rem?wsdl

     

    2010年5月31日 9:57
  • IIS,我有设虚拟目录的.
    2010年5月31日 10:00
  • OK,谢了.有问题再请教.是我搞错了,忘了去掉string strUrl = "service1_0/test.rem";service1_0
    2010年5月31日 10:03
  • 你好!
        我现在遇到个这样的问题,就是.NET Remoting 的服务器端程序在运行了一天的样子就会出现,Remoting 挂掉,Client 通过TCP-> System.Activator.GetObject(type, url); 能获取远程对象,但是调该对象的方法时就会一直处于等待状态,最后只有重启服务器端,才能恢复正常。 希望您能给小弟指点一下。谢谢!
    2011年1月17日 10:09