解惑

解己之惑,解人之惑

标签:.net (第1页共2页)

反射获取集合中指定下标的元素

不废话了,直接上代码吧:

public static object GetElementFromCollection(object obj, int index)
{
Type type = obj.GetType();
if (type.IsArray)
{
return ((Array) obj).GetValue(index);
}
else
{
object[] attributes = type.GetCustomAttributes(typeof(DefaultMemberAttribute), true);
DefaultMemberAttribute attribute = (DefaultMemberAttribute) attributes[0];
String indexerName = attribute.MemberName;
type.GetProperties();
PropertyInfo pi2 = type.GetProperty(indexerName, new Type[] { typeof(int) });
return pi2.GetValue(obj, new Object[] {index});
}
}

用C#动态调用WebService

其实利用的都是前人的成果:C# – Dynamically Invoke Web Service At Runtime

这个文章的问题是没有提及需要认证的时候怎么办,但是后面很多回帖都问到了,总结下:

在读取WSDL的时候有几种方式,我使用的是:

WebClient client = new WebClient();

if (_needCredential)
{
client.Credentials = _credential;
}
Stream stream = client.OpenRead(WSDL);
XmlTextReader xmlreader = new XmlTextReader(stream);

//XmlTextReader xmlreader = new XmlTextReader(Uri);
ServiceDescriptionImporter descriptionImporter = BuildServiceDescriptionImporter(xmlreader);
Assembly library = CompileAssembly(descriptionImporter);

在真正生成WebService的Instance以后,需要设置Instance的几个Property:

if (_needCredential)
{
PropertyInfo preAuthenticate = GetRealType().GetProperty(“PreAuthenticate”);
preAuthenticate.SetValue(Result, true, null);
PropertyInfo url = GetRealType().GetProperty(“Url”);
url.SetValue(Result, Url, null);
CredentialCache cache = new CredentialCache();
Uri uri = new Uri(Url);
cache.Add(uri, “Basic”, _credential);
PropertyInfo credentials = GetRealType().GetProperty(“Credentials”);
credentials.SetValue(Result, cache, null);
}

测试框架

最近在做C#版的测试框架,目的其实是让QA不用写代码就可以测试API,QA需要写一些XML,然后交给这个测试框架运行。

设计其实比较直接,把功能测试中的一些概念抽取出来包装下就可以了,XML要人可读可写,然后能够直接转换为对应的类,免去解析的过程最好。

我提取出来的主要概念如下:

  • Library,对应的其实就是DLL,就像java中的jar一样,可以从指定的路径load,也可以从系统的GAC(windows特定的东西)里面load。
  • Instance,其实本来想叫Object,因为是关键字,只能取这个比较紧似的名字,另外,声明的也确实是对象的instance而不是对象定义。
    • List,集合类型,可以当成List或者Array用。
    • WebService,这个是Instance的子类可能有点怪,但是框架的工作机制是生成WebService的Stub的对应的类,所以其实也是Instance,只是有一些额外的属性。
  • Operation,其实就是操作了,有很多子类型:
    • Method,就是方法调用了
    • Verify,主要是为了做结果验证,其实也是Method,只不过掩盖了实现,我用的就是NUit的实现。
    • Task,Operation的集合,本来想加一个Function的,但是感觉Function和Task功能完全一样。Task就相当于功能测试或者单元测试的一个方法。
    • Express,表达式,主要是为了支持简单的字符串连接和数学运算。
    • Field,获取或者设置Instance的field,我掩盖了C#中的Property和Field的区别,只提供Field,两种都可以访问。
    • Loop,其实也是Operation的集合,但是会把集合中的Operation重复执行很多次,用于性能测试或者批量调用,会生成一个索引值供Operation引用生成不同的值。
    • Indexer,访问集合类型中的某个指定下标的元素,主要是因为C#没有像Java一样提供Get(int index)方法,否则这个完全没有,直接用Method 就可以实现了。
    • Finder,主要是简化了从集合类型中查找某个元素,框架没有提供if/else这样的逻辑控制,只能提供这个变向的方式。
    • Wait,主要是提供Sleep以及异步调用支持,是Verify的子类型,可以每隔一段时间Verify一下,看看结果是不是match,然后有超时,超时就认为Veirfy失败。
  • Define,就是组件声明,里面包含的就是上面提到的那些东西。
  • Suite,就是Test Case了,包含Define列表和Task列表,以及Startup/Teardown

基本上已经涵盖测试中需要的大部分内容了。

一些额外的想法,Operation还是有很大扩展余地的,例如可以支持外部调用,例如调用一个命令行或者其它的程序。

调试COM

对于熟悉的人而言,这个可能不是什么问题,但是对于我这个.net菜鸟和其它的菜鸟,可能还是有用的。

我们新的项目是基于.NET开发的,而我们要调用或者说依赖很多C++的COM组件,我们有COM的源代码,我们的.NET代码在调用COM的时候经常会有问题,但是我们想知道到底是什么问题,这样就需要跟踪进COM里面,详细的步骤在这里:
http://support.microsoft.com/kb/919519
这个KB是How to debug a COM+ component by using Visual Studio 2005 or by using Visual Studio .NET

不过这个KB还不够,它指出了原理性的东西,但是还有些细节没有说:
如果你的工程是C#的工程或者是其他的.NET的工程,那么需要修改工程的debug属性,把Enable unmanaged code debugging选中(如果不选中这个,那么会出现the symbol file does not match the module,即使其实他们是match的)。
那个KB很长,其实重点就是两个:

  • 在Solution的属性里面,把COM的源代码的目录加进去
  • 在VS的选项里面,把COM的symbol加进去,这样就不用在你自己的代码里面设断点再load symbol了

另外文章中的那个加载dllhost那个进程的操作似乎是不需要的,我现在没有操作,可能那个操作对调试COM+有用,对于普通的COM不需要。

思路不能太僵化

原来的一个项目是Java的,构建的自动发布是采用的FTP+SSH,用FTP把文件上传到目标服务器,然后SSH登录过去重启Service使得新的Deploy生效
现在换到.Net下了,思路没有变,因为有原来的成功经验在啊。
先搜索了下,发现NAnt虽然不支持FTP,但是有第三方的东西支持,下载了,但是发现不好使。
去上了趟厕所,突然想到,我的目的是把文件拷贝到目标目录,为什么不用文件共享呢,这个最简单了,Windows直接支持,不需要任何额外的东西。
至于SSH,估计NAnt也是不支持的,但是powershell是支持远程控制其他的计算机的,重启个服务应该还是很简单的,还没有试,明天再弄了。

.NET平台下的持续集成

比Java平台下的麻烦太多。光是一个Unit Test就折腾了很长时间,很多都推荐NUnit,但是用Visual Studio还得让大家都安装NUnit,也为了看看完全用微软的方案是否可行。
由于我们现在的持续集成的工具选的是TeamCity,所以主的build脚本只能基于NAnt,因为TeamCity虽然支持MSBuild或者VS,但是没有对应的Runner或者兼容的Agent,所以基本上等于不支持。
从NAnt里面调用VisualStudio的工程文件编译是没有问题,因为有nantcontrib,但是运行Unit Test就成问题了,google了很长时间也没有找到好的解决方案,有人自己写了dll去掉整个solution的unit test(微软的msunit),还有个Gallio项目,都不怎么好用,最后回到起点:使用命令行的方式,但是需要在TeamCity的机器上安装Visual Studio,还好我们是大企业版,随便装。
最后出来的build.xml:

<?xml version="1.0"?>
<project name="POC" default="build" basedir=".">
    <property name="nantcontribdll" value="c:/nantcontrib-0.85/bin/NAnt.Contrib.Tasks.dll"/>
    <property name="mstestcommand" value="C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe"/>
    <property name="unittestdir" value="unittest"/>
    <property name="outputtype" value="debug"/>
   
    <target name="build" description="compiles the source code">
        <loadtasks assembly="${nantcontribdll}" />

        <msbuild project="MyProject\MyProject.csproj">
                <property name="teamcity_dotnet_use_msbuild_v35" value="true"/>
        </msbuild>
        <msbuild project="MyProjectTest\MyProjectTest.csproj">
                <property name="teamcity_dotnet_use_msbuild_v35" value="true"/>
        </msbuild>
    </target>
   
    <target name="unittest" description="Run unit test" depends="build">
        <delete dir="${unittestdir}" />
        <mkdir dir="${unittestdir}" />
       
        <exec program ="${mstestcommand}" commandline="/testcontainer:MyProjectTest\bin\${outputtype}\MyProjectTest.dll /resultsfile:${unittestdir}\MyProjectTest.trx" basedir="MyProjectTest"/>
    </target>
   
    <target name="clean" description="Clean output">
        <loadtasks assembly="${nantcontribdll}" />
        <delete dir="${unittestdir}" />
        <msbuild project="MyProject\MyProject.csproj" target="clean">
                <property name="teamcity_dotnet_use_msbuild_v35" value="true"/>
        </msbuild>
        <msbuild project="MyProjectTest\MyProjectTest.csproj" target="clean">
                <property name="teamcity_dotnet_use_msbuild_v35" value="true"/>
        </msbuild>
    </target>
</project>

对于NAnt需要特别说明的是:在TeamCity里面可以用NAnt0.85版本,但是本地调用的话必须用NAnt0.86beta1(当前最新版本),只有这个版本支持.net3.5,而TeamCity使用自己的方式支持.net3.5,就是我们看到的丑陋的teamcity_dotnet_use_msbuild_v35,不能定义一个全局的property了事,必须在每个msbuild任务里面定义这个property。

到底是谁?

Windows的IIS应用的身份真的是太复杂了一点。
首先是IIS的Service是有运行用户的
然后是应用使用的Application Pool也有运行用户
然后是应用也可以指定Impersonate的用户
而如果应用没有使用Windows的用户,那么还可能有另外一个用户。

以前没有搞过Windows的Web的开发,不太清楚这个里面的最佳实践。

目前的感觉是:
IIS的身份一般不去动,因为是大家共享的
如果需要比较强的用户身份,而且比较固定,建议修改Application Pool的运行身份,另外建议创建自己的Application Pool,如果应用只是简单的需要某种身份访问系统中的资源,例如读写文件、服务数据库,那么建议简单的修改web.config,使用Impersonate指定一个用户。

SandCastle使用入门

看了网上的SandCastle入门,但是我使用的时候还是遇到很多问题。
秉承我的一贯作风写个我的入门指南:

  • 下载SandCastle并安装
  • 设置系统环境变量DXROOT指向SandCastle安装的目录,默认是C:\Program Files\Sandcastle\
  • 把SandCastle的productiontools加到系统环境变量PATH里面%DXROOT%\productiontools;
  • 把SandCastle的example的bat文件拷贝出来备用:C:\Program Files\Sandcastle\Examples\sandcastle\build_Sandcastle.bat,建议把bat重命名为generate_chm.bat
  • 如果你使用Visual Studio,那么修改工程的属性,把Build的Output中的XML Documentation File勾中,如果没有使用Visual Studio,那么可以使用csc命令生成这个XML文件 csc /doc:Xxx.xml Xxx.cs,如果编译依赖其他的东西,也需要在命令行中提供。
  • Build工程,把Build生成的bin下的所有内容(debug或者release),注意是所有内容拷贝到其他的新建的目录下,然后把generate_chm.bat也拷贝过去,然后在DOS下进入那个目录: generate_chm vs2005 Xxx。不要直接在Visual Studio的工程下面运行,一个是生成很多中间的目录和文件,二是好像影响正常生成(我开始都是在Visual Studio下弄的,总是不成功)。

看似简单实际很难

这几天搞.NET最大的感受就是看似简单实际很难
先说MSBuild,我们要做Daily Build,看了下文档,好像Visual Studio的编译也是基于MSBuild,所以Daily Build应该很简单,在开发环境下用MSBuild调用Solution的配置文件,顺利完成,但是到了Daily Build的环境下就不行了,我们用的TeamCity,TeamCity也是看似支持MSBuild和Visual Studio Solution2008,但是如果选用那些Runner会提示没有可用的Agent,不得已先用Command Line的方式直接调用MSBuild,基本可行,但是我们有MSTest的Project,这个Project不能编译,复制了份sln文件,把MSTest的工程去掉了,正常过了没有问题,后来仔细看了下,发现那些Installer的工程没有编译出结果,又不支持。下载了个Wix,发现也很麻烦,因为我们的工程师Web的工程,Installer不光要配置需要的文件,还得安装到IIS中去。最后放弃,目前就只是编译整个工程,不做Unit Test和生成Installer。发现TeamCity对第三方的东西反倒支持得更好(NAnt, NUnit)。
再说API Doc,看书的时候说也支持自动文档,我想应该也是抄袭的JavaDoc吧,应该很简单,今天实际一搞,发现不一样,SDK只能帮你生成XML格式的文档,这个没有办法看,然后看了下,说有开源的工具是NDoc,下载了下,发现不支持.net2.0以上版本,仔细一看,2005年就停止开发了,又搜索了下,发现MS自己有个SandCastle,可以生成CHM格式的文档,试了下,一堆的错误,没有心情搞了。

对MS一如既往的失望和鄙视。

从Java转向.NET需要注意的问题

从Java转向.NET已经一个多月了,最开始的时候很轻视,因为C#和Java语法相差不多,真正开始写代码开发应用以后才发现很多的不同:

  • 开发工具几乎没得选:Visual Studio,既然用了MS的东西就得都用,否则遇到问题很难得到帮助,因为别人都是用的这一套。
  • Visual Studio给你封装了很多东西,有些开发因此变得很容易,但是也因此不能很灵活可控。而且你很难也往往不需要知道很多底层细节(例如写Web Service的客户端程序,添加一个Service ReferenceVS就会生成代码,根本不需要懂SOAP的细节)。
  • 你需要了解Windows平台的很多东西,例如安全机制,ODBC,Profile等等,而Java是跨平台的,这些配置以及安全等等都是作为jar包的方式引用和使用的,根本不应该依赖Windows内置的机制。
  • .NET有时候会使用很多遗留的东西,例如DLL,COM,而且因为版本不一样不见得好用,而Java比较简单,几乎只有jar,虽然也有版本问题,但是要知道jar里面包含那些类还是很容易的,但是DLL和COM之类的就很麻烦,似乎没有很好的工具帮助你查找哪个DLL或者COM有你需要的类。

现在还是刚刚对.NET有点感觉,没有被搞得头晕脑胀。

最后说一下,如果不是逼不得已,不要转向.NET,Java乱是乱了点,但是资源是大把大把的,而搞.NET,还是跟紧MS吧。

更早的文章

© 2019 解惑

本主题由Anders Noren提供向上 ↑