내 목표는 여러 어셈블리를 구문 분석하고 계약을 감지하고 서비스를 호스팅 할 수있는 호스트 응용 프로그램을 만드는 것입니다.리플렉션을 사용하여 Wcf 동적 호스팅
서비스를로드하려면 일반적으로 servicehost 인스턴스화를 하드 코딩해야합니다. 다음 코드는 찾고있는 동작이 아니더라도 작동합니다.
ServiceHost wService1Host = new ServiceHost(typeof(Service1));
wService1Host.Open();
ServiceHost wService2Host = new ServiceHost(typeof(Service2));
wService2Host.Open();
그러나 이것은 서비스가 무엇인지 미리 알고 있음을 의미합니다. 서비스가 포함 된 어셈블리에 대한 참조가 필요하지 않습니다. 호스트가 어떤 서비스가 어셈블리에 포함되어 있는지 알지 못하게하고 싶습니다. 예를 들어 어셈블리 중 하나에 새 서비스를 추가하면 호스트 측에서 변경하지 않아도됩니다.
이것은 question과 매우 유사하지만 위에 언급 한 이유 때문에 복잡성이 추가됩니다.
여기에 내가 지금까지 제공 한 호스트 코드가 있습니다. 나는 서비스를 관리하는 것을 지금 당장 마음에 두지 않는다, 나는 단지 그들이 제대로 적재되기를 바란다.
class Program
{
static void Main(string[] args)
{
// find currently executing assembly
Assembly curr = Assembly.GetExecutingAssembly();
// get the directory where this app is running in
string currentLocation = Path.GetDirectoryName(curr.Location);
// find all assemblies inside that directory
string[] assemblies = Directory.GetFiles(currentLocation, "*.dll");
// enumerate over those assemblies
foreach (string assemblyName in assemblies)
{
// load assembly just for inspection
Assembly assemblyToInspect = Assembly.ReflectionOnlyLoadFrom(assemblyName);
// I've hardcoded the name of the assembly containing the services only to ease debugging
if (assemblyToInspect != null && assemblyToInspect.GetName().Name == "WcfServices")
{
// find all types
Type[] types = assemblyToInspect.GetTypes();
// enumerate types and determine if this assembly contains any types of interest
// you could e.g. put a "marker" interface on those (service implementation)
// types of interest, or you could use a specific naming convention (all types
// like "SomeThingOrAnotherService" - ending in "Service" - are your services)
// or some kind of a lookup table (e.g. the list of types you need to find from
// parsing the app.config file)
foreach (Type ty in types)
{
Assembly implementationAssembly = Assembly.GetAssembly(ty);
// When loading the type for the service, load it from the implementing assembly.
Type implementation = implementationAssembly.GetType(ty.FullName);
ServiceHost wServiceHost = new ServiceHost(implementation); // FAIL
wServiceHost.Open();
}
}
}
Console.WriteLine("Service are up and running.");
Console.WriteLine("Press <Enter> to stop services...");
Console.ReadLine();
}
}
내가 ServiceHost를 만들려고 다음과 같은 오류 얻을 : 위의 링크에서
"It is illegal to reflect on the custom attributes of a Type loaded via ReflectionOnlyGetType (see Assembly.ReflectionOnly) -- use CustomAttributeData instead."
을, 사람은 그가 어떤 서비스를 미리 알고 있기 때문에 대해서 typeof 사용하여 문제를 해결 한 것 같다 그는 폭로하고 싶다. 불행히도, 이것은 내 경우가 아닙니다.
참고 : 호스팅 부분에는 실제로 3 개의 프로젝트가 있습니다. 첫 번째는 호스트 응용 프로그램 (위 참조)이고 두 번째 응용 프로그램은 모든 내 서비스 계약 (인터페이스)을 포함하는 어셈블리이며 마지막 어셈블리는 서비스 구현을 포함합니다.
여기 서비스를 호스팅하는 데 실제로 사용하는 app.config가 있습니다. 구현을 포함하는 어셈블리의 이름은 "WcfServices"이며 두 개의 서비스가 포함되어 있습니다. 하나는 콜백과 기타 기본 서비스 만 노출하는 것입니다.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WcfServices.Service1"
behaviorConfiguration="metadataBehavior">
<endpoint address="Service1Service"
binding="basicHttpBinding"
contract="WcfServices.IService1"
name="basicHttp"/>
<endpoint binding="mexHttpBinding"
contract="IMetadataExchange"
name="metadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/Service1"/>
</baseAddresses>
</host>
</service>
<service name="WcfServices.Service2"
behaviorConfiguration="metadataBehavior">
<endpoint address="Service2Service"
binding="wsDualHttpBinding"
contract="WcfServices.IService2"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/Service2"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
그래서, 명확하게하기 위해, 여기에 내가 무엇을 찾고 있어요 : 그것은
3. 만약에 어떤 계약도 구현이있는 경우 현재 응용 프로그램 디렉토리에
1.로드 어셈블리
2. 외모가 그 순간에 app.config를 사용하여 해당 서비스를 인스턴스화하십시오.
우선 무엇이 가능합니까? (내 생각 엔 wcfstorm이라는 응용 프로그램이 이걸로 보이는 것 같습니다.
분명히 어떻게 위의 코드를 만들 수 있습니까?
감사합니다.
private static void LoadServices()
{
// find currently executing assembly
Assembly Wcurr = Assembly.GetExecutingAssembly();
// get the directory where this app is running in
string wCurrentLocation = Path.GetDirectoryName(Wcurr.Location);
// enumerate over those assemblies
foreach (string wAssemblyName in mAssemblies)
{
// load assembly just for inspection
Assembly wAssemblyToInspect = null;
try
{
wAssemblyToInspect = Assembly.LoadFrom(wCurrentLocation + "\\" + wAssemblyName);
}
catch (System.Exception ex)
{
Console.WriteLine("Unable to load assembly : {0}", wAssemblyName);
}
if (wAssemblyToInspect != null)
{
// find all types with the HostService attribute
IEnumerable<Type> wTypes = wAssemblyToInspect.GetTypes().Where(t => Attribute.IsDefined(t, typeof(HostService), false));
foreach (Type wType in wTypes)
{
ServiceHost wServiceHost = new ServiceHost(wType);
wServiceHost.Open();
mServices.Add(wServiceHost);
Console.WriteLine("New Service Hosted : {0}", wType.Name);
}
}
}
Console.WriteLine("Services are up and running.");
}
참고 :
끔찍한 해결책이지만 ...액티베이터를 사용하여 구현의 인스턴스를 만든 다음 해당 인스턴스에서 GetType을 호출하여 ServiceHost에 유형을 전달할 수 있습니까? – RobH
@Munchies 다음을 추가하면됩니다 :'var test = Activator.CreateInstance (implementation);'요청 된 작업은 ReflectionOnly 컨텍스트에서 유효하지 않습니다. "라는 오류 메시지가 나타납니다. 또한 각 서비스를 두 번 인스턴스화하는 것이 비효율적이지 않습니까? (ServiceHost 객체를 생성함으로써 서비스의 새로운 인스턴스가 생성된다고 생각합니다) – Sim
방금 문제를 발견했습니다. 리플렉션 전용 컨텍스트에서 어셈블리를로드하고 있습니다. Assembly.Load 또는 Assembly.LoadFrom을 사용하여 어셈블리를로드하면 원래 코드가 작동합니다. – RobH