InteXX
InteXX

Reputation: 6367

Error generating service reference in VS 2015

OK, this worked just fine in VS 2013. It's only when I started work anew on the project after my upgrade to 2015 that the problem has showed up.

In a nutshell, I'm unsure how to tell the WCF Proxy Generator to specify a CLR namespace for a property type; apparently this is required now.

Here's my contract:

<ServiceContract>
Friend Interface IService
  <OperationContract> Function CheckFiles() As List(Of String)
  <OperationContract> Function CreateBackup(AllFiles As List(Of String)) As BackupResult
End Interface

Here's the class being returned:

Public Class BackupResult
  Public Property DbService As New DbService
  Public Property TmpFolder As System.IO.DirectoryInfo ' <== Problem here '
  Public Property Chunks As Integer
End Class

And just for clarity, here's the class for the DbService property (although its only relevance for this question is to show that it doesn't have any System.IO references).

Public Class DbService
  Public Property ErrorMessage As String = String.Empty
  Public Property HasError As Boolean = False
End Class

My problem is that the proxy generator doesn't seem to be able to see that DirectoryInfo is in the System.IO namespace—it keeps generating it in the service's namespace. (When I comment out the CreateBackup() function, rerun the service and update the reference, the QbBackup.DirectoryInfo class isn't generated. I don't get the warning shown below and everything works—like it did in 2013—but of course without the property I need.)

Here's the generated code:

Namespace QbServer

  ' ...                                          '
  '                                              '
  ' Other generated code here                    '
  '                                              '
  ' ...                                          '
  '                                              '
  ' Note the generated DirectoryInfo class and   '
  ' the BackupResult.TmpFolder property of type  '
  ' QbServer.DirectoryInfo, when the namespace   '
  ' should be System.IO instead                  '
  '                                              '

  <System.Diagnostics.DebuggerStepThroughAttribute(),
     System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0"),
     System.Runtime.Serialization.DataContractAttribute(Name:="BackupResult", [Namespace]:="http://schemas.datacontract.org/2004/07/Service"),
     System.SerializableAttribute()>
  Partial Public Class BackupResult
    Inherits Object
    Implements System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged

    <System.NonSerializedAttribute()>
    Private extensionDataField As System.Runtime.Serialization.ExtensionDataObject

    <System.Runtime.Serialization.OptionalFieldAttribute()>
    Private ChunksField As Integer

    <System.Runtime.Serialization.OptionalFieldAttribute()>
    Private DbServiceField As QbServer.DbService

    <System.Runtime.Serialization.OptionalFieldAttribute()>
    Private TmpFolderField As QbServer.DirectoryInfo

    <Global.System.ComponentModel.BrowsableAttribute(False)>
    Public Property ExtensionData() As System.Runtime.Serialization.ExtensionDataObject Implements System.Runtime.Serialization.IExtensibleDataObject.ExtensionData
      Get
        Return Me.extensionDataField
      End Get
      Set
        Me.extensionDataField = Value
      End Set
    End Property

    <System.Runtime.Serialization.DataMemberAttribute()>
    Public Property Chunks() As Integer
      Get
        Return Me.ChunksField
      End Get
      Set
        If (Me.ChunksField.Equals(Value) <> True) Then
          Me.ChunksField = Value
          Me.RaisePropertyChanged("Chunks")
        End If
      End Set
    End Property

    <System.Runtime.Serialization.DataMemberAttribute()>
    Public Property DbService() As QbServer.DbService
      Get
        Return Me.DbServiceField
      End Get
      Set
        If (Object.ReferenceEquals(Me.DbServiceField, Value) <> True) Then
          Me.DbServiceField = Value
          Me.RaisePropertyChanged("DbService")
        End If
      End Set
    End Property

    <System.Runtime.Serialization.DataMemberAttribute()>
    Public Property TmpFolder() As QbServer.DirectoryInfo
      Get
        Return Me.TmpFolderField
      End Get
      Set
        If (Object.ReferenceEquals(Me.TmpFolderField, Value) <> True) Then
          Me.TmpFolderField = Value
          Me.RaisePropertyChanged("TmpFolder")
        End If
      End Set
    End Property

    Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub RaisePropertyChanged(ByVal propertyName As String)
      Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
      If (Not (propertyChanged) Is Nothing) Then
        propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
      End If
    End Sub
  End Class

  <System.Diagnostics.DebuggerStepThroughAttribute(),
     System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")>
  Public Class DirectoryInfo
  End Class
End Namespace

And here's the warning I'm getting in Visual Studio 2015:

Custom tool warning: Cannot import wsdl:portType Detail: An exception was thrown while running a WSDL import extension: System.ServiceModel.Description.DataContractSerializerMessageContractImporter Error: ISerializable type with data contract name 'DirectoryInfo' in namespace 'http://schemas.datacontract.org/2004/07/System.IO' cannot be imported. The data contract namespace cannot be customized for ISerializable types and the generated namespace 'QbServer' does not match the required CLR namespace 'System.IO'. Check if the required namespace has been mapped to a different data contract namespace and consider mapping it explicitly using the namespaces collection. XPath to Error Source: //wsdl:definitions[@targetNamespace='http://tempuri.org/']/wsdl:portType[@name='IService'] ConsoleTest D:\Dev\Customers\OIT\Active\ConsoleTest\Service References\QbServer\Reference.svcmap 1

This all results in the proxy classes not being generated.

I've been reading this and this, but they seem to pertain to custom namespaces at the service level. I need to know how to tell the generator to recognize the property type as a CLR type and NOT generate a DirectoryInfo class of its own.

Upvotes: 0

Views: 491

Answers (1)

jessehouwing
jessehouwing

Reputation: 114461

The class System.IO.DirectoryInfo is not supported by the DataContractSerializer. Instead you could try using the XmlSerializer, but you'll likely run into other issues.

A simple solution is to add a string property which captures the data needed to recreate the correct objects. You can keep the original property as well, just be sure to mark it with the [NonSerialized] attribute.

Alternatively you can use the OnSerializing and OnDeserializing attributes to ensure that the DirectoryInfo value is stored in the string field and so that the DirectoryInfo is restored after deserialization.

For more information see:

Upvotes: 2

Related Questions