WCF 数据服务中的自定义路由
我需要为 WCF 数据服务创建一个自定义路由,其中包含必须提取以用于过滤数据的段。
示例:
http://mysample.net/mysamplesvc/client123/Users
我需要提取 client123从路线。看起来 Route 类可能提供类似的东西,但我不确定如何为数据服务实现 IRouteHandler。
这是正确的道路吗?周围有好的例子吗?
蒂亚!
更新:
我已经成功通过 IDispatchMessageInspector 中的一些自定义 URL 重写来实现我需要的解决方案。下面的代码是我最初的黑客攻击,需要大量清理。但是,它似乎正在发挥作用。如果有人发现任何明显错误的地方,请告诉我。
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
...Additional logic for handling Query formats in OData
UriTemplate template = new UriTemplate("mysamplesvc/{ClientId}", true);
Uri prefix = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
Uri uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
UriTemplateMatch results = template.Match(prefix, uri);
if (results != null && !string.IsNullOrEmpty(results.BoundVariables["ClientId"]))
{
_clientId = results.BoundVariables["clientId"].ToString();
}
if (!string.IsNullOrEmpty(_clientId))
{
httpmsg.Headers.Add("ClientId", _clientId);
rewriteRequest();
}
return null;
}
private void rewriteRequest()
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
if (WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
{
Uri serviceUri = HttpContext.Current.Session["ServiceUri"] as Uri;
Uri requestUri = null;
UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
if (serviceUri == null)
{
UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri);
serviceUri = serviceUriBuilder.Uri;
HttpContext.Current.Session["ServiceUri"] = serviceUri;
}
if (serviceUri != null)
{
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUri;
UriBuilder requestUriBuilder = new UriBuilder(match.RequestUri);
string path = string.Empty;
if (match.RelativePathSegments[0] == _clientId)
{
foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
{
if (seg.Index != 0)
{
path += "/";
path += seg.Value;
}
}
}
else
{
foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
{
path += "/";
path += seg.Value;
}
}
UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri + path);
// because we have overwritten the Root URI, we need to make sure the request URI shares the same host
// (sometimes we have request URI resolving to a different host, if there are firewall re-directs
serviceUriBuilder.Host = serviceUri.Host;
requestUri = serviceUriBuilder.Uri;
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUri;
OperationContext.Current.IncomingMessageProperties["Via"] = requestUri;
}
}
}
}
谢谢大家!
I need to create a custom route for a WCF data service that contains a segment that must be extracted for use in filtering data.
Example:
http://mysample.net/mysamplesvc/client123/Users
I need to extract the client123 from the route. It looks like the Route class might provide something similar but I am not sure how to implement an IRouteHandler for a Data service.
Is this the correct path? Are there good examples around?
TIA!
UPDATE:
I have managed to achieve the solution I needed via some custom URL re-writing in the IDispatchMessageInspector. The below code is my initial hack and needs a bunch of clean-up. but, it appears to be working. If anybody sees anything galringly wrong, please let me know.
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
HttpRequestMessageProperty httpmsg = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
...Additional logic for handling Query formats in OData
UriTemplate template = new UriTemplate("mysamplesvc/{ClientId}", true);
Uri prefix = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
Uri uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
UriTemplateMatch results = template.Match(prefix, uri);
if (results != null && !string.IsNullOrEmpty(results.BoundVariables["ClientId"]))
{
_clientId = results.BoundVariables["clientId"].ToString();
}
if (!string.IsNullOrEmpty(_clientId))
{
httpmsg.Headers.Add("ClientId", _clientId);
rewriteRequest();
}
return null;
}
private void rewriteRequest()
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
if (WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
{
Uri serviceUri = HttpContext.Current.Session["ServiceUri"] as Uri;
Uri requestUri = null;
UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
if (serviceUri == null)
{
UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri);
serviceUri = serviceUriBuilder.Uri;
HttpContext.Current.Session["ServiceUri"] = serviceUri;
}
if (serviceUri != null)
{
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUri;
UriBuilder requestUriBuilder = new UriBuilder(match.RequestUri);
string path = string.Empty;
if (match.RelativePathSegments[0] == _clientId)
{
foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
{
if (seg.Index != 0)
{
path += "/";
path += seg.Value;
}
}
}
else
{
foreach (var seg in match.RelativePathSegments.Select((x, i) => new { Value = x, Index = i }))
{
path += "/";
path += seg.Value;
}
}
UriBuilder serviceUriBuilder = new UriBuilder(match.BaseUri + path);
// because we have overwritten the Root URI, we need to make sure the request URI shares the same host
// (sometimes we have request URI resolving to a different host, if there are firewall re-directs
serviceUriBuilder.Host = serviceUri.Host;
requestUri = serviceUriBuilder.Uri;
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUri;
OperationContext.Current.IncomingMessageProperties["Via"] = requestUri;
}
}
}
}
Thanks all!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
另一种选择是使用从以下位置获取的 IncomingWebRequestContext WebOperationContext。传入请求。这将允许您直接访问 URI。缺点是您必须使用 Uri.Segments 进行解析,然后将另一段代码与 uri 格式相关联。
您的问题最终源于这样一个事实:尽管 WCF 声称不支持 REST,但它并不支持 REST。 REST应该是对由 URI 标识的资源进行的一组操作。相反,WCF 提供了一个“静态”端点和一组比真正的 REST 更类似于 old-skool XML/SOAP 的方法。
我个人发现 WCF 在处理作用于 URI/资源的 REST 服务时存在很大问题。坦率地说,它几乎没有提供任何价值,而且只是造成了阻碍。市面上有很多 REST 架构,其中许多都遭受着同样的限制。您可能会考虑使用 WCF 并找到支持您想要公开的格式的有效负载序列化库。
我目前最喜欢的是 protobuf-csharp-port,它支持 XML、JSON、协议缓冲区和 URI 编码消息。有一个简单介绍使用 protobuf-csharp-port 构建 REST 服务。尽管此示例也是一个服务端点,而不是基于资源的 REST,但底层序列化模式确实是您所追求的。
Another option is to use the IncomingWebRequestContext obtained from WebOperationContext.IncomingRequest. This will allow you directly access to the URI. The downside is that you will have to parse with Uri.Segments and will then have another piece of code tied to the uri-format.
You're problem ultimately stems from the fact that WCF, for all it's claims, does not support REST. REST should be a set of operations that take place on a resource identified by the URI. Instead, WCF provides a 'static' endpoint and a set of methods more similar to old-skool XML/SOAP than true REST.
I've personally found WCF to very problematic when dealing with REST services that act on a URI/resource. Frankly it provided little value and just got in the way. There are lots of REST architectures out there, many suffer this same limitation. You might consider bailing on WCF and find a payload serialization library that supports the formats you want to expose.
My current favorite is protobuf-csharp-port which supports XML, JSON, Protocol Buffers, and URI encoded messages. There is a brief introduction to building a REST service using protobuf-csharp-port. Although this sample is also a service-endpoint and not resource-based REST, the underlying serialization pattern is really what you're after.
我假设这是一个 MVC 项目
,我相信 MVC 中的典型路由是这样工作的:
您可以像这样添加自定义路由:
所以视图看起来像:
所以理论上,您应该能够这样做您的 WCF 服务。除非我完全误解了你的意思,否则我会很乐意尝试更新我的答案
I'm assuming this is a MVC project
the typical routes in MVC, I believe, work like this:
You can add custom routes like this:
so the view then looks like:
so you should, in theory, be able to do that to your WCF service. Unless I'm completely misunderstanding what you're saying at which I will happily try to update my answer