¿Qué reemplaza a WCF en .Net Core?

96

Estoy acostumbrado a crear una aplicación de consola .Net Framework y exponer una Add(int x, int y)función a través de un servicio WCF desde cero con Class Library (.Net Framework). Luego utilizo la aplicación de consola para llamar a esta función dentro del servidor.

Sin embargo, si uso la aplicación de consola (.Net Core) y una biblioteca de clases (.Net Core), System.ServiceModel no está disponible. He hecho algunas búsquedas en Google, pero no he descubierto qué "reemplaza" a WCF en este caso.

¿Cómo expongo una Add(int x, int y)función dentro de una biblioteca de clases a una aplicación de consola dentro de .Net Core? Veo System.ServiceModel.Web, y dado que esto intenta ser multiplataforma, ¿tengo que crear un servicio RESTful?

Sigex
fuente
do I have to create a RESTful service?- AFAIK, sí (o use alguna solución de terceros que no conocería para .NET Core)
Christoph Fink
3
Es probable que WCF no se migre a .NET Core, porque la mayor parte del código base depende de las bibliotecas internas de Windows. ¿Puedes usar ASP.NET Core? Allí tendrá un servidor HTTP que es fácilmente multiplataforma
Camilo Terevinto
2
El lado del cliente de WCF ya es compatible (no sé cuánto), el lado del servidor es una solicitud de función muy debatida y votada.
Henk Holterman
Parece que Visual Studio 2017 15.5 y versiones posteriores admiten la generación de clases de proxy de cliente .NET Core . También hay una lista de funciones compatibles .
jamiebarrow
5
En resumen: CoreWCF
Ognyan Dimitrov

Respuestas:

35

WCF no es compatible con .NET Core porque es una tecnología específica de Windows y se supone que .NET Core es multiplataforma.

Si está implementando la comunicación entre procesos, considere probar el proyecto IpcServiceFramework .

Permite crear servicios en estilo WCF como este:

  1. Crear contrato de servicio

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Implementar el servicio

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Alojar el servicio en la aplicación de consola

    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. Invocar el servicio desde el proceso del 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
fuente
3
¡Agradable! Puede que valga la pena actualizarlo para aprovechar .Net core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…
Sigex
Lo siento, ¿me estoy perdiendo algo importante aquí? ¿No se supone que las tuberías son solo para comunicaciones con el mismo host?
user1034912
2
Sí, lo que se está perdiendo es que esto demuestra brevemente que IpcServiceFramework, como WCF, le permite cambiar sin problemas entre diferentes tecnologías de mensajería.
Chris F Carroll
4
WCF puede considerarse específico de Windows en algunos de los protocolos que abstrae, pero los servicios SOAP no. ¿Cómo se crearía un servicio web SOAP en .net core?
Jeremy
3
Nota: el autor de este proyecto escribió el siguiente comentario: "Chicos, por razones personales, no tengo tiempo para mantener este proyecto desde hace unos meses. Mientras tanto, .NET Core 3.0 se lanza con la función gRPC". ( github.com/jacqueskang/IpcServiceFramework/issues/… ). Vea la segunda respuesta para gRPC.
gerard
64

Puede utilizar gRPC para alojar servicios web dentro de la aplicación principal .NET.

ingrese la descripción de la imagen aquí

Introducción

  1. gRPC es un marco de trabajo RPC de código abierto de alto rendimiento desarrollado inicialmente por Google.
  2. El marco se basa en un modelo cliente-servidor de llamadas a procedimientos remotos. Una aplicación cliente puede llamar directamente a métodos en una aplicación de servidor como si fuera un objeto local.

Ejemplo

Código del 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();
    }
}

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

Clases compartidas entre cliente y 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; }
}

Descriptores de servicio

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

Serializador / Deserializador

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

Salida

Salida de cliente de muestra

Salida del servidor de muestra

Referencias

  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
fuente
7
A marzo de 2019, esta respuesta es más relevante. Consulte github.com/grpc/grpc-dotnet (y actualizaciones de ASP.NET Core en .NET Core 3.0 ).
resnyanskiy
1
Creo que esta es la respuesta más cercana, pero aún así, lamentablemente, no proporciona ningún comportamiento o soporte de estrangulamiento.
Joe
4
Tenga en cuenta también que a partir de ahora gRPCno se compila con la cadena de herramientas nativas .net en VS 2019 (16.0.2) y, por lo tanto, no funcionará con UWP.
Samuel
2
Si está buscando soporte de tubería con nombre, escribí un transporte de gRPC
Cyanfish
1
Tenga en cuenta que (a partir de 2020-04-06) grpc-dotnet no tiene paquetes para ARM.
GafferMan2112
23

Parece que habrá un proyecto CoreWCF mantenido por .NET Foundation con soporte de Microsoft.

Más detalles en Bienvenido a Core WCF a .NET Foundation

Inicialmente, solo se implementarán el transporte netTcp y http.

Rafał Straszewski
fuente
Esta es una respuesta engañosa. Microsoft solo ha portado el cliente wcf. Wcf host o servicehost no está disponible y no tienen la intención de hacerlo. Aprendí esto de la manera más difícil. gRPC es el camino a seguir
user1034912
@ user1034912 no es correcto. CoreWCF es un servidor WCF ligero que se transfiere a .NET core. Tiene limitaciones, pero en algunos casos es una buena opción.
Acceso denegado el
Sí, solo si es un Cliente Consumidor, no hay implementación de
servicehost
@ user1034912 No, el lado del servidor está disponible. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…
Acceso denegado el
9

WCF hace muchas cosas; es una manera fácil de realizar llamadas a procedimientos remotos entre dos aplicaciones (procesos) en una máquina, utilizando canalizaciones con nombre; puede ser un canal de comunicación cliente-servidor interno de alto volumen entre componentes .NET, utilizando serialización binaria sobre TCPIP; o puede proporcionar una API de tecnología cruzada estandarizada, por ejemplo, a través de SOAP. Incluso tiene soporte para cosas como mensajería asincrónica, a través de MSMQ.

Para .NET Core, existen diferentes reemplazos según el propósito.

Para API multiplataforma, lo reemplazaría con un servicio REST usando ASP.NET.

Para conexiones entre procesos, o conexión cliente-servidor, gRPC sería bueno, con una excelente respuesta dada por @Gopi.

Entonces, la respuesta a "Lo que reemplaza a WCF" depende de para qué lo esté usando.

Grifo astuto
fuente
5

Hay un repositorio de la comunidad https://github.com/CoreWCF/CoreWCF que implementa algunas partes de WCF. Puede usarlo para admitir algunos servicios WCF simples. Sin embargo, no todas las funciones son compatibles.

Orellabac
fuente
4

Entonces, de mi investigación, la mejor solución no tiene las clases de proxy generadas automáticamente. Esta mejor solución es crear un servicio RESTful y serializar el cuerpo de respuesta en objetos de modelo. Donde los modelos son los objetos de modelo habituales que se encuentran en el patrón de diseño MVC.

Gracias por sus respuestas

Sigex
fuente
Sí, eran las clases de proxy generadas automáticamente lo que quería. Estoy usando servicios RESTful / RPC para esta funcionalidad
Sigex
Este repositorio es solo para las bibliotecas cliente
orellabac
Restful no admite comunicaciones dúplex
user1034912
1

También puede autohospedar la API 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
fuente
Asp core web api no admite comunicaciones dúplex en un solo puerto como lo hace wcf.
user1034912
0

Hay un puerto .NET Core disponible: https://github.com/dotnet/wcf Todavía está en versión preliminar, pero lo están desarrollando activamente.

Flupp
fuente
14
Creo que este puerto es para la comunicación de Core a WCF pero no para escribir WCF en Core.
hal9000
7
El repositorio de github vinculado dice claramente: "Este repositorio contiene las bibliotecas WCF orientadas al cliente que permiten que las aplicaciones creadas en .NET Core se comuniquen con los servicios WCF".
Bahaa
0

Como en la actualidad, todos los selfhost disponibles de WCFCore no son tan fáciles de instalar y usar.
Lo mejor para HostedService serán las alternativas como gRPC mostró en la respuesta anterior y observe que en 1 año pueden cambiar muchas cosas, seguro que WCF es compatible con Core solo como un cliente que funciona bien.

Jorge Alvarado
fuente