e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
384 lines
16 KiB
C#
384 lines
16 KiB
C#
//----------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System.Collections.Generic;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.ServiceModel.Description;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
struct ChannelRequirements
|
|
{
|
|
public bool usesInput;
|
|
public bool usesReply;
|
|
public bool usesOutput;
|
|
public bool usesRequest;
|
|
public SessionMode sessionMode;
|
|
|
|
public static void ComputeContractRequirements(ContractDescription contractDescription,
|
|
out ChannelRequirements requirements)
|
|
{
|
|
requirements = new ChannelRequirements();
|
|
|
|
requirements.usesInput = false;
|
|
requirements.usesReply = false;
|
|
requirements.usesOutput = false;
|
|
requirements.usesRequest = false;
|
|
requirements.sessionMode = contractDescription.SessionMode;
|
|
|
|
for (int i = 0; i < contractDescription.Operations.Count; i++)
|
|
{
|
|
OperationDescription operation = contractDescription.Operations[i];
|
|
bool oneWay = (operation.IsOneWay);
|
|
if (!operation.IsServerInitiated())
|
|
{
|
|
if (oneWay)
|
|
{
|
|
requirements.usesInput = true;
|
|
}
|
|
else
|
|
{
|
|
requirements.usesReply = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (oneWay)
|
|
{
|
|
requirements.usesOutput = true;
|
|
}
|
|
else
|
|
{
|
|
requirements.usesRequest = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Type[] ComputeRequiredChannels(ref ChannelRequirements requirements)
|
|
{
|
|
if (requirements.usesOutput || requirements.usesRequest)
|
|
{
|
|
switch (requirements.sessionMode)
|
|
{
|
|
case SessionMode.Allowed:
|
|
return new Type[] {
|
|
typeof(IDuplexChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.Required:
|
|
return new Type[] {
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.NotAllowed:
|
|
return new Type[] {
|
|
typeof(IDuplexChannel),
|
|
};
|
|
}
|
|
}
|
|
else if (requirements.usesInput && requirements.usesReply)
|
|
{
|
|
switch (requirements.sessionMode)
|
|
{
|
|
case SessionMode.Allowed:
|
|
return new Type[] {
|
|
typeof(IRequestChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.Required:
|
|
return new Type[] {
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.NotAllowed:
|
|
return new Type[] {
|
|
typeof(IRequestChannel),
|
|
typeof(IDuplexChannel),
|
|
};
|
|
}
|
|
}
|
|
else if (requirements.usesInput)
|
|
{
|
|
switch (requirements.sessionMode)
|
|
{
|
|
case SessionMode.Allowed:
|
|
return new Type[] {
|
|
typeof(IOutputChannel),
|
|
typeof(IOutputSessionChannel),
|
|
typeof(IRequestChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.Required:
|
|
return new Type[] {
|
|
typeof(IOutputSessionChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.NotAllowed:
|
|
return new Type[] {
|
|
typeof(IOutputChannel),
|
|
typeof(IRequestChannel),
|
|
typeof(IDuplexChannel),
|
|
};
|
|
}
|
|
}
|
|
else if (requirements.usesReply)
|
|
{
|
|
switch (requirements.sessionMode)
|
|
{
|
|
case SessionMode.Allowed:
|
|
return new Type[] {
|
|
typeof(IRequestChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.Required:
|
|
return new Type[] {
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.NotAllowed:
|
|
return new Type[] {
|
|
typeof(IRequestChannel),
|
|
typeof(IDuplexChannel),
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (requirements.sessionMode)
|
|
{
|
|
case SessionMode.Allowed:
|
|
return new Type[] {
|
|
typeof(IOutputSessionChannel),
|
|
typeof(IOutputChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IRequestChannel),
|
|
typeof(IDuplexChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.Required:
|
|
return new Type[] {
|
|
typeof(IOutputSessionChannel),
|
|
typeof(IRequestSessionChannel),
|
|
typeof(IDuplexSessionChannel),
|
|
};
|
|
|
|
case SessionMode.NotAllowed:
|
|
return new Type[] {
|
|
typeof(IOutputChannel),
|
|
typeof(IRequestChannel),
|
|
typeof(IDuplexChannel),
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static bool IsSessionful(Type channelType)
|
|
{
|
|
return (channelType == typeof(IDuplexSessionChannel) ||
|
|
channelType == typeof(IOutputSessionChannel) ||
|
|
channelType == typeof(IInputSessionChannel) ||
|
|
channelType == typeof(IReplySessionChannel) ||
|
|
channelType == typeof(IRequestSessionChannel));
|
|
}
|
|
|
|
public static bool IsOneWay(Type channelType)
|
|
{
|
|
return (channelType == typeof(IOutputChannel) ||
|
|
channelType == typeof(IInputChannel) ||
|
|
channelType == typeof(IInputSessionChannel) ||
|
|
channelType == typeof(IOutputSessionChannel));
|
|
}
|
|
|
|
public static bool IsRequestReply(Type channelType)
|
|
{
|
|
return (channelType == typeof(IRequestChannel) ||
|
|
channelType == typeof(IReplyChannel) ||
|
|
channelType == typeof(IReplySessionChannel) ||
|
|
channelType == typeof(IRequestSessionChannel));
|
|
}
|
|
|
|
public static bool IsDuplex(Type channelType)
|
|
{
|
|
return (channelType == typeof(IDuplexChannel) ||
|
|
channelType == typeof(IDuplexSessionChannel));
|
|
}
|
|
|
|
public static Exception CantCreateListenerException(IEnumerable<Type> supportedChannels, IEnumerable<Type> requiredChannels, string bindingName)
|
|
{
|
|
string contractChannelTypesString = "";
|
|
string bindingChannelTypesString = "";
|
|
|
|
Exception exception = ChannelRequirements.BindingContractMismatchException(supportedChannels, requiredChannels, bindingName,
|
|
ref contractChannelTypesString, ref bindingChannelTypesString);
|
|
|
|
if (exception == null)
|
|
{
|
|
// none of the obvious speculations about the failure holds, so we fall back to the generic error message
|
|
exception = new InvalidOperationException(SR.GetString(SR.EndpointListenerRequirementsCannotBeMetBy3,
|
|
bindingName, contractChannelTypesString, bindingChannelTypesString));
|
|
}
|
|
|
|
return exception;
|
|
}
|
|
|
|
public static Exception CantCreateChannelException(IEnumerable<Type> supportedChannels, IEnumerable<Type> requiredChannels, string bindingName)
|
|
{
|
|
string contractChannelTypesString = "";
|
|
string bindingChannelTypesString = "";
|
|
|
|
Exception exception = ChannelRequirements.BindingContractMismatchException(supportedChannels, requiredChannels, bindingName,
|
|
ref contractChannelTypesString, ref bindingChannelTypesString);
|
|
|
|
if (exception == null)
|
|
{
|
|
// none of the obvious speculations about the failure holds, so we fall back to the generic error message
|
|
exception = new InvalidOperationException(SR.GetString(SR.CouldnTCreateChannelForType2, bindingName, contractChannelTypesString));
|
|
}
|
|
|
|
return exception;
|
|
}
|
|
|
|
public static Exception BindingContractMismatchException(IEnumerable<Type> supportedChannels, IEnumerable<Type> requiredChannels,
|
|
string bindingName, ref string contractChannelTypesString, ref string bindingChannelTypesString)
|
|
{
|
|
StringBuilder contractChannelTypes = new StringBuilder();
|
|
bool contractRequiresOneWay = true;
|
|
bool contractRequiresRequestReply = true;
|
|
bool contractRequiresDuplex = true;
|
|
bool contractRequiresTwoWay = true; // request-reply or duplex
|
|
bool contractRequiresSession = true;
|
|
bool contractRequiresDatagram = true;
|
|
foreach (Type channelType in requiredChannels)
|
|
{
|
|
if (contractChannelTypes.Length > 0)
|
|
{
|
|
contractChannelTypes.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator);
|
|
contractChannelTypes.Append(" ");
|
|
}
|
|
string typeString = channelType.ToString();
|
|
contractChannelTypes.Append(typeString.Substring(typeString.LastIndexOf('.') + 1));
|
|
|
|
if (!ChannelRequirements.IsOneWay(channelType))
|
|
{
|
|
contractRequiresOneWay = false;
|
|
}
|
|
if (!ChannelRequirements.IsRequestReply(channelType))
|
|
{
|
|
contractRequiresRequestReply = false;
|
|
}
|
|
if (!ChannelRequirements.IsDuplex(channelType))
|
|
{
|
|
contractRequiresDuplex = false;
|
|
}
|
|
if (!(ChannelRequirements.IsRequestReply(channelType) || ChannelRequirements.IsDuplex(channelType)))
|
|
{
|
|
contractRequiresTwoWay = false;
|
|
}
|
|
if (!ChannelRequirements.IsSessionful(channelType))
|
|
{
|
|
contractRequiresSession = false;
|
|
}
|
|
else
|
|
{
|
|
contractRequiresDatagram = false;
|
|
}
|
|
}
|
|
|
|
StringBuilder bindingChannelTypes = new StringBuilder();
|
|
bool bindingSupportsOneWay = false;
|
|
bool bindingSupportsRequestReply = false;
|
|
bool bindingSupportsDuplex = false;
|
|
bool bindingSupportsSession = false;
|
|
bool bindingSupportsDatagram = false;
|
|
bool bindingSupportsAtLeastOneChannelType = false;
|
|
foreach (Type channelType in supportedChannels)
|
|
{
|
|
bindingSupportsAtLeastOneChannelType = true;
|
|
if (bindingChannelTypes.Length > 0)
|
|
{
|
|
bindingChannelTypes.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator);
|
|
bindingChannelTypes.Append(" ");
|
|
}
|
|
string typeString = channelType.ToString();
|
|
bindingChannelTypes.Append(typeString.Substring(typeString.LastIndexOf('.') + 1));
|
|
|
|
if (ChannelRequirements.IsOneWay(channelType))
|
|
{
|
|
bindingSupportsOneWay = true;
|
|
}
|
|
if (ChannelRequirements.IsRequestReply(channelType))
|
|
{
|
|
bindingSupportsRequestReply = true;
|
|
}
|
|
if (ChannelRequirements.IsDuplex(channelType))
|
|
{
|
|
bindingSupportsDuplex = true;
|
|
}
|
|
if (ChannelRequirements.IsSessionful(channelType))
|
|
{
|
|
bindingSupportsSession = true;
|
|
}
|
|
else
|
|
{
|
|
bindingSupportsDatagram = true;
|
|
}
|
|
}
|
|
bool bindingSupportsTwoWay = bindingSupportsRequestReply || bindingSupportsDuplex;
|
|
|
|
if (!bindingSupportsAtLeastOneChannelType)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportAnyChannelTypes1, bindingName));
|
|
}
|
|
if (contractRequiresSession && !bindingSupportsSession)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportSessionButContractRequires1, bindingName));
|
|
}
|
|
if (contractRequiresDatagram && !bindingSupportsDatagram)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesntSupportDatagramButContractRequires, bindingName));
|
|
}
|
|
if (contractRequiresDuplex && !bindingSupportsDuplex)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportDuplexButContractRequires1, bindingName));
|
|
}
|
|
if (contractRequiresRequestReply && !bindingSupportsRequestReply)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportRequestReplyButContract1, bindingName));
|
|
}
|
|
if (contractRequiresOneWay && !bindingSupportsOneWay)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportOneWayButContractRequires1, bindingName));
|
|
}
|
|
if (contractRequiresTwoWay && !bindingSupportsTwoWay)
|
|
{
|
|
return new InvalidOperationException(SR.GetString(SR.BindingDoesnTSupportTwoWayButContractRequires1, bindingName));
|
|
}
|
|
|
|
contractChannelTypesString = contractChannelTypes.ToString();
|
|
bindingChannelTypesString = bindingChannelTypes.ToString();
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|