无文件动态承载WCF服务

本文介绍如何在IIS中不使用.svc文件部署WCF服务,通过自定义虚拟路径提供者、虚拟文件及服务宿主工厂实现动态加载服务。适用于希望简化部署流程的开发者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

For hosting WCF Services in IIS you usually need a .svc file. This File exposes your Service.
With ASP.NET virtual Paths you have the opportunity to load your service without a .svc file.
You can put the WCF Service inside a DLL without adding a reference to the ASP.NET WebApp.

Implementation:

- Create a Class derived from VirtualPathProvider and override the MethodsGetFile and FileExists.
- Create a Class derived from VirtualFile and override the Method Open.
- Create a Class derived from ServiceHostFactory and override the MethodCreateServiceHost.
- The VirtualPathProvider manages the calling URLs and returns a VirtualFile, if the client calls a WCF Service.
- The VirtualFile generates the .svc Content.
- The ServiceHostFactory hosts the WCF Service.
- Register the VirtualPathProvider in global.asax

Here is the code: (VirtualPathProvider)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ServicePathProvider : VirtualPathProvider
{
    public override VirtualFile GetFile(string virtualPath)
    {
        if (!this.IsServiceCall(virtualPath))
            return this.Previous.GetFile(virtualPath);
        return new ServiceFile(virtualPath);
    }
 
    private bool IsServiceCall(string virtualPath)
    {
        // Check if it is a wcf service call
        virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);
        return (virtualPath.ToLower().StartsWith("~/srv_"));
    }
 
    public override bool FileExists(string virtualPath)
    {
        if (!this.IsServiceCall(virtualPath))
            return this.Previous.FileExists(virtualPath);
        return true;
    }
}

VirtualFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ServiceFile : VirtualFile
{
    public ServiceFile(string virtualPath)
        : base(virtualPath)
    { }
 
    public string GetCallingServiceName
    {
        get
        {
            // Return class name. srv_hello.svc => hello
            return base.VirtualPath.Replace("/srv_", string.Empty)
                        .Replace(".svc", string.Empty).ToLower();
        }
    }
 
    public string GetService()
    {
 
        string srv = this.GetCallingServiceName;
        // hello => Hello
        return srv[0].ToString().ToUpper() + srv.Substring(1);
    }
 
    public override Stream Open()
    {
        var serviceDef = new MemoryStream();
        var defWriter = new StreamWriter(serviceDef);
 
        // Write host definition
        defWriter.Write("<%@ ServiceHost Language=\"C#\" Debug=\"true\" Service=\"Services."+ this.GetService() + "\"  " +
                        "Factory=\"DynamicServices.DynamicHostFactory, DynamicServices\" %>");
        defWriter.Flush();
 
        serviceDef.Position = 0;
        return serviceDef;
    }
}

ServiceHostFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class DynamicHostFactory : ServiceHostFactory
{
    public DynamicHostFactory() { }
 
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        // Load bin/services.dll
        var asm = Assembly.Load("Services");
        var serviceType = asm.GetType(constructorString);
        var host = new ServiceHost(serviceType, baseAddresses);
 
        // Add endpoints. (In this example only IHello interface)
        foreach (Type contract in serviceType.GetInterfaces())
        {
            var attribute = (ServiceContractAttribute)
                Attribute.GetCustomAttribute(contract, typeof(ServiceContractAttribute));
            if (attribute != null)
                host.AddServiceEndpoint(contract, new BasicHttpBinding(), "");
        }
        // Add metdata behavior for generating wsdl
        var metadata = new ServiceMetadataBehavior();
        metadata.HttpGetEnabled = true;
        host.Description.Behaviors.Add(metadata);
 
        return host;
    }
}

Global.asax

1
2
3
4
void Application_Start(object sender, EventArgs e)
{
    HostingEnvironment.RegisterVirtualPathProvider(new ServicePathProvider());
}

Example:
I created a DLL (Services.dll) with a WCF service. Here the Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ServiceContract]
public interface IHello
{
    [OperationContract]
    string SayHello(string name);
}
 
public class Hello : IHello
{
    public string SayHello(string name)
    {
        return "Hello " + name;
    }
}

I compiled the DLL and copied it into the bin Folder of the ASP.NET Application.
When I start the WebApp and call the URL “http://localhost:{Port}/srv_hello.svc” the Service UI of the Hello Service (Services.dll) will be generated. Voila! ;)
WCF Service (DLL)

EDIT:
Since WCF 4.0 there is another way to achieve the same thing. It is called “file less activation”. :)
Example:

1
2
3
4
5
6
7
<system.servicemodel>
    <servicehostingenvironment>
      <serviceactivations>
        <add relativeaddress="/Hello" service="“svc_Hello.svc"/">
      </add></serviceactivations>
    </servicehostingenvironment>
  </system.servicemodel>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值