Updated Answer -
After looking at your comment I got the point. So you want to supply the string and then cast it before OperationInovker comes into picture. So I got my hands dirty playing around and finally did it.
Here's What I have done. A new class that derives from WebHttpBehavior
which would give a place where we can extend or override the existing behavior of WebHttpBidning
.
public class MyWebHttpBehavior : WebHttpBehavior
{
}
Though it's a hack and but this would work. The problem with Typed argument was that the URL Template formatter was throwing exception by checking the method signature for type string
so I got rid of that by over riding the BindingInformation
by overiding method GetRequestDispatchFormatter
.
protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
foreach (var item in operationDescription.Messages[0].Body.Parts)
{
item.Type = typeof(string);
}
return base.GetRequestDispatchFormatter(operationDescription, endpoint);
}
After applying this behavior the run time will no more throw exception for String argument check. Now I need to change the OperationInvoker because if you run this then this will throw excpetion when you invoke the opration from client saying Invalid cast
.
Now here comes the IOperationInvoker
in picture. I have simply taken the value from input[] of type object converted the value from String
to Guid
and passed it back to the Invoker.
public class ValueCastInvoker : IOperationInvoker
{
readonly IOperationInvoker _invoker;
public ValueCastInvoker(IOperationInvoker invoker)
{
_invoker = invoker;
}
public ValueCastInvoker(IOperationInvoker invoker, Type type, Object value)
{
_invoker = invoker;
}
public object[] AllocateInputs()
{
return _invoker.AllocateInputs().ToArray();
}
private object[] CastCorrections(object[] inputs)
{
Guid obj;
var value = inputs[0] as string;
if (Guid.TryParse(value, out obj))
{
return new[] { (object)obj }.Concat(inputs.Skip(1)).ToArray();
}
return inputs.ToArray();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
return _invoker.Invoke(instance, CastCorrections(inputs), out outputs);
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return _invoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return _invoker.InvokeEnd(instance, out outputs, result);
}
public bool IsSynchronous
{
get { return _invoker.IsSynchronous; }
}
}
Now here what took me a long time to figure out is how to inject this custom operation inovker in pipeline. I found a relevants stackoverflow answer here. And implemented the way person suggested and it worked.
Adding summary here: A new IOperationBehavior has to be implemented and attach it with DispatcherRuntime.
public class MyOperationBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Invoker = new ValueCastInvoker(dispatchOperation.Invoker);
}
public void Validate(OperationDescription operationDescription)
{
}
}
Now in MyWebHttpBehavior override the ApplyDispatchBehavior
and introduce above implemented IOperationBehavior
.
public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
foreach (var operation in endpoint.Contract.Operations)
{
if (operation.Behaviors.Contains(typeof(MyOperationBehavior)))
continue;
operation.Behaviors.Add(new MyOperationBehavior());
}
base.ApplyDispatchBehavior(endpoint, endpointDispatcher);
}
Now all these hacks and extensions would make this Legal.
[WebInvoke(Method = "GET", UriTemplate = "/{id}")]
string GetValue(Guid id);
Disclaimer: I had fun experimenting this exntesion and applying custom behavior but I havn't checked the impacted areas. So use it own your own risk and feel free to change/enhance as you may. Sorry for Typos.
Update 2
I have created a library to wrap this web http behavior extension. The library provides more support of other value types in method parameters(multiple). Check this out.