2015-06-23 128 views
13

一個人如何通過WCF不使用WCF項目來爲每個方法公開一個由幾個類組成的API。從現有API自動生成服務器端WCF服務

例如,假設我有以下

public interface RainfallMonitor 
{ 
    [ExposeToWeb] 
    void RecordRainfall(string county, float rainfallInches); 

    [ExposeToWeb] 
    float GetTotalRainfall(string county); 

    void ClearRainfall(string county); 
} 

我知道我可以創建一個WCF服務庫和往常一樣,只是添加一個名爲「RainfallMonitor」 WCF服務。

我在探索的是......有可能/合理的以某種方式在編譯時爲整個API生成所有與WCF相關的代碼,而無需實際製作類WCF服務。可能使用諸如ExposeToWeb之類的屬性來表示通過服務公開哪些方法。得到的將功能類似這樣:

  1. 創建/項目稱爲RainfallAPI
  2. 編譯修改類和有其他項目/ DLL自動生成名爲RainfallService

本質:

  • 如果這是可能的,我可以採取什麼方法來真正實現 呢?
  • 我可以遇到哪些嚴重的缺陷?
  • 是否有任何現有的代碼庫,做類似的事情,我可以看看靈感

爲了澄清:我不是問自動生成客戶端存根,我問在服務器端創建服務。

+2

我可以想到兩個潛在的問題:1)方法重載不能映射到1個多個OperationContracts(名稱必須不同)。 2)API中使用的所有複雜類型必須是可序列化的(例如[DataContracts]),因此API作者必須知道他們的API將作爲WCF服務公開。 – nodots

回答

0

對於你的問題關於「我的意思是探索......是有可能/合理的以某種方式產生所有在編譯時WCF相關的代碼對整個API而實際上使類的WCF服務。」有是選擇,但他們都會花費大量的工作。

您需要編寫一個代碼生成應用程序/庫,以利用諸如CSharpCodeProvider(還有一個用於VB)和反射來檢查庫作爲後期構建步驟,在內存中構建所需的代碼,並將其保存爲DLL。

此應用程序需要找到您創建的自定義屬性,以指示它應該是WCF服務,並根據您定義的規則輸出WCF代碼。

實際上你需要使用CodeDOM模型,這需要一個非常不同的方式思考代碼編寫代碼。不是每個人都能夠將他們的想法抽象到這個層面。

請記住,利用CodeDOM模型,您可以克服nodot提到的一些問題,例如需要序列化的數據合同。這可以被添加,並且基於CodeDOM的反射庫可以輸出一個新的DLL。

通過周到的設計和相當多的工作,可以實現您正在尋找的輸出。這只是一條黑暗的道路,有很多陷阱。

1

我最近圖書館負責人:Fody。據我所知,它可以鉤入構建過程並將IL注入程序集。我不完全確定它是如何工作的,但是可以通過搜索IL來找到所有具有ExposeToWeb屬性的方法,並使用它來將WCF服務的合約發送到程序集中。

但是另一方面,如果您已經爲該類添加屬性,爲什麼不直接添加正確的WFC屬性開始,然後使用SvcUtil在後期構建中生成合約?

編輯: 這裏是你如何可以使用一個例子svcutil

C#:

[ServiceContract] 
public interface IRainfallMonitor 
{ 
    [OperationContract] 
    void RecordRainfall(string county, float rainfallInches); 
} 

public class RainfallMonitor : IRainfallMonitor 
{ 
    public void RecordRainfall(string county, float rainfallInches) 
    { 
     // code 
    } 
} 

後生成的PowerShell:

$svcutil = "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\SvcUtil.exe" 
$csc = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" 
$assembly = "bin/debug/ProjectWithoutWCF.dll" 
$service = "ProjectWithoutWCF.RainfallMonitor" 
$outputns = "ProjectWithoutWCF.RainfallMonitor.Service" 
$outputdir = "bin/debug" 

md svcutil_tmp 
cd svcutil_tmp 

& $svcutil /serviceName:"$service" "../$assembly" 
& $svcutil *.wsdl *.xsd /importxmltypes /out:"output.cs" /n:"*,$outputns" 
& $csc /target:library /out:$outputns.dll "output.cs" 

cp "$outputns.dll" "../$outputdir" 
cp output.config "../$outputdir/$outputns.dll.config" 
cd .. 
rm -r .\svcutil_tmp 

,您將需要在這樣的事情你項目配置:

<system.serviceModel> 
    <services> 
    <service name="ProjectWithoutWCF.RainfallMonitor" > 
     <endpoint address="" binding="basicHttpBinding" contract="ProjectWithoutWCF.IRainfallMonitor"> 
     </endpoint> 
    </service> 
    </services> 
</system.serviceModel> 

它有點煩瑣,你很可能需要對腳本和配置進行一些調整。但結果是你有一個ProjectWithoutWCF.RainfallMonitor.Service.dll文件與WCF服務合同。

0

是的,這可以通過使用正確的工具進行適度的努力來完成。如果你有Visual Studio,你已經有微軟的T4代碼生成器。它允許您通過編寫「文本模板」來生成代碼,這很容易讓人想起ASP.NET的RAZOR語法。使用T4,您可以實際實例化現有類並使用反射來讀取所有類名稱和方法簽名,並最終生成您的WCF服務。這並不難!

下面是Oleg Sych's tutorial樣品T4模板:

<#@ template language=「C#v3.5」 #> 
<#@ output extension=「SQL」 #> 
<#@ assembly name=「Microsoft.SqlServer.ConnectionInfo」 #> 
<#@ assembly name=「Microsoft.SqlServer.Smo」 #> 
<#@ import namespace=「Microsoft.SqlServer.Management.Smo」 #> 
<# 
    Server server = new Server(); 
    Database database = new Database(server, 「Northwind」); 
    Table table = new Table(database, 「Products」); 
    table.Refresh(); 
#> 
create procedure <#= table.Name #>_Delete 
<# 
    PushIndent(」\t」); 
    foreach (Column column in table.Columns) 
    { 
     if (column.InPrimaryKey) 
      WriteLine(」@」 + column.Name + 」 」 + column.DataType.Name); 
    } 
    PopIndent(); 
#> 
as 
    delete from <#= table.Name #> 
    where 
<# 
    PushIndent(」\t\t」); 
    foreach (Column column in table.Columns) 
    { 
     if (column.InPrimaryKey) 
      WriteLine(column.Name + 」 = @」 + column.Name); 
    } 
    PopIndent(); 
#> 

輸出應該是這樣的:

create procedure Products_Delete 
    @ProductID int 
as 
    delete from Products 
    where ProductID = @ProductID 

當然,你的榜樣,你會在你現有的類庫使用反射,而不是的SQL查詢。您生成的WCf服務可以簡單地調用您現有的庫,這樣就不必複製所有實際的域邏輯。

MSDN

https://msdn.microsoft.com/en-us/library/bb126445.aspx