Enumerations don''t work correctly with svcutil or .svc generated schemas
There is a bug when the svc file automatically creates schemas where enumerated values are included in the method parameter list. I included an enum with no data contract, which is supposed to work fine as the enum is automatically serializeable. When I viewed the schema that was automatically created from the .svc file, the EnumerationValue element was missing for one of the enum values.
Also, with the enum values as method parameters, there are errors generated from svcutil (to C#) when creating the code for the class. I get errors that DataContractAttribute and EnumMemberAttribute do not exist in System.Runtime.Serialization. When I removed these attributes from the .cs file, my client code ran fine, but am I going to have to call all of my clients and tell them to remove these attributes so their code works?
Also, when is SvcUtil going to work for code written in C++/CLI? When I run code from C++/CLI that uses a web reference (which I have heard uses svcutil in the background), I get an unhandled exception because a SOAP header Action was not understood.
[1098 byte] By [
jvshore] at [2008-1-8]
This is the C++/CLI code (implementation file excluded):
INTERFACE FILE:
// CallRouting.h
#pragma once
using namespace System;
using namespace System::Xml;
using namespace System:
erviceModel;
using namespace System:
erviceModel::Channels;
using namespace System::Runtime:
erialization;
using namespace VPBXEnums;
#include <msclr\com\ptr.h>
namespace VPBXCallRouting {
[ServiceContract(Namespace="http://virtualpbx.com/webservices/2007/08/08")]
public interface class ICallRouting
{
[OperationContract]
String^ Login(String^ dnis, long extensionID, String^ password);
[OperationContract]
String^ getInfo(String^ sessionID);
[OperationContract]
void setScreening(String^ sessionID, bool toScreen);
[OperationContract]
void setFollowMe(String^ sessionID, bool toFollow);
[OperationContract]
void setAvailability(String^ sessionID, bool avail);
[OperationContract]
void setDefaultContactByID(String^ sessionID, VConsoleEnums::ContactID contactID);
[OperationContract]
void setDefaultContactByANI(String^ sessionID, String^ phoneNumber);
[OperationContract]
void setFollowMeContactByID(String^ sessionID, VConsoleEnums::ContactID contactID, bool toFollow);
[OperationContract]
void setFollowMeContactByANI(String^ sessionID, String^ phoneNumber, bool toFollow);
[OperationContract]
void setContactNumberInfo(String^ sessionID, VConsoleEnums::ContactID contactID, String^ ANI, bool isDefault, bool isDirectConnect,
bool isPasswordEnabled, bool followMeExclude, VConsoleEnums::RingNoAnswerTO ringNoAnswerTO, bool ringNoAnswerOverride);
};
[ServiceBehavior(Namespace="http://virtualpbx.com/webservices/2007/08/08")]
public ref class CallRouting : ICallRouting
{
public:
CallRouting() { m_cookiePtr.CreateInstance("VPBXCookieManager.CookieManager"); }
virtual String^ Login(String^ dnis, long extensionID, String^ password);
virtual String^ getInfo(String^ sessionID);
virtual void setScreening(String^ sessionID, bool toScreen);
virtual void setFollowMe(String^ sessionID, bool toFollow);
virtual void setAvailability(String^ sessionID, bool avail);
virtual void setDefaultContactByID(String^ sessionID, VConsoleEnums::ContactID contactID);
virtual void setDefaultContactByANI(String^ sessionID, String^ phoneNumber);
virtual void setFollowMeContactByID(String^ sessionID, VConsoleEnums::ContactID contactID, bool toFollow);
virtual void setFollowMeContactByANI(String^ sessionID, String^ phoneNumber, bool toFollow);
virtual void setContactNumberInfo(String^ sessionID, VConsoleEnums::ContactID contactID, String^ ANI, bool isDefault, bool isDirectConnect,
bool isPasswordEnabled, bool followMeExclude, VConsoleEnums::RingNoAnswerTO ringNoAnswerTO, bool ringNoAnswerOverride);
private:
msclr::com:
tr<ICookiePersist> m_cookiePtr;
String^ CreateSession(String^ contents);
String^ ReadSessionInfo(String^ sessionID);
String^ MakeGatewayCall(String^ resource, String^ params);
};
}
INCLUDED ENUM FILE, DEFINING ContactID and RingNoAnswerTO enumerations:
// VPBXEnums.h
#pragma once
using namespace System;
namespace VPBXEnums {
public ref class VConsoleEnums abstract sealed
{
public:
static enum struct ContactID
{
Contact1 = 1,
Contact2 = 2,
Contact3 = 3,
Contact4 = 4
};
static enum struct RingNoAnswerTO
{
RnaTO10 = 10,
RnaTO20 = 20,
RnaTO30 = 30,
RnaTO45 = 45,
RnaTO60 = 60,
RnaTO120 = 120
};
};
}
OUTPUT SCHEMA:
<?xml version="1.0" encoding="utf-8"?>
<xs
chema xmlns:tns="http://schemas.datacontract.org/2004/07/VPBXEnums" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/VPBXEnums" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="https://vconsole.virtualpbx.com/CallRouting/CallRouting_1.xsd" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xs
impleType name="VConsoleEnums.ContactID">
<xs:restriction base="xs
tring">
<xs:enumeration value="Contact4">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">4</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Contact3">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">3</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="Contact2">
<xs:enumeration value="Contact1">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs
impleType>
<xs:element name="VConsoleEnums.ContactID" nillable="true" type="tns:VConsoleEnums.ContactID" />
<xs
impleType name="VConsoleEnums.RingNoAnswerTO">
<xs:restriction base="xs
tring">
<xs:enumeration value="RnaTO120">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">120</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RnaTO60">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">60</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RnaTO45">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">45</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RnaTO30">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">30</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RnaTO20">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">20</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="RnaTO10">
<xs:annotation>
<xs:appinfo>
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">10</EnumerationValue>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs
impleType>
<xs:element name="VConsoleEnums.RingNoAnswerTO" nillable="true" type="tns:VConsoleEnums.RingNoAnswerTO" />
</xs
chema>
PORTION OF GENERATED .cs from svcutil:
namespace VPBXEnums
{
using System.Runtime.Serialization;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="VConsoleEnums.ContactID")]
public enum VConsoleEnumsContactID : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
Contact4 = 4,
[System.Runtime.Serialization.EnumMemberAttribute()]
Contact3 = 3,
[System.Runtime.Serialization.EnumMemberAttribute()]
Contact2 = 2,
[System.Runtime.Serialization.EnumMemberAttribute()]
Contact1 = 1,
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="VConsoleEnums.RingNoAnswerTO")]
public enum VConsoleEnumsRingNoAnswerTO : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO120 = 120,
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO60 = 60,
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO45 = 45,
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO30 = 30,
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO20 = 20,
[System.Runtime.Serialization.EnumMemberAttribute()]
RnaTO10 = 10,
}
}
As you can see, the enumeration for contactid is incorrect, as contact2 does not have own enumerated section. Also, as you can see from the .cs sample, an error is produced at compile time because DataContractAttribute and EnumMemberAttribute are not part of System.Runtime.Serialization. If you take out these attributes, you can recompile fine.
Another really important thing: The .svc file used for the web service does not work in a load balanced environment, since it hard codes the schema paths with the machine name. There should be an additional query parameter to the svc file where you can submit the domain name, so it will override the machine name. As it stands now, if I want the .svc file to be used to produce the wsdl and schema for me, I have to set the external reference to a wsdl file I created and create the xsds files, putting the wsdl and xsd files in the virtual directory.
Thanks,
John Shore