Уменьшить повторяющиеся вложенные удостоверения в конфигурации WCF
Мой web.config для моего приложения WCF имеет ряд конечных точек, определенных следующим образом:
<system.serviceModel>
<services>
<service behaviorConfiguration="whatever" name="MyService">
<endpoint name="Endpoint1" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract1">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint2" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract2">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint3" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract3">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint4" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract4">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
Что я хотел бы сделать, это
<system.serviceModel>
<services>
<service behaviorConfiguration="whatever" name="MyService">
<endpoint name="Endpoint1" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract1" />
<endpoint name="Endpoint2" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract2" />
<endpoint name="Endpoint3" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract3" />
<endpoint name="Endpoint4" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract4" />
с определением идентичности по умолчанию, указанным один раз в другом месте (даже просто верхний уровень в элементе system.serviceModel).
В основном я хочу СУХОЙ, потому что конфигурация последовательна на всем протяжении. Мне нужна помощь от SO, где найти элемент конфигурации "идентификация по умолчанию для всех конечных точек". MSDN не очень помогает, и я не уверен, где отразить библиотеки.NET, чтобы увидеть, как это интерпретируется, когда web.configs читается при запуске приложения.
2 ответа
Резюме
Используйте стандартные конечные точки для создания настраиваемой конечной точки с соответствующей идентификационной информацией, которую можно настроить из файла конфигурации.
подробность
Спасибо за вопрос!. Я хотел иметь в виду унифицированную конфигурацию служб WCF, чтобы уменьшить накладные расходы, и ваш вопрос дал мне только повод для этого.
Я решил эту проблему с помощью стандартных конечных точек, которые существовали с.NET 4. Основная часть работы выполняется путем наследования отStandardEndpointElement
:
namespace WcfEx
{
public class X509EndpointElement : StandardEndpointElement
{
private static string _findValueKey = "findValue";
private static string _storeNameKey = "storeName";
private static string _storeLocationKey = "storeLocation";
private static string _x509FindTypeKey = "x509SearchType";
public virtual string FindValue
{
get { return base[_findValueKey] as string; }
set { base[_findValueKey] = value; }
}
public virtual StoreName StoreName
{
get { return this[_storeNameKey] is StoreName ? (StoreName) this[_storeNameKey] : (StoreName) 0; }
set { this[_storeNameKey] = value; }
}
public virtual StoreLocation StoreLocation
{
get
{
return this[_storeLocationKey] is StoreLocation
? (StoreLocation) this[_storeLocationKey]
: (StoreLocation) 0;
}
set { this[_storeLocationKey] = value; }
}
public virtual X509FindType X509FindType
{
get { return this[_x509FindTypeKey] is X509FindType ? (X509FindType) this[_x509FindTypeKey] : (X509FindType) 0; }
set { this[_x509FindTypeKey] = value; }
}
protected override ConfigurationPropertyCollection Properties
{
get
{
ConfigurationPropertyCollection properties = base.Properties;
properties.Add(new ConfigurationProperty(_findValueKey, typeof (string), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_storeNameKey, typeof (StoreName), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_storeLocationKey, typeof (StoreLocation), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_x509FindTypeKey, typeof (X509FindType), null,
ConfigurationPropertyOptions.None));
return properties;
}
}
protected override Type EndpointType
{
get { return typeof (ServiceEndpoint); }
}
protected override ServiceEndpoint CreateServiceEndpoint(ContractDescription contract)
{
return new ServiceEndpoint(contract);
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ServiceEndpointElement serviceEndpointElement)
{
endpoint.Address = new EndpointAddress(endpoint.Address.Uri,
EndpointIdentity.CreateX509CertificateIdentity(
GetCertificateFromStore()));
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ChannelEndpointElement channelEndpointElement)
{
endpoint.Address = new EndpointAddress(endpoint.Address.Uri,
EndpointIdentity.CreateX509CertificateIdentity(
GetCertificateFromStore()));
}
private X509Certificate2 GetCertificateFromStore()
{
var certificateStore = new X509Store(StoreName, StoreLocation);
certificateStore.Open(OpenFlags.ReadOnly);
var matchingCertificates = certificateStore.Certificates.Find(X509FindType, FindValue, false);
X509Certificate2 matchingCertificate = null;
if (matchingCertificates.Count > 0)
matchingCertificate = matchingCertificates[0];
else throw new InvalidOperationException("Could not find specified certificate");
certificateStore.Close();
return matchingCertificate;
}
protected override void OnInitializeAndValidate(ChannelEndpointElement channelEndpointElement)
{
}
protected override void OnInitializeAndValidate(ServiceEndpointElement serviceEndpointElement)
{
}
}
}
Краткое описание приведенного выше кода:
- Этот класс можно сделать видимым в файле.config - так что его свойства могут быть установлены через конфигурацию;
- Существует четыре свойства, которые определяют параметры для выбора сертификата X509;
- В какой-то момент времени существования этого класса адрес конечной точки устанавливается с идентификатором, указанным сертификатом, удовлетворяющим критериям поиска.
Вам нужен класс коллекции, в котором хранятся элементы вышеупомянутого класса:
namespace WcfEx
{
public class X509EndpointCollectionElement : StandardEndpointCollectionElement<ServiceEndpoint, X509EndpointElement>
{
}
}
system.serviceModel
Раздел файла.config выглядит так:
<system.serviceModel>
<extensions>
<endpointExtensions>
<add name="x509Endpoint" type="WcfEx.X509EndpointCollectionElement, WcfEx, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</endpointExtensions>
</extensions>
<standardEndpoints>
<x509Endpoint>
<standardEndpoint storeLocation="LocalMachine" storeName="TrustedPeople" findValue="cert name" x509SearchType="FindBySubjectName"/>
</x509Endpoint>
</standardEndpoints>
<services>
<service name="WcfHost.Service1">
<endpoint address="" binding="wsHttpBinding" contract="WcfHost.IService1" kind="x509Endpoint" >
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Что следует отметить:
- Будьте очень осторожны с ценностью
type
атрибут здесь - он должен быть точно таким же, какtypeof (X509EndpointElement).AssemblyQualifiedName
, - После регистрации мы можем добавить соответствующую конфигурацию в
standardEndpoints
элемент. - Мы помечаем конечную точку как имеющую настройку, используя
kind
приписывать.
Я признаю, что я еще не использовал это сам, но если вы используете WCF 4, вы можете использовать его функции привязки / конфигурации по умолчанию. См. Раздел "Упрощенная настройка" по http://msdn.microsoft.com/en-us/library/ee354381.aspx