flush
[mcs.git] / class / System.ServiceModel.Routing / System.ServiceModel.Routing / RoutingService.cs
blob83e4b8c43a91658d3e5a3d52c787513acadb6267
1 using System;
2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.Linq;
5 using System.Reflection;
6 using System.ServiceModel;
7 using System.ServiceModel.Channels;
8 using System.ServiceModel.Description;
9 using System.ServiceModel.Dispatcher;
11 namespace System.ServiceModel.Routing
13 [ServiceBehavior (AddressFilterMode = AddressFilterMode.Any, InstanceContextMode = InstanceContextMode.PerSession, UseSynchronizationContext = false, ValidateMustUnderstand = false)]
14 public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter
17 class SimplexDatagramClient : ClientBase<ISimplexDatagramRouter>, ISimplexDatagramRouter
19 public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
21 return Channel.BeginProcessMessage (message, callback, state);
24 public void EndProcessMessage (IAsyncResult result);
26 Channel.EndProcessMessage (result);
30 class SimplexSessionClient : ClientBase<ISimplexSessionRouter>, ISimplexSessionRouter
32 public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
34 return Channel.BeginProcessMessage (message, callback, state);
37 public void EndProcessMessage (IAsyncResult result);
39 Channel.EndProcessMessage (result);
43 class DuplexSessionClient : ClientBase<IDuplexSessionRouter>, IDuplexSessionRouter
45 public IAsyncResult BeginProcessMessage (Message message, AsyncCallback callback, object state)
47 return Channel.BeginProcessMessage (message, callback, state);
50 public void EndProcessMessage (IAsyncResult result);
52 Channel.EndProcessMessage (result);
56 class RequestReplyClient : ClientBase<IRequestReplyRouter>, IRequestReplyRouter
58 public IAsyncResult BeginProcessRequest (Message message, AsyncCallback callback, object state)
60 return Channel.BeginProcessRequest (message, callback, state);
63 public Message EndProcessRequest (IAsyncResult result);
65 return Channel.EndProcessRequest (result);
70 internal RoutingService ()
74 internal RoutingConfiguration Configuration { get; set; }
76 Action<Message> process_message_duplex_session_handler;
77 Action<Message> process_message_simplex_datagram_handler;
78 Action<Message> process_message_simplex_session_handler;
79 //Func<Message,Message> process_request_handler;
81 Dictionary<ServiceEndpoint,ChannelFactory> factories = new Dictionary<ServiceEndpoint,ChannelFactory> ();
82 ChannelFactory<IRequestReplyRouter> request_reply_factory;
83 IRequestReplyRouter request_reply_channel;
84 //Dictionary<ServiceEndpoint,IChannel> sessions = new Dictionary<ServiceEndpoint,IChannel> ();
86 IEnumerable<ServiceEndpoint> GetMatchingEndpoints (Message message)
88 IEnumerable<ServiceEndpoint> ret;
89 if (!Configuration.FilterTable.GetMatchingValue (message, out ret))
90 throw new EndpointNotFoundException ();
91 return ret;
94 static readonly MethodInfo create_factory_method = typeof (ChannelFactory).GetMethod ("CreateFactory", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
96 void ProcessMessageDuplexSession (Message message)
98 var sel = GetMatchingEndpoints (message);
99 foreach (var se in sel) {
100 ChannelFactory cf;
101 if (!factories.TryGetValue (se, out cf)) {
102 cf = new ChannelFactory<IDuplexSessionRouter> (se);
103 factories [se] = cf;
105 // FIXME: possibly reuse session channels, though I doubt saving session *at the router* makes sense...
106 var ch = ((ChannelFactory<IDuplexSessionRouter>) cf).CreateChannel ();
107 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
111 void ProcessMessageSimplexDatagram (Message message)
113 var sel = GetMatchingEndpoints (message);
114 foreach (var se in sel) {
115 ChannelFactory cf;
116 if (!factories.TryGetValue (se, out cf)) {
117 cf = new ChannelFactory<ISimplexDatagramRouter> (se);
118 factories [se] = cf;
120 var ch = ((ChannelFactory<ISimplexDatagramRouter>) cf).CreateChannel ();
121 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
125 void ProcessMessageSimplexSession (Message message)
127 var sel = GetMatchingEndpoints (message);
128 foreach (var se in sel) {
129 ChannelFactory cf;
130 if (!factories.TryGetValue (se, out cf)) {
131 cf = new ChannelFactory<ISimplexSessionRouter> (se);
132 factories [se] = cf;
134 // FIXME: possibly reuse session channels, though I doubt saving session *at the router* makes sense...
135 var ch = ((ChannelFactory<ISimplexSessionRouter>) cf).CreateChannel ();
136 ch.EndProcessMessage (ch.BeginProcessMessage (message, null, null));
140 IAsyncResult IDuplexSessionRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
142 if (process_message_duplex_session_handler == null)
143 process_message_duplex_session_handler = new Action<Message> (ProcessMessageDuplexSession);
144 return process_message_duplex_session_handler.BeginInvoke (message, callback, state);
147 void IDuplexSessionRouter.EndProcessMessage (IAsyncResult result)
149 if (process_message_duplex_session_handler == null)
150 throw new InvalidOperationException ("Async operation has not started");
151 process_message_duplex_session_handler.EndInvoke (result);
154 IAsyncResult IRequestReplyRouter.BeginProcessRequest (Message message, AsyncCallback callback, object state)
156 if (request_reply_channel != null)
157 throw new InvalidOperationException ("Another async request operation is in progress");
159 var sel = GetMatchingEndpoints (message);
160 ServiceEndpoint se = null;
161 foreach (var se_ in sel) {
162 if (se != null)
163 throw new InvalidOperationException ("Multiple endpoints cannot be specified for request-reply channel");
164 se = se_;
166 if (se == null)
167 throw new InvalidOperationException ("No service endpoint is registered to the request-reply channel");
169 if (request_reply_factory == null)
170 request_reply_factory = new ChannelFactory<IRequestReplyRouter> (se);
171 request_reply_channel = request_reply_factory.CreateChannel ();
172 return request_reply_channel.BeginProcessRequest (message, null, null);
175 Message IRequestReplyRouter.EndProcessRequest (IAsyncResult result)
177 if (request_reply_channel == null)
178 throw new InvalidOperationException ("Async request has not started");
179 var ch = request_reply_channel;
180 request_reply_channel = null;
181 return ch.EndProcessRequest (result);
184 IAsyncResult ISimplexDatagramRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
186 if (process_message_simplex_datagram_handler == null)
187 process_message_simplex_datagram_handler = new Action<Message> (ProcessMessageSimplexDatagram);
188 return process_message_simplex_datagram_handler.BeginInvoke (message, callback, state);
191 void ISimplexDatagramRouter.EndProcessMessage (IAsyncResult result)
193 if (process_message_simplex_datagram_handler == null)
194 throw new InvalidOperationException ("Async operation has not started");
195 process_message_simplex_datagram_handler.EndInvoke (result);
198 IAsyncResult ISimplexSessionRouter.BeginProcessMessage (Message message, AsyncCallback callback, object state)
200 if (process_message_simplex_session_handler == null)
201 process_message_simplex_session_handler = new Action<Message> (ProcessMessageSimplexSession);
202 return process_message_simplex_session_handler.BeginInvoke (message, callback, state);
205 void ISimplexSessionRouter.EndProcessMessage (IAsyncResult result)
207 if (process_message_simplex_session_handler == null)
208 throw new InvalidOperationException ("Async operation has not started");
209 process_message_simplex_session_handler.EndInvoke (result);