Category Archives: .NET

XmlSerializer: Changes from .NET4 to 4.5

As I wrote in one of my last post (XmlSerializer bug in .NET4.5 and legacy serializer) was the XmlSerializer completely redesignd and rewritten in .NET 4.5. This leads to several problems (see my last post).

Also it leads to problems if you use a newer development environmen as you have supported environments in the field. Especially if your application must support .NET4 and you use for development a later VS version (>2010). In this case you might use indirectly Features, which are not available in a pure .NET4 environment. One of the feature affects serialization of “lists”.

Here is a small example, which works perfectly in .NET4.5 and later, but fails with .NET4:

using System.Collections.Generic;
using System.Xml.Serialization;
namespace ConsoleApplication
{
    public class Program
    {
        public Program() { Persons = new List<Person>(); }
        static void Main()
        {
            var ser = new XmlSerializer(typeof(Program));
            var r = new System.IO.StringReader("<Program><Persons><Person><Name>TEST</Name></Person></Persons></Program>");
            ser.Deserialize(r);
        }
        public List<Person> Persons { get; private set; }
    }
    public class Person
    {
        public string Name { get; set; }
    }
}

Starting this with a computer having only .NET4 will lead to the following error message during generation of the XmlSerializer:

Unbehandelte Ausnahme: System.InvalidOperationException: TemporΓ€re Klasse kann nicht generiert werden (result=1).
error CS0200: Property or indexer 'ConsoleApplication.Program.Persons' cannot be assigned to -- it is read only
error CS0200: Property or indexer 'ConsoleApplication.Program.Persons' cannot be assigned to -- it is read only

   bei System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
   bei System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
   bei System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
   bei System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
   bei System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   bei ConsoleApplication.Program.Main() in ...\ConsoleApplication6\Program.cs:Line 12.

So what is the problem here in .NET4?

It seems that if there is a setter available (regardless of private or public), the serializer will try to use it… you can even test it with a newer .NET Version, by using the “legacy XmlSerializer” in your “app.config”:

<configuration>
  <appSettings> 
    <add key="System:Xml:Serialization:UseLegacySerializerGeneration" value="true" />
  </appSettings>
</configuration>

Solution: Just remove the setter from the property “Persons” and it works in .NET4 and .NET4.5 and later:

using System.Collections.Generic;
using System.Globalization;
using System.Xml.Serialization;
namespace ConsoleApplication
{
    public class Program
    {
        public Program() { Persons = new List<Person>(); }
        static void Main()
        {
            var ser = new XmlSerializer(typeof(Program));
            var r = new System.IO.StringReader("<Program><Persons><Person><Name>TEST</Name></Person></Persons></Program>");
            ser.Deserialize(r);
        }
        public List<Person> Persons { get; }
    }
    public class Person
    {
        public string Name { get; set; }
    }
}

XmlSerializer bug in .NET4.5 and legacy serializer

Starting with .NET4.5 (which is an in-place update of .NET4) Microsoft created a completely new XmlSerializer. And as a developer you know, that it is almost impossible to re-write a software and match the whole features of the original software.
But Microsoft was sure, that the new implementation is not only faster, but will also replace the old XmlSerializer for almost all cases… that was the reason why Microsoft are using the new implementation by default. This is even true, if you only have shipped your app with .NET4 and a different program installs the .NET4.5 update on the computer… then your old programm will also use the new XmlSerializer…

And my (simple) program fails in that case! If I want to serialize an object, if throws and System.InvalidProgramException exception ;(

using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApplication1
{
  public class Program
  {
    static void Main()
    {
      new XmlSerializer(typeof (Program)).Serialize(new StringWriter(), new Program());
    }

    [DefaultValue(0.0)]
    public decimal Value;
  }
}

What is now the problem? For me it seems very normal… The problem is, that I used a “DefaultValue”, which is a “double” and a field which is a “decimal”. With the old XmlSerializer this was no problem… internally the conversion was done correctly. But it seems that the new one, now tries to assign the double to the decimal and fails

Now there are two possibilities to solve this problem:

  1. Replace “0.0” with “0” which leads to an interger (int) and this can be assigned to a decimal
  2. Enable the old bahavior again πŸ˜‰

Microsoft also knew about the impossibility to replace an old component with a new one, which exactly the same behavior πŸ˜‰ Therefor you can enable the old XmlSerializer via app.config:

<configuration>
  <system.xml.serialization>
    <xmlSerializer useLegacySerializerGeneration="true"/>
  </system.xml.serialization>
</configuration>

But there is a big warning in the knowledgebase article: “We do not recommend that you apply this workaround on a computer that is running a version of the .Net framework that is earlier than the .Net framework 4.5.”

So if you want to ship your application with the old behavior and you are not sure that .NET4.5 is installed, then you should use the following app.config entry, which works in .NET4 and 4.5 πŸ˜‰

<configuration>
  <appSettings> 
    <add key="System:Xml:Serialization:UseLegacySerializerGeneration" value="true" />
  </appSettings>
</configuration>

Of course, I have choosen the first optional and have replaced “DefaultValue(0.0)” with “DefaultValue(0)”. Lukily, we had no decimal places πŸ˜‰

Why NOT to use a “TFS local workspace”

If you use VS2013 (with TFS2013) your VS suggest to use a local TFS Workspace.

At the first view, this seems to be a good idea… but after a depper look there seems to be a bad implementation, at least in this Version.

The main disadvantages are:

  • If you want to use multiple VS2013 instances at the same time (This is a show-stopper for me); quote from Microsoft: “it is more likely to cause problems if you are using a local workspace” (by the way: It is also not supported with a server-workspace; but I never have seen any problems)
  • If you want to use VS2010 within the same workspace
  • If you want to see, which team member has checked-out a file (this is not possible for local workspaces, because there is no “check-out”)
  • If you want to enforce “check-out lock”; especially in small teams, this is a good idea, to prevent merges.
  • If you want to use “Enabled get latest on check-out” (because there is no check-out…)
  • If your workspace contains many files (or Versions of files), then it uses a hughe amount of space to use the local workspace (ok, this is by design and cannot be changed; the same is true for git). Microsoft recommends a local workspace only for less than “100,000 items” (means files and versions).

For more info see also: Decide between using a local or a server workspace

ANN: Community Forums NNTP Bridge

After looking deeper into the MSDN Forums Client and into an C# NNTP server, I decided to integrate both Ms-PL projects into a single project:

Community Forums NNTP bridge

The result is a single “Community Forums NNTP Bridge” which can replace the MS NNTP Bridge. It also integrates both web services (*social*, *answers*) into a single NNTP server; so the “feeling” is like before the split πŸ˜‰

If you are interested, you can take a look (with full source code) into the alternative:
http://communitybridge.codeplex.com/

Better sos.dll for debugging in WinDbg available!

Finally MS release a *better* sos.dll extension for WinDbg (psscor2.dll), which has many more features. One of my favorite feature is “displaying callstacks with line infos”!

Also it has a good “!Analysis” command for dump-files.

The output of “!Help” is:

-------------------------------------------------------------------------------
PSSCOR is a debugger extension DLL designed to aid in the debugging of managed
programs. Functions are listed by category, then roughly in order of
importance. Shortcut names for popular functions are listed in parenthesis.
Type "!help " for detailed info on that function. 

Object Inspection                  Examining code and stacks
-----------------------------      -----------------------------
DumpObj (do)                       Threads
DumpArray (da)                     CLRStack
DumpStackObjects (dso)             IP2MD
DumpAllExceptions (dae)            BPMD
DumpHeap                           U
DumpVC                             DumpStack
GCRoot                             EEStack
ObjSize                            GCInfo
FinalizeQueue                      EHInfo
PrintException (pe)                COMState
TraverseHeap
DumpField (df)
DumpDynamicAssemblies (dda)
GCRef
DumpColumnNames (dcn)
DumpRequestQueues
DumpUMService

Examining CLR data structures      Diagnostic Utilities
-----------------------------      -----------------------------
DumpDomain                         VerifyHeap
EEHeap                             DumpLog
Name2EE                            FindAppDomain
SyncBlk                            SaveModule
DumpThreadConfig (dtc)             SaveAllModules (sam)
DumpMT                             GCHandles
DumpClass                          GCHandleLeaks
DumpMD                             VMMap
Token2EE                           VMStat
EEVersion                          ProcInfo 
DumpModule                         StopOnException (soe)
ThreadPool                         MinidumpMode 
DumpHttpRuntime                    FindDebugTrue
DumpIL                             FindDebugModules
PrintDateTime                      Analysis
DumpDataTables                     CLRUsage
DumpAssembly                       CheckCurrentException (cce)
RCWCleanupList                     CurrentExceptionName (cen)
PrintIPAddress                     VerifyObj
DumpHttpContext                    HeapStat
ASPXPages                          GCWhere
DumpASPNETCache (dac)              ListNearObj (lno)
DumpSig
DumpMethodSig                      Other
DumpRuntimeTypes                   -----------------------------
ConvertVTDateToDate (cvtdd)        FAQ
ConvertTicksToDate (ctd)
DumpRequestTable
DumpHistoryTable
DumpBuckets
GetWorkItems
DumpXmlDocument (dxd)
DumpCollection (dc)

Examining the GC history
-----------------------------
HistInit
HistStats
HistRoot
HistObj
HistObjFind
HistClear

Major bug in the new dbghelp.dll

The latest dbghelp.dll (version 6.12.2.633), which can be downloaded via the newest WDK, seems to have a major bug regarding the function SymGetModuleInfo64 (which is used in almost every project, if you want to display module-infos).

A user reported this bug in the WinDbg newsgroup.

I now build a small repro-code, which shows the problem. You can download the code here: dbghelp_bug_6.12.2.633.zip

The problem is, that the size of the struct “IMAGEHLP_MODULE64” has changed. They added two DWORDs at the end (the struct has now a size of 0x690 bytes). This is normally not a problem because the struct has a “SizeOfStruct” member, which must be set, prior to calling the “SymGetModuleInfo64” function.

But the new version does not support the older version of the struct with a size of 0x688 bytes, which is commonly used because this was the last version since 2003!!! It only supports the older versions from 2002 and before.

So I hope that this major bug will soon get fixed… but after the WinDbg-Release seems to be coupled to the WDK-release, we can wait until next year…

Forums NntpBridge and DateTime

There is a “research” project to access the msdn-web forums via a nntp-bridge. The offical version is “V1″… but I must say, that it is still Beta1 πŸ˜‰

For example, there is a bug with the DateTime-Format, which uses the current system locale… This bug was reported severaly months ago, and nothing happend… In january and february it was not a problem, because “Jan” and “Feb” are the same in english and german… but in “MΓ€rz” the NntpBridge started to report all postings with “01.01.1970 01:00″… because it will report the date as “Mrz” instead of “Mar”… which is somehow bad…

So I decided to make a quick fix for this behavior. You just need to add the System.Globalization.CultureInfo.InvariantCulture as parameter to the ToString method.

Here are the steps, how you can fix this by yourself:

  1. Locale the directory of the Nntp-Bridge (normally “C:\Program Files (x86)\Microsoft Community Tools\Microsoft Forums NNTP Bridge”
  2. Copy the file “nntp.dll” to “nntp_org.dll” so you have the original version saved
  3. Copy “nntp.dll” into a temporary directory like “c:\temp\nntp_fix”
  4. Open a “Visual Studio 2005/2008 Command Prompt (x86)”
  5. Go to the temporary directory (cd /D c:\temp\nntp_fix)
  6. Disassemble the nntp.dll
    ildasm nntp.dll /out=nntp.il
  7. Now you need to change the content of the nntp.il file
  8. Find the method “GetMessageFormat” and change it from
    .method public hidebysig static string  GetMessageFormat(valuetype [mscorlib]System.DateTime dateTime) cil managed
    {
      // Code size       28 (0x1c)
      .maxstack  8
      IL_0000:  ldstr      "{0} {1}"
      IL_0005:  ldarga.s   dateTime
      IL_0007:  ldstr      "ddd, d MMM yyyy HH:mm:ss"
      IL_000c:  call       instance string [mscorlib]System.DateTime::ToString(string)
      IL_0011:  ldsfld     string Nntp.NntpTimeUtility::GmtTimeZoneOffset
      IL_0016:  call       string [mscorlib]System.String::Format(string,
                                                                  object,
                                                                  object)
      IL_001b:  ret
    } // end of method NntpTimeUtility::GetMessageFormat
    

    to

    .method public hidebysig static string  GetMessageFormat(valuetype [mscorlib]System.DateTime dateTime) cil managed
    {
      // Code size       33 (0x21)
      .maxstack  8
      IL_0000:  ldstr      "{0} {1}"
      IL_0005:  ldarga.s   dateTime
      IL_0007:  ldstr      "ddd, d MMM yyyy HH:mm:ss"
      IL_000c:  call       class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
      IL_0011:  call       instance string [mscorlib]System.DateTime::ToString(string,
                                                                               class [mscorlib]System.IFormatProvider)
      IL_0016:  ldsfld     string Nntp.NntpTimeUtility::GmtTimeZoneOffset
      IL_001b:  call       string [mscorlib]System.String::Format(string,
                                                                  object,
                                                                  object)
      IL_0020:  ret
    } // end of method NntpTimeUtility::GetMessageFormat
    
  9. Then compile the nntp.dll again (and delete the original dll before compiling (del nntp.dll)):
    ilasm /dll nntp.il /resource=nntp.res
  10. Now you can copy the patched nntp.dll into the original directory (be sure, the application is not running).

Now it looks better:

That’s all! Happy NntpBridging πŸ˜‰

The mystic variable “$I” during for each

A poster in the german C/C++ forum asked if there is an index available while using a for each loop. He accidently saw in the debug-window a variable called “$I”.
And indeed: There is a “hidden” variable “$I” which can be used inside the for each loop. This variable is the number of the loop-iteration.

Here is a simple example:

int main()
{
  array<int> ^MyArray = { 100, 200, 300, 400 };
  for each( int v in MyArray )
  {
    System::Console::WriteLine(v.ToString() + " " + $I);
  }
  return 0;
}

As you can see, it uses a variable “$I” which was never decalred!
And it will output the following:

100 0
200 1
300 2
400 3

If you debug a normal for each loop and take a look in the “local-watch-window”, you will see the following variables, while you are inside the for each loop:

You can see two “hidden” variables “$I” and “$S1”. And if you step through the loop, you will see that the “$I” variable is incremented for each iteration. “$S1” is a reference to the array.

If you dig further into this issue, you will find out, that for each and the normal “for” loop will result in the identical IL code! This is also true for C#!
See also:
FOREACH Vs. FOR (C#)
To foreach or not to foreach that is the question.

As we can see, the “$I” variable is just a side-effect of the for each loop. It is a compiler generated variable which is used to transform the “for each” into a normal for-loop!

Of course, this is only true in special cases like arrays.
If you have a list which only implements the “IEnumerable” interface and is not an array (like “System::Collections::Generic::List”), then the mistic variable “$I” is gone, because now the compiler uses the “IEnumerable” interface to gbuild a “real” “for each” loop:

In this case “$I” is gone but “$S1” is still there. And “S1” is the enumerator of the list (in this case

System::Collections::Generic::List::Enumerator<int>

).

The conclusion is:
Do not rely on the compiler generated variable “$I”, and do not use “for each” if you need a index-variable, just use a normal for loop.

TFS: Automatically insert Check-In comments into source-code

TFS is in most cases very wonderfull. But if you have projects, which will also be used “outside” of the TFS environment (for example in an other subsidary without TFS access), then it has one disadvantage:
The comments for every check-in is only stored in the TFS version history.

While this is enough, if you always have access to the TFS. But if you work without TFS, then it would be helpfull if these comments are also included in the source-file (like in the old days, when we were using cvs (a feature called keyword-substitution)

I searched the web for any plugin for TFS which has almost the same features… but could not find any plugin….

So I wrote my own plugin, which at least puts the check-in comments into the source-file.
You just need to install this plugin and activate it in the “Check-In policy”.

Then your source-file will contai the comment, after you checked it in:

/*
 * $log$
 * 
 * Comment: And another test
 *          with a multiline
 *          comment...
 * User: xyz
 * DateTime: 2009-07-23 22:05:24
 * Change: edit
 * 
 * Comment: This is an test
 * User: xyz
 * DateTime: 2009-07-23 21:01:22
 * Change: add, edit
 *
 */

I can also customize (like templates) the position and contents of the comments…

If you are interested in this plugin-in, please let me know…

Just a small addition: Here is a post about “keyword expansion” and TFS; and possible side-effects:
http://blogs.msdn.com/buckh/archive/2007/07/07/keyword-expansion-in-tfs.aspx

EDIT: 2009-08-08:
Today I published my first release of the LogSubstPol on CodePlex.

C++/CLI quiz: Answer

In one of my last post, I asked the question, how does the callstack look like.
It was is simple unmanaged class with a virtual function. If you had executed the sample program, and set a breakpoint into the “Foo” method, you can see in the callstack-window of VS, the following callstack:
Callstack of (native) virtual function in managed code

As you can see, there are two transitions which we had not expected. One transition to native code, and one transition back to managed code.

And if you put a “printf” statement into the copy-constructor of the V-struct, you will see that the copy-constructor is called tiwce! This can have very strong performance effects…

So what might be the course of this “unnecessary” transitions?

The problem is: We have written an unmanaged virtual function as a managed function (the whole file is compiled with /clr). This means, that all unmanaged virtual functions will have two entry points. One entry point is for the “native” v-table call (thiscall); and the other is for the managed entry (clrcall).

If you call a unmanaged virtual function in a managed world, the compiler does not know which function must be callled. This is only examined at runtime through the v-table. Therefor the compiler needs to call the native function which uses the v-table. Then this “proxy”-function is calling the managed entry point. And because there are two functiions involved, the copy-constructor the the V-struct is called twice.

Conclusion:
Be aware that virtual functions in unmanaged classes which are compiled with /clr might lead to performance decrease.
If you have a big codebase, you should only enable /clr for specific files which implements the “wrapper”.
Be aware that every managed/unmanaged transition has additional execution-costs on your application. So prevent this transitions as much as possible.

C++/CLI quiz: What is the exact callstack?

I have a small quiz:
Here is a small code, compiled with “/clr” (this is important).
Can you tell me, what is the exact callstack inside the method “Foo”?
(And how can you prove this)

struct V
{
  V() {}
  V(const V &v) 
  {
    this->i = v.i;
  }
  int i;
};

class C
{
public:
  void CallFoo()
  {
    V v;
    Foo(v);
  }
  virtual void Foo(V v)
  {
    // TODO: What is the callstack!?
  }
};

int main()
{
  C c;
  c.CallFoo();
}

Any hints can be posted as comments.
By the way: VS208 does not show you the exact callstack, but it gives you a hint, that there is something that you do not see πŸ˜‰

WebService in native Code (WS-*)

After the support for the SOAP-Toolkit was retired, there was no library from Microsoft, to write or consume Web-Services in native code. The suggested solution was to move to the .NET-SOAP classes. Of course, this is not always a solution, for big native code-bases.

It seems that MS has reflected this situation and also has found, that it is a “must have” to have a native WS-* library.

Starting with Windows 7 and Windoes Server 2008 R2, the OSwill have build-in support for native Web-Services.

The APIis called WWS-API (Windows Web Service API). To get an overview and also some examples, you can take a look at the code.msdn-Site.

Also, if you have an existing application and want to move to WWSAPI, you can join a virtual lab, to get help in implementing your web-service (either consuming or exposing).

EDIT:
Nikola added an comment, that WWSAPI will be also available on XP-SP2 and later! These are really great news!
You can already download the beta-bits, see:
Release of WWSAPI beta for Windows XP, Vista, Server 2003 and Server 2008