Removing the .svc Extension for RESTful WCF Services May, 2009
This has been done over and over on the web so I'll add my solution to the mix. Basically it automatically discovers the services in the web application and builds a static mapping table. Then it examines each request and attempts to find a mapping. If it finds one it performs the url rewriting, if not it lets it go though as is. Just register the module and your good to go.
Http Module:
public class ServiceAnonymityModule : IHttpModule { #region IHttpModule Implementation public void Dispose() { } public void Init(HttpApplication app) { app.BeginRequest += (s, e) => ServiceAnonymityMapper.EnsureServiceMapping(); } #endregion }
Mapping:
public static class ServiceAnonymityMapper { #region Private Fields private static IEnumerable<KeyValuePair<string, string>> serviceMapping; #endregion #region Static Constructor static ServiceAnonymityMapper() { serviceMapping = GetServiceMapping(); } #endregion #region Public Methods public static void EnsureServiceMapping() { string path = HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath; Func<KeyValuePair<string, string>, bool> serviceMatch = map => !path.StartsWith(map.Value) && ( path.StartsWith(map.Key + '?', StringComparison.OrdinalIgnoreCase) || path.StartsWith(map.Key + '/', StringComparison.OrdinalIgnoreCase) || string.Compare(path, map.Key, true) == 0 ); KeyValuePair<string, string> mapping = serviceMapping.FirstOrDefault(serviceMatch); if (mapping.Key != null && mapping.Value != null) { HttpContext.Current.RewritePath( mapping.Value + "/", path.Remove(0, mapping.Key.Length), HttpContext.Current.Request.QueryString.ToString(), false); } } #endregion #region Private Methods private static IEnumerable<KeyValuePair<string, string>> GetServiceMapping() { List<KeyValuePair<string, string>> serviceMapping = new List<KeyValuePair<string, string>>(); string webRoot = HttpContext.Current.Server.MapPath("~/"); string[] serviceFiles = Directory.GetFiles( webRoot, "*.svc", SearchOption.AllDirectories); Func<string, bool, string> getRelative = (path, ext) => "~/" + Path.Combine(Path.GetDirectoryName(path), ext ? Path.GetFileNameWithoutExtension(path) : Path.GetFileName(path)) .Remove(0, webRoot.Length).Replace('\\', '/'); var servicePaths = from servicePath in serviceFiles orderby servicePath.Length descending select new KeyValuePair<string, string>( getRelative(servicePath, true), getRelative(servicePath, false)); serviceMapping.AddRange(servicePaths); return serviceMapping; } #endregion }