Fixing the Shared Type Schema Importer Extension for nullable value types

When you add a Web Reference to your project, Visual Studio will also import all schema types defined in the WSDL’s schema section. You can create a schema importer extension (SIE) to influence the way the XSD schema types are mapped to your CLR types. There is a very nice article by Jelle Druyts on a SIE that shows how you can create a extension that will map based on an XML configuration section in your devenv.exe.config file. Go read that one first, then read on.

<?xml version=1.0 encoding=utf-8 ?>

<schemaImporterExtensions>

  <sharedTypeMappings>

    <mapping xmlNamespace=http://schemas.samplebusiness.net/SharedTypes

            xmlTypeName=Customer

            clrAssemblyPath=C:SampleSampleBusinessTypes.dll

            clrClassName=SampleBusinessTypes.Customer />

  </sharedTypeMappings>

</schemaImporterExtensions>

It a reasonably straightforward process of looking up the imported XML element name and namespace in the mapping elements and adding returning the mapped CLR class name instead of the 1–1 mapping that would normally occur. We are using this schema importer extension on a project, but project-colleague Frans Harinck found that it did not map nullable enums correctly. So I ventured out to fix this.

The problem is that nullable value types on the web service will now have a xsd:nillable=”true” attribute set in the WSDL schema. This was always true for reference types, which (of course) can have a null value. Value types couldn’t until .NET 2.0. The SIE from Jelle did not take this into account (although SIE was introduced in Visual Studio 2005). When you debug the SIE (side note: Set the build path directly into the folder C:Program FilesMicrosoft Visual Studio 8Common7IDEPrivateAssemblies and attach the debugger to another VS2005 instance. In the attached instance Add or Update a Web Reference and your breakpoints should be hit), you will see how the name and namespace of your nullable value type pass by. These are mapped to your own CLR type, but not as nullable. You can determine whether your type is marked xsd:nillable=”true” by evaluating the XmlSchemaObject object supplied. This indicates that the corresponding schema element is nillable, and that it is a simpleType. The combination tells you the type is nullable. So instead of returning the mapped CLR name, it should return System.Nullable<CLR name>.

Below is the bolded change you need to make to the source code from the article, i.e. the SharedTypeSchemaImporterExtension.cs file to be exact.

public override string ImportSchemaType(string name, string ns,

  XmlSchemaObject context, XmlSchemas schemas,

  XmlSchemaImporter importer, CodeCompileUnit compileUnit,

  CodeNamespace mainNamespace, CodeGenerationOptions options,

  CodeDomProvider codeProvider)

{

  try

  {

    foreach (SharedTypeMappingElement mapping in

      SchemaImporterExtensionsConfiguration.Instance.SharedTypeMappings)

    {

      // Check if the namespace and type name match.

      if (mapping.Matches(ns, name))

      {

        // Add an assembly reference.

        if (!string.IsNullOrEmpty(mapping.ClrAssemblyPath))

        {

          compileUnit.ReferencedAssemblies.Add(mapping.ClrAssemblyPath);

        }

 

        // Indicate that no XML schema type should be imported but that a

        // well-known shared CLR type will be used.

 

       // Valuetypes can be nullable in .NET 2.0

       XmlSchemaElement schemaElement = context as XmlSchemaElement;

       if (schemaElement != null && schemaElement.IsNillable &&

           schemaElement.ElementSchemaType is XmlSchemaSimpleType)

       {

         return String.Format(“System.Nullable<{0}>”, mapping.ClrClassName);

       }

 

        return mapping.ClrClassName;

      }

    }

  }

  catch (Exception exc)

  {

    System.Windows.Forms.MessageBox.Show(exc.Message + Environment.NewLine +

      exc.StackTrace, “SharedTypeSchemaImporterExtension Exception”,

      System.Windows.Forms.MessageBoxButtons.OK,

      System.Windows.Forms.MessageBoxIcon.Error);

  }

 

  // No match, delegate to the base class.

  return base.ImportSchemaType(name, ns, context, schemas, importer,

    compileUnit, mainNamespace, options, codeProvider);

}

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s