Co zastępuje WCF w .Net Core?


101

Jestem przyzwyczajony do tworzenia aplikacji konsolowej .Net Framework i eksponowania Add(int x, int y)funkcji za pośrednictwem usługi WCF od podstaw za pomocą Class Library (.Net Framework). Następnie używam aplikacji konsoli do wywołania tej funkcji na serwerze przez proxy.

Jeśli jednak używam aplikacji konsoli (.Net Core) i biblioteki klas (.Net Core), System.ServiceModel nie jest dostępny. Zrobiłem kilka Google, ale nie wiem, co „zastępuje” WCF w tym przypadku.

Jak udostępnić Add(int x, int y)funkcję w bibliotece klas aplikacji konsolowej w ramach .Net Core? Widzę System.ServiceModel.Web, a ponieważ próbuję działać na wielu platformach, czy muszę utworzyć usługę RESTful?


do I have to create a RESTful service?- AFAIK tak (lub użyj rozwiązania innej firmy, którego nie znam dla .NET Core)
Christoph Fink

3
Program WCF prawdopodobnie nie zostanie przeniesiony do platformy .NET Core, ponieważ większość podstawy kodu zależy od wewnętrznych bibliotek systemu Windows. Czy możesz używać ASP.NET Core? Będziesz mieć serwer HTTP, który jest łatwo wieloplatformowy
Camilo Terevinto

2
Po stronie klienta WCF jest już obsługiwana (nie wiem ile), po stronie serwera jest gorąco debatowane i głosowane żądanie funkcji.
Henk Holterman

Wygląda na to, że program Visual Studio 2017 15.5 i nowsze obsługują generowanie klas proxy klienta .NET Core . Istnieje również lista obsługiwanych funkcji .
jamiebarrow

5
W skrócie: CoreWCF
Ognyan Dimitrov

Odpowiedzi:


35

Usługa WCF nie jest obsługiwana w programie .NET Core, ponieważ jest to technologia specyficzna dla systemu Windows, a platforma .NET Core powinna być wieloplatformowa.

Jeśli wdrażasz komunikację między procesami, rozważ wypróbowanie projektu IpcServiceFramework .

Umożliwia tworzenie usług w stylu WCF w następujący sposób:

  1. Utwórz umowę serwisową

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Wdrażaj usługę

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Hostuj usługę w aplikacji konsolowej

    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. Wywołaj usługę z procesu klienta

    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
Miły! Może warto zaktualizować, aby skorzystać z .Net core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…
Sigex

Przepraszam, czy brakuje mi czegoś ważnego? Czy potoki nie powinny służyć tylko do komunikacji z tym samym hostem?
user1034912

2
Tak, brakuje Ci tego, że to pokrótce pokazuje, że IpcServiceFramework, podobnie jak WCF, umożliwia bezproblemowe przełączanie się między różnymi technologiami przesyłania wiadomości.
Chris F Carroll

4
WCF można uznać za specyficzne dla systemu Windows w niektórych protokołach, które są abstrakcyjne, ale usługi SOAP nie są. Jak można stworzyć usługę sieciową SOAP w .net core?
Jeremy

3
Uwaga: autor tego projektu napisał następujący komentarz: „Chłopaki, z powodów osobistych nie mam czasu zajmować się tym projektem od kilku miesięcy. W międzyczasie .NET Core 3.0 jest udostępniany z funkcją gRPC”. ( github.com/jacqueskang/IpcServiceFramework/issues/… ). Zobacz drugą odpowiedź dla gRPC.
gerard

68

Możesz użyć gRPC do hostowania usług internetowych w aplikacji .NET core.

wprowadź opis obrazu tutaj

Wprowadzenie

  1. gRPC to wysokowydajna platforma RPC typu open source pierwotnie opracowana przez Google.
  2. Struktura jest oparta na modelu klient-serwer zdalnych wywołań procedur. Aplikacja kliencka może bezpośrednio wywoływać metody w aplikacji serwera, tak jakby była obiektem lokalnym.

Przykład

Kod serwera

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

Kod klienta

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

Klasy współdzielone między klientem a serwerem

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

Deskryptory usług

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

Serializator / Deserializator

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

Wynik

Przykładowe dane wyjściowe klienta

Przykładowe dane wyjściowe serwera

Bibliografia

  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

Benchmarki

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

7
Od marca 2019 r. Ta odpowiedź jest bardziej odpowiednia. Zobacz github.com/grpc/grpc-dotnet (i aktualizacje ASP.NET Core w .NET Core 3.0 ).
resnyanskiy

1
Myślę, że jest to najbliższa odpowiedź, ale niestety nie zapewnia ona żadnego zachowania ani obsługi dławienia.
joe

4
Należy również pamiętać, że na razie gRPCnie kompiluje się z natywnym łańcuchem narzędzi .net w VS 2019 (16.0.2) i dlatego nie będzie działać z UWP.
Samuel

2
Jeśli szukasz obsługi nazwanych potoków, napisałem transport gRPC
Cyanfish

1
Należy zauważyć, że (od 2020-04-06) grpc-dotnet nie ma pakietów dla ARM.
GafferMan2112

23

Wygląda na to, że powstanie projekt CoreWCF obsługiwany przez .NET Foundation przy wsparciu Microsoft.

Więcej informacji na temat powitania Core WCF w .NET Foundation

Początkowo zaimplementowany zostanie tylko transport netTcp i http.


To jest myląca odpowiedź. Firma Microsoft przeniosła tylko klienta wcf. Host lub usługodawca Wcf nie jest dostępny i nie mają takiego zamiaru. Nauczyłem się tego na własnej skórze. gRPC to droga do zrobienia
user1034912

@ user1034912 nie masz racji. CoreWCF to lekki serwer WCF przeniesiony do .NET core. Ma ograniczenia, ale w niektórych przypadkach jest dobrym wyborem.
Odmowa dostępu

Tak, tylko jeśli jesteś
Konsumentem

@ user1034912 Nie, strona serwera jest dostępna. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/ ...
Odmowa dostępu


9

WCF robi wiele rzeczy; jest to łatwy sposób na zdalne wywołanie procedur między dwiema aplikacjami (procesami) na jednym komputerze przy użyciu nazwanych potoków; może to być wewnętrzny kanał komunikacyjny klient-serwer o dużej objętości między komponentami .NET, wykorzystujący serializację binarną przez TCPIP; lub może zapewnić znormalizowany interfejs API obejmujący różne technologie, np. za pośrednictwem protokołu SOAP. Obsługuje nawet takie rzeczy, jak asynchroniczne przesyłanie wiadomości za pośrednictwem usługi MSMQ.

W przypadku platformy .NET Core istnieją różne zamienniki w zależności od celu.

W przypadku interfejsu API dla wielu platform należy go zastąpić usługą REST przy użyciu programu ASP.NET.

W przypadku połączeń między procesami lub połączeń klient-serwer gRPC byłby dobry, z doskonałą odpowiedzią udzieloną przez @Gopi.

Tak więc odpowiedź na pytanie „Co zastępuje WCF” zależy od tego, do czego go używasz.



4

Z moich badań wynika, że ​​najlepsze rozwiązanie nie ma automatycznie generowanych klas proxy. Najlepszym rozwiązaniem jest utworzenie usługi RESTful i serializacja treści odpowiedzi do obiektów modelu. Gdzie modele są zwykłymi obiektami modelu znalezionymi we wzorcu projektowym MVC.

Dziękuję za odpowiedzi



Tak, to były automatycznie generowane klasy proxy, które chciałem. Używam usług RESTful / RPC dla tej funkcji
Sigex,

To repozytorium jest tylko dla bibliotek klienckich
orellabac

1

Możesz również samodzielnie hostować ASP.NET Core Web API.

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

Rdzeń interfejsu API sieci Web ASP nie obsługuje komunikacji dwustronnej na jednym porcie, tak jak robi to wcf.
user1034912

0

Dostępny jest port .NET Core: https://github.com/dotnet/wcf Nadal jest w wersji zapoznawczej, ale aktywnie go rozwijają.


14
Uważam, że ten port służy do komunikacji z Core do WCF, ale nie do pisania WCF w Core.
hal9000

7
Połączone repozytorium github wyraźnie mówi: „To repozytorium zawiera biblioteki WCF zorientowane na klienta, które umożliwiają aplikacjom
opartym

0

Ponieważ obecnie wszystkie dostępne usługi Selfhost WCFCore nie są tak łatwe w instalacji i obsłudze.
Najlepszym rozwiązaniem dla HostedService będą alternatywy, jak pokazał gRPC w poprzedniej odpowiedzi i zauważ, że w ciągu 1 roku może zmienić wiele rzeczy, na pewno WCF jest obsługiwany w Core tylko jako klient, który działa dobrze.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.