Разграничение доступа из кода в WCF - Реализация класса AppDomainHost
ОГЛАВЛЕНИЕ
Реализация класса AppDomainHost
Реализация класса выполняется в два приема: создание новой области приложений и внедрение экземпляра размещения службы, затем последующее выполнение размещения службы (и экземпляра службы) в условиях частичного доверия. Для создания экземпляра размещения службы и активирования его в отдельной области приложения я написал класс ServiceHostActivator, показанный на рис. 7.
Рис. 7 Класс ServiceHostActivator
class ServiceHostActivator : MarshalByRefObject {
ServiceHost m_Host;public void CreateHost(Type serviceType,Uri[] baseAddresses) {
m_Host = new ServiceHost(serviceType,baseAddresses);
}
public void Open() {
m_Host.Open();
}
public void Close() {
m_Host.Close();
}
public void Abort() {
m_Host.Abort();
}//Rest of the implementation
}
Класс ServiceHostActivator представляет собой простую обертку стандартного экземпляра класса ServiceHost, предоставляемого платформой WCF. ServiceHostActivator порождается от MarshalByRefObject таким образом, чтобы класс AppDomainHost мог вызывать его через границу области приложений. В методе CreateHost инкапсулировано конструирование нового экземпляра ServiceHost. Остальные методы класса ServiceHostActivator просто пересылают удаленные вызовы базовому экземпляру размещения.
AppDomainHost предлагает несколько перегружаемых конструкторов. Эти конструкторы могут вызывать друг друга (см. рис. 8), даже создавая по пути новую область приложений, и в конечном итоге конструирование завершается использованием защищенного конструктора, принимающего тип службы, экземпляр новой области приложений, полномочия для новой области и базовые адреса.
Рис. 8. Реализация класса AppDomainHost
public class AppDomainHost : IDisposable {
ServiceHostActivator m_ServiceHostActivator;public AppDomainHost(Type serviceType,
params Uri[] baseAddresses) :
this(serviceType,"AppDomain Host for "+
serviceType+" "+Guid.NewGuid(),
baseAddresses) {
}public AppDomainHost(Type serviceType,
string appDomainName,
params Uri[] baseAddresses) : this(serviceType,
new PermissionSet(PermissionState.Unrestricted),
appDomainName,baseAddresses) {
}public AppDomainHost(Type serviceType,
PermissionSet permissions,
string appDomainName,
params Uri[] baseAddresses) :
this(serviceType,AppDomain.CreateDomain(appDomainName),
permissions,baseAddresses) {
}//More constructors
protected AppDomainHost(Type serviceType,
AppDomain appDomain,
PermissionSet permissions,Uri[] baseAddresses) {string assemblyName = Assembly.GetAssembly(
typeof(ServiceHostActivator)).FullName;
m_ServiceHostActivator = appDomain.CreateInstanceAndUnwrap(
assemblyName,typeof(ServiceHostActivator).ToString()) as
ServiceHostActivator;CodeAccessSecurityHelper.SetPermissionsSet(appDomain,permissions);
m_ServiceHostActivator.CreateHost(serviceType,baseAddresses);
}public void Open() {
m_ServiceHostActivator.Open();
}
public void Close() {
m_ServiceHostActivator.Close();
}
public void Abort() {
m_ServiceHostActivator.Abort();
}
void IDisposable.Dispose() {
Close();
}
}
Защищенный конструктор класса AppDomainHost использует технологию удаленного вызова .NET для внедрения в новую область приложений экземпляра класса ServiceHostActivator, завершая предоставлением ему удаленного прокси, хранящегося в члене m_ServiceHostActivator.
По умолчанию новая область приложений создается с полным доверием. Класс AppDomainHost использует метод SetPermissionsSet моего класса CodeAccessSecurityHelper для установки в новой области приложений новой политики CAS. Эта политика разрешает только предлагаемые полномочия и отказывает в остальных.
public static class CodeAccessSecurityHelper {
public static void SetPermissionsSet(
AppDomain appDomain,
PermissionSet permissions) {PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();
policy.RootCodeGroup.PolicyStatement =
new PolicyStatement(permissions);
appDomain.SetAppDomainPolicy(policy);
}
//More members
}
Это так же просто, как создание новой политики безопасности на уровне области приложений и вызов метода SetAppDomainPolicy класса AppDomain.
public sealed class AppDomain :
MarshalByRefObject,... {public void SetAppDomainPolicy(
PolicyLevel domainPolicy);
//More members
}
Между прочим, подобный прием используется в технологии ClickOnce для принудительного частично доверенного выполнения приложений, развернутых с применением ClickOnce.
При вызове других методов класса AppDomainHost, таких как Open или Close, используется прокси класса ServiceHostActivator с целью вызова другой области приложений и обеспечения открытия или закрытия им его экземпляра размещения. Поскольку экземпляр службы будет выполняться в области приложений, которой случилось открыть его размещение, служба также будет выполняться согласно политике безопасности этой области приложений.