e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
429 lines
13 KiB
C#
429 lines
13 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.ServiceModel.ComIntegration
|
|
{
|
|
using System;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.ServiceModel.Description;
|
|
using System.Collections.Generic;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.EnterpriseServices;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Configuration;
|
|
using System.Transactions;
|
|
using SR = System.ServiceModel.SR;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.Runtime;
|
|
|
|
// The values of the enum are reflected from the values in the
|
|
// COM+ Admin SDK.
|
|
//
|
|
enum Bitness
|
|
{
|
|
Bitness32 = 0x01,
|
|
Bitness64 = 0x02
|
|
}
|
|
|
|
enum ThreadingModel
|
|
{
|
|
MTA,
|
|
STA
|
|
}
|
|
|
|
enum HostingMode
|
|
{
|
|
ComPlus, // Living in a DllHost.exe
|
|
WebHostOutOfProcess, // From webhost to dllhost.exe
|
|
WebHostInProcess // Inside webhost
|
|
}
|
|
|
|
class ServiceInfo
|
|
{
|
|
ServiceElement service;
|
|
Guid clsid;
|
|
Guid appid;
|
|
HostingMode hostingMode;
|
|
Guid partitionId;
|
|
Bitness bitness;
|
|
ThreadingModel threadingModel;
|
|
TransactionOption transactionOption;
|
|
IsolationLevel isolationLevel;
|
|
bool checkRoles;
|
|
string[] componentRoleMembers;
|
|
bool objectPoolingEnabled;
|
|
int maxPoolSize;
|
|
Type managedType;
|
|
List<ContractInfo> contracts;
|
|
string serviceName;
|
|
Dictionary<Guid, List<Type>> udts;
|
|
|
|
|
|
public string ServiceName
|
|
{
|
|
get
|
|
{
|
|
return serviceName;
|
|
}
|
|
}
|
|
|
|
|
|
// NOTE: Construction of this thing is quite inefficient-- it
|
|
// has several nested loops that could probably be
|
|
// improved. Such optimizations have been left for when
|
|
// it turns out to be a performance problem, for the
|
|
// sake of simplicity.
|
|
//
|
|
public ServiceInfo(Guid clsid,
|
|
ServiceElement service,
|
|
ComCatalogObject application,
|
|
ComCatalogObject classObject,
|
|
HostingMode hostingMode)
|
|
{
|
|
// Simple things...
|
|
//
|
|
this.service = service;
|
|
this.clsid = clsid;
|
|
this.appid = Fx.CreateGuid((string)application.GetValue("ID"));
|
|
this.partitionId = Fx.CreateGuid((string)application.GetValue("AppPartitionID"));
|
|
this.bitness = (Bitness)classObject.GetValue("Bitness");
|
|
this.transactionOption = (TransactionOption)classObject.GetValue("Transaction");
|
|
this.hostingMode = hostingMode;
|
|
this.managedType = TypeCacheManager.ResolveClsidToType(clsid);
|
|
this.serviceName = application.Name + "." + classObject.Name;
|
|
this.udts = new Dictionary<Guid, List<Type>>();
|
|
|
|
// Isolation Level
|
|
COMAdminIsolationLevel adminIsolationLevel;
|
|
adminIsolationLevel = (COMAdminIsolationLevel)classObject.GetValue("TxIsolationLevel");
|
|
switch (adminIsolationLevel)
|
|
{
|
|
case COMAdminIsolationLevel.Any:
|
|
this.isolationLevel = IsolationLevel.Unspecified;
|
|
break;
|
|
case COMAdminIsolationLevel.ReadUncommitted:
|
|
this.isolationLevel = IsolationLevel.ReadUncommitted;
|
|
break;
|
|
case COMAdminIsolationLevel.ReadCommitted:
|
|
this.isolationLevel = IsolationLevel.ReadCommitted;
|
|
break;
|
|
case COMAdminIsolationLevel.RepeatableRead:
|
|
this.isolationLevel = IsolationLevel.RepeatableRead;
|
|
break;
|
|
case COMAdminIsolationLevel.Serializable:
|
|
this.isolationLevel = IsolationLevel.Serializable;
|
|
break;
|
|
default:
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
|
|
SR.GetString(SR.InvalidIsolationLevelValue,
|
|
this.clsid, adminIsolationLevel)));
|
|
}
|
|
|
|
// Threading Model
|
|
//
|
|
COMAdminThreadingModel adminThreadingModel;
|
|
adminThreadingModel = (COMAdminThreadingModel)classObject.GetValue("ThreadingModel");
|
|
switch (adminThreadingModel)
|
|
{
|
|
case COMAdminThreadingModel.Apartment:
|
|
case COMAdminThreadingModel.Main:
|
|
this.threadingModel = ThreadingModel.STA;
|
|
objectPoolingEnabled = false;
|
|
break;
|
|
|
|
default:
|
|
this.threadingModel = ThreadingModel.MTA;
|
|
objectPoolingEnabled = (bool)classObject.GetValue("ObjectPoolingEnabled");
|
|
break;
|
|
}
|
|
|
|
// Object Pool settings
|
|
//
|
|
|
|
if (objectPoolingEnabled)
|
|
{
|
|
maxPoolSize = (int)classObject.GetValue("MaxPoolSize");
|
|
}
|
|
else
|
|
maxPoolSize = 0;
|
|
// Security Settings
|
|
//
|
|
bool appSecurityEnabled;
|
|
appSecurityEnabled = (bool)application.GetValue(
|
|
"ApplicationAccessChecksEnabled");
|
|
if (appSecurityEnabled)
|
|
{
|
|
|
|
bool classSecurityEnabled;
|
|
classSecurityEnabled = (bool)classObject.GetValue(
|
|
"ComponentAccessChecksEnabled");
|
|
if (classSecurityEnabled)
|
|
{
|
|
this.checkRoles = true;
|
|
}
|
|
}
|
|
|
|
// Component Roles
|
|
//
|
|
ComCatalogCollection roles;
|
|
roles = classObject.GetCollection("RolesForComponent");
|
|
this.componentRoleMembers = CatalogUtil.GetRoleMembers(application, roles);
|
|
// Contracts
|
|
// One ContractInfo per unique IID exposed, so we need to
|
|
// filter duplicates.
|
|
//
|
|
this.contracts = new List<ContractInfo>();
|
|
ComCatalogCollection interfaces;
|
|
interfaces = classObject.GetCollection("InterfacesForComponent");
|
|
foreach (ServiceEndpointElement endpoint in service.Endpoints)
|
|
{
|
|
ContractInfo contract = null;
|
|
if (endpoint.Contract == ServiceMetadataBehavior.MexContractName)
|
|
continue;
|
|
|
|
Guid iid;
|
|
if (DiagnosticUtility.Utility.TryCreateGuid(endpoint.Contract, out iid))
|
|
{
|
|
// (Filter duplicates.)
|
|
bool duplicate = false;
|
|
foreach (ContractInfo otherContract in this.contracts)
|
|
{
|
|
if (iid == otherContract.IID)
|
|
{
|
|
duplicate = true;
|
|
break;
|
|
}
|
|
}
|
|
if (duplicate) continue;
|
|
|
|
foreach (ComCatalogObject interfaceObject in interfaces)
|
|
{
|
|
Guid otherInterfaceID;
|
|
if (DiagnosticUtility.Utility.TryCreateGuid((string)interfaceObject.GetValue("IID"), out otherInterfaceID))
|
|
{
|
|
if (otherInterfaceID == iid)
|
|
{
|
|
contract = new ContractInfo(iid,
|
|
endpoint,
|
|
interfaceObject,
|
|
application);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (contract == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
|
|
SR.GetString(SR.EndpointNotAnIID,
|
|
clsid.ToString("B").ToUpperInvariant(),
|
|
endpoint.Contract)));
|
|
}
|
|
this.contracts.Add(contract);
|
|
}
|
|
}
|
|
|
|
public Type ServiceType
|
|
{
|
|
get { return this.managedType; }
|
|
}
|
|
|
|
public ServiceElement ServiceElement
|
|
{
|
|
get { return this.service; }
|
|
}
|
|
|
|
public Guid Clsid
|
|
{
|
|
get { return this.clsid; }
|
|
}
|
|
|
|
public Guid AppID
|
|
{
|
|
get { return this.appid; }
|
|
}
|
|
public Guid PartitionId
|
|
{
|
|
get { return this.partitionId; }
|
|
}
|
|
|
|
public Bitness Bitness
|
|
{
|
|
get { return this.bitness; }
|
|
}
|
|
|
|
public bool CheckRoles
|
|
{
|
|
get { return this.checkRoles; }
|
|
}
|
|
|
|
|
|
public ThreadingModel ThreadingModel
|
|
{
|
|
get { return this.threadingModel; }
|
|
}
|
|
|
|
public TransactionOption TransactionOption
|
|
{
|
|
get { return this.transactionOption; }
|
|
}
|
|
|
|
public IsolationLevel IsolationLevel
|
|
{
|
|
get { return this.isolationLevel; }
|
|
}
|
|
|
|
public string[] ComponentRoleMembers
|
|
{
|
|
get { return this.componentRoleMembers; }
|
|
}
|
|
|
|
public List<ContractInfo> Contracts
|
|
{
|
|
get { return this.contracts; }
|
|
}
|
|
|
|
public HostingMode HostingMode
|
|
{
|
|
get { return this.hostingMode; }
|
|
}
|
|
|
|
public bool Pooled
|
|
{
|
|
get { return this.objectPoolingEnabled; }
|
|
}
|
|
|
|
public int MaxPoolSize
|
|
{
|
|
get { return this.maxPoolSize; }
|
|
}
|
|
|
|
internal Guid[] Assemblies
|
|
{
|
|
get
|
|
{
|
|
Guid[] ret = new Guid[this.udts.Keys.Count];
|
|
this.udts.Keys.CopyTo(ret, 0);
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
internal bool HasUdts()
|
|
{
|
|
// use the assembly count since we only add assemblies when we got UDTs
|
|
return (this.udts.Keys.Count > 0);
|
|
}
|
|
|
|
internal Type[] GetTypes(Guid assemblyId)
|
|
{
|
|
List<Type> ret = null;
|
|
udts.TryGetValue(assemblyId, out ret);
|
|
if (null == ret)
|
|
return new Type[0];
|
|
|
|
|
|
return ret.ToArray();
|
|
}
|
|
|
|
internal void AddUdt(Type udt, Guid assemblyId)
|
|
{
|
|
if (!udts.ContainsKey(assemblyId))
|
|
udts[assemblyId] = new List<Type>();
|
|
|
|
if (!udts[assemblyId].Contains(udt))
|
|
udts[assemblyId].Add(udt);
|
|
}
|
|
|
|
}
|
|
|
|
class ContractInfo
|
|
{
|
|
string name;
|
|
Guid iid;
|
|
string[] interfaceRoleMembers;
|
|
List<OperationInfo> operations;
|
|
|
|
public ContractInfo(Guid iid,
|
|
ServiceEndpointElement endpoint,
|
|
ComCatalogObject interfaceObject,
|
|
ComCatalogObject application)
|
|
{
|
|
this.name = endpoint.Contract;
|
|
this.iid = iid;
|
|
|
|
// Interface Roles
|
|
//
|
|
ComCatalogCollection roles;
|
|
roles = interfaceObject.GetCollection("RolesForInterface");
|
|
this.interfaceRoleMembers = CatalogUtil.GetRoleMembers(application,
|
|
roles);
|
|
|
|
// Operations
|
|
//
|
|
this.operations = new List<OperationInfo>();
|
|
|
|
ComCatalogCollection methods;
|
|
methods = interfaceObject.GetCollection("MethodsForInterface");
|
|
foreach (ComCatalogObject method in methods)
|
|
{
|
|
this.operations.Add(new OperationInfo(method,
|
|
application));
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return this.name; }
|
|
}
|
|
|
|
public Guid IID
|
|
{
|
|
get { return this.iid; }
|
|
}
|
|
|
|
public string[] InterfaceRoleMembers
|
|
{
|
|
get { return this.interfaceRoleMembers; }
|
|
}
|
|
|
|
public List<OperationInfo> Operations
|
|
{
|
|
get { return this.operations; }
|
|
}
|
|
}
|
|
|
|
class OperationInfo
|
|
{
|
|
string name;
|
|
string[] methodRoleMembers;
|
|
|
|
public OperationInfo(ComCatalogObject methodObject,
|
|
ComCatalogObject application)
|
|
{
|
|
this.name = (string)methodObject.GetValue("Name");
|
|
|
|
// Method Roles
|
|
//
|
|
ComCatalogCollection roles;
|
|
roles = methodObject.GetCollection("RolesForMethod");
|
|
this.methodRoleMembers = CatalogUtil.GetRoleMembers(application,
|
|
roles);
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return this.name; }
|
|
}
|
|
|
|
public string[] MethodRoleMembers
|
|
{
|
|
get { return this.methodRoleMembers; }
|
|
}
|
|
}
|
|
}
|