O que substitui o WCF no .Net Core?

100

Estou acostumado a criar um aplicativo de console .Net Framework e expor uma Add(int x, int y)função por meio de um serviço WCF do zero com a biblioteca de classes (.Net Framework). Em seguida, uso o aplicativo de console para chamar de proxy essa função no servidor.

No entanto, se eu usar o aplicativo de console (.Net Core) e uma biblioteca de classes (.Net Core), o System.ServiceModel não estará disponível. Eu fiz algumas pesquisas no Google, mas não descobri o que "substitui" o WCF neste caso.

Como exponho uma Add(int x, int y)função dentro de uma biblioteca de classes para um aplicativo de console dentro do .Net Core? Vejo System.ServiceModel.Web e, uma vez que se trata de uma plataforma cruzada, tenho que criar um serviço RESTful?

Sigex
fonte
do I have to create a RESTful service?- AFAIK sim (ou use alguma solução de terceiros que não conheço para .NET Core)
Christoph Fink
3
O WCF provavelmente não será transferido para o .NET Core, porque a maior parte do código-base depende das bibliotecas internas do Windows. Você pode usar o ASP.NET Core? Lá você terá um servidor HTTP que é facilmente multiplataforma
Camilo Terevinto
2
O lado do cliente WCF já é suportado (não sei quanto), o lado do servidor é uma solicitação de recurso muito debatida e votada.
Henk Holterman
Parece que o Visual Studio 2017 15.5 e posterior oferecem suporte à geração de classes de proxy de cliente .NET Core . Também há uma lista de recursos com suporte .
jamiebarrow
5
Resumindo: CoreWCF
Dimitrov

Respostas:

35

O WCF não é compatível com o .NET Core, pois é uma tecnologia específica do Windows e o .NET Core deve ser multiplataforma.

Se você estiver implementando a comunicação entre processos, considere tentar o projeto IpcServiceFramework .

Ele permite criar serviços no estilo WCF como este:

  1. Criar contrato de serviço

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Implementar o serviço

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Hospedar o serviço no aplicativo de 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>();
        }
    }
    
  4. Chame o serviço do processo do cliente

    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
fonte
3
Agradável! Pode valer a pena atualizar para aproveitar as vantagens do .Net core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…
Sigex
Desculpe, estou perdendo algo importante aqui? Os tubos não deveriam ser apenas para as mesmas comunicações de host?
user1034912
2
Sim, o que está faltando é que isso demonstra brevemente que o IpcServiceFramework, como o WCF, permite que você alterne facilmente entre diferentes tecnologias de mensagens.
Chris F Carroll,
4
O WCF pode ser considerado específico do Windows em alguns dos protocolos que ele abstrai, mas os serviços SOAP não são. Como alguém criaria um serviço da web SOAP no núcleo .net?
Jeremy
3
Nota: o autor deste projeto escreveu o seguinte comentário: "Pessoal, por motivos pessoais, não tenho tempo para manter este projeto há alguns meses. Enquanto isso, o .NET Core 3.0 é lançado com o recurso gRPC." ( github.com/jacqueskang/IpcServiceFramework/issues/… ). Veja a segunda resposta para gRPC.
gerard
68

Você pode usar o gRPC para hospedar serviços da web dentro do aplicativo .NET core.

insira a descrição da imagem aqui

Introdução

  1. gRPC é uma estrutura RPC de código aberto de alto desempenho desenvolvida inicialmente pelo Google.
  2. A estrutura é baseada em um modelo cliente-servidor de chamadas de procedimento remoto. Um aplicativo cliente pode chamar métodos diretamente em um aplicativo de servidor como se fosse um objeto local.

Exemplo

Código do Servidor

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

Código do cliente

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

Aulas compartilhadas entre cliente e servidor

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

Descritores de serviço

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

Resultado

Saída de amostra do cliente

Resultado do servidor de amostra

Referências

  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
fonte
7
Em março de 2019, essa resposta é mais relevante. Consulte github.com/grpc/grpc-dotnet (e atualizações do ASP.NET Core no .NET Core 3.0 ).
resnyanskiy
1
Acho que esta é a resposta mais próxima, mas ainda assim, infelizmente, não fornece nenhum comportamento ou suporte de limitação.
joe
4
Esteja ciente também de que, a partir de agora gRPC, não compila na cadeia de ferramentas nativas .net no VS 2019 (16.0.2) e, portanto, não funcionará com UWP.
Samuel
2
Se você está procurando suporte para named pipe, escrevi um transporte gRPC
Cyanfish
1
Observe que (a partir de 2020-04-06) grpc-dotnet não tem pacotes para ARM.
GafferMan2112
23

Parece que haverá um projeto CoreWCF mantido pela .NET Foundation com suporte da Microsoft.

Mais detalhes em Welcoming Core WCF to the .NET Foundation

Inicialmente, apenas transporte netTcp e http serão implementados.

Rafał Straszewski
fonte
Esta é uma resposta enganosa. A Microsoft apenas portou o cliente wcf. O host wcf ou servicehost não está disponível e eles não têm a intenção de fazê-lo. Aprendi isso da maneira mais difícil. gRPC é o caminho a seguir
user1034912
@ user1034912 você não está correto. CoreWCF é um servidor WCF leve que é portado para o .NET core. Tem limitações, mas para alguns casos é uma boa escolha.
Acesso negado em
Sim, apenas se você for um cliente consumidor, não há implementação de
servicehost
@ user1034912 Não, o lado do servidor está disponível. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…
Acesso negado em
9

O WCF faz muitas coisas; é uma maneira fácil de realizar chamadas de procedimento remoto entre dois aplicativos (processos) em uma máquina, usando canais nomeados; pode ser um canal de comunicação cliente-servidor interno de alto volume entre componentes .NET, usando serialização binária sobre TCPIP; ou pode fornecer uma API de tecnologia cruzada padronizada, por exemplo, via SOAP. Ele ainda tem suporte para coisas como mensagens assíncronas, via MSMQ.

Para o .NET Core, existem diferentes substituições com base na finalidade.

Para API de plataforma cruzada, você deve substituir isso por um serviço REST usando ASP.NET.

Para conexões entre processos, ou conexão cliente-servidor, gRPC seria bom, com uma excelente resposta dada por @Gopi.

Portanto, a resposta para "O que substitui o WCF" depende de para que você o está usando.

Sly Gryphon
fonte
5

Há um repositório da comunidade https://github.com/CoreWCF/CoreWCF que implementa algumas partes do WCF. Você pode usá-lo para oferecer suporte a alguns serviços WCF simples. No entanto, nem todos os recursos são suportados.

orelabac
fonte
4

Portanto, de acordo com minha pesquisa, a melhor solução não possui as classes de proxy geradas automaticamente. A melhor solução é criar um serviço RESTful e serializar o corpo de resposta em objetos de modelo. Onde os modelos são os objetos de modelo usuais encontrados no padrão de projeto MVC.

Obrigado por suas respostas

Sigex
fonte
Sim, eram as classes de proxy geradas automaticamente que eu queria. Estou usando serviços RESTful / RPC para esta funcionalidade
Sigex
Este repo é apenas para as bibliotecas de cliente
orellabac
1

Você também pode hospedar a API da Web ASP.NET Core.

<!-- 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
fonte
A API da web do núcleo do Asp não suporta comunicações duplex em uma única porta como o wcf faz.
user1034912
0

Há uma porta .NET Core disponível: https://github.com/dotnet/wcf Ela ainda está em visualização, mas eles estão desenvolvendo-a ativamente.

Flupp
fonte
14
Eu acredito que esta porta é para comunicação do Core para o WCF, mas não para escrever o WCF no Core.
hal9000,
7
O repositório github vinculado diz claramente: "Este repo contém as bibliotecas WCF orientadas para o cliente que permitem que os aplicativos desenvolvidos no .NET Core se comuniquem com os serviços WCF."
Bahaa
0

Como hoje, todos os selfhost disponíveis WCFCore não são tão fáceis de instalar e usar.
O melhor para HostedService serão as alternativas como gRPC mostrou na resposta anterior e observe que em 1 ano pode mudar muitas coisas se o WCF é suportado no Core apenas como um cliente que funciona bem.

Jorge Alvarado
fonte