internal static ContractDescription GetContractInternal(Type givenContractType, Type givenServiceType, Type serviceTypeForCallback)
{
if (givenContractType == null)
{
throw new ArgumentNullException("givenContractType");
}
// FIXME: serviceType should be used for specifying attributes like OperationBehavior.
Type exactContractType = null;
ServiceContractAttribute sca = null;
Dictionary <Type, ServiceContractAttribute> contracts =
GetServiceContractAttributes(serviceTypeForCallback ?? givenServiceType ?? givenContractType);
if (contracts.ContainsKey(givenContractType))
{
exactContractType = givenContractType;
sca = contracts [givenContractType];
}
else
{
foreach (Type t in contracts.Keys)
{
if (t.IsAssignableFrom(givenContractType))
{
if (t.IsAssignableFrom(exactContractType)) // exact = IDerived, t = IBase
{
continue;
}
if (sca != null && (exactContractType == null || !exactContractType.IsAssignableFrom(t))) // t = IDerived, exact = IBase
{
throw new InvalidOperationException("The contract type of " + givenContractType + " is ambiguous: can be either " + exactContractType + " or " + t);
}
exactContractType = t;
sca = contracts [t];
}
}
}
if (exactContractType == null)
{
exactContractType = givenContractType;
}
if (sca == null)
{
if (serviceTypeForCallback != null)
{
sca = contracts.Values.First();
}
else
{
return(null); // no contract
}
}
string name = sca.Name ?? exactContractType.Name;
string ns = sca.Namespace ?? "http://tempuri.org/";
ContractDescription cd =
new ContractDescription(name, ns);
cd.ContractType = exactContractType;
cd.CallbackContractType = sca.CallbackContract;
cd.SessionMode = sca.SessionMode;
if (sca.ConfigurationName != null)
{
cd.ConfigurationName = sca.ConfigurationName;
}
else
{
cd.ConfigurationName = exactContractType.FullName;
}
if (sca.HasProtectionLevel)
{
cd.ProtectionLevel = sca.ProtectionLevel;
}
foreach (var icd in cd.GetInheritedContracts())
{
FillOperationsForInterface(icd, icd.ContractType, givenServiceType, false);
foreach (var od in icd.Operations)
{
if (!cd.Operations.Any(o => o.Name == od.Name && o.SyncMethod == od.SyncMethod &&
o.BeginMethod == od.BeginMethod && o.InCallbackContract == od.InCallbackContract))
{
cd.Operations.Add(od);
}
}
}
FillOperationsForInterface(cd, cd.ContractType, givenServiceType, false);
if (cd.CallbackContractType != null)
{
FillOperationsForInterface(cd, cd.CallbackContractType, null, true);
}
// FIXME: enable this when I found where this check is needed.
/*
* if (cd.Operations.Count == 0)
* throw new InvalidOperationException (String.Format ("The service contract type {0} has no operation. At least one operation must exist.", contractType));
*/
return(cd);
}