zoukankan      html  css  js  c++  java
  • WCF开发之宿主(Hosting) (转载)

    WCF想要对外提供服务,那么需要一个宿主来容纳这些服务。

    宿主环境
    • Self-hosting
    – 控制台应用程序,Windows应用程序,Windows服务
    – HTTP, TCP, named pipes, Microsoft® Message Queuing (MSMQ)
    • IIS/Microsoft® ASP.NET
    – HTTP
    • Windows Activation Service (windows2008/IIS7的新东西)
    – HTTP, TCP, named pipes, MSMQ

    下面分别介绍这几种不同的宿主:

    Self-Hosting
    • ServiceHost实例必须进行初始化来为服务暴露出端点(endpoint)
    • 每个ServiceHost与指定的服务类型(接口)相关联
    • Self-hosting环境手动创建实例
    • 核心方法:
    – Open() – 打开信道监听器
    – Close() – 关闭信道监听器

    ServiceHost配置(1)
    • 可以通过程序进行配置:
    ServiceHost host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService));
    host.AddServiceEndpoint(typeof(HelloIndigo.IHelloIndigoService), new NetTcpBinding(),"net.tcp://localhost:9000/HelloIndigo");
    host.Open();

    ServiceHost配置(2)
    以通过置设置进行初始化
    ServiceHost host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService));
    host.Open();

    • 可配:
    <system.serviceModel>
    <services>
    <service name="HelloIndigo.HelloIndigoService" >
    <endpoint address="net.tcp://localhost:9000/HelloIndigoService" binding="netTcpBinding" contract="HelloIndigo.IHelloIndigoService" />
    </service>
    </services>
    </system.serviceModel>

    这2个Demo就不给大家作了,在前面的文章中作了无数遍,呵呵。节约时间,继续往下看。

    多服务(1)
    ServiceHost hostA = null;
    ServiceHost hostB = null;
    try
    {
    hostA = new ServiceHost(typeof(BusinessServices.ServiceA));
    hostB = new ServiceHost(typeof(BusinessServices.ServiceB));
    hostA.Open();
    hostB.Open();
    Console.ReadLine();
    }
    finally
    {
    hostA.Close();
    hostB.Close();
    }

    多服务(2)
    <services>
    <service name="BusinessServices.ServiceA">
    <endpoint address="http://localhost:8000/ServiceA" contract="BusinessServices.IServiceA" binding="basicHttpBinding" />
    </service>
    <service name="BusinessServices.ServiceB">
    <endpoint address="http://localhost:8000/ServiceB" contract="BusinessServices.IServiceB" binding="basicHttpBinding" />
    </service>
    </services>

    ServiceHost事件
    • 可以钩住ServiceHost事件:
    – Opening, Opened
    – Closing, Closed
    – Faulted, UnknownMessageReceived
    ServiceHost host = new ServiceHost(typeof(ExceptionService.Service));
    host.Faulted += new EventHandler(OnFaulted);
    host.Open();
    static void OnFaulted(object sender, EventArgs e)
    {
    // TODO: report to administrator
    }

    服务行为(Service Behaviors)
    • 可以通过程序与服务行为进行交互, 也可以通过配置的方式
    ServiceHost host = new ServiceHost(typeof(ExceptionService.Service));
    ServiceDebugBehavior debugBehavior = host.Description.Behaviors.Find<ServiceDebugBehavior>();
    if (debugBehavior == null)
    {
    debugBehavior = new ServiceDebugBehavior();
    host.Description.Behaviors.Add(debugBehavior);
    }
    debugBehavior.IncludeExceptionDetailInFaults = true;
    host.Open();

    IIS/WAS宿主
    请求根据.svc文件在IIS中的扩展映射到中WCFService中
    <% @ServiceHost="HelloIndigo.HelloIndigoService" %>
    • 服务类型与@ServiceHost的声明相关
    • ServiceHost实例化为服务类型

    Self-Hosting 与 IIS/WAS
    • Self-hosted的端点(endpoint)可以直接进行配置
    • IIS/WAS 端点与.svc文件相关联

    对于传统的IIS来说,如果WCF用它来做宿主,那么只支持Http的binding。

    对于传统的IIS作为宿主有一个好处,就是当客户端发起一个请求,每个不同的请求会在同一服务进程的不同Domain里处理,也就是说如果一个恶意的攻击成功了,他只会影响到某一个App Domain,其他的Domain不会受到影响仍然可以正常工作,服务本身的进程也不会受到影响、那些运行的dll也不会受到影响,这是IIS和.Net Framework的运行方式决定的,是特性。如果用命令行窗口程序的话,一旦恶意攻击成功,那么整个服务就用可能完全瘫痪。

    WAS(Windows Process Activation Service)他扩展出了不同Binding的监听器和接口,所以它可以适应更多的通信方式。IIS7中才支持。

    Demo:

    对于WAS目前只支持在IIS7中支持,并且操作系统Server2008。可以在Server Manager添加IIS7这个Feature,然后把WAS也同时安装进去,并且启动WAS服务Windows Process Activation Service。同时可以检查下Services里的相关监听器服务是否已启用(e.g. Net.Tcp.ListenerAdapter服务)。这些都没有问题了就可以使用WAS了。个人建议把所有WebServer的Feature都装上。

    VS2008可以创建一个Web方式的WCF工程,很方便,变成方式一样,配置方式也差不多。应为时IIS管理服务,如果在IE中看不到服务的话,可以尝试选中目标虚拟目录,双击Directory Browsing,然后启用即可,一般都可以搞定。

    唯一不太一样的地方是Service.svc: <%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %> 其他都差不多,配置是防盗Web.config里的。

    <%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>
    Web.config代码
    <?xml version="1.0" encoding="UTF-8"?>
    <!--
        Note: As an alternative to hand editing this file you can use the 
        web admin tool to configure settings for your application. Use
        the Website->Asp.Net Configuration option in Visual Studio.
        A full list of settings and comments can be found in 
        machine.config.comments usually located in 
        \Windows\Microsoft.Net\Framework\v2.x\Config 
    -->
    <configuration>


        
    <configSections>
          
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
            
    <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
              
    <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
              
    <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
                
    <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" />
                
    <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                
    <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                
    <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
              
    </sectionGroup>
            
    </sectionGroup>
          
    </sectionGroup>
        
    </configSections>  


        
    <appSettings />
        
    <connectionStrings />

        
    <system.web>
            
    <!--
                Set compilation debug="true" to insert debugging 
                symbols into the compiled page. Because this 
                affects performance, set this value to true only 
                during development.
            
    -->
            
    <compilation debug="false">

              
    <assemblies>
                
    <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                
    <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                
    <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                
    <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
              
    </assemblies>

            
    </compilation>
            
    <!--
                The <authentication> section enables configuration 
                of the security authentication mode used by 
                ASP.NET to identify an incoming user. 
            
    -->
            
    <authentication mode="Windows" />
            
    <!--
                The <customErrors> section enables configuration 
                of what to do if/when an unhandled error occurs 
                during the execution of a request. Specifically, 
                it enables developers to configure html error pages 
                to be displayed in place of a error stack trace.

            <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
                <error statusCode="403" redirect="NoAccess.htm" />
                <error statusCode="404" redirect="FileNotFound.htm" />
            </customErrors>
            
    -->


          
    <pages>
            
    <controls>
              
    <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            
    </controls>
          
    </pages>

          
    <httpHandlers>
            
    <remove verb="*" path="*.asmx" />
            
    <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            
    <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            
    <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false" />
          
    </httpHandlers>
          
    <httpModules>
            
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          
    </httpModules>


        
    </system.web>

        
    <system.codedom>
          
    <compilers>
            
    <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
              
    <providerOption name="CompilerVersion" value="v3.5" />
              
    <providerOption name="WarnAsError" value="false" />
            
    </compiler>
            
    <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
              
    <providerOption name="CompilerVersion" value="v3.5" />
              
    <providerOption name="OptionInfer" value="true" />
              
    <providerOption name="WarnAsError" value="false" />
            
    </compiler>
          
    </compilers>
        
    </system.codedom>

        
    <system.web.extensions>
          
    <scripting>
            
    <webServices>
              
    <!--
                  Uncomment this section to enable the authentication service. Include 
                  requireSSL="true" if appropriate. 

              <authenticationService enabled="true" requireSSL = "true|false"/>
              
    -->
              
    <!--
                  Uncomment these lines to enable the profile service, and to choose the 
                  profile properties that can be retrieved and modified in ASP.NET AJAX 
                  applications.

               <profileService enabled="true"
                               readAccessProperties="propertyname1,propertyname2"
                               writeAccessProperties="propertyname1,propertyname2" />
              
    -->
              
    <!--
                  Uncomment this section to enable the role service.

              <roleService enabled="true"/>
              
    -->
            
    </webServices>
            
    <!--
            <scriptResourceHandler enableCompression="true" enableCaching="true" />
            
    -->
          
    </scripting>
        
    </system.web.extensions>
        
    <!--
            The system.webServer section is required for running ASP.NET AJAX under Internet
            Information Services 7.0.  It is not necessary for previous version of IIS.
        
    -->
        
    <system.webServer>
          
    <validation validateIntegratedModeConfiguration="false" />
          
    <modules>
            
    <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          
    </modules>
          
    <handlers>
            
    <remove name="WebServiceHandlerFactory-Integrated" />
            
    <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            
    <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            
    <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          
    </handlers>
            
    <directoryBrowse enabled="true" />
        
    </system.webServer>


      
    <system.serviceModel>
        
    <services>
          
    <service name="Service" behaviorConfiguration="ServiceBehavior">
            
    <!-- Service Endpoints -->
            
    <endpoint address="wsHttp" binding="wsHttpBinding" contract="IService" name="wsHttpBinding_IService">
              
    <!-- 
                  Upon deployment, the following identity element should be removed or replaced to reflect the 
                  identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
                  automatically.
              
    -->
              
    <identity>
                
    <dns value="localhost" />
              
    </identity>
            
    </endpoint>

            
    <endpoint address="netTcp" contract="IService" binding="netTcpBinding" name="netTcpBinding_IService" />
            
    <endpoint address="netPipe" contract="IService" binding="netNamedPipeBinding" name="netNamedPipeBinding_IService" />
            
    <endpoint address="basicHttp" contract="IService" binding="basicHttpBinding" name="basicHttpBinding_IService" />
            
            
            
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          
    </service>
        
    </services>
        
    <behaviors>
          
    <serviceBehaviors>
            
    <behavior name="ServiceBehavior">
              
    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
              
    <serviceMetadata httpGetEnabled="true" />
              
    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
              
    <serviceDebug includeExceptionDetailInFaults="true" />
            
    </behavior>
          
    </serviceBehaviors>
        
    </behaviors>
      
    </system.serviceModel>
    </configuration>
    Service.cs 代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;

    // NOTE: If you change the interface name "IService" here, you must also update the reference to "IService" in Web.config.
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        
    string GetData(int value);
    }

    public class Service : IService
    {
        
    public string GetData(int value)
        {
            
    return string.Format("You entered: {0}", value);
        }
    }
    Client 代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ConsoleApplication1
    {
        
    class Program
        {
            
    static void Main(string[] args)
            {
                ServiceReference.ServiceClient proxy 
    = new ConsoleApplication1.ServiceReference.ServiceClient("wsHttpBinding_IService");
                
    string s = proxy.GetData(1);
                Console.WriteLine(s);

                proxy 
    = new ConsoleApplication1.ServiceReference.ServiceClient("netTcpBinding_IService");
                s 
    = proxy.GetData(2);
                Console.WriteLine(s);

                proxy 
    = new ConsoleApplication1.ServiceReference.ServiceClient("netNamedPipeBinding_IService");
                s 
    = proxy.GetData(3);
                Console.WriteLine(s);

                proxy 
    = new ConsoleApplication1.ServiceReference.ServiceClient("basicHttpBinding_IService");
                s 
    = proxy.GetData(4);
                Console.WriteLine(s);
            }
        }
    }

    可以看出客户端是通过名字来区别使用哪个通信协议的。

    在这里还要提一下WAS的配置方法,本人搞了半天才研究明白。

    这些是默认站点的Binding配置,使自动建立的,我们需要知道Type的名称。然后,把这些Type到家到服务的虚拟目录的Advanced-Settings里,如下图:

    只用作了上面的配置,WCF的服务才可以利用WAS来正常被客户端引用,否则会报出异常。

    Windows应用程序: 通常用于在客户端安装,来控制WCF服务的开启和关闭。

    Windows应用程序(1)
    • Windows® Forms 或者WPF
    • 从客户端主机暴露服务
    • 需要对上下文同步有所认识
    – UI线程或者其他线程
    • 值得注意:
    – ServiceHost需要手动打开
    –判断服务是否需要上下文同步

    Windows应用程序(2)
    • 如果ServiceHost在非UI线程上打开,服务操
    作会在新线程上进行操作
    • 如果在UI线程上调用,服务会自动加入到该线
    程上,除非UseSynchronizationContext
    设置为false
    – 可配置的服务行为(service behavior)

    有些东西要知道:

    [ServiceBehavior(UseSynchronizationContext=true, ConcurrencyMode=ConcurrencyMode.Reentrant)]主要区别在于对线程的管理。

    ConcurrencyMode.Single:对于一个服务对象的调用,同时只允许一个现成在处理。不可重入的调用模型。
    ConcurrencyMode.Reentrant:可重入的调用模型,同时只允许一个现成在处理,当一个调用请求调用了服务的一个方法,在服务方法中有调用了自己本身。
    ConcurrencyMode.Multiple:完全并发访问,同时只允许多个现成在处理,可重入,但要代码控制线程安全。

    Callback的过程:

    Client--Service Request-->Service (1)

    Client<--Callback Request--Service (2)

    Client--Callback Response-->Service (3)

    Client<--Service Response--Service (4) 

    总体看来,Window应用程序作为宿主,要考虑很多线程方便的东西,尤其是在callback的方式下,其他的宿主可以自动控制,所以相比之下Windows应用程序在这方便相对麻烦一些。

    Demo:

    MessagingService 代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Threading;
    using System.Windows.Forms;

    namespace Messaging
    {
        [ServiceContract(Namespace 
    = "http://www.cnblogs.com/charlesliu", CallbackContract = typeof(IMessagingServiceCallback))]
        
    public interface IMessagingService
        {
            [OperationContract(IsOneWay
    =false)]
            
    void SendMessage(string message);
        }

        
    public interface IMessagingServiceCallback
        {
            [OperationContract(IsOneWay
    =true)]
            
    void MessageNotification(string message);
        }

        [ServiceBehavior(UseSynchronizationContext
    =true, ConcurrencyMode=ConcurrencyMode.Reentrant)]
        
    public class MessagingService : IMessagingService
        {
            
    public void SendMessage(string message)
            {
                IMessagingServiceCallback callback 
    = OperationContext.Current.GetCallbackChannel<IMessagingServiceCallback>();
                MessageBox.Show(String.Format(
    "Message '{0}' received on thread {1} : MessageLoop = {2}", message, Thread.CurrentThread.GetHashCode(), Application.MessageLoop), "MessagingService.SendMessage()");
                callback.MessageNotification(
    string.Format("MessagingService received message at {0}", DateTime.Now.ToLongTimeString()));
            }
        }
    }
    Windows host 代码
    // © 2007 Michele Leroux Bustamante. All rights reserved 
    // Book: Learning WCF, O'Reilly
    // Book Blog: www.thatindigogirl.com
    // Michele's Blog: www.dasblonde.net
    // IDesign: www.idesign.net

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.ServiceModel;
    using System.Threading;

    namespace WindowsHost
    {
        
    public partial class Form1 : Form
        {
            ServiceHost m_serviceHost;

            
    public Form1()
            {
                InitializeComponent();
                
    this.button2.Enabled=false;

                m_serviceHost 
    = new ServiceHost(typeof(Messaging.MessagingService));
            }

            
    private void button1_Click(object sender, EventArgs e)
            {
                
    this.button1.Enabled = false;
                
    this.button2.Enabled = true;
                m_serviceHost.Open();
            }

            
    private void button2_Click(object sender, EventArgs e)
            {
                
    this.button1.Enabled = true;
                
    this.button2.Enabled = false;
                m_serviceHost.Close();
            }

            
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                DialogResult result 
    = MessageBox.Show("Are you sure you want to close the service?""Service Controller", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

                
    if (result == DialogResult.Yes)
                {
                    
    if (m_serviceHost != null)
                    {
                        m_serviceHost.Close();
                        m_serviceHost 
    = null;
                    }
                }
                
    else
                    e.Cancel
    =true;
            }

            
    private void Form1_Load(object sender, EventArgs e)
            {
                
    this.Text += ": UI Thread " + Thread.CurrentThread.GetHashCode();
            }


        }
    }
    Host config代码
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <system.web>
        
    <compilation debug="true" />
      
    </system.web>
      
    <!-- When deploying the service library project, the content of the config file must be added to the host's 
      app.config file. System.Configuration does not support config files for libraries. 
    -->
      
    <system.serviceModel>
        
    <services>
          
    <service name="Messaging.MessagingService" behaviorConfiguration="Messaging.Service1Behavior">
            
    <host>
              
    <baseAddresses>
                
    <add baseAddress = "net.tcp://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/" />
                
    <add baseAddress = "http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/" />
              
    </baseAddresses>
            
    </host>
            
    <!-- Service Endpoints -->
            
    <!-- Unless fully qualified, address is relative to base address supplied above -->
            
    <endpoint address ="" binding="netTcpBinding" contract="Messaging.IMessagingService">
              
    <!-- 
                  Upon deployment, the following identity element should be removed or replaced to reflect the 
                  identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
                  automatically.
              
    -->
              
    <identity>
                
    <dns value="localhost"/>
              
    </identity>
            
    </endpoint>
            
    <!-- Metadata Endpoints -->
            
    <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
            
    <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
            
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          
    </service>
        
    </services>
        
    <behaviors>
          
    <serviceBehaviors>
            
    <behavior name="Messaging.Service1Behavior">
              
    <!-- To avoid disclosing metadata information, 
              set the value below to false and remove the metadata endpoint above before deployment 
    -->
              
    <serviceMetadata httpGetEnabled="True"/>
              
    <!-- To receive exception details in faults for debugging purposes, 
              set the value below to true.  Set to false before deployment 
              to avoid disclosing exception information 
    -->
              
    <serviceDebug includeExceptionDetailInFaults="False" />
            
    </behavior>
          
    </serviceBehaviors>
        
    </behaviors>
      
    </system.serviceModel>
    </configuration>
    Client 代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    using WindowsClient.ServiceReference1;
    using System.ServiceModel;

    namespace WindowsClient
    {
        
    public partial class Form1 : Form
        {
            ServiceReference1.MessagingServiceClient proxy;

            
    public Form1()
            {
                InitializeComponent();
                
    this.Text += ": ThreadId " + Thread.CurrentThread.GetHashCode().ToString();
                MessagingServiceCallback callbackType 
    = new MessagingServiceCallback();
                InstanceContext context 
    = new InstanceContext(callbackType);
                proxy 
    = new MessagingServiceClient(context);

                
            }

            
    private void button1_Click(object sender, EventArgs e)
            {
                proxy.SendMessage(
    string.Format("Hello from {0} "this.Text));
            }
        }

        [CallbackBehavior(UseSynchronizationContext 
    = false)]
        
    internal class MessagingServiceCallback : IMessagingServiceCallback
        {
            
    #region IMessagingServiceCallback Members

            
    public void MessageNotification(string message)
            {
                MessageBox.Show(String.Format(
    "Message '{0}' received on thread {1} : MessageLoop = {2}", message, Thread.CurrentThread.GetHashCode(), Application.MessageLoop), "IMessagingServiceCallback.MessageNotification()");
            }

            
    #endregion
        }
    }

    Windows服务宿主

    • 用于无人值守的服务器主机
    • 也可以部署在客户端主机
    – 需要对Windows服务进行额外的配置
    • 当主机启动时,宿主环境初始化,如果发生错误可以重新启动
    • 打开与关闭Windows服务时,ServiceHost实例也会被打开与关闭

    Demo:

     

    Service 代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Threading;
    using System.Windows.Forms;

    namespace Messaging
    {
        [ServiceContract(Namespace 
    = "http://www.cnblogs.com/charlesliu")]
        
    public interface IMessagingService
        {
            [OperationContract]
            
    string SendMessage(string message);
        }

        [ServiceBehavior(UseSynchronizationContext
    =false)]
        
    public class MessagingService : IMessagingService
        {
            
    public string SendMessage(string message)
            {
                
    return String.Format("Message '{0}' received on thread {1}", message, Thread.CurrentThread.GetHashCode());
            }
        }
    }

     

    Windows Service Host代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.ServiceModel;
    using Messaging;

    namespace WindowsServiceHost
    {
        
    public partial class ServiceHost : ServiceBase
        {
            System.ServiceModel.ServiceHost host;

            
    public ServiceHost()
            {
                InitializeComponent();
                
    this.ServiceName = "MessageServiceHost_EventLog";
            }

            
    protected override void OnStart(string[] args)
            {
                host 
    = new System.ServiceModel.ServiceHost(typeof(MessagingService));
                host.Faulted
    +=new EventHandler(host_Faulted);
                host.Open();

                
    string baseAddresses = "";
                
    foreach (Uri address in host.BaseAddresses)
                {
                    baseAddresses 
    += " " + address.AbsoluteUri;
                }
                
    string s = String.Format("{0} listening at {1}"this.ServiceName, baseAddresses);
                
    this.EventLog.WriteEntry(s, EventLogEntryType.Information);
            }

            
    void host_Faulted(object sender, EventArgs e)
            {
                
    string s = String.Format("{0} has faulted, notify administrators of this problem"this.ServiceName);
                
    this.EventLog.WriteEntry(s, EventLogEntryType.Error);
            }

            
    protected override void OnStop()
            {
                
    if (host != null)
                {
                    host.Close();
                    
    string s = String.Format("{0} stopped"this.ServiceName);
                    
    this.EventLog.WriteEntry(s, EventLogEntryType.Information);
                }

                host 
    = null;
            }
        }
    }
    Host config 代码
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <system.web>
        
    <compilation debug="true" />
      
    </system.web>
      
    <!-- When deploying the service library project, the content of the config file must be added to the host's 
      app.config file. System.Configuration does not support config files for libraries. 
    -->
      
    <system.serviceModel>
        
    <services>
          
    <service name="Messaging.MessagingService" behaviorConfiguration="Messaging.Service1Behavior">
            
    <host>
              
    <baseAddresses>
                
    <add baseAddress = "net.tcp://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/" />
                
    <add baseAddress = "http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/" />
              
    </baseAddresses>
            
    </host>
            
    <!-- Service Endpoints -->
            
    <!-- Unless fully qualified, address is relative to base address supplied above -->
            
    <endpoint address ="" binding="netTcpBinding" contract="Messaging.IMessagingService">
              
    <!-- 
                  Upon deployment, the following identity element should be removed or replaced to reflect the 
                  identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
                  automatically.
              
    -->
              
    <identity>
                
    <dns value="localhost"/>
              
    </identity>
            
    </endpoint>
            
    <!-- Metadata Endpoints -->
            
    <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
            
    <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
            
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          
    </service>
        
    </services>
        
    <behaviors>
          
    <serviceBehaviors>
            
    <behavior name="Messaging.Service1Behavior">
              
    <!-- To avoid disclosing metadata information, 
              set the value below to false and remove the metadata endpoint above before deployment 
    -->
              
    <serviceMetadata httpGetEnabled="True"/>
              
    <!-- To receive exception details in faults for debugging purposes, 
              set the value below to true.  Set to false before deployment 
              to avoid disclosing exception information 
    -->
              
    <serviceDebug includeExceptionDetailInFaults="False" />
            
    </behavior>
          
    </serviceBehaviors>
        
    </behaviors>
      
    </system.serviceModel>
    </configuration>

    对于Windows Service的开发这里不详细探讨,可以参考其他学习资料。其实很简单,上边的就是核心代码,写完后再设计窗口右键鼠标,选择Add Installer,会自动产生安装类。然后再VS2008.NET Command窗口,用installutil servicename.exe (/u)来安装和写在Windows Service, 然后就可以在管理工具/Service下找到这个Service了,开启服务后,Client就可以调用WCF服务了。

    Client 代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    using WindowsClient.ServiceReference1;
    using System.ServiceModel;

    namespace WindowsClient
    {
        
    public partial class Form1 : Form
        {
            ServiceReference1.MessagingServiceClient proxy;

            
    public Form1()
            {
                InitializeComponent();
                
    this.Text += ": ThreadId " + Thread.CurrentThread.GetHashCode().ToString();

                proxy 
    = new MessagingServiceClient();

                
            }

            
    private void button1_Click(object sender, EventArgs e)
            {
                MessageBox.Show(proxy.SendMessage(
    string.Format("Hello from {0} "this.Text)));
            }
        }
    }

    宿主的应用场景
    • 在每个平台上选择不同类型的宿主
    • Windows Server® 2003
    – 在IIS 6上应用HTTP协议
    – 在Windows服务上应用non-HTTP
    • Windows Server® 2008(Longhorn)
    – 在IIS 7/WAS可以应用所有的协议
    • Windows® XP Service Pack 2 与Windows Vista®
    – 客户端主机运行Windows应用程序,或者Windows服务

    (完)

    转载地址:http://www.cnblogs.com/CharlesLiu/archive/2010/03/29/1689785.html

  • 相关阅读:
    人生转折点:弃文从理
    人生第一站:大三暑假实习僧
    监听器启动顺序和java常见注解
    java常识和好玩的注释
    182. Duplicate Emails (Easy)
    181. Employees Earning More Than Their Managers (Easy)
    180. Consecutive Numbers (Medium)
    178. Rank Scores (Medium)
    177. Nth Highest Salary (Medium)
    176. Second Highest Salary(Easy)
  • 原文地址:https://www.cnblogs.com/cuihongyu3503319/p/1868161.html
Copyright © 2011-2022 走看看