深入了解SOAPCore:在.NET 6中构建基于SOAP的Web服务

作者:微信公众号:【架构师老卢】
1-26 14:40
204

概述:本文介绍了在.NET Core和.NET 5+中不再支持WCF服务的情况下,如何使用SOAPCore库创建基于SOAP的Web服务。通过示例和代码演示了如何使用SOAPCore创建和调用基于SOAP的Web服务,以及解决方案的结构和实现细节。

在 .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>
  1. SoapClient:这是一个控制台应用程序。它包含自动生成的配置文件服务客户端代码。这个项目演示了我们将如何使用现有的基于 SOAP 的 Web 服务。

服务层项目 在本项目中,我们定义了 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。FaultException 的 Detail 属性是 MissingProfileFault 的实例。

相关留言评论
昵称:
邮箱:
阅读排行