I have a WebAPI method and in it I have a an IEnumerable of objects where the type of T is not known until runtime. So, I need to execute a foreach on the IEnumerable collection. The problem is I cannot replace the T with a specific type since that type is not known until runtime. So, I get the type of T using some reflection in a helper method and store it into a variable "type". But apparently, I cannot use IEnumerable. It throws an error saying a variable cannot be used as a type.
My WebAPI method needs to log activity whenever an update happens to certain types of data. So, I have a custom ActionFilter attribute setup to do the dirty work.
Here is my WebAPI method (this is just a dummy test method):
[HttpPost]
[Route("testlogging")]
[PhiLog]
public IEnumerable<Person> UpdateTestData(Person person)
{
IList<Person> persons = new List<Person>();
persons.Add( person );
persons.Add( person );
return persons;
}
When OnActionExecuted is executed, we don't know the type of response content returned to the caller. It could be just null, or just a string, or just an int or IList or IEnumerable and the type of T is not known. Here is my Custom Attribute:
public class PhiLogAttribute : ActionFilterAttribute
{
public override void OnActionExecuted( HttpActionExecutedContext actionExecutedContext )
{
var user = AuthenticationHelper.GetCurrentUserFromRequest( actionExecutedContext.Request );
var actionDescriptor = actionExecutedContext.Request.GetActionDescriptor();
var controllerName = actionDescriptor.ControllerDescriptor.ControllerName;
var methodName = actionDescriptor.ActionName;
var action = string.Format( "{0}/{1}", controllerName, methodName );
var responsePayload = actionExecutedContext.Response.Content as ObjectContent;
var payloadType = responsePayload.ObjectType;
/* The variable below (payloadObj) could be of any type - an int, a string or a generic ICollection. The code below is just assuming it is of type IList<Person>. This is for my test purpose */
var payloadObj = responsePayload.Value;
/* AppHelper.GetEnumerableType returns the type of the generic parameter T.
In this case, a Person type
*/
var type = AppHelper.GetEnumerableType( payloadObj.GetType());
if ( payloadType.GetInterfaces().Any( x => x.GetType().Name == "ICollection`1") )
{
/* This is where I am stumped. I need to walk this ICollection<T> and log some value from few properties of T. At runtime, payloadObj is of type object. I need to cast it into the correct ICollection type */
foreach (var x in (ICollection<type>)payloadObj)
{
//do something with var x here.
/* But ICollection<type> throws an error "type is a variable but used like a type" */
}
}
}
}
Here is my helper method to get the type of the type parameter T.
public static Type GetEnumerableType( Type type )
{
var interfaceTypes = type.GetInterfaces();
foreach ( Type interfaceType in interfaceTypes )
{
if ( interfaceType.IsGenericType && interfaceType.Name == "ICollection`1" )
return interfaceType.GetGenericArguments()[ 0 ];
}
return null;
}
I have commented inline in the code where the problem is. Anyone please tell me how can I use a variable in place of T in an IEnumerable. Thanks.
Aucun commentaire:
Enregistrer un commentaire