Was ersetzt WCF in .Net Core?

95

Ich bin es gewohnt, eine .Net Framework-Konsolenanwendung zu erstellen und eine Add(int x, int y)Funktion über einen WCF-Dienst von Grund auf mit Class Library (.Net Framework) verfügbar zu machen. Ich benutze dann die Konsolenanwendung, um diese Funktion innerhalb des Servers als Proxy aufzurufen.

Wenn ich jedoch die Konsolen-App (.Net Core) und eine Klassenbibliothek (.Net Core) verwende, ist das System.ServiceModel nicht verfügbar. Ich habe ein bisschen gegoogelt, aber ich habe nicht herausgefunden, was WCF in diesem Fall "ersetzt".

Wie mache ich eine Add(int x, int y)Funktion in einer Klassenbibliothek für eine Konsolenanwendung in .Net Core verfügbar? Ich sehe System.ServiceModel.Web, und da dies versucht, plattformübergreifend zu sein, muss ich einen RESTful-Service erstellen?

Sigex
quelle
do I have to create a RESTful service?- AFAIK ja (oder verwenden Sie eine Drittanbieterlösung, die ich für .NET Core nicht kennen würde)
Christoph Fink
3
WCF wird wahrscheinlich nicht auf .NET Core portiert, da der größte Teil der Codebasis von internen Windows-Bibliotheken abhängt. Können Sie ASP.NET Core verwenden? Dort haben Sie einen HTTP-Server, der leicht plattformübergreifend ist
Camilo Terevinto
2
Die clientseitige WCF-Seite wird bereits unterstützt (ich weiß nicht, wie viel), die serverseitige ist eine heiß diskutierte und abgestimmte Feature-Anfrage.
Henk Holterman
Es scheint, dass Visual Studio 2017 15.5 und höher das Generieren von .NET Core-Client-Proxyklassen unterstützt . Es gibt auch eine Liste der unterstützten Funktionen .
Jamie Barrow
5
Kurzum: CoreWCF
Ognyan Dimitrov

Antworten:

34

WCF wird in .NET Core nicht unterstützt, da es sich um eine Windows-spezifische Technologie handelt und .NET Core plattformübergreifend sein soll.

Wenn Sie prozessübergreifende Kommunikation implementieren, versuchen Sie es mit dem IpcServiceFramework- Projekt.

Es ermöglicht das Erstellen von Diensten im WCF-Stil wie folgt:

  1. Servicevertrag anlegen

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Implementieren Sie den Service

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Hosten Sie den Dienst in der Konsolenanwendung

    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>();
        }
    }
    
  4. Rufen Sie den Service vom Client-Prozess aus auf

    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));
    
Jacques Kang
quelle
3
Nett! Könnte eine Aktualisierung wert sein, um die Vorteile des .Net-Kernsystems system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/… zu nutzen
Sigex
Entschuldigung, fehlt mir hier etwas Wichtiges? Sollen Pipes nicht nur für die gleiche Host-Kommunikation verwendet werden?
user1034912
2
Ja, was Sie vermissen, ist, dass dies kurz zeigt, dass IpcServiceFramework wie WCF es Ihnen ermöglicht, nahtlos zwischen verschiedenen Messaging-Technologien zu wechseln.
Chris F Carroll
4
WCF kann in einigen der abstrahierten Protokolle als Windows-spezifisch angesehen werden, SOAP-Dienste jedoch nicht. Wie würde man einen SOAP-Webdienst im .net-Kern erstellen?
Jeremy
3
Hinweis: Der Autor dieses Projekts schrieb den folgenden Kommentar: "Leute, aus persönlichen Gründen habe ich seit einigen Monaten keine Zeit mehr, dieses Projekt zu warten. In der Zwischenzeit wird .NET Core 3.0 mit der gRPC-Funktion veröffentlicht." ( github.com/jacqueskang/IpcServiceFramework/issues/… ). Siehe die zweite Antwort für gRPC.
Gerard
63

Sie können gRPC zum Hosten von Webdiensten in der .NET-Kernanwendung verwenden.

Geben Sie hier die Bildbeschreibung ein

Einführung

  1. gRPC ist ein leistungsstarkes Open-Source-RPC-Framework, das ursprünglich von Google entwickelt wurde.
  2. Das Framework basiert auf einem Client-Server-Modell von Remoteprozeduraufrufen. Eine Clientanwendung kann Methoden in einer Serveranwendung direkt aufrufen, als wäre es ein lokales Objekt.

Beispiel

Servercode

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();
    }
}

Kundencode

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();
    }
}

Gemeinsame Klassen zwischen Client und Server

[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; }
}

Service-Deskriptoren

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));
}

Serializer / Deserializer

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;
    }
}

Ausgabe

Beispiel für eine Client-Ausgabe

Beispielserverausgabe

Verweise

  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

Benchmarks

  1. http://csharptest.net/787/benchmarking-wcf-compared-to-rpclibrary/index.html
Gopi
quelle
7
Ab März 2019 ist diese Antwort relevanter. Siehe github.com/grpc/grpc-dotnet (und ASP.NET Core-Updates in .NET Core 3.0 ).
resnyanskiy
1
Ich denke, dies ist die naheliegendste Antwort, aber leider bietet sie kein Verhalten oder keine Drosselungsunterstützung.
Joe
4
gRPCBeachten Sie auch, dass derzeit keine Kompilierung mit der nativen .net-Toolkette in VS 2019 (16.0.2) möglich ist und daher nicht mit UWP funktioniert.
Samuel
2
Wenn Sie nach
Named
1
Beachten Sie, dass grpc-dotnet (Stand 2020-04-06) keine Pakete für ARM enthält.
GafferMan2112
23

Es scheint, dass es ein CoreWCF- Projekt geben wird, das von .NET Foundation mit Microsoft-Unterstützung verwaltet wird.

Weitere Informationen finden Sie unter Begrüßung von Core WCF bei der .NET Foundation

Zunächst werden nur netTcp- und http-Transporte implementiert.

Rafał Straszewski
quelle
Dies ist eine irreführende Antwort. Microsoft hat nur den wcf-Client portiert. Wcf-Host oder -Servicehost ist nicht verfügbar und sie haben nicht die Absicht, dies zu tun. Ich habe das auf die harte Tour gelernt. gRPC ist der
richtige
@ user1034912 Sie sind nicht korrekt. CoreWCF ist ein leichter WCF-Server, der auf den .NET-Kern portiert ist. Es hat Einschränkungen, aber in einigen Fällen ist es eine gute Wahl.
Zugriff
Ja, nur wenn Sie ein Consuming Client sind, gibt es
Service-Host-
@ user1034912 Nein, die Serverseite ist verfügbar. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…
Zugriff
9

WCF macht viele Dinge; Es ist eine einfache Möglichkeit, Remoteprozeduraufrufe zwischen zwei Anwendungen (Prozessen) auf einem Computer mithilfe von Named Pipes durchzuführen. Es kann sich um einen internen Client-Server-Kommunikationskanal mit hohem Volumen zwischen .NET-Komponenten handeln, der eine binäre Serialisierung über TCPIP verwendet. oder es kann eine standardisierte technologieübergreifende API bereitstellen, z. B. über SOAP. Es unterstützt sogar asynchrones Messaging über MSMQ.

Für .NET Core gibt es je nach Zweck unterschiedliche Ersetzungen.

Bei einer plattformübergreifenden API würden Sie diese mithilfe von ASP.NET durch einen REST-Service ersetzen.

Für prozessübergreifende Verbindungen oder Client-Server-Verbindungen wäre gRPC gut, mit einer ausgezeichneten Antwort von @Gopi.

Die Antwort auf "Was ersetzt WCF" hängt also davon ab, wofür Sie es verwenden.

Schlauer Greif
quelle
5

Es gibt ein Community-Repo https://github.com/CoreWCF/CoreWCF , das einige Teile von WCF implementiert. Sie können damit einige einfache WCF-Dienste unterstützen. Es werden jedoch nicht alle Funktionen unterstützt.

Orellabac
quelle
4

Aus meiner Forschung hat die beste Lösung also nicht die automatisch generierten Proxy-Klassen. Diese beste Lösung besteht darin, einen RESTful-Service zu erstellen und den Antworttext in Modellobjekte zu serialisieren. Wo die Modelle die üblichen Modellobjekte sind, die im MVC-Entwurfsmuster gefunden werden.

Vielen Dank für Ihre Antworten

Sigex
quelle
Ja, es waren die automatisch generierten Proxy-Klassen, die ich wollte. Ich benutze RESTful Services / RPC für diese Funktionalität
Sigex
Dieses Repo ist nur für die Client-Bibliotheken
Orellabac
Restful unterstützt keine Duplex-Kommunikation
user1034912
1

Sie können die ASP.NET Core-Web-API auch selbst hosten.

<!-- SelfHosted.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <!-- see: https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#framework-reference -->
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.0" />
  </ItemGroup>

</Project>
// Program.cs
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace SelfHosted
{
    class Program
    {
        static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            // see: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1
            return Host.CreateDefaultBuilder(args)
                .ConfigureHostConfiguration(configHost =>
                {
                    configHost.SetBasePath(Directory.GetCurrentDirectory());
                    configHost.AddJsonFile("appsettings.json", optional: true);
                    configHost.AddEnvironmentVariables(prefix: "SelfHosted_");
                    configHost.AddCommandLine(args);
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.CaptureStartupErrors(true);
                    webBuilder.UseStartup<Startup>();
                });
        }
    }
}
// Startup.cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace SelfHosted
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            // see: https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/web-api/index/samples/3.x
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
// Controllers\TestController.cs
using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;

namespace SelfHosted.Controllers
{
    [ApiController]
    [Produces(MediaTypeNames.Application.Json)]
    [Route("[controller]")]
    public class HelloController : SelfHostedControllerBase
    {
        [HttpGet]
        public ActionResult<string> HelloWorld() => "Hello World!";

        [HttpGet("{name}")]
        public ActionResult<string> HelloName(string name) => $"Hello {name}!";
    }
}
DoronG
quelle
Die Asp Core Web-API unterstützt keine Duplex-Kommunikation an einem einzelnen Port, wie dies bei wcf der Fall ist.
user1034912
0

Es ist ein .NET Core-Port verfügbar: https://github.com/dotnet/wcf Er befindet sich noch in der Vorschau, wird jedoch aktiv weiterentwickelt.

Flupp
quelle
14
Ich glaube, dieser Port dient zur Kommunikation von Core zu WCF, aber nicht zum Schreiben von WCF in Core.
hal9000
7
Das verknüpfte Github-Repository sagt deutlich: "Dieses Repo enthält die clientorientierten WCF-Bibliotheken, mit denen auf .NET Core basierende Anwendungen mit WCF-Diensten kommunizieren können."
Bahaa
0

Wie heute sind alle verfügbaren WCFCore-Selfhosts nicht so einfach zu installieren und zu verwenden.
Das Beste für HostedService sind die Alternativen, wie gRPC in der vorherigen Antwort gezeigt hat. Beachten Sie, dass sich in einem Jahr viele Dinge ändern können, um sicherzustellen, dass WCF in Core nur als Client unterstützt wird, der einwandfrei funktioniert.

Jorge Alvarado
quelle