Okay, I've searched a bunch for answers to this question and I can only seem to find articles and documents for .NET 3.5 from 2011 and back... so I'm hoping to find more recent information for WCF in .NET 4.5 (and up).
好的,我已经搜索了一堆这个问题的答案,我似乎只能从2011年找到.NET 3.5的文章和文档,然后回来......所以我希望在.NET 4.5中找到WCF的最新信息(及以上)。
I've got a WCF service that is bound to a webHttpBinding. It uses a Uri template that passes the identity of the item to be retrieved with a Uri template as such:
我有一个绑定到webHttpBinding的WCF服务。它使用Uri模板,使用Uri模板传递要检索的项的标识:
[WebInvoke(Method="GET", UriTemplate = "/{identity}")]
public ResponseItem Get(string identity)
{
//Convert identity to a Guid which is the correct type for the identity
//Retrieve object
}
What I'd really like to do is remove the conversion of the value to the Guid and move it up the stack to clean up the code and have:
我真正想要做的是删除将值转换为Guid并将其向上移动到堆栈以清理代码并具有:
[WebInvoke(Method="GET", UriTemplate = "/{identity}")]
public ResponseItem Get(Guid identity)
{
//Retrieve object
}
I realize with other types of binding this is possible using a custom Behaviour and QueryStringConverter. I also realize that the reason for this being string by default in webHttpBinding is that inherently values passed in the address should semantically be strings - as an address is string based. So perhaps what I'm asking may not make sense.
我意识到使用其他类型的绑定可以使用自定义Behavior和QueryStringConverter。我也意识到在webHttpBinding中默认为字符串的原因是,在地址中传递的固有值在语义上应该是字符串 - 因为地址是基于字符串的。所以也许我所要求的可能没有意义。
In the context of my application, string is not semantically correct and it's irritating me that this class is cluttered with conversion code which shouldn't be a concern of the class, but changing the binding is not an option as existing clients are using it.
在我的应用程序的上下文中,字符串在语义上是不正确的,并且令我恼火的是,这个类混乱了转换代码,这不应该是类的关注,但是改变绑定不是现有客户端使用它的选项。
Is there an extensibility point in the WCF pipeline for the current versions of WCF (for instance IParameterInspector, IServiceBehavior) where conversion of this value is both possible and appropriate so that by the time the method is invoked, the parameter can be of the correct type?
在当前版本的WCF(例如IParameterInspector,IServiceBehavior)的WCF管道中是否存在可扩展点,其中此值的转换既可能又适当,以便在调用方法时,参数可以是正确的类型?
2 个解决方案
#1
4
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.
看完你的评论后我明白了。所以你想提供字符串然后在OperationInovker进入图片之前投射它。所以我把手弄脏了,最后做到了。
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
.
这就是我所做的。一个派生自WebHttpBehavior的新类,它可以为我们提供扩展或覆盖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
.
虽然这是一个黑客,但这将有效。 Typed参数的问题在于,URL模板格式化程序通过检查类型字符串的方法签名来抛出异常,因此我通过覆盖方法GetRequestDispatchFormatter来覆盖BindingInformation。
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
.
应用此行为后,运行时将不再为String参数检查抛出异常。现在我需要更改OperationInvoker,因为如果你运行它,那么当你从客户端调用无效转换时,这将抛出excpetion。
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.
现在来看IOperationInvoker图片。我只是从类型对象的input []中获取值,将值从String转换为Guid并将其传递回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 * answer here. And implemented the way person suggested and it worked.
现在我花了很长时间才弄清楚如何在管道中注入这个自定义操作inovker。我在这里找到了相关的*答案。并实现了人们建议和工作的方式。
Adding summary here: A new IOperationBehavior has to be implemented and attach it with DispatcherRuntime.
在此处添加摘要:必须实现新的IOperationBehavior并将其与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
.
现在在MyWebHttpBehavior中覆盖ApplyDispatchBehavior并介绍上面实现的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
更新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.
我创建了一个库来包装这个Web http行为扩展。该库在方法参数(多个)中提供对其他值类型的更多支持。看一下这个。
#2
0
You need to supply a custom implementation of QueryStringConverter. Here's the code you need. Simply add the GuidConverterWebHttpBehavior as a service behavior and everything should just work.
您需要提供QueryStringConverter的自定义实现。这是您需要的代码。只需将GuidConverterWebHttpBehavior添加为服务行为,一切都应该正常工作。
class GuidQueryStringConverter : QueryStringConverter
{
public override bool CanConvert(Type type)
{
return type == typeof(Guid) || base.CanConvert(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
if (parameterType == typeof(Guid))
{
Guid guid;
if(Guid.TryParse(parameter, out guid))
{
return guid;
}
}
return base.ConvertStringToValue(parameter, parameterType);
}
}
public class GuidConverterWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new GuidQueryStringConverter();
}
}
#1
4
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.
看完你的评论后我明白了。所以你想提供字符串然后在OperationInovker进入图片之前投射它。所以我把手弄脏了,最后做到了。
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
.
这就是我所做的。一个派生自WebHttpBehavior的新类,它可以为我们提供扩展或覆盖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
.
虽然这是一个黑客,但这将有效。 Typed参数的问题在于,URL模板格式化程序通过检查类型字符串的方法签名来抛出异常,因此我通过覆盖方法GetRequestDispatchFormatter来覆盖BindingInformation。
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
.
应用此行为后,运行时将不再为String参数检查抛出异常。现在我需要更改OperationInvoker,因为如果你运行它,那么当你从客户端调用无效转换时,这将抛出excpetion。
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.
现在来看IOperationInvoker图片。我只是从类型对象的input []中获取值,将值从String转换为Guid并将其传递回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 * answer here. And implemented the way person suggested and it worked.
现在我花了很长时间才弄清楚如何在管道中注入这个自定义操作inovker。我在这里找到了相关的*答案。并实现了人们建议和工作的方式。
Adding summary here: A new IOperationBehavior has to be implemented and attach it with DispatcherRuntime.
在此处添加摘要:必须实现新的IOperationBehavior并将其与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
.
现在在MyWebHttpBehavior中覆盖ApplyDispatchBehavior并介绍上面实现的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
更新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.
我创建了一个库来包装这个Web http行为扩展。该库在方法参数(多个)中提供对其他值类型的更多支持。看一下这个。
#2
0
You need to supply a custom implementation of QueryStringConverter. Here's the code you need. Simply add the GuidConverterWebHttpBehavior as a service behavior and everything should just work.
您需要提供QueryStringConverter的自定义实现。这是您需要的代码。只需将GuidConverterWebHttpBehavior添加为服务行为,一切都应该正常工作。
class GuidQueryStringConverter : QueryStringConverter
{
public override bool CanConvert(Type type)
{
return type == typeof(Guid) || base.CanConvert(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
if (parameterType == typeof(Guid))
{
Guid guid;
if(Guid.TryParse(parameter, out guid))
{
return guid;
}
}
return base.ConvertStringToValue(parameter, parameterType);
}
}
public class GuidConverterWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new GuidQueryStringConverter();
}
}