2

This is making me crazy... I'm trying to have a custom WCF auth token that derives from System.IdentityModel.Tokens.SecurityToken for example:

    public class TestSecurityToken : SecurityToken
    {
        public override string Id
        { get { return "123"; } }

        public override ReadOnlyCollection<SecurityKey> SecurityKeys
        { get { return new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>(0)); } }

        public override DateTime ValidFrom
        { get { return DateTime.MinValue; } }

        public override DateTime ValidTo
        {get { return DateTime.MaxValue; } }

        public string Property1 { get; set; }
    }

I know I can write a custom serializer for it that extends WSSecurityTokenSerializer, but I am trying to find a way to do that in a generic way, where I can make a serializer that can serialize any <T> where T : SecurityToken

Here is what I have tried, and failed:


Attempt 1: Make the SecurityToken a DataContract

[DataContract]
public class TestSecurityToken : SecurityToken

Fails because you cant have a DataContract that derives from a base class that isn't a DataContract, which SecurityToken is not.


Attempt 2: Serialize with an XmlSerializer

public class SecurityTokenSerializer<T> : WSSecurityTokenSerializer where T : SecurityToken
{
    private readonly XmlSerializer serializer;

    public SecurityTokenSerializer()
    {
        serializer = new XmlSerializer(typeof (T));
    }

    protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
    {
        serializer.Serialize(writer, token);
    }

This fails with the error:

System.InvalidOperationException: There was an error reflecting type 'PartsSource.Services.Core.ServiceModel.SecurityTokenSerializerTest.TestSecurityToken'. ---> System.InvalidOperationException: To be XML serializable, types which inherit from ICollection must have an implementation of Add(System.IdentityModel.Tokens.SecurityKey) at all levels of their inheritance hierarchy. System.Collections.ObjectModel.ReadOnlyCollection`1[[System.IdentityModel.Tokens.SecurityKey, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] does not implement Add(System.IdentityModel.Tokens.SecurityKey).

Due to this property on my custom SecurityToken:

        public override ReadOnlyCollection<SecurityKey> SecurityKeys
        { get { return new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>(0)); } }

Attempt 3: Same as above, but try to tell the XmlSerializer to ignore that SecurityKeys property:

public class SecurityTokenSerializer<T> : WSSecurityTokenSerializer where T : SecurityToken
{
    private readonly XmlSerializer serializer;

    public SecurityTokenSerializer()
    {
        var xOver = new XmlAttributeOverrides();
        xOver.Add(typeof(T), "SecurityKeys", new XmlAttributes { XmlIgnore = true });
        serializer = new XmlSerializer(typeof (T), xOver);
    }

This errors with the same message as the previous attempt. It does not ignore this property.


Does anyone have any other ideas on how to just serialize any SecurityToken to an XmlReader / XmlWriter? It seems like it should have been dead simple, but no...

CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138

1 Answers1

0

Since I found no other good way to do this, what I ended up doing was making my custom SecurityToken also implement IXmlSerializable, and then changed the definition of my serializer to:

public class SecurityTokenSerializer<T> : WSSecurityTokenSerializer
    where T : SecurityToken, IXmlSerializable

My custom security token is then defined as:

public class MySecurityToken : SecurityToken, IXmlSerializable

Then the serializer can delegate serialization to the custom security token. It probably isn't the cleanest solution (I'd say it violates the single-responsibility principal), but it does seem to work and let me not have to write a serializer for every custom token.

CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138
  • Please can you put an example of code of how the Serializable works on MySecurityToken? @CodingWithSpike – Zinov Mar 05 '15 at 19:36
  • @Zinov. You can find those anywhere..that problem isn't specific to SecurityTokens. http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly http://stackoverflow.com/questions/279534/proper-way-to-implement-ixmlserializable – granadaCoder Oct 28 '15 at 21:21
  • Can you show your serialization code? I mimicked you, but got same error (The token Serializer cannot serialize 'TestSecurityToken '. If this is a custom type you must supply a custom serializer.) .. (start code after this) XmlWriterSettings xws = new XmlWriterSettings(); /**/ xws.Indent = false; /**/ xws.NewLineHandling = NewLineHandling.None; /**/ /**/ SecurityTokenSerializer ser = new SecurityTokenSerializer();/**/ using (XmlWriter xw = XmlWriter.Create(@"C:\temp\myfile.xml", xws))/**/ { ser.WriteToken(xw, myToken);/**/ } – granadaCoder Oct 28 '15 at 21:28