2011-06-01 102 views
2

我有一个问题,使OutputCaching与HttpContext.RewritePath一起使用WCF 4.0 WebHttp服务。WCF休息4.0,动态路由和OutputCache

我的服务已本地化。这个想法是,你这样称呼一个URL:

/languageCode/ServiceName/Method 
e.g. 
/en/MyService/GetItems 

它会返回结果本地化到正确的语言。

我的计划基于this article。这个想法是创建一个RouteBase的衍生物,创建一个独特的“私人”路线到真正的服务。当用户提出请求时,语言代码将从URL中解压缩并设置为当前线程的文化,然后HttpContext.RewritePath用于加载实际服务。

对于我的生活,我无法弄清楚如何将OutputCaching加入混合。我用AspNetCacheProfile装饰了我的服务方法,并且看到我自己的VaryByCustom覆盖呼叫。尽管如此,尽管从VaryByCustom收到重复的结果,.NET继续进入我的服务方法。

下面有很多代码,对于转储抱歉,但我怀疑它是所有相关的。


如何我的Global.asax.cs

RouteTable.Routes.Add(new CulturedServiceRoute(
    "devices", 
    new StructureMapServiceHostFactory(), 
    typeof(DeviceService))); 

VaryByCustom是覆盖添加路由在Global.asax.cs中:

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; 
    } 

UPDATE:我的缓存配置文件:

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

回答

0

嗯好像对我有效的方法。缓存配置文件配置是否正确?是不是varyByCustom多次调用,并且某些缓存不需要更新时返回相同的结果?

+0

缓存配置文件似乎对我很好,我将它添加到问题的底部以防万一。 VaryByCustom每次肯定会返回相同的响应。 – roufamatic 2011-06-01 08:22:16

+0

就像测试一样,你可以去掉varyByHeader =“accept”varyByParam =“*”设置吗?所以只有varyByCustom仍然存在? – maartenba 2011-06-01 12:16:47

+0

我删除varyByHeader,但无法删除varyByParam(抛出一个异常),所以我只是把它留空。不用找了。 Hrmmm。与您的情况相比,我的情况非常简单,所以我将尝试使用BeginRequest和RewritePath更简单的方法。 – roufamatic 2011-06-01 16:09:22