340 lines
11 KiB
C#
340 lines
11 KiB
C#
|
//-----------------------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
namespace System.ServiceModel.Dispatcher
|
||
|
{
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.ServiceModel;
|
||
|
using System.ServiceModel.Channels;
|
||
|
using System.ServiceModel.Diagnostics;
|
||
|
|
||
|
public class EndpointDispatcher
|
||
|
{
|
||
|
MessageFilter addressFilter;
|
||
|
bool addressFilterSetExplicit;
|
||
|
ChannelDispatcher channelDispatcher;
|
||
|
MessageFilter contractFilter;
|
||
|
string contractName;
|
||
|
string contractNamespace;
|
||
|
ServiceChannel datagramChannel;
|
||
|
DispatchRuntime dispatchRuntime;
|
||
|
MessageFilter endpointFilter;
|
||
|
int filterPriority;
|
||
|
Uri listenUri;
|
||
|
EndpointAddress originalAddress;
|
||
|
string perfCounterId;
|
||
|
string perfCounterBaseId;
|
||
|
string id; // for ServiceMetadataBehavior, to help get EndpointIdentity of ServiceEndpoint from EndpointDispatcher
|
||
|
bool isSystemEndpoint;
|
||
|
|
||
|
internal EndpointDispatcher(EndpointAddress address, string contractName, string contractNamespace, string id, bool isSystemEndpoint)
|
||
|
: this(address, contractName, contractNamespace)
|
||
|
{
|
||
|
this.id = id;
|
||
|
this.isSystemEndpoint = isSystemEndpoint;
|
||
|
}
|
||
|
|
||
|
public EndpointDispatcher(EndpointAddress address, string contractName, string contractNamespace)
|
||
|
: this(address, contractName, contractNamespace, false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public EndpointDispatcher(EndpointAddress address, string contractName, string contractNamespace, bool isSystemEndpoint)
|
||
|
{
|
||
|
this.originalAddress = address;
|
||
|
this.contractName = contractName;
|
||
|
this.contractNamespace = contractNamespace;
|
||
|
|
||
|
if (address != null)
|
||
|
{
|
||
|
this.addressFilter = new EndpointAddressMessageFilter(address);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.addressFilter = new MatchAllMessageFilter();
|
||
|
}
|
||
|
|
||
|
this.contractFilter = new MatchAllMessageFilter();
|
||
|
this.dispatchRuntime = new DispatchRuntime(this);
|
||
|
this.filterPriority = 0;
|
||
|
this.isSystemEndpoint = isSystemEndpoint;
|
||
|
}
|
||
|
|
||
|
EndpointDispatcher(EndpointDispatcher baseEndpoint, IEnumerable<AddressHeader> headers)
|
||
|
{
|
||
|
EndpointAddressBuilder builder = new EndpointAddressBuilder(baseEndpoint.EndpointAddress);
|
||
|
foreach (AddressHeader h in headers)
|
||
|
{
|
||
|
builder.Headers.Add(h);
|
||
|
}
|
||
|
EndpointAddress address = builder.ToEndpointAddress();
|
||
|
|
||
|
this.addressFilter = new EndpointAddressMessageFilter(address);
|
||
|
// channelDispatcher is Attached
|
||
|
this.contractFilter = baseEndpoint.ContractFilter;
|
||
|
this.contractName = baseEndpoint.ContractName;
|
||
|
this.contractNamespace = baseEndpoint.ContractNamespace;
|
||
|
this.dispatchRuntime = baseEndpoint.DispatchRuntime;
|
||
|
// endpointFilter is lazy
|
||
|
this.filterPriority = baseEndpoint.FilterPriority + 1;
|
||
|
this.originalAddress = address;
|
||
|
if (PerformanceCounters.PerformanceCountersEnabled)
|
||
|
{
|
||
|
this.perfCounterId = baseEndpoint.perfCounterId;
|
||
|
this.perfCounterBaseId = baseEndpoint.perfCounterBaseId;
|
||
|
}
|
||
|
this.id = baseEndpoint.id;
|
||
|
}
|
||
|
|
||
|
public MessageFilter AddressFilter
|
||
|
{
|
||
|
get { return this.addressFilter; }
|
||
|
set
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
||
|
}
|
||
|
this.ThrowIfDisposedOrImmutable();
|
||
|
this.addressFilter = value;
|
||
|
this.addressFilterSetExplicit = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool AddressFilterSetExplicit
|
||
|
{
|
||
|
get { return this.addressFilterSetExplicit; }
|
||
|
}
|
||
|
|
||
|
public ChannelDispatcher ChannelDispatcher
|
||
|
{
|
||
|
get { return this.channelDispatcher; }
|
||
|
}
|
||
|
|
||
|
public MessageFilter ContractFilter
|
||
|
{
|
||
|
get { return this.contractFilter; }
|
||
|
set
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
||
|
}
|
||
|
this.ThrowIfDisposedOrImmutable();
|
||
|
this.contractFilter = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string ContractName
|
||
|
{
|
||
|
get { return this.contractName; }
|
||
|
}
|
||
|
|
||
|
public string ContractNamespace
|
||
|
{
|
||
|
get { return this.contractNamespace; }
|
||
|
}
|
||
|
|
||
|
internal ServiceChannel DatagramChannel
|
||
|
{
|
||
|
get { return this.datagramChannel; }
|
||
|
set { this.datagramChannel = value; }
|
||
|
}
|
||
|
|
||
|
public DispatchRuntime DispatchRuntime
|
||
|
{
|
||
|
get { return this.dispatchRuntime; }
|
||
|
}
|
||
|
|
||
|
internal Uri ListenUri
|
||
|
{
|
||
|
get { return this.listenUri; }
|
||
|
}
|
||
|
|
||
|
internal EndpointAddress OriginalAddress
|
||
|
{
|
||
|
get { return this.originalAddress; }
|
||
|
}
|
||
|
|
||
|
public EndpointAddress EndpointAddress
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this.channelDispatcher == null)
|
||
|
{
|
||
|
return this.originalAddress;
|
||
|
}
|
||
|
|
||
|
if ((this.originalAddress != null) && (this.originalAddress.Identity != null))
|
||
|
{
|
||
|
return this.originalAddress;
|
||
|
}
|
||
|
|
||
|
IChannelListener listener = this.channelDispatcher.Listener;
|
||
|
EndpointIdentity identity = listener.GetProperty<EndpointIdentity>();
|
||
|
if ((this.originalAddress != null) && (identity == null))
|
||
|
{
|
||
|
return this.originalAddress;
|
||
|
}
|
||
|
|
||
|
EndpointAddressBuilder builder;
|
||
|
if (this.originalAddress != null)
|
||
|
{
|
||
|
builder = new EndpointAddressBuilder(this.originalAddress);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
builder = new EndpointAddressBuilder();
|
||
|
builder.Uri = listener.Uri;
|
||
|
}
|
||
|
builder.Identity = identity;
|
||
|
return builder.ToEndpointAddress();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool IsSystemEndpoint
|
||
|
{
|
||
|
get { return this.isSystemEndpoint; }
|
||
|
}
|
||
|
|
||
|
internal MessageFilter EndpointFilter
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (this.endpointFilter == null)
|
||
|
{
|
||
|
MessageFilter addressFilter = this.addressFilter;
|
||
|
MessageFilter contractFilter = this.contractFilter;
|
||
|
|
||
|
// Can't optimize addressFilter similarly.
|
||
|
// AndMessageFilter tracks when the address filter matched so the correct
|
||
|
// fault can be sent back.
|
||
|
if (contractFilter is MatchAllMessageFilter)
|
||
|
{
|
||
|
this.endpointFilter = addressFilter;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this.endpointFilter = new AndMessageFilter(addressFilter, contractFilter);
|
||
|
}
|
||
|
}
|
||
|
return this.endpointFilter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int FilterPriority
|
||
|
{
|
||
|
get { return this.filterPriority; }
|
||
|
set { this.filterPriority = value; }
|
||
|
}
|
||
|
|
||
|
internal string Id
|
||
|
{
|
||
|
get { return this.id; }
|
||
|
set { this.id = value; }
|
||
|
}
|
||
|
|
||
|
internal string PerfCounterId
|
||
|
{
|
||
|
get { return this.perfCounterId; }
|
||
|
}
|
||
|
|
||
|
internal string PerfCounterBaseId
|
||
|
{
|
||
|
get { return this.perfCounterBaseId; }
|
||
|
}
|
||
|
|
||
|
internal int PerfCounterInstanceId { get; set; }
|
||
|
|
||
|
static internal EndpointDispatcher AddEndpointDispatcher(EndpointDispatcher baseEndpoint,
|
||
|
IEnumerable<AddressHeader> headers)
|
||
|
{
|
||
|
EndpointDispatcher endpoint = new EndpointDispatcher(baseEndpoint, headers);
|
||
|
baseEndpoint.ChannelDispatcher.Endpoints.Add(endpoint);
|
||
|
return endpoint;
|
||
|
}
|
||
|
|
||
|
internal void Attach(ChannelDispatcher channelDispatcher)
|
||
|
{
|
||
|
if (channelDispatcher == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channelDispatcher");
|
||
|
}
|
||
|
|
||
|
if (this.channelDispatcher != null)
|
||
|
{
|
||
|
Exception error = new InvalidOperationException(SR.GetString(SR.SFxEndpointDispatcherMultipleChannelDispatcher0));
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
|
||
|
}
|
||
|
|
||
|
this.channelDispatcher = channelDispatcher;
|
||
|
this.listenUri = channelDispatcher.Listener.Uri;
|
||
|
}
|
||
|
|
||
|
internal void Detach(ChannelDispatcher channelDispatcher)
|
||
|
{
|
||
|
if (channelDispatcher == null)
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channelDispatcher");
|
||
|
}
|
||
|
|
||
|
if (this.channelDispatcher != channelDispatcher)
|
||
|
{
|
||
|
Exception error = new InvalidOperationException(SR.GetString(SR.SFxEndpointDispatcherDifferentChannelDispatcher0));
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
|
||
|
}
|
||
|
|
||
|
this.ReleasePerformanceCounters();
|
||
|
this.channelDispatcher = null;
|
||
|
}
|
||
|
|
||
|
internal void ReleasePerformanceCounters()
|
||
|
{
|
||
|
if (PerformanceCounters.PerformanceCountersEnabled)
|
||
|
{
|
||
|
PerformanceCounters.ReleasePerformanceCountersForEndpoint(this.perfCounterId, this.perfCounterBaseId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool SetPerfCounterId()
|
||
|
{
|
||
|
Uri keyUri = null;
|
||
|
if (null != this.ListenUri)
|
||
|
{
|
||
|
keyUri = this.ListenUri;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EndpointAddress endpointAddress = this.EndpointAddress;
|
||
|
if (null != endpointAddress)
|
||
|
{
|
||
|
keyUri = endpointAddress.Uri;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (null != keyUri)
|
||
|
{
|
||
|
this.perfCounterBaseId = keyUri.AbsoluteUri.ToUpperInvariant();
|
||
|
this.perfCounterId = this.perfCounterBaseId + "/" + contractName.ToUpperInvariant();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThrowIfDisposedOrImmutable()
|
||
|
{
|
||
|
ChannelDispatcher channelDispatcher = this.channelDispatcher;
|
||
|
if (channelDispatcher != null)
|
||
|
{
|
||
|
channelDispatcher.ThrowIfDisposedOrImmutable();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|