C# WCF数据服务中的自定义路由

C# WCF数据服务中的自定义路由,c#,c#-4.0,wcf-data-services,C#,C# 4.0,Wcf Data Services,我需要为WCF数据服务创建一个自定义路由,该服务包含一个必须提取以用于过滤数据的段 例如: 我需要从路线中提取客户123。看起来Route类可能提供类似的功能,但我不确定如何为数据服务实现IRoutHandler 这条路对吗?有好的例子吗 蒂亚 更新: 通过在IDispatchMessageInspector中重新编写一些自定义URL,我成功地实现了所需的解决方案。下面的代码是我最初的破解,需要一系列的清理。但是,它似乎在起作用。如果有人发现有什么大问题,请告诉我 public obj

我需要为WCF数据服务创建一个自定义路由,该服务包含一个必须提取以用于过滤数据的段

例如:

我需要从路线中提取客户123。看起来Route类可能提供类似的功能,但我不确定如何为数据服务实现IRoutHandler

这条路对吗?有好的例子吗

蒂亚

更新:

通过在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;
                }
            }

        }
    }

谢谢大家

我假设这是一个MVC项目

我相信MVC中的典型路线是这样工作的:

//url looks like /controller/Details/42
public ViewResult Details(int id) {
  //do something
}
routes.MapRoute(
           "my special little route", // Route name
           "customer/{Cid}/programs/{Pid}",
           new { controller = "customer", action = "Details" }
       );
您可以像这样添加自定义管线:

//url looks like /controller/Details/42
public ViewResult Details(int id) {
  //do something
}
routes.MapRoute(
           "my special little route", // Route name
           "customer/{Cid}/programs/{Pid}",
           new { controller = "customer", action = "Details" }
       );
因此,视图如下所示:

//url looks like /customer/{21}/programs/42
public ViewResult Details(int Cid, int Pid) {
  //do something
}

因此,从理论上讲,您应该能够对您的WCF服务做到这一点。除非我完全误解了你的意思,否则我很乐意尝试更新我的答案,另一个选择是使用从。。这将允许您直接访问URI。缺点是您必须使用Uri.Segments进行解析,然后将另一段代码绑定到Uri格式

您的问题最终源于一个事实,即WCF尽管声称不支持REST。REST应该是在URI标识的资源上进行的一组操作。相反,WCF提供了一个“静态”端点和一组比真正的REST更类似于旧的SkoolXML/SOAP的方法

我个人发现,在处理作用于URI/资源的REST服务时,WCF非常有问题。坦率地说,它没有什么价值,只是起了阻碍作用。有很多REST架构,很多都有相同的限制。您可以考虑WCF上的BAILD,并找到一个支持您想要公开的格式的有效载荷序列化库。
我目前最喜欢的是支持XML、JSON、协议缓冲区和URI编码的消息。有一个简单的介绍。尽管此示例也是一个服务端点,而不是基于资源的REST,但底层序列化模式确实是您所追求的。

在您的域中,
client123
代表什么?典型的情况是
http://mysample.net/mysamplesvc/Users?client=client123
但我想这不是你想要的?@oleksii:它实际上是我们saas产品的客户或租户。我们的想法是需要这个id,并通过查询参数来要求它,这似乎有点尴尬,与我们使用其他RESTful服务所做的不匹配。我也通过注册serviceroute来尝试实现此路由。问题在于,服务路由中似乎不支持占位符。请帮忙-感谢您的快速响应。这实际上不是一个MVC项目,不幸的是,我使用的是一个带有WCF数据服务的标准web项目。我没有尝试将MVC与WCF数据服务一起使用。你知道这是否可能吗?如果是的话,这可能是我的灵丹妙药,因为我对MVC路由更为熟悉。是的,你可以将WCF与MVC结合使用。不过,我并不完全确定路由,因为我通常通过
foo.com/service.svc
访问它,我会自己测试,但我正在测试VS 11,MS知道WCF数据服务模板有问题。对不起,但是你知道在ASP.net MVC应用程序中托管WCF数据服务的好例子吗?我似乎找不到任何适合我的情况。主要是将MVC站点绑定到WCF数据服务的示例。谢谢斯科特·汉斯曼(Scott Hanslmen)是一名关于使用SOs数据库的专家,而netflix odataThanks则负责休息。这是非常宝贵的。不幸的是,我不能完全确定我是否能够支持protobuf,因为我需要支持WCF数据服务的OData功能。还是我遗漏了什么?作为一种选择,我考虑使用WebOperationContext,但随后需要在没有clientid的情况下重新编写请求,以避免数据服务认为Client123是EF资源。我一直在摆弄这个,但我有点笨手笨脚。@RockyMountainHigh是的,如果你需要odata,你就卡住了。URL重写可能是最好的选择。我本想提出这个建议,但听起来你已经开始了:)有很多很棒的建议,但是@csharptest.net让我最接近我的最终解决方案,无论是对是错。谢谢