NullReferenceException when setting an element

Aug 25, 2011 at 4:01 PM

Getting a NullReferenceException when trying to set a property on a Linq2Xsd class.

Here's my code:

            var input = new ProcessEventsFormInput() { EventsForm = output.EventsForm};
            input.UserContext = new UserContext() { UserID = 6 };
Here's the generated code

 

        public UserContext UserContext {
            get {
                XElement x = this.GetElement(XName.Get("UserContext", "XXXX"));
                return ((UserContext)(x));
            }
            set {
                this.SetElement(XName.Get("UserContext", "XXXX"), value); <-- Fails here
            }
        }

 

Here's the stack trace:

 

 	Xml.Schema.Linq.dll!Xml.Schema.Linq.SchemaAwareContentModelEntity.FindElementPosition(Xml.Schema.Linq.NamedContentModelEntity namedEntity = {Xml.Schema.Linq.NamedContentModelEntity}, System.Xml.Linq.XElement parentElement, bool addToExisting = false, out Xml.Schema.Linq.EditAction editAction = None) Line 153 + 0x43 bytes	C#
 	Xml.Schema.Linq.dll!Xml.Schema.Linq.SchemaAwareContentModelEntity.AddElementInPosition(System.Xml.Linq.XName name = {{XXXX}UserContext}, System.Xml.Linq.XElement parentElement, bool addToExisting = false, Xml.Schema.Linq.XTypedElement xObj = {
  6
}) Line 235 + 0x2d bytes	C#
 	Xml.Schema.Linq.dll!Xml.Schema.Linq.SchemaAwareContentModelEntity.AddElementToParent(System.Xml.Linq.XName name = {{XXXX}UserContext}, object value = {
  6
}, System.Xml.Linq.XElement parentElement, bool addToExisting = false, System.Xml.Schema.XmlSchemaDatatype datatype = null) Line 262 + 0x63 bytes	C#
 	Xml.Schema.Linq.dll!Xml.Schema.Linq.XTypedElement.SetElement(System.Xml.Linq.XName name = {{XXXX}UserContext}, object value = {
  6
}, bool addToExisting = false, System.Xml.Schema.XmlSchemaDatatype datatype = null) Line 205 + 0x3f bytes	C#
 	Xml.Schema.Linq.dll!Xml.Schema.Linq.XTypedElement.SetElement(System.Xml.Linq.XName name = {{XXXX}UserContext}, Xml.Schema.Linq.XTypedElement typedElement = {
  6
}) Line 154 + 0x20 bytes	C#

Here's the Schemas:

<xs:schema xmlns="XXXXX " xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="XXXXX " elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xs:include schemaLocation="WS2Types.xsd"/>
	<xs:include schemaLocation="EventsForm.xsd"/>
	<xs:element name="ProcessEventsFormInput" substitutionGroup="WS2MethodInput">
		<xs:annotation>
			<xs:documentation>Contains the details required to trigger an event on a case</xs:documentation>
		</xs:annotation>
		<xs:complexType>
			<xs:complexContent>
				<xs:extension base="WS2MethodInput">
					<xs:sequence>
						<xs:element name="EventsForm" type="EventsForm"/>
					</xs:sequence>
				</xs:extension>
			</xs:complexContent>
		</xs:complexType>
	</xs:element>
</xs:schema>
Here's the relevant bit from WS2Types.xsd

	<xs:complexType name="UserContext">
		<xs:sequence>
			<xs:element name="UserID" type="xs:int"/>
			<xs:element ref="ds:Signature"/>
		</xs:sequence>
	</xs:complexType>

<xs:complexType name="WS2MethodInput">
		<xs:sequence>
			<xs:element name="UserContext" type="UserContext"/>
		</xs:sequence>
	</xs:complexType>

<xs:element name="WS2MethodInput" type="WS2MethodInput"/>

 
It references the schema defining xml signatures, hence ds:signature

This has always worked perfectly, but I refactored some older schemas to bring them in line with out current way of structuring them.

Now I get this when I try to set the user context element!

Anybody got any ideas?

Regards,

James.
Aug 25, 2011 at 4:12 PM

OK, running it with the source code for LinqToXsd attached now, here's where it's failing:

 

        internal XElement FindElementPosition(NamedContentModelEntity namedEntity, XElement parentElement, bool addToExisting, out EditAction editAction) {
            Debug.Assert(namedEntity != null);
            editAction = EditAction.None;
            int newElementPos = namedEntity.ElementPosition;
            XElement lastElement = GetLastElement(parentElement);
            if (lastElement != null) { //Optimization to check last first
                int lastElementPos = GetNamedEntity(lastElement.Name).ElementPosition;
                if (newElementPos == lastElementPos) {
                    if (addToExisting) {
                        editAction = EditAction.Append;
                    }
                    else {
                        editAction = EditAction.Update;
                    }
                    return lastElement;                        
                }
                if (newElementPos > lastElementPos) { //We need to add the new element at the end
                    editAction = EditAction.Append;
                    return lastElement;
                }
            }
            int instanceElementPos = -1;
            XElement instanceElem = null;
            IEnumerator<XElement> enumerator = parentElement.Elements().GetEnumerator();
            
            while(enumerator.MoveNext()) {
                instanceElem = enumerator.Current;
                instanceElementPos = GetElementPosition(instanceElem.Name);
                if (instanceElementPos == newElementPos) { 
                    if (!addToExisting) { //Matching element found for update
                        editAction = EditAction.Update;
                        return instanceElem;
                    }
                }
                else if (instanceElementPos > newElementPos) { //Found first element greater than new position
                    editAction = EditAction.AddBefore;
                    return instanceElem;
                }
            }
            //Either its the first element being added or Scanned the whole list, end of list reached         
            editAction = EditAction.Append;
            return instanceElem;
        }

On this line:

int lastElementPos = GetNamedEntity(lastElement.Name).ElementPosition;

GetNamedEntity(lastElement.Name) returns null.

Regards,

James.

 

Aug 25, 2011 at 4:20 PM

Found the cause and a workaround.

Setting EventsForm before UserContext breaks the wrapper.

Other way around works fine.

Regards,

James.