wcf icon indicating copy to clipboard operation
wcf copied to clipboard

Auto-generated client code may use incorrect type

Open jflevesque-genetec opened this issue 1 year ago • 6 comments

Describe the bug When generating client implementation from https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl, the generator generates incorrect code. If you look at the following line: https://github.com/jflevesque-genetec/wcf/blob/2d051c83b3f141ab6dddf51aeb4ce3477981e228/ClassLibrary1/Connected%20Services/ServiceReference1/Reference.cs#L8277 the type specified in the attribute is incorrect. It should have been typeof(DNAttributeTypeAndValue[])

To Reproduce Sample: https://github.com/jflevesque-genetec/wcf

Callstacks:
System.ServiceModel.CommunicationException: There was an error in serializing body of message GetAllCertPathValidationPoliciesRequest: 'CodeGenError(IsNotAssignableFrom): Cannot convert source type [ServiceReference1.DNAttributeTypeAndValue[]] to target type [ServiceReference1.DNAttributeTypeAndValue].'.  Please see InnerException for more details.
 ---> System.InvalidOperationException: CodeGenError(IsNotAssignableFrom): Cannot convert source type [ServiceReference1.DNAttributeTypeAndValue[]] to target type [ServiceReference1.DNAttributeTypeAndValue].
 ---> System.Xml.Serialization.CodeGeneratorConversionException: CodeGenError(IsNotAssignableFrom): Cannot convert source type [ServiceReference1.DNAttributeTypeAndValue[]] to target type [ServiceReference1.DNAttributeTypeAndValue].
   at System.Xml.Serialization.CodeGenerator.InternalConvert(Type source, Type target, Boolean isAddress)
   at System.Xml.Serialization.SourceInfo.InternalLoad(Type elementType, Boolean asAddress)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElement(SourceInfo source, ElementAccessor element, String arrayName, Boolean writeAccessor)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElements(SourceInfo source, String enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, String arrayName, Boolean writeAccessors, Boolean isNullable)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteArrayItems(ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc arrayTypeDesc, String arrayName, String choiceName)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElement(SourceInfo source, ElementAccessor element, String arrayName, Boolean writeAccessor)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElements(SourceInfo source, String enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, String arrayName, Boolean writeAccessors, Boolean isNullable)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteMember(SourceInfo source, String choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc memberTypeDesc, Boolean writeAccessors)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteStructMethod(StructMapping mapping)
   at System.Xml.Serialization.XmlSerializationILGen.GenerateReferencedMethods()
   at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateEnd()
   at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types)
   at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location)
   at System.Xml.Serialization.XmlSerializer.GetSerializersFromCache(XmlMapping[] mappings, Type type)
   at System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[] mappings, Type type)
   at System.ServiceModel.Description.XmlSerializerHelper.FromMappingsViaReflection(XmlMapping[] mappings, Type type)
   at System.ServiceModel.Description.XmlSerializerHelper.FromMappings(XmlMapping[] mappings, Type type)
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.SerializerGenerationContext.CreateSerializersFromMappings(XmlMapping[] mappings, Type type)
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.SerializerGenerationContext.GenerateSerializers()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.SerializerGenerationContext.GetSerializer(Int32 handle)
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.SerializerStub.GetSerializer()
   at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.MessageInfo.get_BodySerializer()
   at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
   --- End of inner exception stack trace ---
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass1_0.<CreateGenericTask>b__0(IAsyncResult asyncResult)
--- End of stack trace from previous location ---
   at ClassLibrary1.Class1.<>c__DisplayClass0_0.<<Test>b__0>d.MoveNext() in C:\Genetec\github\wcf\ClassLibrary1\Class1.cs:line 37
--- End of stack trace from previous location ---
   at FluentAssertions.Specialized.AsyncFunctionAssertions`2.NotThrowAsync(String because, Object[] becauseArgs).
   at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Specialized.DelegateAssertionsBase`2.NotThrowInternal(Exception exception, String because, Object[] becauseArgs)
   at FluentAssertions.Specialized.AsyncFunctionAssertions`2.NotThrowAsync(String because, Object[] becauseArgs)
   at ClassLibrary1.Class1.Test() in C:\Genetec\github\wcf\ClassLibrary1\Class1.cs:line 39
   at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 285
--- End of stack trace from previous location ---
   at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90

WSDL: https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl

Expected behavior Auto-generated code to work out of the box.

Additional context To reproduce, simply run the Test method in Class1.cs

jflevesque-genetec avatar Jan 29 '24 20:01 jflevesque-genetec

@imcarolwang can you please try to repro this? Also, please try to see if this works with svcutil.exe.

HongGit avatar Jan 31 '24 22:01 HongGit

The problem could be reproduced, and code generated by svcutil.exe behaves the same.

imcarolwang avatar Feb 02 '24 02:02 imcarolwang

I have the same issue as @jflevesque-genetec with one of the Workday webservices (https://community.workday.com/sites/default/files/file-hosting/productionapi/Human_Resources/v41.0/Human_Resources.wsdl).

This issue exists with the version 2.2.0-preview1.23462.5 and the version 2.1.0 of the dotnet-svcutil tool.

GillesTourreau avatar Jun 21 '24 13:06 GillesTourreau

I seem to experience the same or at least pretty similar issue, too.

I'm generating classes from an xsd file with the following command: > xsd.exe Infrastructure\DTO\rlmdl.xsd /classes /namespace:MotionSimulation.Infrastructure.DTO /out:Infrastructure\DTO

xsd.exe /?
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.8.3928.0]
Copyright (C) Microsoft Corporation. All rights reserved.

(I notice that the tool mentions .net framework, however my application targets .net 8; shouldn't make a difference though.)

This is the source xsd: https://github.com/roboticslibrary/rl-examples/blob/127964ce3dfc2571cd761e60d712c5822bd0bf13/rlmdl/rlmdl.xsd

The generated code causes an error when executing var serializer = new XmlSerializer(typeof(DTO.rlMdl));

This is the error:

    System.InvalidOperationException
      HResult=0x80131509
      Message=CodeGenError(IsNotAssignableFrom): Cannot convert source type [System.Double[][]] to target type [System.Double[]].
      Source=System.Private.Xml
      StackTrace:
       at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location)
       at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace, String location)
       at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
       at MotionSimulation.Infrastructure.Data.RobotModelRepository.ParseRobotModel(String xmlFilePath) in C:\Users\s.kraemer\source\repos\motion-simulation\Infrastructure\Data\RobotModelRepository.cs:line 67
       at MotionSimulation.Infrastructure.Data.RobotModelRepository.GetRoboticModel(String filePath) in C:\Users\s.kraemer\source\repos\motion-simulation\Infrastructure\Data\RobotModelRepository.cs:line 17
       at MotionSimulation.Infrastructure.Data.Tests.RobotModelRepositoryTests.GetRoboticModelTest() in C:\Users\s.kraemer\source\repos\motion-simulation\Tests\MotionSimulationTests\Infrastructure\Data\RobotModelRepositoryTests.cs:line 19
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
       at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

      This exception was originally thrown at this call stack:
        [External Code]

    Inner Exception 1:
    CodeGeneratorConversionException: CodeGenError(IsNotAssignableFrom): Cannot convert source type [System.Double[][]] to target type [System.Double[]].

You can see that the inner exception is also an CodeGeneratorConversionException, as reported here. I think I will have to adapt some return types ([][] to [] or [][][] to [][]) manually. Still investigating.

sebkraemer avatar Aug 06 '24 08:08 sebkraemer

So indeed the following manual changes to the issue let me initialize the XmlSerializer:

diff --git a/Infrastructure/DTO/rlmdl.cs b/Infrastructure/DTO/rlmdl.cs
index ccd1704..143df38 100644
--- a/Infrastructure/DTO/rlmdl.cs
+++ b/Infrastructure/DTO/rlmdl.cs
@@ -85,13 +85,13 @@ namespace MotionSimulation.Infrastructure.DTO {

         private frameType[] frameField;

-        private double[][][] gammaPositionField;
+        private double[][] gammaPositionField;

-        private double[][][] gammaVelocityField;
+        private double[][] gammaVelocityField;

         private helicalType[] helicalField;

-        private homeTypeQ[][] homeField;
+        private homeTypeQ[] homeField;

         private prismaticType[] prismaticField;

@@ -180,7 +180,7 @@ namespace MotionSimulation.Infrastructure.DTO {
         [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
         [System.Xml.Serialization.XmlArrayItemAttribute("row", typeof(double[]), Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
         [System.Xml.Serialization.XmlArrayItemAttribute("col", typeof(double), Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false, NestingLevel=1)]
-        public double[][][] gammaPosition {
+        public double[][] gammaPosition {
             get {
                 return this.gammaPositionField;
             }
@@ -193,7 +193,7 @@ namespace MotionSimulation.Infrastructure.DTO {
         [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
         [System.Xml.Serialization.XmlArrayItemAttribute("row", typeof(double[]), Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
         [System.Xml.Serialization.XmlArrayItemAttribute("col", typeof(double), Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false, NestingLevel=1)]
-        public double[][][] gammaVelocity {
+        public double[][] gammaVelocity {
             get {
                 return this.gammaVelocityField;
             }
@@ -216,7 +216,7 @@ namespace MotionSimulation.Infrastructure.DTO {
         /// <remarks/>
         [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
         [System.Xml.Serialization.XmlArrayItemAttribute("q", typeof(homeTypeQ), Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
-        public homeTypeQ[][] home {
+        public homeTypeQ[] home {
             get {
                 return this.homeField;
             }

Btw. for correct parsing of an actual such xml, I had to initialize the serializer to the target type rlmdl instead of rlMdl (quite confusing, and note sure if the latter is really necessary, but I'll leave it at that).

			var serializer = new XmlSerializer(typeof(DTO.rlmdl));
			using (var stream = new FileStream(xmlFilePath, FileMode.Open))
			{
				var rl = serializer.Deserialize(stream) as DTO.rlmdl;
				// ... inspect stuff
			}

sebkraemer avatar Aug 06 '24 10:08 sebkraemer

@sebkraemer , you are my hero. I spent so many times to discover what is the matter with my new generated .cs Thanks!

Dev-GLC avatar Apr 30 '25 15:04 Dev-GLC