none
How to configure ServiceKnownType in app.config

    Question

  • I need to be able to transfer types unknown to the application at compile-time. For this I figured I could use the dataContractSerializer tag in the app.config and add the types as known types. This works as long as the types added are subtypes of a concrete or abstract class which is not System.Object.

    However, I do not want to impose this restriction, in fact I would like the service contract to simply specify that an IEnumerable<object> (or alternatively IEnumerable<MyInterface>) should be transferred and then add the concrete classes as known types in the config file.

    It can be done using the ServiceKnownType attribute at compile time, but this does not seem to be available in the configuration file.

    Does anyone know of a way around this.

    / Rasmus
    Tuesday, August 25, 2009 5:58 AM

Answers

  • I don't think this can be done at config. You can, however, use the [ServiceKnwonType("MethodName")], and then in the implementation of MethodName, you can load data from the configuration (or some other source) to determine the known types for that operation / service.
    Tuesday, August 25, 2009 8:48 AM

All replies

  • I don't think this can be done at config. You can, however, use the [ServiceKnwonType("MethodName")], and then in the implementation of MethodName, you can load data from the configuration (or some other source) to determine the known types for that operation / service.
    Tuesday, August 25, 2009 8:48 AM
  • Thanks for the reply it helped me move on. This is how I solved it in the end:

    Just use the [ServiceKnownType("GetKnownTypes", typeof(Helper))] attribute and then have the GetKnownTypes method read AssemblyQualifiedNames from a file and return the types.

        [ServiceKnownType("GetKnownTypes", typeof(Helper))]
        public interface MyService
        {
            ...
        }
    
    	static class Helper
    	{
    		public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    		{
    			List<Type> knownTypes = new List<System.Type>();
    			// Add any types to include here.			
    			string[] types = File.ReadAllLines(@"..\..\..\types.txt");
    			foreach (string type in types)
    			{
    				knownTypes.Add(Type.GetType(type));
    			}
    			
    			return knownTypes;
    		}
    	}
    types.txt:
    NameSpace.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    NameSpace.MyOtherType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    • Proposed as answer by LoudRock Tuesday, February 16, 2010 7:22 PM
    Wednesday, August 26, 2009 7:33 AM
  • Rasmus, THANK YOU!!  And Carlos for getting Rasmus the idea.  This has been illuding me for days....even weeks !!  Because of my assembly structure, I wasn't able to put a concrete in via the attribute, because it was in an assembly dependent upon the assembly with the ServiceContract (aka, it would have created a cyclic reference).




    [ServiceContract]
    public interface IMySuperCoolService
    {
        [OperationContract]
        [ServiceKnownType(typeof(EmployeeConcreteInAnotherAssembly))] /*<<This won't work in my assembly setup*/
        void AddPerson(IPerson);
    }

    Aka, in my scenario, IPerson was in Assembly1.dll and EmployeeConcreteInAnotherAssembly was in Assembly2.dll.  And Assembly2.dll referenced Assembly1.dll.

    Now I can dynamically add in the ServiceKnownType's, and use a configuration file.  Aka, I'm able to swap out EmployeeConcreteInAnotherAssembly(.cs) for another (future) concrete IPerson dynamically............which keeps my future options open.
    This is the SOA to OO bridge I've been looking for.

    ROCK IT!  Thanks again (and for posting a complete working example, and not just a "Nevermind, I figured it out" type reply.  I hate those..........



    • Edited by LoudRock Tuesday, February 16, 2010 4:51 PM misspelling
    Tuesday, February 16, 2010 4:37 PM
  • Below is some helper code to show it all got wired up correctly.



    ServiceHost serviceHost1 = new ServiceHost(/* Your code here for declaring your ServiceHost */);

                    Console.WriteLine("-Host Description: " + serviceHost1.Description.Name);
                    foreach (System.ServiceModel.Description.ServiceEndpoint endpoint in serviceHost1.Description.Endpoints)
                    {
                        Console.WriteLine("--endpoint: " + endpoint.Name);
                        foreach (System.ServiceModel.Description.OperationDescription operation in endpoint.Contract.Operations)
                        {
                            Console.WriteLine("----operation: " + operation.Name);
                            System.Collections.ObjectModel.Collection<Type> ct = operation.KnownTypes;

                            foreach (Type kt in operation.KnownTypes)
                            {
                                Console.WriteLine("------type: " + kt.Name);
                            }
                        }
                        Console.WriteLine("\n\r\n\r-------------------");
                    }



    And I get something along the lines of:

    ----operation: AddAnIPerson  
    ------type:EmployeeConcreteInAnotherAssembly


    where my implementation of AddAnIPerson  looks like:

     public interface MyService
    { bool AddAnIPerson(IPerson p);
    }  /*Note , this interface definition is NOT a complete example, just showing the method */


    And I can dynamically swap in another Concrete class now (via types.txt).
    • Edited by LoudRock Tuesday, February 16, 2010 6:02 PM formatting
    Tuesday, February 16, 2010 6:01 PM
  • Hey Rasmus,

    Is there way that the file path for "types" to be determined by reading the registry or possible even the app.config that is in the service? Thanks!

    Tuesday, March 09, 2010 8:02 PM
  •  

    Here is a slight variation on the "types.txt" solution:

     

    http://stackoverflow.com/questions/771560/how-do-you-configure-wcf-known-types-programmatically/

     

    Find the post "Web .Config"

     

    with this date and author:

     

    Dec 17 '10 at 0:22
    Friday, April 08, 2011 6:59 PM
  • Thanks for the reply it helped me move on. This is how I solved it in the end:

    Just use the [ServiceKnownType("GetKnownTypes", typeof(Helper))] attribute and then have the GetKnownTypes method read AssemblyQualifiedNames from a file and return the types.

        [ServiceKnownType("GetKnownTypes", typeof(Helper))]
        public interface MyService
        {
            ...
        }
    
    	static class Helper
    	{
    		public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    		{
    			List<Type> knownTypes = new List<System.Type>();
    			// Add any types to include here.			
    			string[] types = File.ReadAllLines(@"..\..\..\types.txt");
    			foreach (string type in types)
    			{
    				knownTypes.Add(Type.GetType(type));
    			}
    			
    			return knownTypes;
    		}
    	}
    
    types.txt:
    NameSpace.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    NameSpace.MyOtherType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

    Is it possible to add two known type as

     [ServiceKnownType(typeof(List<long>))]
     [ServiceKnownType(typeof(long[]))]

    While running throws error.

    Please suggest

    Wednesday, April 18, 2012 10:00 AM