static OperationDescription GetOrCreateOperation (
ContractDescription cd, MethodInfo mi, MethodInfo serviceMethod,
OperationContractAttribute oca,
Type asyncReturnType,
bool isCallback)
{
string name = oca.Name ?? (oca.AsyncPattern ? mi.Name.Substring (5) : mi.Name);
OperationDescription od = cd.Operations.FirstOrDefault (o => o.Name == name);
if (od == null) {
od = new OperationDescription (name, cd);
od.IsOneWay = oca.IsOneWay;
if (oca.HasProtectionLevel)
od.ProtectionLevel = oca.ProtectionLevel;
od.Messages.Add (GetMessage (od, mi, oca, true, isCallback, null));
if (!od.IsOneWay)
od.Messages.Add (GetMessage (od, mi, oca, false, isCallback, asyncReturnType));
foreach (ServiceKnownTypeAttribute a in cd.ContractType.GetCustomAttributes (typeof (ServiceKnownTypeAttribute), false))
foreach (Type t in a.GetTypes ())
od.KnownTypes.Add (t);
foreach (ServiceKnownTypeAttribute a in serviceMethod.GetCustomAttributes (typeof (ServiceKnownTypeAttribute), false))
foreach (Type t in a.GetTypes ())
od.KnownTypes.Add (t);
foreach (FaultContractAttribute a in mi.GetCustomAttributes (typeof (FaultContractAttribute), false)) {
var fname = a.Name ?? a.DetailType.Name + "Fault";
var fns = a.Namespace ?? cd.Namespace;
var fd = new FaultDescription (a.Action ?? cd.Namespace + cd.Name + "/" + od.Name + fname) { DetailType = a.DetailType, Name = fname, Namespace = fns };
#if !NET_2_1
if (a.HasProtectionLevel)
fd.ProtectionLevel = a.ProtectionLevel;
#endif
od.Faults.Add (fd);
}
cd.Operations.Add (od);
}
else if (oca.AsyncPattern && od.BeginMethod != null && od.BeginMethod != mi ||
!oca.AsyncPattern && od.SyncMethod != null && od.SyncMethod != mi)
throw new InvalidOperationException (String.Format ("contract '{1}' cannot have two operations for '{0}' that have the identical names and different set of parameters.", name, cd.Name));
if (oca.AsyncPattern)
od.BeginMethod = mi;
else
od.SyncMethod = mi;
od.IsInitiating = oca.IsInitiating;
od.IsTerminating = oca.IsTerminating;
if (mi != serviceMethod)
foreach (object obj in mi.GetCustomAttributes (typeof (IOperationBehavior), true))
od.Behaviors.Add ((IOperationBehavior) obj);
if (serviceMethod != null) {
foreach (object obj in serviceMethod.GetCustomAttributes (typeof(IOperationBehavior),true))
od.Behaviors.Add ((IOperationBehavior) obj);
}
#if !NET_2_1
if (od.Behaviors.Find<OperationBehaviorAttribute>() == null)
od.Behaviors.Add (new OperationBehaviorAttribute ());
#endif
// FIXME: fill KnownTypes, Behaviors and Faults.
if (isCallback)
od.InCallbackContract = true;
else
od.InOrdinalContract = true;
return od;
}