说起wcf,一直以来总是直接创建wpf的应用程序,这样默认的宿主是IIS。如果想更换宿主,那么我们首先得创建wcf类库。
这个类库会自动创建一个app.config文件。到最后部署的时候,把它移到宿主的项目下。看看IService1.cs:
1 using Newtonsoft.Json; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Runtime.Serialization; 6 using System.ServiceModel; 7 using System.Text; 8 9 namespace WcfServiceLibrary1 10 { 11 [ServiceContract] 12 public interface IService1 13 { 14 [OperationContract] 15 string GetDataUsingDataContract(CompositeType composite); 16 17 // TODO: 在此添加您的服务操作 18 } 19 20 // 可以将 XSD 文件添加到项目中。在生成项目后,可以通过命名空间“WcfServiceLibrary1.ContractType”直接使用其中定义的数据类型。 21 [DataContract] 22 public class CompositeType 23 { 24 [DataMember] 25 public string UserName{set;get;} 26 27 [DataMember] 28 public string FullName { set; get; } 29 30 [DataMember] 31 public string Sex { set; get; } 32 [DataMember] 33 public string Email { set; get; } 34 [DataMember] 35 public string Depart { set; get; } 36 /// <summary> 37 /// 工作性质 38 /// </summary> 39 [DataMember] 40 public string WorkType { set; get; } 41 [DataMember] 42 public string Phone { set; get; } 43 44 [DataMember] 45 public string ID { set; get; } 46 47 public string ToJson() 48 { 49 return JsonConvert.SerializeObject(this); 50 } 51 } 52 }
该接口只提供一个方法,接收一个对象,返回string,再来看它的实现:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Runtime.Serialization; 5 using System.ServiceModel; 6 using System.Text; 7 8 namespace WcfServiceLibrary1 9 { 10 public class Service1 : IService1 11 { 12 public string GetDataUsingDataContract(CompositeType composite) 13 { 14 if (composite == null) 15 { 16 throw new ArgumentNullException("composite"); 17 } 18 19 return "你好:" + composite.UserName; 20 } 21 } 22 }
然后,我们创建宿主程序。
一、wpf寄宿:
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Net; 6 using System.ServiceModel; 7 using System.ServiceModel.Description; 8 using System.Text; 9 using System.Threading.Tasks; 10 using System.Windows; 11 using System.Windows.Controls; 12 using System.Windows.Data; 13 using System.Windows.Documents; 14 using System.Windows.Input; 15 using System.Windows.Media; 16 using System.Windows.Media.Imaging; 17 using System.Windows.Navigation; 18 using System.Windows.Shapes; 19 using WcfServiceLibrary1; 20 21 namespace WpfInterface 22 { 23 public partial class MainWindow : Window 24 { 25 public MainWindow() 26 { 27 InitializeComponent(); 28 } 29 private void Window_Loaded(object sender, RoutedEventArgs e) 30 { 31 WCFInit(); 32 } 33 34 private ServiceHost Host = null; 35 void WCFInit() 36 { 37 if (Host == null) 38 { 39 Host = new ServiceHost(typeof(WcfServiceLibrary1.Service1)); 40 41 Host.Open(); 42 43 this.wcfService.Text = "wcf服务已启动"; 44 } 45 } 46 47 private void Window_Closed(object sender, EventArgs e) 48 { 49 if (Host != null) 50 { 51 Host.Close(); 52 } 53 } 54 } 55 }
ServiceHost来自 命名空间:System.ServiceModel,WcfServiceLibrary1.Service1来自类库,所以宿主项目必须引用 System.ServiceModel和wcf类库。39-41行,能够如此简洁地实例化ServiceHost,得益于App.config:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 4 <appSettings> 5 <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> 6 </appSettings> 7 <system.web> 8 <compilation debug="true" /> 9 </system.web> 10 <!-- 部署服务库项目时,必须将配置文件的内容添加到 11 主机的 app.config 文件中。System.Configuration 不支持库的配置文件。--> 12 <system.serviceModel> 13 14 <services> 15 <service name="WcfServiceLibrary1.Service1"> 16 <host> 17 <baseAddresses> 18 <add baseAddress = "http://localhost:8003/Service1/" /> 19 </baseAddresses> 20 </host> 21 <!-- Service Endpoints --> 22 <!-- 除非完全限定,否则地址将与上面提供的基址相关 --> 23 <endpoint address="" binding="basicHttpBinding" contract="WcfServiceLibrary1.IService1"> 24 <!-- 25 部署时,应删除或替换下列标识元素,以反映 26 用来运行所部署服务的标识。删除之后,WCF 将 27 自动推断相应标识。 28 --> 29 <identity> 30 <dns value="localhost"/> 31 </identity> 32 </endpoint> 33 <!-- Metadata Endpoints --> 34 <!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 --> 35 <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除--> 36 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 37 </service> 38 </services> 39 <behaviors> 40 <serviceBehaviors> 41 <behavior> 42 <!-- 为避免泄漏元数据信息, 43 请在部署前将以下值设置为 false --> 44 <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/> 45 <!-- 要接收故障异常详细信息以进行调试, 46 请将以下值设置为 true。在部署前设置为 false 47 以避免泄漏异常信息--> 48 <serviceDebug includeExceptionDetailInFaults="False" /> 49 </behavior> 50 </serviceBehaviors> 51 </behaviors> 52 </system.serviceModel> 53 54 </configuration>
wcf配置的三要素,简称ABC。
baseAddress:http://localhost:8003/Service1(地址)
binding:basicHttpBinding(通讯协议)
contract:WcfServiceLibrary1.IService1(契约)
针对这三要素,最复杂的和不好理解的就是bingding。binding背后隐藏了wcf的通讯机制,需要再单独研究。
二、word插件寄宿:
1 private void ThisAddIn_Startup(object sender, System.EventArgs e) 2 { 3 try 4 { 5 //创建宿主的基地址 6 Uri baseAddress = new Uri("http://localhost:8004/Service1"); 7 8 //创建宿主 9 host = new ServiceHost(typeof(WcfServiceLibrary1.Service1), baseAddress); 10 11 host.AddServiceEndpoint(typeof(WcfServiceLibrary1.IService1), new WSHttpBinding(), ""); 12 13 //将HttpGetEnabled属性设置为true 14 ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); 15 smb.HttpGetEnabled = true; 16 17 //将行为添加到Behaviors中 18 host.Description.Behaviors.Add(smb); 19 20 //打开宿主 21 host.Open(); 22 Console.WriteLine("WCF中的HTTP监听已启动...."); 23 } 24 catch (Exception ex) 25 { 26 Console.WriteLine(ex.Message); 27 } 28 finally 29 { 30 Console.WriteLine("word插件已启动"); 31 } 32 }
由于word插件中不能使用配置文件,所以WCF的ABC三要素硬编码实现。
注意:wcf宿主程序启动时,必须以管理员的权限启动,否则会报错。