140 votes

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

J'ai l'habitude de créer une application de console .Net Framework et d'exposer une Add(int x, int y) via un service WCF en partant de zéro avec la bibliothèque de classes (Framework .Net). J'utilise ensuite l'application console pour appeler par proxy cette fonction au sein du serveur.

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

Comment exposer un Add(int x, int y) dans une bibliothèque de classes vers une application console, le tout dans .Net Core ? Je vois System.ServiceModel.Web, et comme il s'agit d'un projet multiplateforme, dois-je créer un service RESTful ?

0 votes

do I have to create a RESTful service? - AFAIK oui (ou utiliser une solution tierce que je ne connais pas pour .NET Core)

3 votes

WCF ne sera probablement pas porté vers .NET Core, car la majeure partie de la base de code dépend des bibliothèques internes de Windows. Pouvez-vous utiliser ASP.NET Core ? Vous disposerez alors d'un serveur HTTP facilement multiplateforme.

2 votes

WCF côté client est déjà supporté (je ne sais pas dans quelle mesure), le côté serveur est une demande de fonctionnalité chaudement débattue et votée.

86voto

Gopi Points 631

Vous pouvez utiliser gRPC pour héberger des services web dans une application .NET core.

enter image description here

Introduction

  1. gRPC est un cadre RPC haute performance, à code source ouvert, initialement développé par Google.
  2. Le cadre est basé sur un modèle client-serveur d'appels de procédures à distance. Une application cliente peut appeler directement des méthodes sur une application serveur comme s'il s'agissait d'un objet local.

Exemple

Code du 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

Repères

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

8 votes

A partir de mars 2019, cette réponse est plus pertinente. Voir github.com/grpc/grpc-dotnet (et Mises à jour ASP.NET Core dans .NET Core 3.0 ).

2 votes

Je pense que c'est la réponse la plus proche, mais malheureusement, elle ne fournit pas de comportement ou de support d'étranglement.

4 votes

Sachez également qu'à l'heure actuelle gRPC ne compile pas contre la chaîne d'outils native .net dans VS 2019 (16.0.2) et ne fonctionnera donc pas avec UWP.

40voto

Jacques Kang Points 336

WCF n'est pas pris en charge par .NET Core car il s'agit d'une technologie spécifique à Windows alors que .NET Core est censé être multiplateforme. Si vous implémentez la communication inter-processus, pensez à essayer ce projet out. 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 : Mettre en œuvre le service

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

Étape 3 - Héberger 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 à partir du 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));

3 votes

Bien vu ! Il pourrait être intéressant de le mettre à jour pour tirer parti du système .io.pipelines du noyau .Net. blogs.msdn.microsoft.com/dotnet/2018/07/09/

0 votes

Désolé, j'ai raté quelque chose d'important ? Les pipes ne sont-elles pas censées être réservées aux communications avec le même hôte ?

3 votes

Oui, ce que vous ne comprenez pas, c'est que cela démontre brièvement qu'IpcServiceFramework, comme WCF, vous permet de passer en quelque sorte sans problème d'une technologie de messagerie à l'autre.

36voto

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

Au départ, seuls les transports netTcp et http seront mis en œuvre.

0 votes

Cette réponse est trompeuse. Microsoft n'a porté que le client wcf. Wcf host ou servicehost n'est pas disponible et ils n'ont pas l'intention de le faire. Je l'ai appris à mes dépens. gRPC est la meilleure solution.

1 votes

@user1034912 vous n'avez pas raison. CoreWCF est un serveur WCF léger qui a été porté sur .NET core. Il a des limites, mais dans certains cas, c'est un bon choix.

0 votes

Oui, seulement si vous êtes un client consommateur, il n'y a pas d'implémentation de servicehost.

4voto

Sigex Points 614

D'après mes recherches, la meilleure solution est donc de ne pas avoir de classes proxy générées automatiquement. Cette meilleure solution consiste à créer un service RESTful et à sérialiser le corps de la réponse dans des objets modèles. Les modèles sont les objets modèles habituels que l'on trouve dans le modèle de conception MVC.

Merci pour vos réponses

2 votes

0 votes

Oui, c'était les classes proxy générées automatiquement que je voulais. J'utilise des services RESTful / RPC pour cette fonctionnalité.

0 votes

Ce repo est réservé aux bibliothèques client

1voto

Flupp Points 563

Un portage .NET Core est disponible : https://github.com/dotnet/wcf Il est encore en phase d'aperçu, mais ils le développent activement.

14 votes

Je pense que ce port est destiné à la communication entre Core et WCF, mais pas à l'écriture de WCF dans Core.

7 votes

Le dépôt github lié dit clairement : " Ce dépôt contient les bibliothèques WCF orientées client qui permettent aux applications construites sur .NET Core de communiquer avec les services WCF. "

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X