我需要为 WCF 数据服务创建一个自定义路由,其中包含一个必须提取以用于过滤数据的段。
例子:
http://mysample.net/mysamplesvc/client123/Users
我需要从路由中提取 client123。看起来 Route 类可能提供类似的东西,但我不确定如何为数据服务实现 IRouteHandler。
这是正确的路径吗?周围有好的例子吗?
TIA!
更新:
我已经设法通过在 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;
}
}
}
}
谢谢大家!
最佳答案
另一种选择是使用 IncomingWebRequestContext从WebOperationContext获得. IncomingRequest .这将允许您直接访问 URI。缺点是您必须使用 Uri.Segments 进行解析,然后将另一段代码绑定(bind)到 uri 格式。
你的问题最终源于这样一个事实,即 WCF,就其所有声明而言,不支持 REST。 REST 应该 是一组发生在由 URI 标识的资源上的操作。相反,WCF 提供了一个“静态”端点和一组比真正的 REST 更类似于老式 XML/SOAP 的方法。
在处理作用于 URI/资源的 REST 服务时,我个人发现 WCF 非常有问题。坦率地说,它提供的值(value)很小,而且只是碍事。那里有很多 REST 架构,许多都受到同样的限制。您可能会考虑放弃 WCF 并找到一个支持您想要公开的格式的有效负载序列化库。
我目前最喜欢的是 protobuf-csharp-port它支持 XML、JSON、 Protocol Buffer 和 URI 编码消息。里面有简介building a REST service using protobuf-csharp-port .尽管此示例也是一个服务端点而不是基于资源的 REST,但底层序列化模式正是您所追求的。
关于c# - WCF 数据服务中的自定义路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8438233/