C# 基于跨项目的代码文件进行构建时代码验证和生成
我正在寻找一种方法,让我使用VisualStudio2010(不是express)和MSBuild在构建过程中验证代码和生成器代码 背景验证: 我正在使用WCFWebAPI编写一个RESTfulWeb服务。在表示web服务的服务类中,我必须定义一个端点,并将其他参数声明为普通测试。当端点声明中的参数名与C#方法的参数不同时,我会得到一个错误——不幸的是,在运行时访问web服务时,而不是在编译时。因此,我认为将web服务类作为编译步骤的一部分进行分析是很好的,因为这样会在出现错误时返回错误 例子: 另外,我想强制执行一些命名规则,例如GET方法必须以“GET”字开头。我相信这将有助于在与几个同事一起工作时使服务保持更高的可维护性 背景生成: 我将在其他几个项目中使用这个RESTWeb服务,因为我需要编写一个客户端来访问这个服务。但我不想为每一项都编写一个客户端,总是在服务发生变化时进行调整。我希望根据web服务代码文件自动生成客户端 以前的做法: 到目前为止,我尝试使用一个使用DTE接口的T4模板来解析代码文件并对其进行验证,或者生成客户端。在VisualStudio中手动保存时,这种方法工作得很好,但在生成过程中集成这种方法效果不太好,因为使用MSBuild无法使用VisualStudio主机C# 基于跨项目的代码文件进行构建时代码验证和生成,c#,visual-studio-2010,build-process,code-generation,build-time,C#,Visual Studio 2010,Build Process,Code Generation,Build Time,我正在寻找一种方法,让我使用VisualStudio2010(不是express)和MSBuild在构建过程中验证代码和生成器代码 背景验证: 我正在使用WCFWebAPI编写一个RESTfulWeb服务。在表示web服务的服务类中,我必须定义一个端点,并将其他参数声明为普通测试。当端点声明中的参数名与C#方法的参数不同时,我会得到一个错误——不幸的是,在运行时访问web服务时,而不是在编译时。因此,我认为将web服务类作为编译步骤的一部分进行分析是很好的,因为这样会在出现错误时返回错误 例子:
欢迎任何建议。:)这可能是一个遥远的目标,但仍然符合“任何建议”: 您可以编译代码,然后运行post-build命令,这将是您必须编写的工具,它使用反射将解析的UriTemplate文本与方法参数名进行比较,捕捉错误并以MSBuild将拾取的方式输出它们。查看以获取有关如何输出的信息,以便MSBuild将错误放入visual studio错误列表中。如果发现错误,则生成后工具可以删除已编译的程序集,从而“模拟”失败的生成 以下是引导我访问MSBuild博客的方法,仅供参考
HTH对于强制执行方面,定制FxCop规则可能非常适合
对于客户机代码生成,有很多可能性。如果您喜欢T4方法,可能有一种方法可以让它与MSBuild一起工作(但是您肯定需要提供更多关于现在不起作用的细节)。如果您想要另一种选择,基于反射的后期构建工具是另一种方式…而不是使用DTE或其他方法来解析C代码,您可以在编译后使用反射(仅使用反射上下文)来检查程序集。使用反射是一个更健壮的解决方案,而且可能更快(特别是如果使用Mono.Cecil进行反射) 对于MSBuild集成,我建议编写一个-它比编写由MSBuild执行的命令行实用程序更简单、更健壮/优雅。这里有一个简短、非常难看的程序,可以在程序集或程序集组上运行(只需将DLL作为参数传递)执行WebGet模板检查。如果您没有通过任何测试,它将在自身上运行(并相应地失败,因为这是它自己的单元测试) 程序将向标准输出缺少参数的方法的名称和缺少参数的名称,如果找到任何参数,将返回非零返回代码(程序失败的标准),使其适合作为生成后事件。如果你的眼睛流血,我不负责:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Web;
namespace ConsoleApplication1
{
class Program
{
static int Main(string[] args)
{
var failList = new ConcurrentDictionary<MethodInfo, ISet<String>>();
var assembliesToRunOn = (args.Length == 0 ? new[] {Assembly.GetExecutingAssembly()} : args.Select(Assembly.LoadFrom)).ToList();
assembliesToRunOn.AsParallel().ForAll(
a => Array.ForEach(a.GetTypes(), t => Array.ForEach(t.GetMethods(BindingFlags.Public | BindingFlags.Instance),
mi =>
{
var miParams = mi.GetParameters();
var attribs = mi.GetCustomAttributes(typeof (WebGetAttribute), true);
if (attribs.Length <= 0) return;
var wga = (WebGetAttribute)attribs[0];
wga.UriTemplate
.Split('/')
.ToList()
.ForEach(tp =>
{
if (tp.StartsWith("{") && tp.EndsWith("}"))
{
var tpName = tp.Substring(1, tp.Length - 2);
if (!miParams.Any(pi => pi.Name == tpName))
{
failList.AddOrUpdate(mi, new HashSet<string> {tpName}, (miv, l) =>
{
l.Add(tpName);
return l;
});
}
}
});
})));
if (failList.Count == 0) return 0;
failList.ToList().ForEach(kvp => Console.Out.WriteLine("Method " + kvp.Key + " in type " + kvp.Key.DeclaringType + " is missing the following expected parameters: " + String.Join(", ", kvp.Value.ToArray())));
return failList.Count;
}
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillPass(String param1, String param2) { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail() { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail2(String param1) { }
}
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
运用系统反思;
使用System.ServiceModel.Web;
命名空间控制台应用程序1
{
班级计划
{
静态int Main(字符串[]args)
{
var failList=新的ConcurrentDictionary();
var assembliesToRunOn=(args.Length==0?new[]{Assembly.GetExecutingAssembly()}:args.Select(Assembly.LoadFrom)).ToList();
assembliesToRunOn.AsParallel().ForAll(
a=>Array.ForEach(a.GetTypes(),t=>Array.ForEach(t.GetMethods(BindingFlags.Public | BindingFlags.Instance),
mi=>
{
var miParams=mi.GetParameters();
var attribs=mi.GetCustomAttributes(typeof(WebGetAttribute),true);
if(attribs.Length
{
if(tp.StartsWith(“{”)和&tp.EndsWith(“}”))
{
var tpName=tp.Substring(1,tp.Length-2);
如果(!miParams.Any(pi=>pi.Name==tpName))
{
failList.AddOrUpdate(mi,新哈希集{tpName},(miv,l)=>
{
l、 添加(tpName);
返回l;
});
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Web;
namespace ConsoleApplication1
{
class Program
{
static int Main(string[] args)
{
var failList = new ConcurrentDictionary<MethodInfo, ISet<String>>();
var assembliesToRunOn = (args.Length == 0 ? new[] {Assembly.GetExecutingAssembly()} : args.Select(Assembly.LoadFrom)).ToList();
assembliesToRunOn.AsParallel().ForAll(
a => Array.ForEach(a.GetTypes(), t => Array.ForEach(t.GetMethods(BindingFlags.Public | BindingFlags.Instance),
mi =>
{
var miParams = mi.GetParameters();
var attribs = mi.GetCustomAttributes(typeof (WebGetAttribute), true);
if (attribs.Length <= 0) return;
var wga = (WebGetAttribute)attribs[0];
wga.UriTemplate
.Split('/')
.ToList()
.ForEach(tp =>
{
if (tp.StartsWith("{") && tp.EndsWith("}"))
{
var tpName = tp.Substring(1, tp.Length - 2);
if (!miParams.Any(pi => pi.Name == tpName))
{
failList.AddOrUpdate(mi, new HashSet<string> {tpName}, (miv, l) =>
{
l.Add(tpName);
return l;
});
}
}
});
})));
if (failList.Count == 0) return 0;
failList.ToList().ForEach(kvp => Console.Out.WriteLine("Method " + kvp.Key + " in type " + kvp.Key.DeclaringType + " is missing the following expected parameters: " + String.Join(", ", kvp.Value.ToArray())));
return failList.Count;
}
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillPass(String param1, String param2) { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail() { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail2(String param1) { }
}
}