• WCF服务承载(笔记)


    自托管(也做自承载)

        承载 WCF 服务最灵活、最便捷的方法就是进行自承载。要能够自承载服务,必须满足两个条件。第一,需要 WCF 运行时;第二,需要可以承载 ServiceHost 的托管 .NET 应用程序。您需要自己动手编写启动和停止宿主的代码。

    什么时候使用自托管?

            当应用程序的各个组件之间需要相互通信,或者在一个本地环境中,客户端和事务的数量都十分受限是常使用自托管。对于企业级方案来说不应考虑自承载方式。自承载适用于企业项目的开发或演示阶段。此外,当您希望用户桌面应用程序进行相互通信或在点对点情况下,可以对服务进行自承载。

    自承载的优点:

    • 易用性:只需几行代码即可使服务运行。

    • 灵活性:通过 ServiceHost<T> 的 Open() 和 Close() 方法,可以轻松控制服务的生存期。

    • 易调试性:可以使用熟悉的调试方式对自承载环境中承载的 WCF 服务进行调试,而不必连接到单个应用程序来激活服务。

    • 易部署性:通常,部署简单 Windows 应用程序与使用 xcopy 一样容易。您不必在服务器场和类似地方部署复杂的方案,即可部署简单的 Windows 应用程序来充当 WCF ServiceHost。

    • 支持所有绑定和传输:自承载并不限制您仅能使用现有的绑定和传输技术。在 Windows XP 和 Windows Server 2003 上,IIS 限制您只能使用 HTTP。(备注:II6以下)

     下面是自承载的缺点:

    •可用性受到限制:服务只有在应用程序运行时才能被访问。
    •功能受到限制:自承载的应用程序在对高可用性、易管理性、可靠性、可恢复性、版本控制和部署方案的支持方面受到一定限制。至少,现有的 WCF 无法提供这些支持,因此在自承载的情况中,您必须自己实现这些功能;例如,默认情况下 IIS 提供了这些功能中几项。

    下面是一个小例子

     1 using System.ServiceModel;
     2 
     3 namespace Halower.SelfHost
     4 {
     5     [ServiceContract(Namespace = "http://www.cnblogs.com/rohelm")]
     6     public interface ICalcuContract
     7     {
     8         [OperationContract]
     9         double Add(int x, int y);
    10 
    11         [OperationContract]
    12         double Substrate(int x, int y);
    13 
    14         [OperationContract]
    15         double Multiply(int x, int y);
    16 
    17         [OperationContract]
    18         double Divide(int x, int y);
    19     }
    20 }
    ICalcuContract
     1 namespace Halower.SelfHost
     2 {
     3     public class CalculatorService : ICalcuContract
     4     {
     5         public double Add(int x, int y)
     6         {
     7             return x + y;
     8         }
     9 
    10         public double Substrate(int x, int y)
    11         {
    12             return x - y;
    13         }
    14 
    15         public double Multiply(int x, int y)
    16         {
    17             return x * y;
    18         }
    19 
    20         public double Divide(int x, int y)
    21         {
    22             return x / y;
    23         }
    24     }
    25 }
    CalculatorService
     1 using System;
     2 using System.ServiceModel;
     3 using System.ServiceModel.Description;
     4 
     5 namespace Halower.SelfHost
     6 {
     7     internal class Program
     8     {
     9         private static void Main(string[] args)
    10         {
    11             Uri[] baseAddresses = new Uri[] {
    12                 new Uri("http://localhost:10101/CalculatorService"),
    13                  new Uri("net.tcp://localhost:10102/CalculatorService")
    14             };
    15             using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddresses))
    16             {
    17                 host.AddDefaultEndpoints();
    18                 try
    19                 {
    20                     host.Open();
    21                     Console.WriteLine("WCF服务已经启动!");
    22                     foreach (var endpoint in host.Description.Endpoints)
    23                     {
    24                         Console.WriteLine("	" + endpoint.Address.Uri.ToString());
    25                     }
    26                     Console.ReadKey();
    27                 }
    28                 catch (CommunicationException ex)
    29                 {
    30                     host.Abort();
    31                 }
    32             }
    33         }
    34     }
    35 }
    Host

      虽然我们知道每一个服务的实现只能有一个serviceHost,但是可以公开多个终结点和接口,同理,我们可以在同一个进程中创建多个serviceHost,而且我们有时候有需求控制他们的启动顺序,我们就是可以尝试着使用一下serviceHost异步启动的方式

     1 using System;
     2 using System.ServiceModel;
     3 
     4 namespace Halower.SelfHost
     5 {
     6     internal class Program
     7     {
     8         private static void Main(string[] args)
     9         {
    10             Uri[] baseAddresses = new Uri[] {
    11                 new Uri("http://localhost:10101/CalculatorService"),
    12                  new Uri("net.tcp://localhost:10102/CalculatorService")
    13             };
    14             using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddresses))
    15             {
    16                 host.AddDefaultEndpoints();
    17                 IAsyncResult result = host.BeginOpen(new AsyncCallback(ServiceHostOpenCallBack), null);
    18                 while (!result.IsCompleted)
    19                 {
    20                     Console.WriteLine("做一些与服务无关的事情");
    21                 }
    22                 Console.ReadKey();
    23             }
    24         }
    25 
    26         private static void ServiceHostOpenCallBack(IAsyncResult ar)
    27         {
    28             Console.WriteLine("服务1已经启动!");
    29             ServiceHost host2 = new ServiceHost(typeof(CalculatorService), new Uri("http://localhost:10103/CalculatorService"));
    30             Console.WriteLine("服务2即将启动!");
    31             host2.Open();
    32             Console.WriteLine("服务2已经启动!");
    33             host2.Close();
    34         }
    35     }
    36 }
    ServiceHost使用异步

    什么有时候需要自定义serviceHost?

      有些时候,我们需要在不同的地方重用配置参数相同的同一个ServiceHost类,例如,我们已经创建了一个ServiceHost对象,可以用编码的方式控制服务配置或者部分配置。在这种情况下,如果使用这个类,就需要扩展并编写自定义的ServiceHost类的实现。

      例如,.NET Framework 提供了专门宿主实现,都极大的方便了我们的操作,而不去自己配置某些关键项:

      WorkflowServiceHost 类,为基于工作流的服务提供宿主。

      WebServiceHost 类,它是对 Windows Communication Foundation (WCF) REST 编程模型的补充  

     1 [ServiceContract]
     2 public interface ICalculator
     3 {
     4     [OperationContract]
     5     [WebInvoke(UriTemplate = "add?x={x}&y={y}")]
     6     long Add(long x, long y);
     7 
     8     [OperationContract]
     9     [WebInvoke(UriTemplate = "sub?x={x}&y={y}")]
    10     long Subtract(long x, long y);
    11 
    12     [OperationContract]
    13     [WebInvoke(UriTemplate = "mult?x={x}&y={y}")]
    14     long Multiply(long x, long y);
    15 
    16     [OperationContract]
    17     [WebInvoke(UriTemplate = "div?x={x}&y={y}")]
    18     long Divide(long x, long y);
    19 
    20     [OperationContract]
    21     [WebGet(UriTemplate = "hello?name={name}")]
    22     string SayHello(string name);
    23 }
    24 
    25 public class CalcService : ICalculator
    26 {
    27     public long Add(long x, long y)
    28     {
    29         return x + y;
    30     }
    31 
    32     public long Subtract(long x, long y)
    33     {
    34         return x - y;
    35     }
    36 
    37     public long Multiply(long x, long y)
    38     {
    39         return x * y;
    40     }
    41 
    42     public long Divide(long x, long y)
    43     {
    44         return x / y;
    45     }
    46 
    47     public string SayHello(string name)
    48     {
    49         return "Hello " + name;
    50     }
    51 }
    52 
    53 class Program
    54 {
    55     static void Main(string[] args)
    56     {
    57         Uri baseAddress = new Uri("http://localhost:8000/");
    58 
    59         WebServiceHost svcHost = new WebServiceHost(typeof(CalcService), baseAddress);
    60 
    61         try
    62         {
    63             svcHost.Open();
    64 
    65             Console.WriteLine("Service is running");
    66             Console.WriteLine("Press enter to quit...");
    67             Console.ReadLine();
    68 
    69             svcHost.Close();
    70         }
    71         catch (CommunicationException cex)
    72         {
    73             Console.WriteLine("An exception occurred: {0}", cex.Message);
    74             svcHost.Abort();
    75         }
    76     }
    77 }
    WebServiceHostDemo

        自定义ServiceHost类说起来用以做起来难,简单的说,如果我们直接继承自ServiceHost,我们要从读取配置文件读取参数后修改他们就重写ServiceHost类的ApplyConfiguration,如果是在宿主创建之前修改配置参数,就可重写ServiceHost类的Opening方法

    IIS承载 

      在 IIS 上的 Web 服务开发长期以来一直是 ASP.NET 的领地。ASP.NET 1.0 发布后,Web 服务框架成为它的一部分。Microsoft 利用 ASP.NET HTTP 管道使 Web 服务在 Windows 平台上成为现实。遗憾的是,ASP.NET 和 Web 服务之间的这种紧密耦合在面向服务的世界中产生了几个限制,对 HTTP 的依赖性是主要原因。在不同宿主上运行 ASP.NET HTTP 管道很困难,因此很少采用这种方案。甚至在此后,ASP.NET Web 服务(也称为 ASMX 服务)在部署方案和配置依赖性方面一直是非常面向 Web 的。Microsoft 最初发布了几个版本的 Web 服务增强 (WSE),以弥补 ASP.NET Web 服务的某些局限,尤其是消除在实现 WS-* 协议方面的限制。但是,WSE 非常依赖于 ASP.NET Web 服务实现。
    WCF 服务采用了完全不同的途径来实现面向服务。WCF 的统一编程模型基于严格分层的模型,以分解面向 Web 的范例,并使服务模型和通道层与受支持的传输方式断开连接。此模型允许 WCF 支持几个不同的宿主,其中 IIS 是最重要的。
    构建 WCF 是为了支持 Windows XP、Windows Server 2003、Windows Vista 和 Windows Server 2007。自从 IIS 5.1(与 Windows XP 一起发布)以来,有了很多变化。但是,Microsoft 仍然继续支持旧版上的 WCF。这可能是因为 Microsoft .NET Framework 和 CLR 提供的功能所导致的,该功能是构建 WCF 的基础。

      IIS 7.0 推动了 Web 服务器领域中的又一重大演进。可以在图中看到两个重要改变。第一,现在特定于协议的侦听器适配器支持所有四种 WCF 传输,而不是仅限于 IIS 6.0 中的 HTTP 传输。此外,出现了称为 Windows 激活服务 (WAS) 的新操作系统服务。W3svc.exe 和 WAS 都运行在称为 SvcHost.exe 的操作系统宿主的内部。为了能够将 IIS 6.0 进程模型的强大功能与 WCF 结合使用,则需要进行这些更改。您可能会问“为什么?”好的,WCF 服务也工作在 IIS 5.1 和 IIS 6.0 中,那么,通过在 IIS 中推广进程模型和激活功能可以获得什么好处呢?很简单:通过推广激活概念使它与协议无关,而不是绑定到 HTTP,可以将平台的激活功能扩展到几乎所有传输类型。

    .

    IIS 7.0 进程模型体系结构 

     

      HTTP、TCP/IP、命名管道和 MSMQ 的特定于协议的侦听器适配器运行于它们自己的进程内部,并将特定传输桥接到 WAS。侦听器适配器要求 WAS 激活工作进程,然后将实际通信转交给这些工作进程内部的特定协议处理程序。因此,WAS 现在拥有 W3svc.exe 中具备的所有功能。通过将此责任拆分成多个单独的进程,其他三种传输也受益于过去内置在 IIS 6.0 中但只用于 HTTP 的进程模型和激活功能。总而言之,使用 IIS 7.0 可以跨越 IIS 中提供的任何传输类型承载任何 WCF 服务

          IIS承载WCF服务的功能建立在Asp.net HTTP管道的基础上,这意味着这类宿主你支持HTTP/HTTPS传输协议。ASP.NET HTTP 管道有HTTP处理器(HTTP Handler)和HTTP模块(HTTP Module)两个概念。尽管HTTP处理器是一个特殊类,可以用它截获及处理传入及传出的信息,但是HTTP处理器会专门负责处理特定的消息。当吧一个扩展名映射到一个实现IHttpHandler接口的类时,就会启动HTTP处理器。在WCF环境下,.svc文件是用来标识服务的扩展名。

    IIS承载WCF服务的的实现很简单,可是使用VS的一键发布工具轻松完成,以下是几个需要注意的地方:

    •      1.按需选择激活HTTP非HTTP协议功能
    •   2.为新建的网站按需添加的协议类型的绑定,为相应的应用程序也添加必须的协议
    •   3.如果安装了 .NET Framework 4,随后启用了 .NET Framework 3.5WCF HTTP 激活,则会发生如下错误。 

         若要解决该问题,请在 Visual Studio 命令提示符下运行下面的命令行:aspnet_regiis.exe -i -enable

  • 相关阅读:
    刷题系列
    元类编程
    Python内置方法与面向对象知识点进阶系列
    json反序列化的时候字符串为单引号的一个坑
    刨根问底,完美解决Django2版本连接MySQL报错的问题
    使用mkdocs撰写技术文档并免费部署上线
    关于Python的源文件编译看这一篇就够了
    SQL查询where语句后面字符串大小写问题
    configparser模块获取settings.ini文件中的配置数据
    Sharepoint 2013列表视图和字段权限扩展插件(免费下载)!
  • 原文地址:https://www.cnblogs.com/rohelm/p/3176592.html
Copyright © 2020-2023  润新知