We help IT Professionals succeed at work.

WCF : Is it possible to pass "anything" as a method argument

Alexandre Simões
Alexandre Simões used Ask the Experts™
on
I need to have a WCF service with a single method that must accept anything as an argument (type Object).
On the service side I want to use reflection to get the object properties, attributes and type name.
Is there a way of doing this?

Currently I'm using a wrapper object that inspects the object and what goes through the wire is the typed wrapper object...
It works great despite the fact that this wrapper object must be on a common assembly of both service and site.
I would like not to have this dependency, I would prefer just to reference the service and call its method.

Thanks!
Alex
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Yes it is
You need to choose between the arguments
Option 1: Cast every thing into object and pass

Option 2: Convert everything into Byte Stream and pass

Hope this will help you :-)
Alexandre SimõesManager / Solutions Architect

Author

Commented:
Hi mate,

Casting to Object doesn't work as it always knows the real type.
This works if we pass CLR types or any other type known by both sides (client & service), if not it throws something like this:

There was an error while trying to serialize parameter http://tempuri.org/:obj. The InnerException message was 'Type 'App.Logger.WebTests._Default+TestObject1' with data contract name '_Default.TestObject1:http://schemas.datacontract.org/2004/07/App.Logger.WebTests' is not expected. Consider using a DataContractResolver or 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.

O don't want to add any types as KnownTypes, I just really want to pass anything or I'll stay as I am.



As for the Byte Stream...
Using BinaryFormatter to serialize the object is out of the question because the object is required to be marked as serializable and the deserialization fails because the object type is unknown on the service side.

Doing a direct cast to Byte[] doesn't work either throwing invalid cast.



My biggest problem is the need for the object to be known on both sides, so I can never pass "Anything" as I always have to know the object types I want to pass...
Can you pass data using collections into service. Where you will be able to send different data types into service.
<collection> dd = new <collection> something like this.
Alexandre SimõesManager / Solutions Architect

Author

Commented:
the task I need to perform needs to inspect the passed object using Reflection.
Currently I'm doing this inspection on the application side and pass a known type through the wire.
When I inspect the object I strip all the relevant information into collections of CLR types, so I have no serialization problems and all types are know on both site and service sides.
This is basically what you suggested on your last post.

Now what I would like to have is a way to do this inspection on the Service side without needing to reference nothing but the service.
Yes you can pass any object as the parameter, but make sure the class is defined using  MessageContract".
Aaron JabamaniTechnical Architect
Commented:
Use XML. You can pass any information.
Alexandre SimõesManager / Solutions Architect

Author

Commented:
True but still there's the need to serialize the object before passing it to the service.
Also, on the service side I must inspect the object to find properties, its type and attibutes, so the serialization wouldn't be easy.

To make things clear, this is to be used on an Audit service.
Currently I have this implemented as an API, where you reference the Audit assembly and there you can pass anything without any problem.

What I want is to also add the support for WCF so that this audit code could be isolated and used across multiple applications.
The way I implemented it was by having a known type on both Client and Service that basically wraps the object that is to be audited, inspects it and gathers all the needed information.
This works perfectly fine but it always needs this "known object" in the middle, its not a true isolated service.

I don't want to require any more work on the caller than just a single method call, so I don't like anything that requires the caller to know any auditing logic in order to use my API.

Btw, if you'd like to see the current available version you can go to:
http://www.codeproject.com/KB/cs/NLogAdvancedTarget.aspx

My WCF version isn't there yet.

Cheers!
Alex
Let me understand the requirement,

Do you want to pass instance of other class which is not there in the WCF Service, to the WCF service as a parameter
Please give the example of the code.
As per my understanding
Your API
class APIClass
{
}
Your Code
Class WCFClass
{
objAPI = new APIClass
WCFMethod(objAPI)
}
is that the same you are looking for..
Alexandre SimõesManager / Solutions Architect

Author

Commented:
Ok, so my current service contract looks like this:

      [ServiceContract]
      public interface ILoggerService
      {
            [OperationContract]
            void Trace(LoggerPackage package);
      }

A single method that receives a LoggerPackage object.
This LoggerPackage is known by both client and service, so everything works perfect.
The problem is that the client can't just use the service, it must also reference a common library where this LoggerPackage object is defined.

The LoggerPackage class is the one attached.
It receives an Objcet type on the constructor and inspects it, enumerating Properties, certain expected Attributes and the actual Object type as a string.

As you can see, the inspection work is done before the service call.
What I would like to know is if there's any way I can do the exact same thing but on the service side.

I hope this made my intentions more clear.

Thanks for the help,
Alex


	[Serializable]
	public class LoggerPackage
	{
		public LoggerPackage(object obj)
		{
			InspectObject(obj);
		}

		private void InspectObject(object obj)
		{
			if (obj == null)
			{
				throw new NullReferenceException("The object to be logged can't be null.");
			}

			PropertiesInfo = new List<ObjectPropertyInfo>();

			TypeName = obj.GetType().ToString();

			// get all object's properties
			foreach (var prop in obj.GetType().GetProperties())
			{
				PropertiesInfo.Add(new ObjectPropertyInfo() { Name = prop.Name });
			}

			// search for LogAttribute
			foreach (var attr in obj.GetType().GetCustomAttributes(true))
			{
				if (attr is App.Logger.Targets.ObjectHistoryLogger.LogAttribute)
				{
					HaveLogAttribute = true;
					break;
				}
			}
		}

		public string TypeName { get; set; }
		public bool HaveLogAttribute { get; set; }
		public List<ObjectPropertyInfo> PropertiesInfo { get; set; }

		[Serializable]
		public class ObjectPropertyInfo
		{
			public string Name { get; set; }
			public string Value { get; set; }
			public bool HaveLogAttribute { get; set; }
		}
	}

Open in new window

Technical Architect
Commented:
To get XML why we need a class at client side ? They can use stringbuilder and LInqtoXML to create a xml.

You should only define the schema that you are expecting as parameter. It is upto the client how he creates the xml and sending to you as parameter.

Anyway you should define schema if you expect as xml or you have a class and let the client use this class to pass. Don't think any other option available.
Alexandre SimõesManager / Solutions Architect

Author

Commented:
apeter:
It is requirement to me that the user of this API must actually use it without having to know anything about how the info is passed to the WCF service.

Plain simple... call a service method and pass the object to be logged. Nothing more.

So I'll keep my wrapper class that encapsulates all the serialization logic, I think is the simplest way I can implement.

Thank you all for the hints!
Alex

Alexandre SimõesManager / Solutions Architect

Author

Commented:
Thanks!