I have this restfull service that I want to be able to call for all classes in a certain namespace or assembly. And I'm going to need to know for which Type it is called inside the operation. In short I want a template that allows both of these:
../MyClass1/some/further/spec
../MyClass2/some/further/spec
I want my uri templates to look something like this:
/{type}/some/further/{info}
And my operation will be something like this:
public void ClassSpecificOfSomeFurtherSpec(Type type, string info)
I'm assuming there's no way to do anything like the following, which I guess is what I'm really trying to achieve. After all, generics have to be decided at compile time I guess. But it illuminates the problem:
public void ClassSpecificOfSomeFurtherSpec<type>(string info)
The problem here is that the input for class is a the short Name of a Type, rather than the FullName, which means Type.GetType(class, true, true) won't work. If it would I could use that in my custom deserialization, and everything would be fine. But since it won't, I'm reluctant to hardcode my namespace into my generic deserialization, since it would make it utterly non-generic.
If I were to add an IParameterInspector, could I then modify the parameter (or only inspect it), and tack on the namespace before the deserialization takes place, or will the order be the other way around?
I've got this feeling that I'm overcomplicating things. Is there a no-brainer way to do this sort of thing that I've missed, or some really convincing reason why I shouldn't generalize my services this much?
Bottom line is that I want to avoid this sort of code for every single operation:
public Response ClassSpecificOfSomeFurtherSpec(string type, string spec)
{
Type theType = Type.GetType("My.NameSpaced."+type, true, true);
//.. and the stuff that does things
}
Update1
So, I found this nice blog post by Carlos describing how to add the option of turning an IParameterInspector into an improved version that can also modify parameters. In the blog he only modifies return values. What I wanted to do was modify the input value. So, I added that capability and added my modifier class:
public class EntityParameterModifier : IParameterModifier
{
public OperationDescription Description { get; private set; }
public EntityParameterModifier(OperationDescription description)
{
Description = description;
}
public object BeforeCall(string operationName, ref object[] inputs)
{
var parts = Description.Messages[0].Body.Parts;
for (int i = 0; i < parts.Count; i++)
{
if (parts[i].Type == typeof(Type) && inputs[i].GetType() == typeof(string))
inputs[i] = EntityStringToType((string)inputs[i]);
}
return null;
}
public void AfterCall(string operationName, object[] outputs, ref object returnValue, object correlationState) { }
private Type EntityStringToType(string entityString)
{
Assembly assembly = Assembly.GetAssembly(typeof(Entity));
Type type = (from t in assembly.GetTypes()
where t.Name == entityString || t.FullName == entityString
select t).SingleOrDefault<Type>();
return type;
}
}
But, of course they've added some blocks to prevent you from doing this sort of thing:
[InvalidOperationException: Operation 'ClassSpecificOfSomeFurtherSpec' in contract
'IMyServiceContract' has a path variable named 'type' which does not have type 'string'.
Variables for UriTemplate path segments must have type 'string'.]
System.ServiceModel.Dispatcher.UriTemplateClientFormatter.Populate(Dictionary`2& pathMapping, Dictionary`2& queryMapping, Int32& totalNumUTVars, UriTemplate& uriTemplate, OperationDescription operationDescription, QueryStringConverter qsc, String contractName) +1128
Which points me in a completely new direction. Is there any way to override the UriTemplateClientFormatter or related classes to achieve what I want?