WCF Rest 4.0、动态路由和OutputCache

WCF Rest 4.0、动态路由和OutputCache,wcf,.net-4.0,routing,outputcache,webhttpbinding,Wcf,.net 4.0,Routing,Outputcache,Webhttpbinding,让OutputCaching与WCF 4.0 WebHttp服务的HttpContext.RewritePath一起工作时遇到问题 我的服务是本地化的。我们的想法是,您可以这样调用URL: /languageCode/ServiceName/Method e.g. /en/MyService/GetItems 它将返回本地化为正确语言的结果 我的计划是基于。其想法是创建RouteBase的衍生产品,从而创建到实际服务的唯一“私有”路由。当用户发出请求时,将从URL中解压缩语言代码并将其设置为当

让OutputCaching与WCF 4.0 WebHttp服务的
HttpContext.RewritePath
一起工作时遇到问题

我的服务是本地化的。我们的想法是,您可以这样调用URL:

/languageCode/ServiceName/Method
e.g.
/en/MyService/GetItems
它将返回本地化为正确语言的结果

我的计划是基于。其想法是创建RouteBase的衍生产品,从而创建到实际服务的唯一“私有”路由。当用户发出请求时,将从URL中解压缩语言代码并将其设置为当前线程的区域性,然后使用
HttpContext.RewritePath
加载实际服务

就我的一生而言,我不知道如何将输出缓存工作到混合中。我已经用
AspNetCacheProfile
修饰了我的服务方法,并且看到调用了我自己的
VaryByCustom
override。然而,尽管从
VaryByCustom
收到了重复的结果,.NET仍然继续进入我的服务方法

下面有很多代码,很抱歉转储,但我怀疑这一切都是相关的


如何在Global.asax.cs中添加路线

RouteTable.Routes.Add(new CulturedServiceRoute(
    "devices", 
    new StructureMapServiceHostFactory(), 
    typeof(DeviceService)));
Global.asax.cs中的VaryByCustom覆盖:

public override string GetVaryByCustomString(
    HttpContext context, string custom)
{

    // This method gets called twice: Once for the initial request, then a 
    // second time for the rewritten URL. I only want it to be called once!

    if (custom == "XmlDataFreshness")
    {
        var outputString = String.Format("{0}|{1}|{2}", 
            XmlDataLoader.LastUpdatedTicks, 
            context.Request.RawUrl, 
            context.Request.HttpMethod);
        return outputString;
    }

    return base.GetVaryByCustomString(context, custom);
}
这是动态服务路由类

public class CulturedServiceRoute : RouteBase, IRouteHandler
{
    private readonly string _virtualPath = null;
    private readonly ServiceRoute _innerServiceRoute = null;
    private readonly Route _innerRoute = null;

    public CulturedServiceRoute(
        string pathPrefix, 
        ServiceHostFactoryBase serviceHostFactory, 
        Type serviceType)
    {
        if (pathPrefix.IndexOf("{") >= 0)
        {
            throw new ArgumentException(
                "Path prefix cannot include route parameters.", 
                "pathPrefix");
        }
        if (!pathPrefix.StartsWith("/")) pathPrefix = "/" + pathPrefix;
        pathPrefix = "{culture}" + pathPrefix;

        _virtualPath = String.Format("Cultured/{0}/", serviceType.FullName);
        _innerServiceRoute = new ServiceRoute(
            _virtualPath, serviceHostFactory, serviceType);
        _innerRoute = new Route(pathPrefix, this);
    }

    public override RouteData GetRouteData(
        HttpContextBase httpContext)
    {
        return _innerRoute.GetRouteData(httpContext);
    }

    public override VirtualPathData GetVirtualPath(
        RequestContext requestContext, RouteValueDictionary values)
    {
        return null;
    }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        // This method is called even if VaryByCustom 
        // returns a duplicate response!

        var culture = requestContext.RouteData.Values["culture"].ToString();
        var ci = new CultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = ci;
        Thread.CurrentThread.CurrentCulture = 
            CultureInfo.CreateSpecificCulture(ci.Name);

        requestContext.HttpContext.RewritePath("~/" + _virtualPath, true);
        return _innerServiceRoute.RouteHandler.GetHttpHandler(requestContext);
    }
}
最后,服务本身的相关部分:

[ServiceContract]
[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class DeviceService
{
    [AspNetCacheProfile("MyCacheProfile")]
    [WebGet(UriTemplate = "")]
    public IEnumerable<DeviceListItemModel> GetDevices()
    {
        // This is called AFTER the first VaryByCustom override is called.
        // I'd expect it not to be called unless VaryByCustom changes!

        var devices =
            from d in _deviceRepository.GetAll()
            where d.ReleaseDate < DateTime.Now
            orderby d.Id descending
            select new DeviceListItemModel(d);

        return devices;
    }
[服务合同]
[aspnet兼容性要求(
RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
公共类设备服务
{
[AspNetCacheProfile(“MyCacheProfile”)]
[WebGet(UriTemplate=”“)]
公共IEnumerable GetDevices()
{
//这是在调用第一个VaryByCustom覆盖后调用的。
//我希望它不会被调用,除非VaryByCustom改变!
无功装置=
来自d in_devicepositional.GetAll()
其中d.ReleaseDate
更新:我的缓存配置文件:

<caching>
  <outputCacheSettings>
    <outputCacheProfiles>
      <add name="MyCacheProfile" varyByCustom="XmlDataFreshness"
           varyByHeader="accept" varyByParam="*" location="Server"
           duration="3600" />
    </outputCacheProfiles>
  </outputCacheSettings>
</caching>


Hmmm对我来说似乎是一种有效的方法。缓存配置文件配置正确吗?是否多次调用varyByCustom,并且在缓存不需要更新时一定会返回相同的结果?

Hmmm对我来说似乎是一种有效的方法。缓存配置文件配置正确吗?是否多次调用varyByCustom,并且为了在缓存不需要更新时返回相同的结果?

缓存配置文件对我来说似乎没问题,我将其添加到问题的底部以防万一。VaryByCustom每次肯定返回相同的响应。作为测试,您是否可以去掉varyByHeader=“accept”varybaram=“*”设置?所以只剩下varyByCustom?我删除了varyByHeader,但无法删除varyByParam(引发异常)所以我只是把它留白了。没有变化。Hrmmm。与你的情况相比,我的情况非常简单,所以我将尝试一种更为幼稚的方法来处理BeginRequest和RewritePath。它按照我之前的评论中的描述工作。仍然好奇为什么它不起作用,但没有那么紧急。:-)奇怪!我认为路由的GetHttpHandler路径重写可能会失败在缓存干扰的不方便时刻到来。应该使用系统中的调试器符号查看一下。Web:-)缓存配置文件对我来说似乎没问题,我将其添加到问题的底部以防万一。VaryByCustom每次肯定都返回相同的响应。作为测试,您能否去掉varyByHeader=“accept”varyByParam=“*”设置?所以只剩下varyByCustom?我删除了varyByHeader,但无法删除varyByParam(引发异常)所以我只是把它留白了。没有变化。Hrmmm。与你的情况相比,我的情况非常简单,所以我将尝试一种更为幼稚的方法来处理BeginRequest和RewritePath。它按照我之前的评论中的描述工作。仍然好奇为什么它不起作用,但没有那么紧急。:-)奇怪!我认为路由的GetHttpHandler路径重写可能会失败正在出现缓存干扰的不方便时刻。应该使用System.Web:-)中的调试器符号查看它