2 // EndpointDispatcher.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.Generic;
30 using System.Collections.ObjectModel;
31 using System.Reflection;
32 using System.ServiceModel.Description;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Dispatcher;
35 using System.ServiceModel.Security.Tokens;
38 namespace System.ServiceModel.Dispatcher
40 public class EndpointDispatcher
42 EndpointAddress address;
43 string contract_name, contract_ns;
44 ChannelDispatcher channel_dispatcher;
45 MessageFilter address_filter;
46 MessageFilter contract_filter;
48 DispatchRuntime dispatch_runtime;
50 // Umm, this API is ugly, since it or its members will
51 // anyways require ServiceEndpoint, those arguments are
52 // likely to be replaced by ServiceEndpoint (especially
53 // considering about possible EndpointAddress inconsistency).
54 public EndpointDispatcher (EndpointAddress address,
55 string contractName, string contractNamespace)
57 if (contractName == null)
58 throw new ArgumentNullException ("contractName");
59 if (contractNamespace == null)
60 throw new ArgumentNullException ("contractNamespace");
62 throw new ArgumentNullException ("address");
64 this.address = address;
65 contract_name = contractName;
66 contract_ns = contractNamespace;
68 dispatch_runtime = new DispatchRuntime (this);
70 this.address_filter = new EndpointAddressMessageFilter (address);
73 public DispatchRuntime DispatchRuntime {
74 get { return dispatch_runtime; }
77 public string ContractName {
78 get { return contract_name; }
81 public string ContractNamespace {
82 get { return contract_ns; }
85 public ChannelDispatcher ChannelDispatcher {
86 get { return channel_dispatcher; }
87 internal set { channel_dispatcher = value; }
90 public MessageFilter AddressFilter {
91 get { return address_filter; }
94 throw new ArgumentNullException ("value");
95 address_filter = value;
99 public MessageFilter ContractFilter {
100 get { return contract_filter ?? (contract_filter = new MatchAllMessageFilter ()); }
103 throw new ArgumentNullException ("value");
104 contract_filter = value;
108 public EndpointAddress EndpointAddress {
109 get { return address; }
112 public int FilterPriority {
113 get { return filter_priority; }
114 set { filter_priority = value; }
117 internal void InitializeServiceEndpoint (bool isCallback, Type serviceType, ServiceEndpoint se)
119 this.ContractFilter = GetContractFilter (se.Contract);
121 this.DispatchRuntime.Type = serviceType;
123 //Build the dispatch operations
124 DispatchRuntime db = this.DispatchRuntime;
125 if (!isCallback && se.Contract.CallbackContractType != null) {
126 var ccd = ContractDescriptionGenerator.GetCallbackContract (db.Type, se.Contract.CallbackContractType);
127 db.CallbackClientRuntime = ccd.CreateClientRuntime ();
128 db.CallbackClientRuntime.CallbackClientType = ccd.ContractType;
130 foreach (OperationDescription od in se.Contract.Operations)
131 if (!db.Operations.Contains (od.Name))
132 PopulateDispatchOperation (db, od);
135 void PopulateDispatchOperation (DispatchRuntime db, OperationDescription od) {
136 string reqA = null, resA = null;
137 foreach (MessageDescription m in od.Messages) {
138 if (m.Direction == MessageDirection.Input)
143 DispatchOperation o =
145 new DispatchOperation (db, od.Name, reqA) :
146 new DispatchOperation (db, od.Name, reqA, resA);
147 bool no_serialized_reply = od.IsOneWay;
148 foreach (MessageDescription md in od.Messages) {
149 if (md.Direction == MessageDirection.Input &&
150 md.Body.Parts.Count == 1 &&
151 md.Body.Parts [0].Type == typeof (Message))
152 o.DeserializeRequest = false;
153 if (md.Direction == MessageDirection.Output &&
154 md.Body.ReturnValue != null) {
155 if (md.Body.ReturnValue.Type == typeof (Message))
156 o.SerializeReply = false;
157 else if (md.Body.ReturnValue.Type == typeof (void))
158 no_serialized_reply = true;
162 foreach (var fd in od.Faults)
163 o.FaultContractInfos.Add (new FaultContractInfo (fd.Action, fd.DetailType));
166 o.Invoker = new DefaultOperationInvoker (od);
169 o.Formatter = new OperationFormatter (od, false, false); // FIXME: pass correct isRpc, isEncoded
171 if (o.Action == "*" && (o.IsOneWay || o.ReplyAction == "*")) {
172 //Signature : Message (Message)
174 //FIXME: void (IChannel)
175 if (!o.DeserializeRequest && (!o.SerializeReply || no_serialized_reply)) // what is this double-ish check for?
176 db.UnhandledDispatchOperation = o;
179 db.Operations.Add (o);
182 MessageFilter GetContractFilter (ContractDescription cd)
184 List<string> actions = new List<string> ();
185 foreach (var od in cd.Operations)
186 foreach (var md in od.Messages)
187 if (md.Direction == MessageDirection.Input)
188 if (md.Action == "*")
189 return new MatchAllMessageFilter ();
191 actions.Add (md.Action);
193 return new ActionMessageFilter (actions.ToArray ());