65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的 WCF 托管和消费

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.83/5 (5投票s)

2008年9月22日

CPOL

4分钟阅读

viewsIcon

51285

downloadIcon

989

简单的 WCF 托管和消费

引言

在本文中,我们将讨论 Windows Communication Foundation (WCF) 的托管选项以及如何消费 WCF 服务。WCF 服务的一种托管方式就像传统的 ASMX Web 服务一样,可以通过 Microsoft Internet Information Services (IIS) 进行托管。Microsoft .NET Framework 3.0 中显著增强了 WCF 服务的其他托管选项。我们不会讨论将托管模型扩展到包括 Windows 服务和自托管选项。我们只会在简单地探索 WCF 服务可用的 IIS 托管选项。

背景

最近,我试图找到一个简单的 WCF 示例,同时了解服务是如何创建的以及它是如何被消费的。然而,我找到的大部分示例要么过时,要么过于复杂,难以理解。因此,我决定自己创建一个。下面的示例使用了 Visual Studio 2008 的默认模板。

WCF 中的“ABC”

现在,这正成为一种理解 WCF 工作原理的流行方式。A 是地址 (Address),B 是绑定 (Binding),C 是契约 (Contract)。

地址是您通信的地方。这与您部署服务的地点不同,而是用于在内部映射请求和响应的 URL。

绑定是您通信的方式。有几种默认的绑定,如 BasicHttp、TCP、NamedPipes、MSMQ 等等。这是服务器和客户端在通信时理解的协议。

契约是您通信的内容。有关契约的详细信息,请参阅下一节。

创建 WCF 服务

首先创建一个新的 Visual Studio 2008 项目,然后选择 WCF 服务应用程序作为新项目。

main.JPG

创建服务契约

在 WCF 中,所有服务都公开为契约。契约是一种描述服务功能的中立方式。下面我们主要讨论四种类型的契约。

服务合同

此契约描述了客户端可以对服务执行的所有可用操作。.NET 使用 System.ServiceModel 命名空间来处理 WCF 服务。ServiceContract 属性用于定义服务契约。我们可以将此属性应用于类或接口。ServiceContract 属性将 CLR 接口(或类)公开为 WCF 契约。OperationContract 属性用于显式指示哪个方法将作为 WCF 契约的一部分公开。我们只能将 OperationContract 属性应用于方法,而不能应用于属性或索引器。[ServiceContract] 应用于类或接口级别。[OperationContract] 应用于方法级别。

[ServiceContract]
public interface IService1 
{
[OperationContract]
Response GetMessage(Request request);

[OperationContract]
string SayHello();

[OperationContract]
string WelcomeHello(string Name);

[OperationContract]
string ViewHello(Request request);

[OperationContract]
int AddService(AddCalculator Number);
}

数据合同

此契约定义了在服务中传递和返回的数据类型。[DataContract] 属性用于自定义数据类型的定义级别,即类或结构级别。[DataMember] 属性用于字段、属性和事件。

// Use a data contract as illustrated in the sample below to add composite
// types to service operations.
[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Request
{
string name;

[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}

[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Response
{
string message;

[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}

[DataContract(Namespace = 
	"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class AddCalculator
{
int x, y;

[DataMember]
public int First_Integer
{
get { return x; }
set { x = value; }
}

[DataMember]
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}

错误合同

此契约描述了服务引发的错误。[FaultContract(<>)] 属性用于定义故障契约。

消息契约

此契约提供了对 SOAP 消息结构的直接控制。这在互操作性场景以及需要遵守现有消息格式的情况下非常有用。[MessageContract] 属性用于将类型定义为 Message 类型。[MessageHeader] 属性用于我们想要放入 SOAP 头的类型的成员。[MessageBodyMember] 属性用于我们想要放入消息 SOAP 主体部分的类型的成员。

在许多情况下您可能想使用此功能,但这超出了本指南的范围。这两种契约可以放在同一个文件中,也可以放在不同的文件中。在我们的例子中,我们将其放入 IService1.cs

构建服务逻辑/内容

您可以将服务逻辑构建到一个新的 C# 文件中,该文件可以在 Service1.svc 的 C# 后台文件中创建,其名称为 Service1.svc.cs

Service1.svc 的内容如下

<%@ServiceHost Language="C#" Service="CalculatorService.Service1"
    CodeBehind="Service1.svc.cs" %>

您可以通过添加 DLL 文件作为引用来将服务逻辑更改为 DLL 服务逻辑,此时 Service1.svc 的内容将如下所示

<%@ServiceHost Language="C#" Service="SampleService.Service" %>

Service1.svc.cs 的内容是设置服务逻辑的地方。我们也可以将其称为 [OperationBehavior]

namespace CalculatorService
{
// NOTE: If you change the class name "Service1" here, you must also update the
// reference to "Service1" in Web.config and in the associated .svc file.
public class Service1 : IService1
{
[OperationBehavior]
public Response GetMessage(Request request)
{
//a response object to return
Response response = new Response();
//check if the request is null, then send error.
if (request == null)
{
response.Message = "Error!";
}
else
{
//set the message
response.Message = "Hello," + request.Name;
}
return response;
}

[OperationBehavior]
// Function that returns a string
public string SayHello()
{
return "Welcome to First WCF Service! \n\nPlease Enter Your Name";
}

[OperationBehavior]
// Function that returns a string by passing one value in
public string WelcomeHello(string Name)
{
return "Hello, " + Name;
}

[OperationBehavior]
// Function that returns an object by passing one value in
public string ViewHello(Request request)
{
//a response object to return
Response response = new Response();
//check if the request is null, then send error.
if (request.Name == null)
{
response.Message = "No Message";
}
if (request == null || request.Name == "")
{
response.Message = response.Message + "Error!";
}
else
{
//set the message
response.Message = response.Message + "Hello, " + request.Name;
}

return response.Message;
}

[OperationBehavior]
// Function that returns a string by passing one value in
public int AddService(AddCalculator Number)
{
return Number.First_Integer + Number.Second_Integer;
}
}
}

测试服务

运行服务时,您将看到下面的页面

done.JPG

创建 WCF Windows 控制台客户端

创建一个新的 Windows 项目,然后选择控制台应用程序作为新项目。创建新项目后,右键单击项目并单击“添加服务引用”。

addservice.JPG

添加服务后,将创建 app.config 文件,并在解决方案资源管理器中获得一个名为“服务引用”的新文件夹。

addservice2.JPG

编辑 app.config 文件。将所有绑定从 wsHttpBinding 更改为 BasicHttpBinding

创建服务代理

服务代理用于与服务通信。

using System;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace CalculatorService
{
[ServiceContract]
public partial interface IService1
{
[OperationContract]
Response GetMessage(Request request);

[OperationContract]
string ViewHello(Request request);

[OperationContract]
string SayHello();

[OperationContract]
string WelcomeHello(string Name);

[OperationContract]
int AddService(AddCalculator Number);
}

[DataContractAttribute(Namespace =
    http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09)] 
    [SerializableAttribute()]
public class Request
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string name;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public string Name
{
get { return name; }
set { name = value; }
}
}

[DataContractAttribute(Namespace =
    "http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class Response
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string message;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public string Message
{
get { return message; }
set { message = value; }
}
}

[DataContractAttribute(Namespace =
    "http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class AddCalculator
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int x,y = 0;

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public int First_Integer
{
get { return x; }
set { x = value; }
}

[DataMemberAttribute]
// Data Member Name must be same as the Data Contract In the Service
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}

public partial class SampleServiceClient : ClientBase, IService1
{
public SampleServiceClient()
{ }
public SampleServiceClient(string endpointConfigurationName) : base(
    endpointConfigurationName)
{ }
public SampleServiceClient(string endpointConfigurationName,
    string remoteAddress) : base(endpointConfigurationName, remoteAddress)
{ }
public SampleServiceClient(string endpointConfigurationName,
    System.ServiceModel.EndpointAddress remoteAddress) : 
    base(endpointConfigurationName,
    remoteAddress)
{ }

public Response GetMessage(Request request)
{
return Channel.GetMessage(request);
}

public string SayHello()
{
return Channel.SayHello();
}

public string WelcomeHello(string name)
{
return Channel.WelcomeHello(name);
}

public string ViewHello(Request request)
{
return Channel.ViewHello(request);
}

public int AddService(AddCalculator Number)
{
return Channel.AddService(Number);
}
}
}

客户端主程序代码

namespace WindowServiceClient
{
class Program
{
static void Main(string[] args)
{
Request request = new Request();
SampleServiceClient service = new SampleServiceClient("BasicHttpBinding_IService1");
// Initiate Welcome Screen
Console.WriteLine(service.SayHello());
Console.WriteLine("\nPlease Enter Your Name \n");
// Say Hello to user entry - Test Return String via string input
string name = Console.ReadLine();
Console.WriteLine(service.WelcomeHello(name));

Console.WriteLine("\nPlease Enter a message \n");
// Say Hello to user entry - Test Return string via string input to object
request.Name = Console.ReadLine();
Console.WriteLine(service.ViewHello(request));

// Say Hello to user entry - Test Return object with string as member via string
// input to object
Console.WriteLine(service.GetMessage(request).Message);
// Call calculator function - Test input with logic and return new result.
AddCalculator number = new AddCalculator();
Console.WriteLine("\nPlease Enter First Number \n");
number.First_Integer = Convert.ToInt32(Console.ReadLine().ToString());

Console.WriteLine("\nPlease Enter Second Number \n");
number.Second_Integer = Convert.ToInt32(Console.ReadLine().ToString());

Console.WriteLine("The Sum of " + number.First_Integer + " + " +
    number.Second_Integer + " = " + service.AddService(number));
Console.ReadKey();
}
}
}

示例输出

result.JPG

result2.JPG

历史

  • 2008年9月22日:初始发布
© . All rights reserved.