步骤: 1. 建立一个空白解决方案blank solution,如:d:/MyProject/MyProject.sln 2. 在d:/MyProject下建一个Web Application的根目录d:/MyProject/WebMis并设为http://localhost/WebMis的虚拟目录 3. 在WebMis目录下根据模块分别新建目录,如:d:/MyProject/WebMis/Login和d:/MyProject/WebMis/CheckOut 4. 在VS.net中根据模块新建web application,如:http://localhost/WebMis/Login和http://localhost/WebMis/CheckOut 5. 新建后Login和CheckOut两个目录自动被设置为虚拟目录 6. 在WebMis项目中添加Login和CheckOut的项目引用 7.在IIS管理器中删除Login和CheckOut的虚拟目录 8. 删除各项目的global.asax(除根项目) 9. 除去个项目的web.config(除根项目)中的如下代码: <authentication mode="Windows" /> <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" /> 或删掉web.config(若不需要在各目录中进行配置) 10. 编译后,即可运行。
.net Remoting 编程中的几个小异常处理; 异常一: An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll Additional information: 由于安全限制,无法访问类型 System.Runtime.Remoting.ObjRef。 在VS2003中,将序列化的安全级别提高了。所以,在注册通道时,应该将TypeFilterLevel设置为Full; 参见:http://www.cnblogs.com/wayfarer/archive/2005/03/15/74587.html 下面是一个简单的演示代码。 服务器端: BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 8085; TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan); 之后就是创建服务器对象的代码,就不写了。
注意,除了服务器段要做这个修改外,客户端也要做对应的修改。 如果只修改服务器段不修改客户端,就会有下面的异常产生: An unhandled exception of type 'System.Runtime.Remoting.RemotingException' occurred in mscorlib.dll Additional information: 此远程处理代理没有信道接收,这意味着服务器没有正在侦听的已注册服务器信道,或者此应用程序没有用来与服务器对话的适当客户端信道。
客户端的代码跟服务器的代码几乎一样 BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 8084; TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan);
注意如果是在同一台机子上作测试,客户端、服务器端的端口号不要一样。 使用 ConfigurationSettings 来读取配置信息下面分几种情况来看.net中,默认那个配置文件起作用。
情况1: 如果是一个标准的Win独立应用,或者一个标准的WEB独立应用,就不用说了,大家都知道。 配置文件定义配置信息 用下面代码,简单读取配置信息。 using System.Configuration; string ww = ConfigurationSettings.AppSettings["SQLConnString"]; // 或者其他 ConfigurationSettings 类的方法获得配置信息 情况2: 如果是一个需要被Win程序调用的DLL组件, 配置信息放在调用它的Win程序的配置文件(app.config)中, 调用代码仍然是情况1简单的那两行调用代码。
情况3: 如果是一个需要被WEB程序调用的DLL组件, 配置信息放在调用它的WEB程序的配置文件(web.config)中, 调用代码仍然是情况1简单的那两行调用代码。
情况4: 如果你编写的是一个独立的Win的服务, 跟情况1完全一样, 把配置信息文件放到Win服务项目中。 Win服务中再用情况1上面的代码直接调用即可。 情况5: 如果是一个组件,被Win服务所调用, 跟情况2、3完全一样, 把配置信息文件放到Win服务项目中。 组件中,再用情况1上面的代码直接调用即可。 情况6: 如果你编写的是一个独立的Com+企业应用。并且这个Com+应用激活模式是“库应用程序”,组件将在创建者进程中被激活。 跟情况 2、3、5 类似,这时候的Com+就可以认为是一个组件。 把配置信息文件放到调用这个Com+的项目中。 这个COM+中,用情况1上面的代码直接调用即可。 分析以上几种情况: 起作用的配置文件其实是当前应用程序域的配置文件,你可以在代码中通过AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 这个代码,获得当前起作用的配置文件。 情况7: 如果你编写的是一个独立的Com+企业应用。并且这个Com+应用激活模式是“服务器应用程序”,组件将在专用服务器进程中被激活。 即这样的配置 [assembly: ApplicationActivation(ActivationOption.Server) ] 这时候,麻烦来了, 我们用 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 获得的是当前有效配置文件是 C:/WINDOWS/system32/dllhost.exe.config 这个文件默认并不存在,我们自己手工创建这个文件,并把配置信息写到这个文件中。 Debug 程序,我们仍看会看到“未将对象引用设置到对象的实例。”这样的异常产生。 以上我们得出的结论并不适用这个情况。
继续分析原因: 微软的Com+并不是一个彻头彻尾的.net应用,里面有大量的非托管代码。 问题就产生在这里,非托管代码中,并没有应用程序域与应用程序域的配置文件的概念。 于是乎,第七种情况就产生了。 第七种情况目前能考虑到的解决方法,就是把配置文件的路径作为一个参数传递进Com+。
另外,如果你的程序是完全意义上的.net程序(也就是不是上述第7中情况) 你是可以修改一个应用程序的默认配置文件的。 具体请看参MSDN中关于 AppDomainSetup.ConfigurationFile 属性 和 IAppDomainSetup.ConfigurationFile 属性 的描述和演示代码。 配置文件描述应用程序域的搜索规则和配置数据。创建应用程序域的宿主负责提供此数据,因为有意义的值因情况不同而异。 例如,ASP.NET 应用程序的配置数据针对每个应用程序、站点和计算机进行存储,而可执行文件的配置数据针对每个应用程序、用户和计算机进行存储。只有宿主知道针对特定情况的配置数据的细节。 当 AppDomain 完成它的第一次绑定后,此属性不得更改。 参见: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemappdomainsetupclassconfigurationfiletopic.asp 手工配置应用程序配置文件的范例可以参看下面一篇文章中提到的代码: Executing ASMX files without a web server http://radio.weblogs.com/0105476/stories/2002/10/24/executingAsmxFilesWithoutAWebServer.html
或者看下面的代码,出处:http://www.gotdotnet.com/team/clr/AppdomainFAQ.aspx // C# Sample Code // File: HelloWorld1.cs using System; using System.Threading; public class HelloWorld { public void SayHello(String greeting) { Console.WriteLine("In the application domain: " + Thread.GetDomain().FriendlyName); Console.WriteLine(greeting); } public static void Main( String[] argv ) { HelloWorld o = new HelloWorld(); o.SayHello("Hello World!"); } } // C# Sample Code // File: ExecAssembly.cs // Creates a remote application domain and executes an assembly // within that application domain.
using System; using System.Reflection; using System.Runtime.Remoting; public class ExecAssembly { public static void Main( String[] argv ) { // Set ApplicationBase to the current directory AppDomainSetup info = new AppDomainSetup(); info.ApplicationBase = "file:///" + System.Environment.CurrentDirectory; // Create an application domain with null evidence AppDomain dom = AppDomain.CreateDomain("RemoteDomain", null, info); // Tell the AppDomain to execute the assembly dom.ExecuteAssembly("HelloWorld1.exe"); // Clean up by unloading the application domain AppDomain.Unload(dom); } }
其他情况待整理中,大家如果看到,请补充。
1. 建立一个空白解决方案blank solution,如:d:/MyProject/MyProject.sln 2. 在d:/MyProject下建一个Web Application的根目录d:/MyProject/WebMis并设为http://localhost/WebMis的虚拟目录 3. 在WebMis目录下根据模块分别新建目录,如:d:/MyProject/WebMis/Login和d:/MyProject/WebMis/CheckOut 4. 在VS.net中根据模块新建web application,如:http://localhost/WebMis/Login和http://localhost/WebMis/CheckOut 5. 新建后Login和CheckOut两个目录自动被设置为虚拟目录 6. 在WebMis项目中添加Login和CheckOut的项目引用 7.在IIS管理器中删除Login和CheckOut的虚拟目录 8. 删除各项目的global.asax(除根项目) 9. 除去个项目的web.config(除根项目)中的如下代码: <authentication mode="Windows" /> <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" /> 或删掉web.config(若不需要在各目录中进行配置) 10. 编译后,即可运行。
.net Remoting 编程中的几个小异常处理; 异常一: An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll Additional information: 由于安全限制,无法访问类型 System.Runtime.Remoting.ObjRef。 在VS2003中,将序列化的安全级别提高了。所以,在注册通道时,应该将TypeFilterLevel设置为Full; 参见:http://www.cnblogs.com/wayfarer/archive/2005/03/15/74587.html 下面是一个简单的演示代码。 服务器端: BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 8085; TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan); 之后就是创建服务器对象的代码,就不写了。
注意,除了服务器段要做这个修改外,客户端也要做对应的修改。 如果只修改服务器段不修改客户端,就会有下面的异常产生: An unhandled exception of type 'System.Runtime.Remoting.RemotingException' occurred in mscorlib.dll Additional information: 此远程处理代理没有信道接收,这意味着服务器没有正在侦听的已注册服务器信道,或者此应用程序没有用来与服务器对话的适当客户端信道。
客户端的代码跟服务器的代码几乎一样 BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 8084; TcpChannel chan = new TcpChannel(props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan);
注意如果是在同一台机子上作测试,客户端、服务器端的端口号不要一样。 使用 ConfigurationSettings 来读取配置信息下面分几种情况来看.net中,默认那个配置文件起作用。
情况1: 如果是一个标准的Win独立应用,或者一个标准的WEB独立应用,就不用说了,大家都知道。 配置文件定义配置信息 用下面代码,简单读取配置信息。 using System.Configuration; string ww = ConfigurationSettings.AppSettings["SQLConnString"]; // 或者其他 ConfigurationSettings 类的方法获得配置信息 情况2: 如果是一个需要被Win程序调用的DLL组件, 配置信息放在调用它的Win程序的配置文件(app.config)中, 调用代码仍然是情况1简单的那两行调用代码。
情况3: 如果是一个需要被WEB程序调用的DLL组件, 配置信息放在调用它的WEB程序的配置文件(web.config)中, 调用代码仍然是情况1简单的那两行调用代码。
情况4: 如果你编写的是一个独立的Win的服务, 跟情况1完全一样, 把配置信息文件放到Win服务项目中。 Win服务中再用情况1上面的代码直接调用即可。 情况5: 如果是一个组件,被Win服务所调用, 跟情况2、3完全一样, 把配置信息文件放到Win服务项目中。 组件中,再用情况1上面的代码直接调用即可。 情况6: 如果你编写的是一个独立的Com+企业应用。并且这个Com+应用激活模式是“库应用程序”,组件将在创建者进程中被激活。 跟情况 2、3、5 类似,这时候的Com+就可以认为是一个组件。 把配置信息文件放到调用这个Com+的项目中。 这个COM+中,用情况1上面的代码直接调用即可。 分析以上几种情况: 起作用的配置文件其实是当前应用程序域的配置文件,你可以在代码中通过AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 这个代码,获得当前起作用的配置文件。 情况7: 如果你编写的是一个独立的Com+企业应用。并且这个Com+应用激活模式是“服务器应用程序”,组件将在专用服务器进程中被激活。 即这样的配置 [assembly: ApplicationActivation(ActivationOption.Server) ] 这时候,麻烦来了, 我们用 AppDomain.CurrentDomain.SetupInformation.ConfigurationFile 获得的是当前有效配置文件是 C:/WINDOWS/system32/dllhost.exe.config 这个文件默认并不存在,我们自己手工创建这个文件,并把配置信息写到这个文件中。 Debug 程序,我们仍看会看到“未将对象引用设置到对象的实例。”这样的异常产生。 以上我们得出的结论并不适用这个情况。
继续分析原因: 微软的Com+并不是一个彻头彻尾的.net应用,里面有大量的非托管代码。 问题就产生在这里,非托管代码中,并没有应用程序域与应用程序域的配置文件的概念。 于是乎,第七种情况就产生了。 第七种情况目前能考虑到的解决方法,就是把配置文件的路径作为一个参数传递进Com+。
另外,如果你的程序是完全意义上的.net程序(也就是不是上述第7中情况) 你是可以修改一个应用程序的默认配置文件的。 具体请看参MSDN中关于 AppDomainSetup.ConfigurationFile 属性 和 IAppDomainSetup.ConfigurationFile 属性 的描述和演示代码。 配置文件描述应用程序域的搜索规则和配置数据。创建应用程序域的宿主负责提供此数据,因为有意义的值因情况不同而异。 例如,ASP.NET 应用程序的配置数据针对每个应用程序、站点和计算机进行存储,而可执行文件的配置数据针对每个应用程序、用户和计算机进行存储。只有宿主知道针对特定情况的配置数据的细节。 当 AppDomain 完成它的第一次绑定后,此属性不得更改。 参见: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemappdomainsetupclassconfigurationfiletopic.asp 手工配置应用程序配置文件的范例可以参看下面一篇文章中提到的代码: Executing ASMX files without a web server http://radio.weblogs.com/0105476/stories/2002/10/24/executingAsmxFilesWithoutAWebServer.html
或者看下面的代码,出处:http://www.gotdotnet.com/team/clr/AppdomainFAQ.aspx // C# Sample Code // File: HelloWorld1.cs using System; using System.Threading; public class HelloWorld { public void SayHello(String greeting) { Console.WriteLine("In the application domain: " + Thread.GetDomain().FriendlyName); Console.WriteLine(greeting); } public static void Main( String[] argv ) { HelloWorld o = new HelloWorld(); o.SayHello("Hello World!"); } } // C# Sample Code // File: ExecAssembly.cs // Creates a remote application domain and executes an assembly // within that application domain.
using System; using System.Reflection; using System.Runtime.Remoting; public class ExecAssembly { public static void Main( String[] argv ) { // Set ApplicationBase to the current directory AppDomainSetup info = new AppDomainSetup(); info.ApplicationBase = "file:///" + System.Environment.CurrentDirectory; // Create an application domain with null evidence AppDomain dom = AppDomain.CreateDomain("RemoteDomain", null, info); // Tell the AppDomain to execute the assembly dom.ExecuteAssembly("HelloWorld1.exe"); // Clean up by unloading the application domain AppDomain.Unload(dom); } }
其他情况待整理中,大家如果看到,请补充。
|