在 .NET Core 和 .NET 5+ 中,不再支持 WCF 服务。如果仍需要使用 .NET 6 开发基于 SOAP 的 Web 服务,则有两个选项:
CoreWCF:CoreWCF 是 Windows Communication Foundation (WCF) 服务端到 .NET Core 的端口。 SoapCore:SoapCore 是一个用于使用 .NET Core/.NET 5+ 创建 SOAP 服务的库。 在本文中,我将向您展示如何使用 SoapCore 创建基于 SOAP 的 Web 服务,以及如何使用基于 SOAP 的 Web 服务。
解决方案结构
演示解决方案中有 3 个项目:
服务层:这是一个库项目。它包含服务功能的接口和实现。在此项目中,我们定义了一个 ProfileService。 SoapService:这是一个使用“ASP.NET Core Empty”项目模板创建的 Web 项目。在这个项目中,我们需要引用 “Service Layer” 项目和 SoapCore nuget 包:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SoapCore" Version="1.1.0.37" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ServiceLayer\ServiceLayer.csproj" />
</ItemGroup>
</Project>
服务层项目 在本项目中,我们定义了 IProfileService 接口及其实现:
轮廓:
namespace ServiceLayer
{
[DataContract]
public class Profile
{
public Profile() { }
[DataMember]
public int ProfileID { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public string HomeAddress { get; set; }
}
}
IProfileService 接口:
using System.ServiceModel;
namespace ServiceLayer
{
[ServiceContract]
public interface IProfileService
{
[OperationContract]
[FaultContract(typeof(MissingProfileFault))]
Profile GetProfile(int profileID);
}
}
您需要使用 [ServiceContract] 属性修饰接口,并使用 [OperationContract] 属性修饰每个方法。需要添加以下 NuGet 包引用才能使用这些属性:
<ItemGroup>
<PackageReference Include="System.ServiceModel.Primitives" Version="4.8.1" />
</ItemGroup>
IProfileService 接口的 GetProfile() 方法有一个 fault 属性,用于定义它可能引发的故障类型。
using System.Runtime.Serialization;
namespace ServiceLayer
{
[DataContract]
public class MissingProfileFault
{
public MissingProfileFault(string message)
{
this.Message = message;
}
[DataMember]
public string Message { get; set; }
}
}
IProfileService 实现:
namespace ServiceLayer
{
public class ProfileService : IProfileService
{
private List<Profile> _profiles = new List<Profile>()
{
new Profile() { FirstName = "Foo", LastName = "Profile1", Email = "fooprofiile1@yahoo.com", HomeAddress = "1 King Street West, Toronto, ON", ProfileID = 1 },
new Profile() { FirstName = "Bar", LastName = "Profile2", Email = "barprofiile2@gmail.com", HomeAddress = "1 Hollywood Avenue, Los Angeles, CA", ProfileID = 2 },
};
public Profile GetProfile(int profileID)
{
var profile = _profiles.FirstOrDefault(p => p.ProfileID == profileID);
if (profile == null)
{
throw new FaultException<MissingProfileFault>(new MissingProfileFault($"A profile with ID {profileID} is missing."),
new FaultReason($"A profile with ID {profileID} is missing."),
new FaultCode("MissingProfile"), null);
}
return profile;
}
}
}
此项目使用 SoapCore 将 ProfileService 公开为基于 SOAP 的 Web 服务。程序 .cs 文件如下所示:
using Microsoft.Extensions.DependencyInjection.Extensions;
using ServiceLayer;
using SoapCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSoapCore();
builder.Services.TryAddSingleton<ProfileService>();
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.UseSoapEndpoint<ProfileService>(
path: "/ProfileService.asmx",
encoder: new SoapEncoderOptions(),
serializer: SoapSerializer.DataContractSerializer,
caseInsensitivePath: true); });
app.Run();
在终结点中注意。UseSoapEndpoint
“path”参数指定服务的 URL 路径。您可以指定任何验证 URL 路径(例如 /profileservice.svc)。
默认情况下,路径区分大小写。如果将路径指定为“/ProfileService.asmx”,并在 URL 中键入“profileservice.asmx”,则会收到 404 错误,您可以通过将“caseInsensitivePath”参数指定为 true 来使其不区分大小写。
生成并运行此项目后,将打开浏览器并显示 404 错误。这是因为网站根目录下没有内容。
您可以在地址中附加我们在 program.cs 文件中指定的服务路径。您应该能够看到此服务的 WSDL 内容。
ProfileService 元数据 (WSDL) 将上述内容保存到本地驱动器的 profileservice.wsdl 文件中。
Soap 客户端 这是使用基于 SOAP 的 Web 服务的客户端应用。您可以通过两种不同的方式生成客户服务代码:
使用 Visual Studio
右键单击项目,然后选择“添加”->“服务参考”
在新的“添加新的 WCF Web 服务引用”对话框中,提供服务 URL 并指定要在其中生成的代码的命名空间。单击“下一步”->“下一步->完成”。
服务引用客户端代码将在“连接的服务”文件夹下生成。
使用 dotnet-svcutil 工具
使用 Visual Studio 生成代码需要你有权访问实时服务。在拥有多层基础架构的大公司中,情况可能并非如此。您可能只能从服务团队获取 WSDL 文件。在这种情况下,需要使用 dotnet CLI 工具手动生成代码。
可以使用名为 dotnet-svcutil 的工具。它类似于 .NET Framework 项目的服务模型元数据 — svcutil 工具。可以将 dotnet-svcutil NuGet 包安装为 CLI 工具:You can Install the dotnet-svcutil NuGet package as a CLI tool:
dotnet tool install --global dotnet-svcutil
成功安装此 CLI 工具后,您可以使用它来生成客户端服务参考代码。
dotnet-svcutil C:\Downloads\ProfileService.wsdl -n ",SoapServiceDemo.ProfileService" -n 参数指定生成的代码的命名空间。第一部分“”表示映射所有 targetNamespace,而无需显式映射到 CLR 命名空间(第二部分:“SoapServiceDemo.ProfileService”)。
代码在当前目录\ServiceReference\Reference.cs 中生成。
调用 SOAP Web 服务 将 reference.cs 文件添加到 SoapClient 项目后,可以将以下代码添加到 program.cs 文件中。
using (var client = new SoapServiceDemo.ProfileService.ProfileServiceClient())
{
try
{
var profile = await client.GetProfileAsync(3);
if (profile != null)
{
Console.WriteLine($"First Name: {profile.FirstName}");
Console.WriteLine($"Last Name: {profile.LastName}");
Console.WriteLine($"Email Address: {profile.Email}");
Console.WriteLine($"Home Address: {profile.HomeAddress}");
}
}
catch (FaultException<MissingProfileFault> ex)
{
Console.WriteLine($"Fault reason: {ex.Reason.ToString()}, fault code: {ex.Code.Name}, detail: {ex.Detail.Message}");
}
catch (FaultException ex)
{
Console.WriteLine(ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
处理故障异常
GetProfile() 方法引发的错误是 MissingProfileFault(由 IProfileService 接口中的 FaultContract 属性定义)。在客户端中,捕获的异常将是 FaultException