基础分步 WCF WebService
创建和使用简单的 WCF Web 服务的基础步骤。
引言
在本文中,我将从头开始创建一个简单的学生注册 Web 服务,该服务使用 WCF 组件。本文不使用 Visual Studio 中的 WCF 项目模板,而是使用构建 WCF 技术的基础组件来创建此 WCF Web 服务。我将把组件分解为单独的离散程序集,以便您更全面地了解 WCF 的全貌。然后,我将在一个简单的控制台应用程序中托管此 Web 服务。最后,我将通过 WPF 应用程序客户端使用该 Web 服务。
背景
WCF 是用于创建分布式应用程序的多种技术的统一,包括 COM+、.NET Enterprise Services、MSMQ、.NET Remoting、Web 服务等,用于通信。因此,WCF 是一个非常广泛的话题,无法在一篇文章中全部涵盖。因此,您应该意识到本文只介绍了 WCF 功能的一小部分。但是,本文将尝试演示 WCF 最基本构建块和体系结构。
更重要的是,如果我们能够创建和测试一个主题,是不是更容易理解它?那么,让我们开始代码项目吧!
使用代码
(注意:为了简单起见,本项目将使用控制台应用程序来托管 Web 服务。有多种方法可以托管 WCF Web 服务。请参考其他讨论这部分内容的文章。另外请注意,本项目使用 Web 服务绑定,特别是 wsHTTPBinding。还有许多类型的绑定可供选择,本文未予讨论。)
第一步 - 定义 WebService 接口
提示 1:在本文中,我只为我们的服务创建一个接口,但您实际上可以在所需的项目中创建任意数量的接口。
提示 2:接口包含客户端可用于与服务器通信的操作、消息和数据的签名。
- 打开 Visual Studio 2010 并创建一个新项目。选择“类库”项目,并将其命名为 BasicWCFWebService。注意:我正在为 WebService 接口创建一个类库,以将其与服务宿主逻辑解耦,并使其可供客户端和宿主应用程序通用。
- 会生成一个默认的类文件 _Class1.cs_。将此文件重命名为 _IStudentEnrollmentService.cs_。此文件将包含此服务公开的“接口”。还将第一个项目重命名为 _SchoolServiceInterfaces_。
- 在“解决方案资源管理器”中,右键单击“引用”文件夹,然后单击“添加引用”。在“.NET”选项卡中,选择 System.ServiceModel 和 System.Runtime.Serialization 程序集,最后单击“确定”按钮。
- System.ServiceModel 包含
ServiceContractAttribute
属性的定义。 - System.Runtime.Serialization 包含
DataContractAttribute
属性的定义。
- System.ServiceModel 包含
- 在添加了后者的程序集引用后,通过为
System.ServiceModel
和System.Runtime.Serialization
命名空间添加using
语句来将其包含在代码中。
IStudentEnrollmentService.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace SchoolServiceInterfaces
{
[ServiceContract]
public interface IStudentEnrollmentService
{
[OperationContract]
void EnrollStudent(Student s);
[OperationContract]
Student[] GetEnrolledStudents();
}
[DataContract]
public class Student
{
private string name;
[DataMember]
public string StudentName
{
set { this.name = value; }
get { return this.name; }
}
}
}
第二步 - 创建数据库“模拟”类
创建一个新的类库项目,并将其命名为 _SchoolDatabase.cs_。
提示 3:这只是一个模拟数据库项目。您可以在实际项目中创建或使用真实的数据库对象。这就是我们为数据库创建单独项目的原因,以便我们可以模拟真实的数据库体系结构。请记住,数据库是一个独立的实体,不与我们的项目绑定。
StudentDatabase.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace SchoolDatabase
{
public class StudentDatabase
{
private static List<string> studentData = new List<string>();
public void AddStudent(string studentName)
{
studentData.Add(studentName);
}
public List<string> GetStudentList()
{
return studentData;
}
}
}
第三步 - 实现 Web 服务接口
- 创建一个新的类库项目,并将其命名为 _SchoolServices_,并将 _Class1.cs_ 重命名为 _StudentEnrollmentService.cs_。然后,添加对 SchoolDatabase 和 SchoolServiceInterfaces 项目的引用。为此,请右键单击 SchoolServices 项目中的“引用”文件夹,然后在“项目”选项卡中,选择 SchoolDatabase 和 StudentServiceInterfaces 项目。
- 实现
IStudentEnrollmentService
接口并使用StudentDatabase
类来存储学生信息。
StudentEnrollmentService.cs
using System;
using System.Collections.Generic;
using System.Text;
using SchoolServiceInterfaces;
using SchoolDatabase;
namespace SchoolServices
{
public class StudentEnrollmentService : IStudentEnrollmentService
{
public void EnrollStudent(Student s)
{
StudentDatabase sd = new StudentDatabase();
sd.AddStudent(s.StudentName);
}
public Student[] GetEnrolledStudents()
{
StudentDatabase sd = new StudentDatabase();
List<string>studentList = sd.GetStudentList();
Student[] studentArray = new Student[studentList.Count];
for (int i = 0; i < studentList.Count; i++)
{
Student s = new Student();
s.StudentName = studentList[i];
studentArray[i] = s;
}
return studentArray;
}
}
}
第四步 - 托管 Web 服务
- 要运行 Web 服务,我们必须托管它。在本文中,我们将只使用一个简单的控制台应用程序来托管我们的 Web 服务。
- 为此,请创建一个新的控制台应用程序项目,并将其命名为 SchoolServiceHost。然后添加对 .NET
System.ServiceModel
和我们的项目 **SchoolServices** 和 **SchoolServiceInterfaces** 的引用。System.ServiceModel 是一个 .Net 组件,包含 .Net Web 服务的基础机制,在这种情况下,使用 ServiceHost 创建服务宿主。我建议您阅读有关 System.ServiceModel 命名空间的更多内容。
Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using SchoolServices;
namespace SchoolServiceHost
{
class Program
{
static ServiceHost host = null;
static void StartService()
{
host = new ServiceHost(typeof(StudentEnrollmentService));
/***********
* if you don't want to use App.Config for the web service host,
* just uncomment below:
***********
host.AddServiceEndpoint(new ServiceEndpoint(
ContractDescription.GetContract(typeof(IStudentEnrollmentService)),
new WSHttpBinding(),
new EndpointAddress("https://:8732/awesomeschoolservice")));
**********/
host.Open();
}
static void CloseService()
{
if (host.State != CommunicationState.Closed)
{
host.Close();
}
}
static void Main(string[] args)
{
StartService();
Console.WriteLine("Student Enrollment Service is running....");
Console.ReadKey();
CloseService();
}
}
}
向 SchoolServiceHost 项目添加 _App.config_ 文件。这将包含我们 WCF Web 服务的 ABC 信息,即:
- “A”代表“地址” - 访问服务的位置。这定义了服务所在或可访问的终结点信息。
- “B”代表“绑定” - 访问服务的方式。这定义了用于访问此服务的传输协议。
- “C”代表“契约” - 在服务中访问什么。这定义了此 Web 服务提供的服务。
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- Server Configuration -->
<system.serviceModel>
<services>
<service name="SchoolServices.StudentEnrollmentService">
<endpoint
address="https://:8732/awesomeschoolservice"
binding="wsHttpBinding"
contract="SchoolServiceInterfaces.IStudentEnrollmentService" />
</service>
</services>
</system.serviceModel>
</configuration>
第五步 - 通过 WPF 客户端使用 Web 服务
添加一个新的 WPF 应用程序项目,并将其命名为 SchoolServiceClient。然后添加对 System.ServiceModel 和
SchoolServiceInterfaces
的引用。
提示 4:客户端只需要知道我们服务的签名,它不需要知道实现或服务是如何实现这些服务的,因此我们将只添加 **SchoolServiceInterfaces** 的引用,其中包含我们感兴趣的 Web 服务的契约。 **System.ServiceModel** 是一个 .Net 组件,包含 .Net Web 服务的基础机制,在这种情况下,使用 ChannelFactory 创建服务客户端。我建议您阅读有关 System.ServiceModel 命名空间的更多内容。
MainWindow.xaml
<Window x:Class="SchoolServiceClient.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="296" Width="293">
<Grid>
<Button Content="Enroll" Height="23" HorizontalAlignment="Left" Margin="184,12,0,0"
Name="enrollBtn" VerticalAlignment="Top" Width="75" Click="enrollBtn_Click" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="studentNameTxt"
VerticalAlignment="Top" Width="152" />
<Button Content="Get Enrolled Students" Height="23" HorizontalAlignment="Left" Margin="136,222,0,0"
Name="getEnrollBtn" VerticalAlignment="Top" Width="123" Click="getEnrollBtn_Click" />
<TextBox Height="165" HorizontalAlignment="Left" Margin="12,51,0,0" Name="enrolledTxt"
VerticalAlignment="Top" Width="247" />
</Grid>
</Window>
MainWindow.cs
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.ServiceModel; //contains the signature(message, data, operation) //of the web service using SchoolServiceInterface; namespace SchoolServiceClient { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void enrollBtn_Click(object sender, RoutedEventArgs e) { if (studentNameTxt.Text == "") return; using (ChannelFactory<IStudentEnrollmentService> schoolServiceProxy = new ChannelFactory<IStudentEnrollmentService>("MyStudentEnrollmentServiceEndpoint")) { schoolServiceProxy.Open(); IStudentEnrollmentService schoolEnrollmentService = schoolServiceProxy.CreateChannel(); Student s = new Student(); s.StudentName = studentNameTxt.Text; schoolEnrollmentService.EnrollStudent(s); schoolServiceProxy.Close(); } studentNameTxt.Text = ""; } private void getEnrollBtn_Click(object sender, RoutedEventArgs e) { enrolledTxt.Text = ""; using (ChannelFactory<IStudentEnrollmentService> schoolServiceProxy = new ChannelFactory<IStudentEnrollmentService>("MyStudentEnrollmentServiceEndpoint")) { schoolServiceProxy.Open(); IStudentEnrollmentService schoolEnrollmentService = schoolServiceProxy.CreateChannel(); Student[] enrolledStudents = schoolEnrollmentService.GetEnrolledStudents(); foreach (Student s in enrolledStudents) { enrolledTxt.AppendText(s.StudentName + "\n"); } schoolServiceProxy.Close(); } } } }
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- Client Configuration -->
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IStudentEnrollmentService" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://:8732/awesomeschoolservice"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IStudentEnrollmentService"
contract="SchoolServiceInterfaces.IStudentEnrollmentService" name="MyStudentEnrollmentServiceEndpoint">
</endpoint>
</client>
</system.serviceModel>
</configuration>
第六步 - 运行并测试 Web 服务
- 构建解决方案,然后转到 _SchoolServiceHost_ 和 _SchoolServiceClient_ 的输出目录。首先运行 _SchoolServiceHost.exe_,然后分别运行 _SchoolServiceClient.exe_。
关注点
解耦组件可大大提高应用程序的可维护性、可伸缩性和稳定性。本主题演示了 WCF 应用程序最基本的部分,而不是使用模板。构建这些小部分可为您提供灵活性,并深入了解其底层技术。现在,您应该能够利用对其体系结构及其构建块的基本理解来创建更高级的 WCF 应用程序。
欢迎您的反馈。