2011-06-01 113 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