Search code examples
wcfknown-types

WCF Known Type error


I get this error when calling my service:

Server Error in '/' Application.
--------------------------------------------------------------------------------

Configuration Error 
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately. 

Parser Error Message: There was an error while trying to serialize parameter http://DSD.myCompany.net/DsdWebServices/2011/05/:config. The InnerException message was 'Type 'System.OrdinalComparer' with data contract name 'OrdinalComparer:http://schemas.datacontract.org/2004/07/System' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Source Error: 


Line 130:            passwordAttemptWindow="10"
Line 131:            passwordStrengthRegularExpression=""
Line 132:            type="DsdWebsite.Providers.DsdMembershipProvider, DsdWebsite.Providers" />
Line 133:      </providers>
Line 134:    </membership>


Source File: C:\Development\DSD Website\WebUI\web.config    Line: 132 


--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.5444; ASP.NET Version:2.0.50727.5420 

The service is a data service for a membership provider. I created a MembershipUser DTO to move data back and forth across the service. It uses only standard classes: string, int, DateTime. I use Guid instead of object for the providerUserKey.

The interface for the service looks like this:

[ServiceContract(Namespace = "http://DSD.myCompany.net/DsdWebServices/2011/05/")]
[ServiceKnownType(typeof(MembershipUserDTO))]
[ServiceKnownType(typeof(NameValueCollection))]
[ServiceKnownType(typeof(Guid))]
[ServiceKnownType(typeof(DateTime))]
public interface IDsdMembershipProviderService
{
    [OperationContract]
    void Initialize(string name, NameValueCollection config);

    [OperationContract]
    MembershipUserDTO CreateUser(string username, 
        string salt,
        string encodedPassword,
    ...

The DTO looks like this

namespace DsdWebsite.Services.Providers
{
    [Serializable]
    [DataContract]
    [KnownType(typeof(Guid))]
    [KnownType(typeof(DateTime))]
    public class MembershipUserDTO
    {
        public MembershipUserDTO(string providerName, string userName, Guid providerUserKey, string email,
                              string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
                              DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate,
                              DateTime lastPasswordChangedDate, DateTime lastLockoutDate,
                              string firstName, string lastName, string cellPhone, string officePhone,
                              string brokerId, bool isAdmin, bool mustChangePassword)
        {
            ProviderName= providerName;
            UserName = userName;
            ProviderUserKey= providerUserKey;
            Email= email;
            PasswordQuestion= passwordQuestion;
            Comment= comment;
            IsApproved=isApproved;
            IsLockedOut= isLockedOut;
            CreationDate= creationDate;
            LastLoginDate= lastLoginDate;
            LastActivityDate= lastActivityDate;
            LastPasswordChangedDate = lastPasswordChangedDate;
            LastLockoutDate=lastLockoutDate;
...

Finally, my web.config looks like this:

<membership
 defaultProvider="DsdMembershipProvider"
 userIsOnlineTimeWindow="15"
 hashAlgorithmType="">   <providers>
     <clear/>
     <add
         name="DsdMembershipProvider"
         connectionStringName="DsdMembershipConnectionString"
         enablePasswordRetrieval="true"
         enablePasswordReset="true"
         requiresQuestionAndAnswer="true"
         applicationName="/DsdWebsite/"
         requiresUniqueEmail="true"
         passwordFormat="Encrypted"
         maxInvalidPasswordAttempts="5"
         minRequiredPasswordLength="7"
         minRequiredNonalphanumericCharacters="0"
         passwordAttemptWindow="10"
         passwordStrengthRegularExpression=""
         type="DsdWebsite.Providers.DsdMembershipProvider,
 DsdWebsite.Providers" />  
 </providers> </membership>

How can I determine what type or object is causing the error? Thanks


Solution

  • Use following ServiceKnownTypeAttribute constructor to specify type of class (declaringType) containing the static method methodName that will return service known types:

    public ServiceKnownTypeAttribute(
        string methodName,
        Type declaringType
    )
    

    Inside the aforementioned static method add all service known types that are already added (although I think you would do good without DateTime and Guid), and add System.OrdinalComparer as well.

    The catch is that System.OrdinalComparer is internal class so you will have to get the type via reflection.

    EDIT:

    System.OrdinalComparer is part of mscorlib assembly. Basically you can get its type in a following manner:

    Type[] types = typeof( string ).Assembly.GetTypes();
    

    and then you can retrieve the wanted type by name (using Linq, add necessary using statements).

    Type type = types.Where( x => x.FullName == "System.OrdinalComparer" );
    

    Previous two line can be combined in one, for simplicity done using two lines.

    If you need more details, just say.