🐥

CoreWCF で Hello World

2024/08/26に公開

CoreWCF のメモがてら Hello world を作成しながら書いてます。

プロジェクト テンプレートのインストール

まずはプロジェクト テンプレートのインストールから。以下のコマンドでインストール出来ます。

dotnet new install CoreWCF.Templates

そうすると以下のようなプロジェクト テンプレートがインストールされます。

選択して新規作成を行うとターゲットフレームワークを選ぶ画面があるのですが、ここの選択肢が以下のようになっていました。

  • .NET Framework 4.6.2
  • .NET Framework 4.7.2
  • .NET Framework 4.8
  • .NET 6
  • .NET 7

ということで、あんまりメンテされてなさそうなので却下です。

ASP.NET Core のプロジェクトに組み込む

ということで .NET 8 の ASP.NET Core の空のプロジェクトに CoreWCF を組み込む方針で行こうと思います。

  • CoreWCF.Primitives
  • CoreWCF.Http

そして次にサービスを定義します。

IHelloWorldService.cs
using CoreWCF;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;

namespace CoreWCFHelloWorld;

[ServiceContract]
public interface IHelloWorldService
{
    [OperationContract]
    [FaultContract(typeof(HelloWorldFault))]
    HelloWorldResponse SayHello(HelloWorldRequest request);
}

[DataContract]
public class HelloWorldFault
{
    [DataMember]
    public required string Message { get; set; }
}

[DataContract]
public class HelloWorldRequest
{
    [DataMember]
    public required string Name { get; set; }
}

[DataContract]
public class HelloWorldResponse
{
    [DataMember]
    public required string Message { get; set; }
}

required キーワードが使えるのかどうかわからずに使ってます…。どうなることやら。

そして、実装を追加します。

HelloWorldService.cs
using CoreWCF;

namespace CoreWCFHelloWorld;

public class HelloWorldService(ILogger<HelloWorldService> logger) : IHelloWorldService
{
    public HelloWorldResponse SayHello(HelloWorldRequest request)
    {
        logger.LogInformation("SayHello called with name: {name}", request.Name);
        if (request.Name == "error")
        {
            throw new FaultException<HelloWorldFault>(new() { Message = "無効な名前です。" });
        }

        return new() { Message = $"Hello, {request.Name}." };
    }
}

名前が error の時は例外で、それ以外はメッセージを返すようにしています。

Program.cs に CoreWCF 系のサービスの追加やエンドポイントの構成などを行います。

Program.cs
using CoreWCF;
using CoreWCF.Channels;
using CoreWCF.Configuration;
using CoreWCF.Description;
using CoreWCFHelloWorld;

var builder = WebApplication.CreateBuilder(args);

// DI 使うなら登録しておく必要がある
builder.Services.AddSingleton<HelloWorldService>();

// CoreWCF に必要なサービスを登録
builder.Services.AddServiceModelServices();
builder.Services.AddServiceModelMetadata();
builder.Services.AddSingleton<IServiceBehavior, UseRequestHeadersForMetadataAddressBehavior>();

var app = builder.Build();

// WCF サービスの登録やエンドポイントの構成
app.UseServiceModel(builder =>
{
    builder.AddService<HelloWorldService>();
    builder.AddServiceEndpoint<HelloWorldService, IHelloWorldService>(
        new BasicHttpBinding(BasicHttpSecurityMode.Transport),
        "/HelloWorldService.svc");
    var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();
    serviceMetadataBehavior.HttpsGetEnabled = true;
});

app.Run();

実行して /HelloWorldService.svc にアクセスすると以下のような画面が出ました。 ?wsdl をつけると WSDL が表示されるので、これで SOAP サービスが作成できたことが確認できます。なんか懐かしいですね。

クライアント側の作成

サービスが出来たのでクライアント側も作っていきましょう。.NET 8 のコンソールアプリを作ってプロジェクトにサービス参照を追加してみました。

サービスの URL を指定する際に、実際に動いていないといけないのでプロジェクトをデバッグ無しで実行した状態で URL を指定しています。後は適当にウィザードを進めていくとクライアント側のコードが生成されます。

GUI ではなく CLI でやる方法も提供されているみたいです。

https://learn.microsoft.com/ja-jp/dotnet/core/additional-tools/dotnet-svcutil-guide?tabs=dotnetsvcutil2x

生成されたコードを使ってサービスの呼び出しを行います。まずは Hello, Tanaka. と帰ってくるのを期待するのと、無効な名前を与えることでエラーが返ってくるのを確認します。

Program.cs
using ServiceReference1;
using System.ServiceModel;

Console.ReadKey();

var service = new HelloWorldServiceClient();
var r = await service.SayHelloAsync(new() { Name = "Tanaka" });
Console.WriteLine(r.Message);

try
{
    await service.SayHelloAsync(new() { Name = "error" });
}
catch (FaultException<HelloWorldFault> e)
{
    Console.WriteLine(e.Detail.Message);
}

実行すると以下のような結果になりました。思ったよりサクッと動きましたね。

Hello, Tanaka.
無効な名前です。

まとめ

Hello world を試してみた範囲ですが CoreWCF は、以下に以下のような印象を受けました。

サービスを実装する側

CoreWCF は ASP.NET Core のような感覚で Program.cs を書いていきます。
Web.config などでやっていた BasicHttpBinding の構成などはコードで行う必要があります。
WSDL からサービスのスケルトンを生成する機能は無さそうなので、WSDL に合わせて作る必要がある場合は手で頑張って ServiceContract などをつけていく必要があります。

クライアント側

CoreWCF とは関係ないですが、クライアント側についてはサービス参照の追加をして従来に近い形で使えます。
WSDL さえあればクライアント側の実装は .NET でも楽にできそうです。
ただ、app.config などでクライアントの BasicHttpBinding の構成などは出来ないので C# で書く必要がありそうです。

Microsoft (有志)

Discussion