如何在不使用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
等属性来表示通过服务公开哪些方法。结果将起到这样的作用:
RainfallAPI
RainfallService
的项目/ dll。本质:
澄清:我不是在询问自动生成客户端存根,我问的是在服务器端创建服务。
答案 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
答案 3 :(得分:0)
你可以使用Roslyn,Roslyn是新编译器作为服务,你可以在其中解析C#文件并根据需要生成源代码。
你可以在这里看到一些例子,
http://www.codeproject.com/Articles/302595/Roslyn-CTP-Three-Introductory-Projects
应该不那么困难。