从现有API自动生成服务器端WCF服务

时间:2015-06-23 22:57:08

标签: c# web-services wcf

如何在不使用WCF项目的情况下,通过WCF将每个方法的API暴露给由多个类组成的API。

例如,我们说我有以下

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. 的项目中创建/修改类
  3. 编译并自动生成另一个名为RainfallService的项目/ dll。
  4. 本质:

    • 如果可行的话,我可以采取什么方法来实际实施 它?
    • 我可能遇到什么严重的陷阱?
    • 是否有任何现有的代码库可以做类似的事情我可以寻找灵感

    澄清:我不是在询问自动生成客户端存根,我问的是在服务器端创建服务。

4 个答案:

答案 0 :(得分:1)

我最近是这个图书馆的负责人:Fody。据我所知,它可以挂钩构建过程并将IL注入到程序集中。我不完全确定它是如何工作的,但是有可能通过IL搜索,找到具有ExposeToWeb属性的所有方法,并使用它将WCF服务的合同发布到程序集中。 / p>

但另一方面,如果您已经在类中添加了属性,为什么不直接添加正确的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
    }
}

post build 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服务合同。

答案 1 :(得分:0)

关于&#34;我正在探索的问题是......是否可能/合理地在编译时为整个API生成所有WCF相关代码而不实际生成类WCF服务。&#34;,有选项,但他们都需要做很多工作。

您需要编写一个代码生成应用程序/库,它使用CSharpCodeProvider等类(也有一个用于VB)和反射来检查您的库作为构建后步骤,构建您的代码想要在内存中,并将其保存为DLL。

此应用程序需要找到您创建的自定义属性,指示它应该是WCF服务,并根据您定义的规则输出WCF代码。

实际上,您需要使用CodeDOM模型编写代码,这需要以非常不同的方式思考代码。不是每个人都能够将他们的思想抽象到那个层次。

请记住,利用CodeDOM模型,您可以克服点头提到的一些问题,例如要求可序列化的数据合同。这可以添加,并由基于CodeDOM的反射库输出新的DLL。

通过周到的设计和相当多的工作,有可能实现您所寻求的输出。这只是一条黑暗的道路,有很多陷阱可以到达那里。

答案 2 :(得分:0)

是的,这可以通过使用正确的工具轻松完成。如果您有Visual Studio,则您已经拥有Microsoft的T4代码生成器。它允许您通过编写&#34;文本模板&#34;来生成代码,这非常让人联想到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

答案 3 :(得分:0)

你可以使用Roslyn,Roslyn是新编译器作为服务,你可以在其中解析C#文件并根据需要生成源代码。

你可以在这里看到一些例子,

http://www.codeproject.com/Articles/302595/Roslyn-CTP-Three-Introductory-Projects

应该不那么困难。