Using the Remoting Callbacks in .Net Applications - 中国WEB开发者网络 (http://www.webasp.net) -- 技术教程 (http://www.webasp.net/article/) --- Using the Remoting Callbacks in .Net Applications (http://www.webasp.net/article/4/3987.htm) |
| -- 作者:未知 -- 发布日期: 2003-07-12 |
| Implementation The sample solution of the Remote Callbacks implemenation is divided into several projects: ContractObject - common abstract definitions (see the above) RemoteCallbackLib - RemoteCallback Custom Attribute (see the above) RemoteObjectA - classic .Net object hosted in the HostServer RemoteObjectX - .Net Service (COM+) hosted in the HostServer RemoteObjectWS - Web Service hosted in the IIS HostServer - console server program RemoteWindowsForm - Windows Form client program also the solution included the following config files: HostServer.exe.config - the Remoting config info for objects hosted by HostServer RemoteWindowsForm.exe.config - the config info for Remoting objects using by this client RemoteCallbackLib The following code snippet shows the implementation of the RemoteCallbackAttribute. Its design is based on the Refection of the "parent" assembly, where located all metadata of the Callback object. The RemoteCallbackLib is built into the separate assembly which it can be reused by another remoting clients. namespace RKiss.RemoteCallbackLib { [AttributeUsage(AttributeTargets.Field)] public class RemoteCallbackAttribute : Attribute { private string _desc; private string _protocol; private int _port; public string desc { get { return _desc; } set {_desc = value; } } public string protocol { get { return _protocol; } set {_protocol = value; } } public int port { get { return _port; } set {_port = value; } } public RemoteCallbackAttribute() : this("tcp", 0) {} public RemoteCallbackAttribute(string sProtocol) : this(sProtocol, 0) {} public RemoteCallbackAttribute(string sProtocol, int iPort) { protocol = sProtocol; port = iPort; } } // Creating remoting stuff based on the properties of the CallbackAttribute // Note that all callback class' have to located in the same (parent) assembly! public class RemoteCallbackSubscriber { private Hashtable HT = Hashtable.Synchronized(new Hashtable()); private string site = "localhost"; public RemoteCallbackSubscriber(object parent) { Type typeParent = parent.GetType(); foreach(FieldInfo fi in typeParent.GetFields()) { foreach(Attribute attr in fi.GetCustomAttributes(true)) { if(attr is RemoteCallbackAttribute) { RemoteCallbackAttribute rca = attr as RemoteCallbackAttribute; // open in/out channel int port = rca.port; if(port == 0) { Random rdmPort = new Random(~unchecked((int)DateTime.Now.Ticks)); port = rdmPort.Next(1, ushort.MaxValue); } // create channel IChannel channel = null; if(rca.protocol == "tcp") channel = new TcpChannel(port); else if(rca.protocol == "http") channel = new HttpChannel(port); else throw new Exception(string.Format("The '{0}' is not recognize protocol.", rca.protocol)); // register channel ChannelServices.RegisterChannel(channel); // register a Callback Object string nameofCallbackObject = fi.FieldType.FullName; Type typeofCallbackObject = typeParent.Assembly.GetType(nameofCallbackObject); RemotingConfiguration.RegisterWellKnownServiceType( typeofCallbackObject, nameofCallbackObject, WellKnownObjectMode.Singleton); // create proxy string urlofCallbackObject = string.Format(@"{0}://{1}:{2}/{3}", rca.protocol, site, port, nameofCallbackObject); object proxyCB = Activator.GetObject(typeofCallbackObject, urlofCallbackObject); fi.SetValue(parent, proxyCB); // //store into the HT HT[fi.Name] = channel; } } } } public IChannel this [string nameofCallback] { get { return HT[nameofCallback] as IChannel; } } } } RemoteObject (A , X and WS) The design pattern of the Remoting methods is the same for any of these remoting objects. The following code snippet shows the RemoteObjectA class derived from the MarshalByRefObject class and IRmObject interface. using RKiss.RemoteObject; // abstract definitions namespace RKiss.RemoteObjectA { public class RmObjectA : MarshalByRefObject, IRmObject { public RmObjectA() { Trace.WriteLine(string.Format("[{0}]RmObjectA activated", GetHashCode())); } public string Echo(string msg) { Trace.WriteLine(string.Format("[{0}]RmObjectA.Echo({1})", GetHashCode(), msg)); return msg; } // stateless callbacks public string GiveMeCallback(int timeinsec, string ticketId, object objwire) { RemoteCallback wire = objwire as RemoteCallback; bool bProgress = true; CallbackEventArgs cea = new CallbackEventArgs(); cea.TicketId = ticketId; cea.State = "running ..."; cea.Sender = GetType().ToString(); wire(cea.Sender, cea); while(timeinsec-- > 0 && bProgress) { Thread.Sleep(1000); cea.State = timeinsec; bProgress = wire(cea.Sender, cea); } cea.State = bProgress?"done":string.Format("aborted at {0}", ++timeinsec); wire(cea.Sender, cea); // Trace.WriteLine(string.Format("[{0}]RmObjectA.GiveMeCallback({1}, {2}, {3})", GetHashCode(), timeinsec, ticketId, wire.GetType().FullName)); return ticketId; } } } There are implementation of two methods of the IRmObject interface in the object. The first one - Echo has a test purpose, the other one - GiveMeCallback simulated some time consuming work with notification of the method state using the Remoting Callback mechanism. The method state is wrapped and serialized by the CallbackEventArgs object. Now I will show you only differencies in the following remote objects: |
| webasp.net |