RSS 2.0 Feed
2004-11 Entries
摘要:  Using directives#region Using directivesusing System;using System.Security.Principal;using System.Runtime.InteropServices;using System.Text.RegularExpressions;#endregionnamespace Impersonal{    class Program    {        测试代码#region 测试代码        public static void Main(string[] args)        {            Console.WriteLine("当前用户是: "    + WindowsIdentity.GetCurrent().Name);            ImpersonatedWork testDel = new ImpersonatedWork(Test);            ImpersonateAndDo("epro\\liping", "88888888", testDel);            Console.WriteLine("当前用户是: "    + WindowsIdentity.GetCurrent().Name);        }        static void Test()        {            Console.WriteLine("当前用户是: "                + WindowsIdentity.GetCurrent().Name);        }        #endregion        [DllImport("advapi32.dll", SetLastError = true)]        public extern static bool LogonUser(String lpszUsername, String lpszDomain,            String lpszPassword, int dwLogonType,            int dwLogonProvider, ref IntPtr phToken);        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]        public extern static bool CloseHandle(IntPtr handle);        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,            int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);        public delegate void ImpersonatedWork();        /**//// <summary>        /// 以指定用户的身份去做一件事情        /// </summary>        /// <param name="UserName"></param>        /// <param name="PWD"></param>        /// <param name="WhatToDo"></param>        public static void ImpersonateAndDo(string UserName, string PWD, ImpersonatedWork WhatToDo)        {            扮演用户#region 扮演用户            string domainName = string.Empty;            string userName = string.Empty;            IntPtr tokenHandle = new IntPtr(0);            IntPtr dupeTokenHandle = new IntPtr(0);            const int LOGON32_PROVIDER_DEFAULT = 0;            const int LOGON32_LOGON_INTERACTIVE = 2;            const int SecurityImpersonation = 2;            if (! Regex.IsMatch(UserName, @"^\w+[\\]?\w+$"))            {                throw new ApplicationException("非法的用户名");            }            string[] tmp = UserName.Split(new char[] { '\\' });            if (tmp.Length > 1)            {                domainName = tmp[0];                userName = tmp[1];            }            else            {                userName = tmp[0];            }            tokenHandle = IntPtr.Zero;            dupeTokenHandle = IntPtr.Zero;            bool returnValue = LogonUser(userName,domainName,  PWD,                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,                ref tokenHandle);            if (!returnValue)            {                throw new ApplicationException("取Handle出错了!");            }            //Console.WriteLine("当前用户是: "            //    + WindowsIdentity.GetCurrent().Name);            bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);            if (!retVal)            {                CloseHandle(tokenHandle);                throw new ApplicationException("复制Handle出错了!");            }            WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);            WindowsImpersonationContext impersonatedUser = newId.Impersonate();            #endregion            以新用户身份调用#region 以新用户身份调用            WhatToDo();            #endregion            取消扮演#region 取消扮演            impersonatedUser.Undo();            if (tokenHandle != IntPtr.Zero)                CloseHandle(tokenHandle);            if (dupeTokenHandle != IntPtr.Zero)                CloseHandle(dupeTokenHandle);            #endregion        }    }} 我去掉在首页显示选项,怎么还是显示在首页?...[阅读全文]

posted @ | Feedback (7) |

摘要:我看了不少关于.NET下关于EnterpriseService的文章,居然都没有谈到跨机器调用服务器端组件的方法,自我感觉,如果真正用到EnterpriseService做过开发,是不能避免遇到这个问题的,目前我的方法是在服务器上起一个服务,通过Remoting将组件引用传递给客户端,相比较在VB+COM世界里,客户端只要安装了代理包,创建远程组件却是非常容易:CreateObject(ProgID)即可.难道.NET下没有更简便的办法? 再一点,刚才测试如下一个组件  public class Class1:ServicedComponent {  public Class1()  {   //   // TODO: Add constructor logic here   //  }  public string Test()  {   System.IO.StreamWriter sw = new System.IO.StreamWriter("c:\\ttt.txt",true);   sw.WriteLine("12345555");   sw.Flush();   sw.Close();   return System.DateTime.Now.ToString();  } } 斜体的代码单独执行没有问题,放在COM+组件中,居然有返回了,而C盘下并没有我预期的ttt.txt文件? 出错了?可没有报错啊?我可是处心积虑说服领导拿.NET来开发新系统,这我怎么能放心?今晚还不能解决这个问题,我就把拿.NET开发的计划给否了,要是那样,心痛啊.   ======写文件失败问题已经解决====== 总结:Terminal环境下开发或调用COM+组件,COM+应用不能使用交互用户,否则会出现许多古怪的问题,切记....[阅读全文]

posted @ | Feedback (11) |

摘要:我们的编程元素如类型、字段、方法和属性,是有自己本身的一些附加的信息,如公有(public)还是私有( private) 如果我们想给我们的编程元素添加一些附加信息怎么办?譬如,我发布的类除了公有私有这些系统内置的附加信息 外,我还想添加自己的一些信息,如类的作者,指定方法有没有测试过等等,.NET给我们提供了这个机制,看下面 的这个例子     public class MyClass    {        public static int Main(string[] args)        {            ObsoleteClass.test();        }    }    [Obsolete]    public class ObsoleteClass    {         public static void test()        {            Console.WriteLine("Haha,Dahuaidan!");        }    } [Obsolete]写在类ObsoleteClass定义的上方,这就是一个特性的例子,它给类ObsoleteClass打上了一个标记(添加了一个附加信息)。注意:这个附加消息是属于这个类的,而不是属于某个实例其实这里[Obsolete]代表了ObsoleteAttribute的实例,中括号中的写法Obsolete其实等同与ObsoleteAttribute也等同与ObsoleteAttribute()说白了,是个构造函数的调用. 例如以下例子[Obsolete("Will be removed in next version")]public class ObsoleteClass{ }就代表有这样一个ObsoleteAttribute的实例:ObsoleteInst = new Obsolete("Will be removed in next version"),ObsoleteInst这个实例被绑定到ObsoleteClass的原数据.特性应用还可以如下写法[Obsolete("Will be removed in next version", Reviewed = true)]其中xx = xxx部分不是构造函数的一部分,而是对构造后的特性类实例的属性赋值. 特性这东西,理解了就没什么,要说起来挺拗口的....[阅读全文]

posted @ | Feedback (29) | Filed Under [ C# 语言 ]

摘要:内容较长.详细内容请见: http://blog.joycode.com/joe/articles/38455.aspx 接下来几天,我会把关于.NET的新特性的内容连载  ...[阅读全文]

posted @ | Feedback (1) | Filed Under [ C# 语言 ]

摘要:好多人都对Remoting中的事件处理很疑惑,现将完整实现Remoting中事件处理的过程写出来,并对容易犯错误的地方进行总结,希望能给大家一些帮助。现假设有一个留言板程序:以下代码中,MsgBoard为以Singleton模式存活于服务器端的共享留言板实例,AddMessage是客户端添加留言的接口,MsgBoard定义如下:     public class MsgBoard:MarshalByRefObject     {        public delegate void EventDelegate(string info);        public event EventDelegate OnInfoAdded;        public void AddMessage(string info)        {            Console.WriteLine(info);             if(OnInfoAdded!=null)                      OnInfoAdded(info);        }    } 在有客户端添加留言时,激发一个事件,我们的客户端去订阅该事件来得到留言板更新的通知。服务器端代码如下: Using directives#region Using directivesusing System;using System.Collections.Generic;using System.Text;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;using System.Runtime.Serialization.Formatters;/**//////#endregionnamespace ConsoleServer{    class Program    {        static void Main(string[] args)        {            RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyLibrary.MsgBoard), "MyUri", WellKnownObjectMode.Singleton);            HttpChannel myChannel = new HttpChannel(1080);            ChannelServices.RegisterChannel(myChannel);            /**///////            IServerChannelSink sc = myChannel.ChannelSinkChain;            while (sc != null)            {                if (sc is BinaryServerFormatterSink)                {                    ((BinaryServerFormatterSink)sc).TypeFilterLevel = TypeFilterLevel.Full;                    //break;                }                if (sc is SoapServerFormatterSink)                {                    ((SoapServerFormatterSink)sc).TypeFilterLevel = TypeFilterLevel.Full;                    //break;                }                sc = sc.NextChannelSink;            }            Console.WriteLine("Server Started");            Console.ReadLine();        }    }} 我们可以不要详细去关心服务器端程序的代码,我们只需要知道:1,服务器注册了远程服务的类型2,TypeFilterLevel = TypeFilterLevel.Full   由于从.NET Framework 1.1起,缺省情况下DelegateSerializationHolder不允许被反序列化,(即FormatterSink.TypeFilterLevel = TypeFilterLevel.low)。为了实现远程事件处理,我们必须解除该约束,使ServerFormatterSink.TypeFilterLevel = TypeFilterLevel.Full 我们更加需要关心的是我们的客户端代码: Using directives#region Using directivesusing System;using System.Collections.Generic;using System.Text;using System.Runtime.Remoting;using System.Runtime.Remoting.Channels;using System.Runtime.Remoting.Channels.Http;using System.Runtime.Serialization.Formatters;#endregionnamespace ConsoleClient{    class Program    {        static void Main(string[] args)        {            try            {                RemotingConfiguration.RegisterWellKnownClientType(typeof(MyLibrary.MsgBoard), "Http://localhost:1080/MyUri");                HttpChannel myChannel = new HttpChannel(1000);                ChannelServices.RegisterChannel(myChannel);                IServerChannelSink sc = myChannel.ChannelSinkChain;                Console.WriteLine("Client Started");                MyLibrary.MsgBoard msgbd = new MyLibrary.MsgBoard();                /**////msgbd.OnInfoAdded += new MyLibrary.MsgBoard.EventDelegate(msgbd_OnInfoAdded);                MyLibrary.eventClass evclass = new MyLibrary.eventClass();                msgbd.OnInfoAdded += new MyLibrary.MsgBoard.EventDelegate(evclass.msgbd_OnInfoAdded);/**////instead                msgbd.AddMessage("Hello all");                Console.ReadLine();            }            catch (Exception exc)            {                Console.WriteLine(exc.StackTrace);                Console.ReadLine();            }        }        public static void msgbd_OnInfoAdded(string info)        {            Console.WriteLine("info on server event:{0}", info);        }    }} 请注意:此处我们使用一个实例方法去订阅服务器组件的事件,该实例类型定义如下:     public class eventClass:MarshalByRefObject     {        public void msgbd_OnInfoAdded(string info)        {            Console.WriteLine("info from server event:{0}", info);        }    } 为什么要这么做?.NET Framework要求,事件的发布者必须拥有事件订阅者的元数据,而提供元数据的简单方法,就是让服务器程序添加对客户端程序的引用,但事实上我们不需要这么做,我们将订阅者声明在远程类的程序集中,而该程序集的元数据原本就是服务器和客户端共有的。此时我们要注意到,订阅事件的类,也被申明成MarshalByRefObject,这是.NET Framework 2.0出现的一个限制,委派在序列化信息中包含了函数对应实例的地址,在服务器端回掉时,可以寻址到客户端订阅的对象实例并执行相应的成员方法,既然能被服务器寻址,则该订阅对象要求是MarshalByRefObject,这不难理解。在.NET Framework 2.0之前,我们可以使用一个包含静态函数的委派去订阅服务器组件的事件,但2.0以后,如果用一个静态成员去订阅,该响应会在服务器空间内被执行,所以我们要记住,远程处理总是处理某种形式的实例成员,而静态成员不能。总结一下:要实现Remoting事件远程处理,要记住以下几个原则:1,缺省情况下DelegateSerializationHolder不允许被反序列化2,事件发起者必须拥有订阅者的元数据3,远程处理总是处理实例成员,且该实例必须是MarshalByReference 附加: 由于HttpChannel将ChannelSinkChain作为公开的属性所以我们能够直接修改TypeFilterLevel,而队TcpChannel,ChannelSinkChain是无法直接访问的,我们可以在监视窗口看到SinkProvider,我们只能在构造TcpChannel时去干涉它,HttpChannel和TcpChannel都可以使用配置文件的方法,但代码有助于理解。 以下是HttpChannel修改TypeFilterLevel的示例: BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider(); serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider(); IDictionary props = new Hashtable(); props["port"] = 1080; // HttpChannel chan = new HttpChannel(props, clientProv, provider); // ChannelServices.RegisterChannel(chan); RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyLibrary.MsgBoard), "MyUri", WellKnownObjectMode.Singleton); TcpChannel myChannel = new TcpChannel(props, clientProv, serverProv); ChannelServices.RegisterChannel(myChannel);     ...[阅读全文]

posted @ | Feedback (26) | Filed Under [ .NET Remoting ]