Thursday, December 21, 2006

(ZT)CTS

通用类型系统(Common Type System,以下简称CTS,有的地方也叫公共类型系统),算是个老话题了,但对于部分.NET程序员来说,可能还是需要这方面的知识。加上CTS是.NET里各种语言的基础,为了更好的进一步学习各种语言特性以及.NET Framework,也不得不了解CTS。我近期也在准备着一些.NET入门到提高学习资料,所以顺便整理下相关资料贴出来供大家参考(有可能的话,会按我整理的从入门到提高的系列一篇篇贴出来,不过就是要等待些时间),哪怕你对其中一点有心领神会的感觉,那也就够了。OK,转入正题。

一、CTS简介

我们都知道,编程语言发展至今已经有几百种,面对这么多的编程语言,经常有人陷入类似“生死抉择”的痛苦,但是有点体会的程序员总会说:“语言是互通的,只要你掌握了编程思想,遵循相应编程规范,就不用怕今天又出现了多少新语言”。我想这句话确实是有道理的。在这众多语言的背后,也隐藏着某种共性,不仅在语言本身,也在使用语言的方法上。就象大家常理解“程序=算法+数据结构”一样,我们也可以这样理解语言的共性,即“语言=语法+语义”。单纯字面上理解(不涉及编译等具体技术),语言实际上就是用各种事先定义好的关键字以一种特定组合方式起来的表现形式,用以定义数据以及描述对数据的操作。
了解了语言的概念,让我们思考下,是否存在一种东西(请原谅我用“东西”这个词)满足所有语言的共性?假如众多语言有了一种共性,是否可以进一步让众多语言之间实现互操作?再者,结合面向对象里的单根对象层次观点让每个对象最终都有相同的基类型,是否就又有了类型的统一功能?接着在统一类型基础上,又有了统一的调试方式、统一的体系框架、统一的开发手段等等呢?好了,再说下去都成完美神话了。上面的“东西”,实际上就是CTS。也正因为有了CTS,才有了.NET里“统一”的诸多特性,把CTS说成CLR(Common Language Runtime 通用语言运行库)的核心,编程人员必须掌握的特性一点也不为过。
下面引用MSDN里的CTS定义让大家有更清楚了解CTS,毕竟MSDN是权威:

通用类型系统定义了如何在运行库中声明、使用和管理类型,同时也是运行库支持跨语言集成的一个重要组成部分。通用类型系统执行以下功能:

  • 建立一个支持跨语言集成、类型安全和高性能代码执行的框架。
  • 提供一个支持完整实现多种编程语言的面向对象的模型。
  • 定义各语言必须遵守的规则,有助于确保用不同语言编写的对象能够交互作用。

清楚了CTS的概念与优点后,我们更进一步来了解CTS。按照上面所讲的语言与CTS的关系,我们可以把CTS看成是.NET是所有语言的超集,也就是说各种符合CTS的语言,实际上都是CTS的一个子集。用数学的集合观点理解就是如下图:

从上图还可以看出在各种语言之间还有个交集——通用语言规范(Common Language Specification,简称CLS),这里也简单说下。我理解中,CTS是一套类型系统,而CLS则是事先定义好的一种规则,遵循这种规则编写的任何代码都可以实现跨语言的互操作性。事实上,通用语言基础结构(Common Language Infrastructure, 简称CLI,是CLR的子集。CLR与CLI的关系类似CTS与CLS的关系。)正是使用CLS来让各种不同的语言使用.Net框架各种资源。在实际应用上,对于CLS,如果我们项目里都只用一种语言,例如C#,那就没必要过度关心CLS。相对地,如果是多种语言结合开发,或者希望你开发的类库能让各种不同语言调用时,那么CLS绝对是你需要进一步了解的内容。

 

二、了解CTS前的准备

1、 首先,说说堆(heap)与栈(stack,也叫堆栈),理解了最起码的堆栈概念,对于理解CTS绝对是必要的,而在最近给公司新员工培训时,发现他们根本不了解这块,所以我也觉得有必要单独再稍微说明下。对于heap和stack,简单的来讲,stack上分配的内存系统自动释放,heap上分配的内存,系统不释放,哪怕程序退出,那一块内存还是在那里。stack一般是静态分配内存,而heap上一般是动态分配内存。也正因为它们这种特性,在.NET里,对于托管堆(managed heap)采取了通过垃圾回收器(Garbage Collection,简称GC)进行自动回收内存操作。下面是stack和heap的对比说明,可以让你更好理解它们:

l Stack:堆栈本身就具有回收特性,每当程序执行到区块的结束点时,该区块的内存就自动被释放(Last-In-First-Out,简称LIFO,后进先出),这让我们没必要担心程序里使用了多少变量,因为变量在区块外立即自动被释放,保证了一直有足够内存空间。堆栈虽好,但可惜的是并不是所有信息都可以存储在堆栈中。例如我们经常使用的string类型变量,之所以把string变量存储在Heap中,是因为字符串的长度是可变的,无法直接在堆栈中分配内存空间,因为堆栈是静态分配内存的。

l Heap:堆上的变量可以在任何地方被创建,在.NET里托管堆通过GC进行回收,至于回收方式,GC是通过标志方式进行回收的,即若有堆中的变量被标志为“待回收”,则未来GC会释放该内存空间。当然GC的回收远远不是这么简单,这里略过(有兴趣可以查看SDK文档或《深入理解.NET内存回收机制》一文)。

2、接着看下C#预定义类型:

运行时类型

C#预定义类型

描述

System.SByte

sbyte

8位有符号整数

System.Byte

byte

8位无符号整数

System.Int16

short

16位有符号整数

System.UInt16

ushort

16位无符号整数

System.Int32

int

32位有符号整数

System.UInt32

uint

32位无符号整数

System.Int64

long

64位有符号整数

System.UInt64

ulong

64位无符号整数

System.Char

char

一个16位Unicode字符

System.Single

float

单精度32位浮点数

System.Double

double

双精度64位浮点数

System.Boolean

bool

布尔值 true/false

System.Decimal

decimal

128位数据类型

System.Object

object

根类

System.String

string

Unicode字符串

在.NET里,所有类型都是对象,而且都直接或间接继承自System.Object类。因此,例如我们声明并创建一个 int 类型时,实际创建了System.Int32的一个实例。例如:

1

public int i = 999;

2

public int j;

上面第1行代码,表示声明了一个 int 类型的变量 i,并赋值999。其实际是创建了 System.Int32 的一个实例,在堆栈Stack(为什么不是在heap堆上创建呢?这个后面会讲到是因为值类型和引用类型的区别)上分配一个内存空间存储了值999。

而第2行代码,只是声明了j,而没有进行赋值操作。在C#里,跟C++等不同的是,当你仅仅进行声明变量时,所发生的事就仅仅是“声明”,而没有进行实例的创建,也就没有进行内存空间的分配。例如,你声明了如下语句:

1

System.Web.UI.Page page;

上面仅仅就是个声明而已,没有真正创建page实例,也就是说没有在内存空间里实际进行内存的分配。而你要进行创建实例,并进行内存分配,有且仅只有通过

1

System.Web.UI.Page page = new System.Web.UI.Page();

进行创建。也正因为这样,我们可以通过ILDASM看到上面声明的 j 实际是没有进行内存分配存储的。这也算是C#的一个新特征。这里额外也说了下。

下面是三个概念的理解:

l Managed Heap: 托管堆。是由CLR动态分配的连续的内存空间,在执行阶段由GC负责管理。整个进程共用一个托管堆。

l Call Stack: 这是由CLR在执行时自动管理的内存空间,每个线程都有自己的Call Stack。每调用一次方法,Call Stack就会多一次记录,调用完毕该记录随即被丢弃。

l Evaluation Stack:这是由CLR在执行时自动管理的内存空间,每个线程都有自己的Evaluation Stack。事实上,我们在CTS里常说的线程堆栈指的就是它。

Tuesday, December 12, 2006

Ref VS Out In C# (ZT)

ref是传递参数的地址,out是返回值,两者有一定的相同之处,不过也有不同点。
  使用ref前必须对变量赋值,out不用。
out的函数会清空变量,即使变量已经赋值也不行,退出函数时所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。
  区别可以参看下面的代码:

 

using System;
class TestApp
{
 static void outTest(out int x, out int y)
 {//离开这个函数前,必须对x和y赋值,否则会报错。
  //y = x;
  //上面这行会报错,因为使用了out后,x和y都清空了,需要重新赋值,即使调用函数前赋过值也不行
  x = 1;
  y = 2;
 }
 static void refTest(ref int x, ref int y)
 {
  x = 1;
  y = x;
 }
 public static void Main()
 {
  //out test
  int a,b;
  //out使用前,变量可以不赋值
  outTest(out a, out b);
  Console.WriteLine("a={0};b={1}",a,b);
  int c=11,d=22;
  outTest(out c, out d);
  Console.WriteLine("c={0};d={1}",c,d);
  //ref test
  int m,n;
  //refTest(ref m, ref n);
  //上面这行会出错,ref使用前,变量必须赋值
  int o=11,p=22;
  refTest(ref o, ref p);
  Console.WriteLine("o={0};p={1}",o,p);
 }
}

Saturday, December 02, 2006

What a Great .NET Developers Ought To Know: Answers(ZT)

Everyone who writes code

  • Describe the difference between a Thread and a Process?
    • A thread is a path of execution that run on CPU, a proccess is a collection of threads that share the same virtual memory. A process have at least one thread of execution, and a thread always run in a process context.
  • What is a Windows Service and how does its lifecycle differ from a "standard" EXE?
    • Windows service doesn't require a logged on user to activate it, (there is a bit more, but that is basicaly it).
  • What is the maximum amount of memory any single process on Windows can address? Is this different than the maximum virtual memory for the system? How would this affect a system design?
    • Hm, that is a tough question, there is the 2Gb of normal user space, 3Gb if you run windows with the right switch (which has problems of its own, apperantly) and the max virutal memory of 32bits machine is 4Gb. This affect system design when you reach big things such as databases, applications server and Enterprise "stuff" that require a lot of memory.
  • What is the difference between an EXE and a DLL?
    • An exe is an EXEutable file that contain instructions for the processor to run as well as an entry point to start execution (main() in C/C++, Public Static Void Main() in .Net). A dll is a file that contain a piece of functionality that an exe will call.
  • What is strong-typing versus weak-typing? Which is preferred? Why?
    • Strong type is checking the types of variables as soon as possible, usually at compile time. While weak typing is delaying checking the types of the system as late as possible, usually to run-time. Which is preferred depends on what you want. For scripts & quick stuff you'll usually want weak typing, because you want to write as much less (is this a correct way to use Ensligh?) code as possible. In big programs, strong typing can reduce errors at compile time. Going any further will cause Holy War, so I stop here.
  • Corillian's product is a "Component Container." Name at least 3 component containers that ship now with the Windows Server Family.
    • No idea what a componenet container is, sorry.
  • What is a PID? How is it useful when troubleshooting a system?
    • Process Identifier, usually so you can kill an offending process (at least that is how I use it) or for logging / debugging purposes.
  • How many processes can listen on a single TCP/IP port?
    • AFAIK, One. It make sense, but I'm not 100% sure. The results of more than one process listenning to the same port would be strange at best.
  • What is the GAC? What problem does it solve?
    • Global Assembly Cache. Versioning. Dll Hell, etc.

Mid-Level .NET Developer

  • Describe the difference between Interface-oriented, Object-oriented and Aspect-oriented programming.
    • That one is tough, Interface oriented would probably be (first time I hear this term) writing everything in terms of interfaces and only using the interfaces, using concentrate classes for instatition only. Object orient is the shebang of classes, polymorphism, inheritance, and the like. Very powerful, allows you to hook your objects together and just let the program run. OO is a must for Interface bases. Aspect Oriented programming is when you have code running on certain aspects of your code (method entry, method return, exception thrown, etc) most useful in logging and security.
  • Describe what an Interface is and how it’s different from a Class.
    • Interface define a contract, but no executable code. Interface is implemented by classes.
  • What is Reflection?
    • A way to explore the structure of assemblies at run-time (discover which classes/resources/methods there are).
  • What is the difference between XML Web Services using ASMX and .NET Remoting using SOAP?
    • Never done either, but XML WS is interoperatable, and .Net Remoting is extensible.
  • Are the type system represented by XmlSchema and the CLS isomorphic?
    • No.
  • Conceptually, what is the difference between early-binding and late-binding?
    • Early binding is knowing at compile time what you are calling, late binding is discovering it in run time. That is not a good explanation, but generally this mean whatever you're using a concentrate class or an interface.
  • Is using Assembly.Load a static reference or dynamic reference?
    • Dynamic reference.
  • When would using Assembly.LoadFrom or Assembly.LoadFile be appropriate?
    • When trying to load a file that is not on your private path. (Plug-ins comes to mind, or things like Reflector).
  • What is an Asssembly Qualified Name? Is it a filename? How is it different?
    • It contain the name of the assembly, its version and its public key, it's not a file name, and it's different in that it allows signing and versioning.
  • Is this valid? Assembly.Load("foo.dll");
    • No, Assembly.Load() accept assemblies names and not file names (got bitten by that a few times).
  • How is a strongly-named assembly different from one that isn’t strongly-named?
    • It's an assembly that has been signed using public/private key pair. It can be placed in the GAC, mainly. It also help is versioning and code verification (if you know the publisher Public Key, you can verify that it hasn't been tampered with.)
  • Can DateTimes be null?
    • No, and it sucks that they can't.
  • What is the JIT? What is NGEN? What are limitations and benefits of each?
    • Just In Time compilation, it allows for better compilation magic because the JIT knows a lot more about the code when it's running, long startup time. NGen is compiling ahead of time, faster startup time, but not as much info for the compiler, so it may not produce as efficent code.
  • How does the generational garbage collector in the .NET CLR manage object lifetime? What is non-deterministic finalization?
    • It divide them to three generations, the first one is short lived and is collected often (and is cheap to collect), the other two are for longer term objects. Non deterministic finalization means that your object's finalizer (destructor in C++) isn't called when it falls out of scope, its memory isn't even neccecarily released when it falls out of scope .OTOH, it may be collected when it's still in scope, if you're not using it anymore.
  • What is the difference between Finalize() and Dispose()?
    • Dispose is called by the user (hopefully via using()) and Finalize is called by the runtime.
  • How is the using() pattern useful? What is IDisposable? How does it support deterministic finalization?
    • Make it harder to forget to release resources, IDisposable is an interface that define a way to release resources in a predicted way. It means that when you're out of the using() statement, then the object's Dispose() has been called and its resources (but not memory, that is up for the GC) are free.
  • What does this useful command line do? tasklist /m "mscor*"
    • Hm... No idea. First time I see the tasklist command. Maybe list only the processes that link to mscor* ? Probably will show all the processes that uses .Net.
  • What is the difference between in-proc and out-of-proc?
    • in proc is faster, out proc require marshaling between the process. There are more, but that is the main thing.
  • What technology enables out-of-proc communication in .NET?
    • Hm, Remoting for one, Windows Messages is another, all of Win32 RPC is yet another. Named piped, memory mapped files, etc.
  • When you’re running a component within ASP.NET, what process is it running within on Windows XP? Windows 2000? Windows 2003?
    • I don't know this one, but I think it's aspnet_wp.exe in XP & 2003 (never worked with that one, sadly) and inetinfo.exe for 200.

Senior Developers/Architects

  • What’s wrong with a line like this? DateTime.Parse(myString);
    • No locale? No variable to store the returned date? Not using ParseExact? No try-catch? Hard to tell.
  • What are PDBs? Where must they be located for debugging to work?
    • No idea what the TLA is, but they are debug symbol that tells the debugger which instruction belong to which line of code.
  • What is cyclomatic complexity and why is it important?
    • Even my dictionary doesn't know what "cyclomatic" is, but I would hazzard a guess and it's probably some sort of measuring method for the complexity of software.
  • Write a standard lock() plus “double check” to create a critical section around a variable access.
    • I know this one, but I can't recall how to do this, I'll finish the rest of the questions and return to it. Okay, I returned and here is my implementation.

      if(shouldLock)
      {
      lock(lockableObj)
       {
      if(shouldLock)
        {
         DoWork();
        }
       }
      }

  • What is FullTrust? Do GAC’ed assemblies have FullTrust?
    • Your code is allowed to do anything in the framework, meaning that all (.Net) permissions are granted. The GAC has FullTrust because it's on the local HD, and that has FullTrust by default, you can change that using caspol (I always think of that as cesspool for some reason.)
  • What benefit does your code receive if you decorate it with attributes demanding specific Security permissions?
    • Early failure if you don't get it. Easily discover what are the permission that the code need, etc.
  • What does this do? gacutil /l | find /i "Corillian"
    • Didn't get to work with gacutil, but /l is probably list, so this print all the assemblies in the GAC that has Corillian (not case sensitive).
  • What does this do? sn -t foo.dll
    • Does something to the strong name of the dll, probably show you the details of it, don't recall sn's CUI in my head.
  • What ports must be open for DCOM over a firewall? What is the purpose of Port 135?
    • Port 135 is for windows RPC, a much abused service. Can't recall what ports are for DCOM, but that is easily discoverable.
  • Contrast OOP and SOA. What are tenets of each?
    • OOP - Objects is everything (inheritance, ploymorphism, interfaces, etc). SOA - Services are the main thing (discoverability, interoperability, versioning, etc. At least those are the buzzwords that I hear, don't have experiance with this).
  • How does the XmlSerializer work? What ACL permissions does a process using it require?
    • It reflect on your object and read the attributes and then output the values according to it. I'm not aware of ACL permissions you need for this (ACL being Windows), but you need ReflectionPermission in order to use it (a .Net permission).
  • Why is catch(Exception) almost always a bad idea?
    • This means that you swallow an exception and not do anything about it. There are very few cases when it's okay to do that, usually when you have an action you don't care if it failed or not, or maybe you just care that it failed, and not why (validating input integer is one such case:

      try

       i = int.Parse(str); 
       Console.WriteLine(i+ " is a number");
      }
      catch (Exception) 

       Console.WriteLine("This is not a number"); 

  • What is the difference between Debug.Write and Trace.Write? When should each be used?
    • The Debug.Write call won't be compiled when the DEBUG symbol is not defined (when doing a release build). Trace.Write calls will be compiled. Debug.Write is for information you want only in debug builds, Trace.Write is for when you want it in release build as well. And in any case, you should use something like log4net because that is both faster and better :-)
  • What is the difference between a Debug and Release build? Is there a significant speed difference? Why or why not?
    • Debug build contain debug symbols and can be debugged while release build doesn't contain debug symbols, doesn't have [Contional("DEBUG")] methods calls compiled, can't be debugged (easily, that is), less checking, etc. There should be a speed difference, because of disabling debug methods, reducing code size etc but that is not a gurantee (at least not a signifcant one)
  • Does JITting occur per-assembly or per-method? How does this affect the working set?
    • I believe that per method, but not certain. The working set should be smaller becaue methods that weren't called weren't JITed (meaning less memory taken, etc).
  • Contrast the use of an abstract base class against an interface?
    • Abstract base class can contain code, but there are some methods that are marked abstracted (no code) that an inheriting class must implement. This is a useful way to have some default action if the inheriting class isn't interested in override some method. Interface has no code, and an implementing class must implement all methods.
  • What is the difference between a.Equals(b) and a == b?
    • The first checks whatever the objects are equal, the second whatever they are reference-equal (the same object). At least that is the way it work in Java, didn't have trouble using just == everywhere in .Net, so far.
  • In the context of a comparison, what is object identity versus object equivalence?
    • Hm, that is a tough one. Object identity can mean either the same object (you've two references for the same object) or (not very often unless you are in ORM world) database identity. Basically, object identity mean that they are the same object (same place in memory or same row in the DB) and object equivalence means that they are a diferent objects but has the same value (all fields are are Equal() ).
  • How would one do a deep copy in .NET?
    • Implement IClonable? That is the way I would do it.
  • Explain current thinking around IClonable.
    • Uh... no comment is not a good answer?
  • What is boxing?
    • Taking a value type (on the stack) and putting it on the heap.
  • Is string a value type or a reference type?
    • reference type with immutable semantics (proof, you can do this: string s = null;).
  • What is the significance of the "PropertySpecified" pattern used by the XmlSerializer? What problem does it attempt to solve?
    • No idea.
  • Why are out parameters a bad idea in .NET? Are they?
    • .Net doesn't verify that an out parameter is set inside a method that uses an out parameter before an exception is called. This mean that you may use an uninitialized parameter without the compiler catching on to this. Use ref parameters instead. Personally, I think that it's a problem.
  • Can attributes be placed on specific parameters to a method? Why is this useful?
    • Yes. I think that for Remoting scenarios, but I'm not sure. I know that I saw such things, but never really paid much attention to it.
  • C# Component (HI, TP) Developers
    • Ha? Is this a question?
  • Juxtapose the use of override with new. What is shadowing?
    • Override means that using your class throught a base class will use your method, while new means your method will only be called if accessing through your class, and when using your class throught a base class the base class method will be called. I think that shadowing is the using new, but I'm not certain.
  • Explain the use of virtual, sealed, override, and abstract.
    • Virtual - a method that can be overriden in an inheriting class, and the invoked method will be the derived class one.
      Sealed - means that you can't inherit from a class, often annoying when it's on the BCL.
      Override - a marker that verify that you indeed override a method and no just create a method with the same name & parameters by mistake
      Abstract - a method that are not implemented, abstract methods are virtual, and abstract classes are explained above.
  • Explain the importance and use of each component of this string: Foo.Bar, Version=2.0.205.0, Culture=neutral, PublicKeyToken=593777ae2d274679d
    • Foo.Bar - (so you won't get Foo.Baz by mistake), Version=2.0.205.0 - The version of the assembly, that you won't get the version 2.0.0.0 (dll hell), Culute=neutral - in case you are into globalization :-), PublicKeyToekn=... - verify that this file is indeed the file you are thinking about and has not been tampered with except by the original publisher.
  • Explain the differences between public, protected, private and internal.
    • Public - anyone can use, protected - only inheriting classes can use, private - only this class can use, internal - only members in this assembly can use.
  • What benefit do you get from using a Primary Interop Assembly (PIA)?
    • IIRC, using a COM compnent?
  • By what mechanism does NUnit know what methods to test?
    • Refection & Attributes.
  • What is the difference between: catch(Exception e){throw e;} and catch(Exception e){throw;}
    • The last one preserve the exception stack, it really should've been rethrow;
  • What is the difference between typeof(foo) and myFoo.GetType()?
    • typeof(foo) is a compile time structute, and foo is a type name, myFoo is an object, and GetType() is a method that return in run-time.
  • Explain what’s happening in the first constructor: public class c{ public c(string a) : this() {;}; public c() {;} } How is this construct useful?
    • The c(string) calls to c(), this is useful if you've a basic constructor that initialize all the fields, and then you can avoid duplication of code.
  • What is this? Can this be used within a static method?
    • a reference to the current object, static methods don't have an object, so they can't use this.

ASP.NET (UI) Developers

{Note, I'm not much of ASP.NET UI developer, but I'll try it anyway}

  • Describe how a browser-based Form POST becomes a Server-Side event like Button1_OnClick.
    • Probably something in the Application that takes the POST and fire an event, the spesifics I never had to find out. 
  • What is a PostBack?
    • A way for the page to notify the asp.net application that some even occured (button clicked, etc).
  • What is ViewState? How is it encoded? Is it encrypted? Who uses ViewState?
    • A way to preserve the state of controls when doing postbacks, I think it's Base64 encoded, I don't think it's encrypted by default, though it probably can be. Nearly all web controls use it.
  • What is the <machinekey> element and what two ASP.NET technologies is it used for?
    • A public key that used for session & caching services when they are done in a cluster and no just a single server.
  • What three Session State providers are available in ASP.NET 1.1? What are the pros and cons of each?
    • in proc - fast, if the process crash then you lose state. out proc - slower, if the process crash you preserve state. Sql Server - slowest (network), you preserve state and can use the state from multiply machines.
  • What is Web Gardening? How would using it affect a design?
    • Clusters? No idea, as a matter of fact.
  • Given one ASP.NET application, how many application objects does it have on a single proc box? A dual? A dual with Web Gardening enabled? How would this affect a design?
    • Hm, no idea again.
  • Are threads reused in ASP.NET between reqeusts? Does every HttpRequest get its own thread? Should you use Thread Local storage with ASP.NET?
    • Yes, threads are reused, Request can jump between threads, and TLS wil not work, use the request context.
  • Is the [ThreadStatic] attribute useful in ASP.NET? Are there side effects? Good or bad?
    • Not really, because request may be served from multiply threads, you may get a different object from another request. Very bad.
  • Give an example of how using an HttpHandler could simplify an existing design that serves Check Images from an .aspx page.
    • No idea what the question is, what is "Check Images" ? Maybe URL Rewriting (my one use for HttpHandlers)
  • What kinds of events can an HttpModule subscribe to? What influence can they have on an implementation? What can be done without recompiling the ASP.NET Application?
    • No idea.
  • Describe ways to present an arbitrary endpoint (URL) and route requests to that endpoint to ASP.NET.
    • No idea, probably URL Rewriting and IIS redirection/virtual directories?
  • Explain how cookies work. Give an example of Cookie abuse.
    • The server tell the browser to put this file in a cookie, and the client then send all the cookies for the domain in each request. Possible abuses are big cookies which affect network traffic and speed of surfing and privacy (1x1 gifs).
  • Explain the importance of HttpRequest.ValidateInput()?
    • I'll have to learn what this is first, sorry.
  • What kind of data is passed via HTTP Headers?
    • document name, size, culture, mime type, basically the document meta data.
  • Juxtapose the HTTP verbs GET and POST. What is HEAD?
    • GET tells the server to send it a spesific page, POST also send variables (in GET they may be trasfered using query string) with the request, HEAD tell the server to send just the headers, and not the actual content.
  • Name and describe at least a half dozen HTTP Status Codes and what they express to the requesting client.
    • 200 - Ok, 404 - Document Not Found, 304 - No Update Neccecary, 500 - Server Error, 401 - Autorization Error
  • How does if-not-modified-since work? How can it be programmatically implemented with ASP.NET?
    Explain <@OutputCache%> and the usage of VaryByParam, VaryByHeader.
    • if-not-modified-since header allows the server to send 304 reponse (not modified) and not the full content of the page. You implement this by capturing the headers, checking for the presence of if-not-modified-since value, and then returning 304 status code. I believe that this is the hard way and OutputCache will do it for you if the client send if-not-modified-since. VaryByParam means that the cache hold different copies of the page for different parameters, and the same is true for different header for VaryByHeader
  • How does VaryByCustom work?
    • Probably by implementing some interface or abstract class, but I don't really know.
  • How would one implement ASP.NET HTML output caching, caching outgoing versions of pages generated via all values of q= except where q=5 (as in http://localhost/page.aspx?q=5)?
    • Use VaryByCustom, I would guess, but I don't count this as an answer as I don't know what VaryByCustom really does.

Developers using XML

(I don't like the angle bracket tax, and it shows)

  • What is the purpose of XML Namespaces?
    • To allows me and you to use the <Id> tag without grief and pain.
  • When is the DOM appropriate for use? When is it not? Are there size limitations?
    • Small documents, and you need to modify the content. Big documents need to be loaded to memory entirely, so it's wasteful. Size limitation - probably so, but the performance is more often a consideration
  • What is the WS-I Basic Profile and why is it important?
    • I'll need to get back to you with that one :-)
  • Write a small XML document that uses a default namespace and a qualified (prefixed) namespace. Include elements from both namespace.
    • I know this, but I can't recall the syntax from the top of my head, (xml:ns?).
  • What is the one fundamental difference between Elements and Attributes?
    • Element can contain another elements and attributes?
  • What is the difference between Well-Formed XML and Valid XML?
    • Valid Xml is validated against a schema/dtd/etc, Well Formed Xml obey only to the grammer of XML, and valid XML is also well formed, but the reversed is not true.
  • How would you validate XML using .NET?
    • XmlValidatingReader, most probably.
  • Why is this almost always a bad idea? When is it a good idea? myXmlDocument.SelectNodes("//mynode");
    • The mean search me and all my childrens, this can cause to bad performace as unneccecary searches are made. It's much more efficent to use the full or relative path. I can't think of a good use right now, maybe when you really do want all the mynode nodes? (For counting them, or doing some work on them, etc).
  • Describe the difference between pull-style parsers (XmlReader) and eventing-readers (Sax)
    • In XmlReader you control the parsing, you move from one place to another using methods, Sax parse the Xml in its own time, and raise events whenever it find something interesting. Personally I like XmlReader, but I've never used Sax, so I can't tell much more.
  • What is the difference between XPathDocument and XmlDocument? Describe situations where one should be used over the other.
    • XPathDocument is not editable, that is the first and most important thing. Otherwise, it allows fast XPath queries. When I want to pull data, I'll use XPathDocument, when I need to edit it, I'll use XmlDocument.
  • What is the difference between an XML "Fragment" and an XML "Document."
    • I think that Xml fragement obey all the rules of Xml, but it doesn't have <?xml?>. No certain about this one, though.
  • What does it meant to say “the canonical” form of XML?
    • Without whitespace etc, just the content, regardless of the way it was saved.
  • Why is the XML InfoSet specification different from the Xml DOM? What does the InfoSet attempt to solve?
    • No idea.
  • Contrast DTDs versus XSDs. What are their similarities and differences? Which is preferred and why?
    • DTD & XSD are both ways to spesify a format for an XML dialect. XSD is written using XML, and DTD looks like a big regex. I rather read XSD, because I don't need to make the mental shift from XML to DTD dialect.
  • Does System.Xml support DTDs? How?
    • I think that it must to offfer a complete support, but I don't know.
  • Can any XML Schema be represented as an object graph? Vice versa?
    • I belive so, but not certain. Vice versa - I don't think so.

Object Relational Mapping in ASP.NET 2.0 (ZT)

http://aspwire.com/brief.asp?12313

Introduction

The task was simple and sounded like a decent Technical challenge and an interesting opportunity.  Build an ASP.NET 2.0 with SQL Server 2005 transactional website that the financial industry can use to list special events and webinars so traders and investors can find it all in one location.  I worked with the business owner and came up with the high level requirements.  They are listed next and will look familiar to most of you.

1. Provide ability for users to register.

2. Allow registered users to list their events and webinars.

3. Allow registered users to perform CRUD actions to entered data (create, read, update, delete).

4. Provide administration interface for CRUD to all application data.

5. Display all events on the website in a format that allows sorting.

Of course, there were more requirements than what is listed above, but this is the core that we focus on moving forward in this article.

I have my own technical requirements that I bring to projects I lead, namely, that it should be as object oriented as possible and utilize the tools and technology available.  ASP.NET is object oriented itself, so extending this concept into the other layers of the application is logical and advantageous.  The second requirement is that the design should not only promote code reuse, it should provide for it.  Repetitive code and functionality is a waste and a design “smell” that I try to avoid. 

This project is the type that could easily end up with repetitive and hard to maintain code, especially in the data layer.  Let us take a look at the options for data access.  First, we could write inline SQL for all data access.  We can rule that one out easily, as it ends up being difficult to maintain and makes OOP concepts difficult to apply.  Let us not jump in the tank with that octopus.

The second option is to use stored procedures and wrap them with their own methods.  This is without a doubt the most popular way to build a data driven solution with any of the .NET languages and technologies.  If you ask any group of developers if they use stored procedures for their data access at any point in time you will see that four out of five reply with an affirmative.  Take that to the next logical step and ask why they use stored procedures; the answer is almost consistently – (a) it is faster because it is compiled and (b) that it is more secure.  I will accept (b) as a technically sound and savvy answer, but will question (a) all night long.  Without rehashing this impassioned argument, I will simple say you can get the speed of stored procedures within .NET without writing a single stored procedure.  Plus, you can get that with a better, cleaner and more object oriented manner.

OR Mappers

What is Object Relational mapping?  In a nutshell, it is a technique to provide automatic retrieval and persistence of data.  Usually this involves using a configuration file, often in XML, to map fields in your custom coded objects to fields and tables in a database.  In this way the OR Mapper can then take ownership of the best way to retrieve, update, insert and delete data and you can focus on building the application and not mess with the plumbing. 

Most professional developers use third-party components at some time and OR mapping products are an example of the acceptance and reliance on these types of components.  The reality of our work is that almost every application has to touch a database and this data access work is error prone, tedious and honestly, just plain boring after a while.  This type of work lends itself to mistakes.  I am reminded of the classic software developers axiom, “if you can reduce risk, then do so.”  This is one reason to use an OR mapper.

Another OR mapper advantage is the speed of development.  Using an OR mapper can drastically reduced the amount of code that needs to be written and debugged, plus it can quicken how you develop.  If you are mapping data directly to your objects, essentially making them entity objects, there is not data conversion between Datasets, data readers, structs or anything else.  This reduces the complexity and makes working with your data essentially the same as working with your objects.  Now your focus is on your domain model and not how ADO.NET is doing this or that task.  Please note that I am not saying that understanding ADO.NET is not important – you should understand these concepts to be a productive and knowledgeable developer – but now that you understand the core concepts you can step beyond it and really take advantage of this knowledge.

True OR mappers, which I consider different than code generators, do all their database access dynamically.  So, they are not generating files with code in them, and they are not using stored procedures.  In the .NET world, the mapper will do all its database access using parameterized queries, which as controversial as it may sound, are just as fast as stored procedures.  Thus, you now have the flexibility of dynamically generated SQL with the speed of a stored procedure.

Use of an OR mapper also provides a level of abstraction between your code libraries and the data source.  Let us say that you are using MS Access as your application data source and you are using an OR mapper.  You can now easily switch from MS Access to SQL Server 2005 without too much trouble because you do not have anything hard coded into your application that ties you to a platform.  Extrapolate this out and you can migrate from Oracle to SQL Server or Access to MySQL, or really any way you wish.

The biggest concept to understand here is that the OR Mapper is providing flexibility.  Flexibility in how you write your objects, flexibility in how you spend your development time and flexibility in what your data source is.  And of course, they are fast at the same time.

Different OR Mappers

There are many different OR mappers available.  The three products that I consider when thinking about the object relational mapping category are NHibernate, LLBL Gen Pro, RapTier and Wilson ORM.

NHibernate is the open source port of the popular OR mapper Hibernate for java.  I am not a java developer so I can not speak to how good of a port it is.  I have not used NHibernate myself, mainly because I have found the documentation of the product to be poor so far.  There is a very active community around this product, but for my project I did not want to participate in their project, I wanted to focus on building mine.  I have read and heard of success stories from colleagues along with their accompanying horror stories with NHibernate.  I do consider NHibernate to be a true mapper because it does not generate code for the developer to manage.  It does all its work dynamically once configured.

The second mapper is LLBL Gen Pro, which comes with its own environment for mapping objects with database tables and fields.  This product does generate code files, so it is not something that I wanted to use this time around.

The third product is called RapTier.  I have used this on a couple different projects earlier this millennium with success.  RapTier does create code files though, so you have to maintain those and is something I would not consider doing now.  But at the time, I experienced this product to be a great time saver because it allowed me to focus on the application and not the data access. The company also provided good support and an aggressive price. 

The last product is WilsonORMapper and is ultimately what I decided to use on this project.

Why WilsonORMapper?

[ Back To Top ]

When push came to shove the choice for this project really came down to the merits of WilsonORMapper versus NHibernate.  They are the two true, non-code generating mappers that I investigated and each had their own pluses and minuses.  I choose WilsonORMapper for a couple key reasons; starting with that Paul Wilson, the creator, provides direct support for the product and the support site includes an active user forum where other users help each other and share advice and support.  Beyond this, Wilson provides staid examples explaining how to use the different features of WilsonORMapper at a very good price.

Compared to NHibernate, these features were much more important to me during this project than the open source community behind NHibernate.  I made the conscious choice to focus on a tool that could help me build my project as opposed to contributing to the tool’s project and would have support behind it.

Domain Objects

[ Back To Top ]

Part of the elegance of using an ORM product is that you can continue to use the domain (or call them entity) objects that you might design before event deciding on using ORM.  This allows you to keep your custom objects and other steps towards a domain model and OOP principles intact while at the same time simplifying your database access.  See Figure 1 for a part of the domain model used on this project.

Figure 1

In the above figure you can see part of the domain model.  Here, we have objects describing a Listing, Feedback, Owner, Event and an interface for Event named IEventDetail. 

Configuration File

The configuration file is what ties together the database tables and fields with your objects as shown in Listing 1.

Listing 1

<?xml version="1.0" encoding="utf-8" ?>
<mappings version="4.2" defaultNamespace="">
    <entity type="Owner" table="Owner"
    keyMember="Id" keyType="Auto" sortOrder="LastName ASC" autoTrack="false">
    <attribute member="Id" field="OwnerId" alias="Id" />
    <attribute member="FirstName" field="FirstName" alias="FirstName" />
    <attribute member="LastName" field="LastName" alias="LastName" />
    <attribute member="Street" field="Street" alias="Street" />
    <attribute member="Street2" field="Street2" alias="Street2" />
    <attribute member="Number" field="Number" alias="Number" />
    <attribute member="City" field="City" alias="City" />
    <attribute member="State" field="State" alias="State" />
    <attribute member="Postal" field="Postal" alias="Postal" />
    <attribute member="Country" field="Country" alias="Country" />
    <attribute member="Company" field="Company" alias="Company" />
    <attribute member="Email" field="Email" alias="Email" />
    <attribute member="UserName" field="UserName" alias="UserName" />
    <attribute member="Salt" field="Salt" alias="Salt" />
    <attribute member="PasswordEncrypted" field="Password" alias="Password" />
    <attribute member="Role" field="Role" alias="Role" />
    <relation relationship="OneToMany" member="Listings" field="OwnerId"
    type="Listing" alias="Listings" lazyLoad="true" cascadeDelete="true" />
    <relation relationship="OneToMany" member="Events" field="OwnerId"
    type="Event" alias="Events" lazyLoad="true" cascadeDelete="false" />
  </entity>

The configuration file is in XML, so the hierarchy of data is simple to read and just as easy to understand after you use it for a short while.  The entire file is wrapped in the mappings element and each table-to-object relationship is defined in an entity element.  The Listing 1 example above ties the object Owner to the table Owner.  It sets the object key, Id, to the tables' primary key via the keymember attribute.  It then sets the default sort order and a attribute named autoTrack which lets the ORM framework know whether or not to watch this object and perform SQL changes on its own.

Each property of the object is then mapped to a database field via an attribute element and member attribute. 

Notice the element relation.  This provides foreign key relationships to other tables.  In this example the field OwnerId in the table Owner is linked to the table Listing with a synonymous field name.  From here we can set the Listing object to be lazy loaded inside of the Owner object.  So, to summarize this, each object is mapped to a table in the configuration file.  Furthermore, a related object can be lazy loaded as a property in another object via foreign key relations.

ObjectSpace Manager

The ObjectSpace object is part of the WilsonORMapper libraries and is the main coordinator that is used by the developer to access data through the framework.  It is best to only have one instance of the ObjectSpace object in an application.  Doing so will help manage concurrency in the application between the data source and the mapper and secondary; the object loads up the xml configuration file from disk.  So, obviously you do not want to repeatedly read from disk or recreate the object over and over.  See Listing 2 for an example of how to create the object, in our case and by example from Wilson, the object is static and named Manager.

Listing 2

public class Global
{
    private static ObjectSpace _Manager;
    public static ObjectSpace Manager
    {
        get
        {
            if (_Manager == null)
            {
                CreateORMapper();
            }
            return _Manager;
        }
    }
 
    private static void CreateORMapper()
    {
string mappingFile =    System.Web.HttpContext.Current.Server.MapPath("~/trader.config");
      _Manager = new ObjectSpace(mappingFile, ConnectString, Provider.Sql2005);
    }
}

Select

Let us take a look at a method that retrieves data from our source by doing a simple SELECT in Listing 3 below.

Listing 3

public Event GetEvent(int Id)
{
   return (Event)Global.Manager.GetObject(typeof(Event), Id);
}

This method simply returns a filled Event object via the Id passed into the method.  We use the GetObject method on the Manager object, which is of type ObjectSpace, and tell it the type of object to return.  The mapper then knows what table the object type is mapped to and does the translation for us. The GetObject method can also then take in the parameter here, which is simply doing a query via the primary key setup in the configuration file.

Notice here how everything is strongly typed.  The code does not have to know anything about ADO.NET or even the internals of the Event object.  The mapping loads the right result set fields into the created Event object properties and fields. 

On a side note, it is a matter of preference if you map your table fields to properties of the object or fields.  The more draconian OOP bylaws would say that if you’re setting data in an object it should be via properties. But here, the mapper can access everything inside of the object anyway – so, it is a matter of preference.

Returning one object is simple, but the world works in large numbers, so let us look at returning a collection of objects. See Listing 4 below.

Listing 4

public IList GetEvents(string sortOrder)
{
    ObjectQuery oq = new ObjectQuery(typeof(Event), "", sortOrder);
    ObjectSet allEvents = Global.Manager.GetObjectSet(oq);
    return allEvents;
}

The GetObjects method of the Manager object returns a collection object called an ObjectSet, which is part of the WilsonORMapper libraries.  Being a well behaved collection it implements the IList interface.  So our GetEvents above can be typed to IList to add some flexibility. 

Insert, Update and Delete

Doing the other parts of the CRUD cycle (create, update and delete) are very similar.  Listing 5 below shows an insert and Listing 6 shows an update.  These are all working against that same Event type.

 Listing 5

public void Insert(Event theEvent)
{
Global.Manager.StartTracking(theEvent, Wilson.ORMapper.InitialState.Inserted);
Global.Manager.PersistChanges(theEvent, Wilson.ORMapper.PersistDepth.ObjectGraph);
Global.Manager.EndTracking(theEvent);
}

Listing 6

public void Update(Event theEvent)
{
Global.Manager.StartTracking(theEvent, Wilson.ORMapper.InitialState.Updated);
Global.Manager.PersistChanges(theEvent, Wilson.ORMapper.PersistDepth.ObjectGraph);
Global.Manager.EndTracking(theEvent);
}

The basics of this operation are that the methods first call a WilsonORMApper method called StartTracking on the Manager object and then does the persistence.  StartTracking lets the mapper know that this object and its associated row in the database are going to have work done to it.  I am not sure if WilsonORMapper locks the row then or not, but it does add safety to the operation.  Part of StartTracking is telling the mapper if we will be inserting and updating data.  Then we call the PersistChanges method and lastly end our tracking of that object and database row. 

Performing a delete is very similar and can be seen in Listing 7.

Listing 7

public void Delete(Event theEvent)
{
Global.Manager.StartTracking(theEvent, Wilson.ORMapper.InitialState.Unchanged);
Global.Manager.MarkForDeletion(theEvent);
Global.Manager.PersistChanges(theEvent, Wilson.ORMapper.PersistDepth.ObjectGraph);
Global.Manager.EndTracking(theEvent);
}

The only addition with the delete is we call MarkForDeletion which is another trigger letting the mapper know what we are about to do to that object and its data.

Lazy Loading

[ Back To Top ]

An aspect of object oriented programming that is simpler to do with an object relational mapper is lazy loading one object type from within another.  For example, if we want to load up the Owner object of an Event object, for instance, the company hosting the event, we can write our lazy load property in the Event object and then simply create an Owner object with the owner id key returned from our Event object load.  In this way your object model can grow and objects maintain a high level of encapsulation.

Conclusion

[ Back To Top ]

An object relational mapper is a powerful tool to use and can save days - and possibly weeks depending on the size of the project - of tedious coding and debugging.  Within a short time you can get up and running and use the object model that you created for the project without having to rework a lot to run stored procedures or other ADO.NET queries.  In the end you can focus on the core business logic part of the application and consider the mapper and your data layer as plumbing that came with the house.  WilsonORMapper simply makes this much easier with better support than other free or complicated OR mapping solutions out there.