web-dev-qa-db-fra.com

Qu'est-ce qui remplace WCF dans .Net Core?

Je suis habitué à créer une application console .Net Framework et à exposer une fonction Add(int x, int y) via un service WCF à partir de zéro avec la bibliothèque de classes (.Net Framework). J'utilise ensuite l'application console pour appeler par proxy cette fonction sur le serveur.

Cependant, si j'utilise Console App (.Net Core) et une bibliothèque de classes (.Net Core), System.ServiceModel n'est pas disponible. J'ai fait quelques recherches sur Google mais je n'ai pas trouvé ce qui "remplace" la WCF dans ce cas.

Comment exposer une fonction Add(int x, int y) dans une bibliothèque de classes à une application console, le tout dans .Net Core? Je vois System.ServiceModel.Web, et puisque ceci essaie d'être multi-plateforme, dois-je créer un service RESTful?

44
Sigex

WCF n'est pas pris en charge dans .NET Core, car il s'agit d'une technologie spécifique à Windows, alors que .NET Core est censé être multi-plateforme. Si vous implémentez une communication inter-processus, envisagez d’essayer ce projet . Il permet de créer des services dans le style WCF:

Étape 1 - Créer un contrat de service

public interface IComputingService
{
    float AddFloat(float x, float y);
}

Étape 2: implémenter le service

class ComputingService : IComputingService
{
    public float AddFloat(float x, float y)
    {
        return x + y;
    }
}

Étape 3 - Hébergez le service dans l'application console

class Program
{
    static void Main(string[] args)
    {
        // configure DI
        IServiceCollection services = ConfigureServices(new ServiceCollection());

        // build and run service Host
        new IpcServiceHostBuilder(services.BuildServiceProvider())
            .AddNamedPipeEndpoint<IComputingService>(name: "endpoint1", pipeName: "pipeName")
            .AddTcpEndpoint<IComputingService>(name: "endpoint2", ipEndpoint: IPAddress.Loopback, port: 45684)
            .Build()
            .Run();
    }

    private static IServiceCollection ConfigureServices(IServiceCollection services)
    {
        return services
            .AddIpc()
            .AddNamedPipe(options =>
            {
                options.ThreadCount = 2;
            })
            .AddService<IComputingService, ComputingService>();
    }
}

Étape 4 - Appeler le service depuis le processus client

IpcServiceClient<IComputingService> client = new IpcServiceClientBuilder<IComputingService>()
    .UseNamedPipe("pipeName") // or .UseTcp(IPAddress.Loopback, 45684) to invoke using TCP
    .Build();

float result = await client.InvokeAsync(x => x.AddFloat(1.23f, 4.56f));
20
Jacques Kang

Vous pouvez utiliser gRPC pour l'hébergement de services Web dans l'application principale .NET.

enter image description here

Introduction

  1. gRPC est un framework RPC open source hautes performances développé initialement par Google.
  2. L'infrastructure est basée sur un modèle client-serveur d'appels de procédures distantes. Une application cliente peut appeler directement des méthodes sur une application serveur comme s'il s'agissait d'un objet local.

Exemple

Code serveur

class Program
{
    static void Main(string[] args)
    {
        RunAsync().Wait();
    }

    private static async Task RunAsync()
    {
        var server = new Grpc.Core.Server
        {
            Ports = { { "127.0.0.1", 5000, ServerCredentials.Insecure } },
            Services =
            {
                ServerServiceDefinition.CreateBuilder()
                    .AddMethod(Descriptors.Method, async (requestStream, responseStream, context) =>
                    {
                        await requestStream.ForEachAsync(async additionRequest =>
                        {
                            Console.WriteLine($"Recieved addition request, number1 = {additionRequest.X} --- number2 = {additionRequest.Y}");
                            await responseStream.WriteAsync(new AdditionResponse {Output = additionRequest.X + additionRequest.Y});
                        });
                    })
                    .Build()
            }
        };

        server.Start();

        Console.WriteLine($"Server started under [127.0.0.1:5000]. Press Enter to stop it...");
        Console.ReadLine();

        await server.ShutdownAsync();
    }
}

Code client

class Program
{
    static void Main(string[] args)
    {
        RunAsync().Wait();
    }

    private static async Task RunAsync()
    {
        var channel = new Channel("127.0.0.1", 5000, ChannelCredentials.Insecure);
        var invoker = new DefaultCallInvoker(channel);
        using (var call = invoker.AsyncDuplexStreamingCall(Descriptors.Method, null, new CallOptions{}))
        {
            var responseCompleted = call.ResponseStream
                .ForEachAsync(async response => 
                {
                    Console.WriteLine($"Output: {response.Output}");
                });

            await call.RequestStream.WriteAsync(new AdditionRequest { X = 1, Y = 2});
            Console.ReadLine();

            await call.RequestStream.CompleteAsync();
            await responseCompleted;
        }

        Console.WriteLine("Press enter to stop...");
        Console.ReadLine();

        await channel.ShutdownAsync();
    }
}

Classes partagées entre le client et le serveur

[Schema]
public class AdditionRequest
{
    [Id(0)]
    public int X { get; set; }
    [Id(1)]
    public int Y { get; set; }
}

[Schema]
public class AdditionResponse
{
    [Id(0)]
    public int Output { get; set; }
}

Descripteurs de service

using Grpc.Core;
public class Descriptors
{
    public static Method<AdditionRequest, AdditionResponse> Method =
            new Method<AdditionRequest, AdditionResponse>(
                type: MethodType.DuplexStreaming,
                serviceName: "AdditonService",
                name: "AdditionMethod",
                requestMarshaller: Marshallers.Create(
                    serializer: Serializer<AdditionRequest>.ToBytes,
                    deserializer: Serializer<AdditionRequest>.FromBytes),
                responseMarshaller: Marshallers.Create(
                    serializer: Serializer<AdditionResponse>.ToBytes,
                    deserializer: Serializer<AdditionResponse>.FromBytes));
}

Sérialiseur/Désérialiseur

public static class Serializer<T>
{
    public static byte[] ToBytes(T obj)
    {
        var buffer = new OutputBuffer();
        var writer = new FastBinaryWriter<OutputBuffer>(buffer);
        Serialize.To(writer, obj);
        var output = new byte[buffer.Data.Count];
        Array.Copy(buffer.Data.Array, 0, output, 0, (int)buffer.Position);
        return output;
    }

    public static T FromBytes(byte[] bytes)
    {
        var buffer = new InputBuffer(bytes);
        var data = Deserialize<T>.From(new FastBinaryReader<InputBuffer>(buffer));
        return data;
    }
}

Sortie

Exemple de sortie client

Exemple de sortie du serveur

Références

  1. https://blogs.msdn.Microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/ =
  2. https://grpc.io/docs/
  3. https://grpc.io/docs/quickstart/csharp.html
  4. https://github.com/grpc/grpc/tree/master/src/csharp

Points de repère

  1. http://csharptest.net/787/benchmarking-wcf-compared-to-rpclibrary/index.html
29
Gopi

Il semble qu'il y aura un projet Core WCF maintenu par .NET Foundation avec le support de Microsoft. Plus de détails ici: https://www.dotnetfoundation.org/blog/2019/06/07/welcoming-core-wcf-to-the-net-foundation

Initialement, seuls les transports netTcp et http seront implémentés.

11
Rafał Straszewski

Donc, d'après mes recherches, la meilleure solution n'a pas les classes de proxy générées automatiquement. La meilleure solution consiste à créer un service RESTful et à sérialiser le corps de la réponse en objets de modèle. Où les modèles sont les objets de modèle habituels trouvés dans le modèle de conception MVC.

Merci pour vos réponses

3
Sigex

Il existe un port .NET Core disponible: https://github.com/dotnet/wcf Il est toujours en aperçu, mais ils le développent activement.

0
Flupp