1. WCF虚拟路径解析(WcfVirtualPathProvider.cs)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Hosting; using System.Web.Caching; using System.Collections; namespace DynamicWcfApp { public class WcfVirtualPathProvider : VirtualPathProvider { public override bool FileExists(string virtualPath) { var appRelativeVirtualPath = ToAppRelativeVirtualPath(virtualPath); if (IsVirtualFile(appRelativeVirtualPath)) { return true; } else { return Previous.FileExists(virtualPath); } } public override System.Web.Hosting.VirtualFile GetFile(string virtualPath) { var appRelativeVirtualPath = ToAppRelativeVirtualPath(virtualPath); if (IsVirtualFile(appRelativeVirtualPath)) { var servicePath = VirtualPathUtility.MakeRelative(Constants.VirtualWcfDirectoryName + "/", virtualPath); if (servicePath.EndsWith(".svc")) servicePath = servicePath.Substring(0, servicePath.IndexOf(".svc")); // check if (!servicePath.Contains(".")) return Previous.GetFile(virtualPath); var assemblyLocation = System.IO.Path.Combine(Constants.AbsolutePath, servicePath.Split('.')[0] + ".dll"); if (!System.IO.File.Exists(assemblyLocation)) return Previous.GetFile(virtualPath); return new WcfVirtualFile(virtualPath, servicePath, typeof(WcfVirtualServiceHostFactory).FullName); } else { return Previous.GetFile(virtualPath); } } public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { var appRelativeVirtualPath = ToAppRelativeVirtualPath(virtualPath); if (IsVirtualFile(appRelativeVirtualPath) || IsVirtualDirectory(appRelativeVirtualPath)) { return null; } else { return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } } private bool IsVirtualFile(string appRelativeVirtualPath) { if (appRelativeVirtualPath.StartsWith(Constants.VirtualWcfDirectoryName + "/", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } private bool IsVirtualDirectory(string appRelativeVirtualPath) { return appRelativeVirtualPath.Equals(Constants.VirtualWcfDirectoryName, StringComparison.OrdinalIgnoreCase); } private string ToAppRelativeVirtualPath(string virtualPath) { var appRelativeVirtualPath = VirtualPathUtility.ToAppRelative(virtualPath); if (!appRelativeVirtualPath.StartsWith("~/")) { throw new HttpException("Unexpectedly does not start with ~."); } return appRelativeVirtualPath; } } public class Constants { public static readonly string VirtualWcfDirectoryName = "~/WcfLibs"; public static readonly string AbsolutePath = HttpContext.Current.Server.MapPath("~/WcfLibs"); } }另外提醒各位看官注意:在 Provider 里 无法直接使用 HttpContext.Current.Server.MapPath 来寻找绝对路径(HttpContext.Current 是 null),因此提前用 Constants 在启动时保存了绝对路径的信息。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Hosting; using System.IO; using System.Globalization; using System.Web; namespace DynamicWcfApp { public class WcfVirtualFile : VirtualFile { private string _service; private string _factory; public WcfVirtualFile(string vp, string service, string factory) : base(vp) { _service = service; _factory = factory; } public override Stream Open() { var ms = new MemoryStream(); var tw = new StreamWriter(ms); tw.Write(string.Format(CultureInfo.InvariantCulture, "<%@ServiceHost language=c# Debug=\"true\" Service=\"{0}\" Factory=\"{1}\"%>", HttpUtility.HtmlEncode(_service), HttpUtility.HtmlEncode(_factory))); tw.Flush(); ms.Position = 0; return ms; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Reflection; using System.ServiceModel.Activation; using System.ServiceModel; using System.ServiceModel.Description; namespace DynamicWcfApp { public class WcfVirtualServiceHostFactory : ServiceHostFactory { public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) { var assmblyName = constructorString.Split('.')[0] + ".dll"; var serviceName = constructorString; assmblyName = System.IO.Path.Combine(Constants.AbsolutePath, assmblyName); var assembly = Assembly.LoadFile(assmblyName); var serviceType = assembly.GetType(serviceName); var host = new ServiceHost(serviceType, baseAddresses); foreach (var iface in serviceType.GetInterfaces()) { var attr = (ServiceContractAttribute)Attribute.GetCustomAttribute(iface, typeof(ServiceContractAttribute)); if (attr != null) host.AddServiceEndpoint(iface, new BasicHttpBinding(), ""); } var metadataBehavior = new ServiceMetadataBehavior(); metadataBehavior.HttpGetEnabled = true; host.Description.Behaviors.Add(metadataBehavior); return host; } } }
HostingEnvironment.RegisterVirtualPathProvider(new WcfVirtualPathProvider());
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); HostingEnvironment.RegisterVirtualPathProvider(new WcfVirtualPathProvider()); }