我的目標是創建一個主機應用程序,能夠解析多個程序集,檢測合同並承載服務。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」幷包含2個服務。一個是公開回調,另一個是基本服務。
<?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>
因此,要明確,這裏就是我在尋找:在當前app目錄
1.裝載組件
2.外貌是否有它
3.如果任何合同執行有是,實例化那些服務(使用app.config的那一刻)
首先,這甚至有可能嗎? (我的猜測是,因爲名爲wcfstorm alread的應用程序似乎是這樣做的)
很明顯,我怎樣才能使代碼高於作品?
謝謝!
可怕的解決方案,但...您可以使用激活器來創建實現的實例,然後通過在該實例上調用GetType將該類型傳遞給ServiceHost。 – RobH
@Munchies通過添加以下內容:'var test = Activator.CreateInstance(implementation);'我收到錯誤「請求的操作在ReflectionOnly上下文中無效。 另外,它不是相當低效實例化每個服務兩次嗎? (通過創建ServiceHost對象,我相信創建了一個新的服務實例) – Sim
我剛剛發現了這個問題。您只在僅反射的上下文中加載程序集。用Assembly.Load或Assembly.LoadFrom加載你的程序集,你的原始代碼應該可以工作。 – RobH