2015-06-23 98 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