Monday, June 18, 2012

Prefer XmlSerializer When Using svcutil To Generate Client Code From WSDL

I have a WSDL from a web service server which includes the following in its types:

<xs:element minOccurs="0" name="countryID" type="xs:int"/>

This is supposed to represent an optional int element named countryID.  When I run svcutil.exe (from C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin) against it, I get the following generated code:
        [System.Runtime.Serialization.DataMemberAttribute()]
public int countryID
{
    get
    {
        return this.countryIDField;
    }
    set
    {
        this.countryIDField = value;
    }
}

The "IsRequired=true" property is not set on the DataMemberAttribute.  But there's no way to indicate that I want a given instance to be absent!  Some googling revealed that I could modify the generated code (which I hate doing) to use "DataMemberAttribute(EmitDefaultValue=false)" (see http://msdn.microsoft.com/en-us/library/aa347792.aspx?ppud=4).  But if I do this, I cannot use a countryID value of zero, as this will be interpreted as the default value, and no countryID element will be generated!

The solution: add the "/serializer:XmlSerializer" command line option, which causes the following to be generated:


    [System.Xml.Serialization.XmlElementAttribute(Order=0)]
    public int countryID
    {
        get
        {
            return this.countryIDField;
        }
        set
        {
            this.countryIDField = value;
        }
    }
   
    ///
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool countryIDSpecified
    {
        get
        {
            return this.countryIDFieldSpecified;
        }
        set
        {
            this.countryIDFieldSpecified = value;
        }
    }


With this construct, as I described in my earlier post about optional attributes, setting countryIDFieldSpecified to "false" will not emit the countryID element.

Friday, June 8, 2012

Uncaught Exception From Delegate Passed To Task.Factory.StartNew() Causes Windows Service To Crash

We have a Windows service written in C# against the .NET 4.0 framework, and it began crashing with the following two items written into the Application event log each time:
EventType clr20r3, P1 x.exe, P2 1.8.1.0, P3 4fd0f5c1, P4 system, P5 4.0.0.0, P6 4ba1dff4, P7 2e49, P8 12d, P9 system.aggregateexception, P10 NIL.
Application: x.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AggregateException
Stack:
   at System.Threading.Tasks.TaskExceptionHolder.Finalize()
Some googling around yielded the following helpful information:


in which it mentions a case in which an error gets thrown within that Finalize() call.

I ended up finding a library our application referenced in which the author called Task.Factory.StartNew(), passing in a delegate which had a catch block which could itself throw an exception--which would end up being considered unhandled in that Finalize() call, and crash the process during garbage collection at some point after the exception occurred.

We're in the process of having that library corrected.

Note that Parallel.ForEach() shouldn't have this problem, because it says that all its tasks' exceptions will be bundled up into an AggregateException and returned to the caller.

Thursday, April 5, 2012

Dropping All Tables In A SQL Server Database

While doing database logical model design, I found it convenient to create a SQL script I could repeatedly execute to ensure that my design was feasible in a real database.  But since my script was essentially a good number of CREATE TABLE statements, I needed to delete all the tables from my previous run.

Internet to the rescue:


which indicates that you can use the very handy command:

EXEC sp_MSforeachtable @command1 = "DROP TABLE ?"

to execute a DROP TABLE on each user table in the database.  If you have relational integrity constraints between tables, you may need to execute this command more than once until all the referencing tables have been deleted, at which point you can execute it again to drop the (previously) referenced tables.

BE WARNED: this will DROP ALL TABLES.  You may not want to do this.  You should not do it anywhere except in a scratch database (for example, one in which you're doing logical data model design).