c# - ¿Qué reemplaza a WCF en.Net Core?
wcf net core 2 (4)
Así que 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 la respuesta en objetos 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
Estoy acostumbrado a crear una aplicación de consola de .Net Framework y exponer una función Add(int x, int y)
través de un servicio WCF desde cero con Class Library (.Net Framework). Luego uso la aplicación de consola para llamar a esta función desde el 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 algo de Google pero no he descubierto qué "reemplaza" a WCF en este caso.
¿Cómo expongo una función Add(int x, int y)
dentro de una biblioteca de clases a una aplicación de consola, todo dentro de .Net Core? Veo System.ServiceModel.Web y, como esto intenta ser multiplataforma, ¿tengo que crear un servicio RESTful?
Hay un puerto .NET Core disponible: github.com/dotnet/wcf Todavía está en vista previa, pero lo están desarrollando activamente.
Puede usar gRPC para hospedar servicios web dentro de la aplicación central de .NET.
Introducción
- gRPC es un marco RPC de código abierto y alto rendimiento desarrollado inicialmente por Google.
- 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 del servidor de muestra
Referencias
- https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/
- https://grpc.io/docs/
- https://grpc.io/docs/quickstart/csharp.html
- https://github.com/grpc/grpc/tree/master/src/csharp
Puntos de referencia
WCF no es compatible con .NET Core ya que es una tecnología específica de Windows, mientras que .NET Core se supone que es multiplataforma. Si está implementando la comunicación entre procesos, considere probar este proyecto . Permite crear servicios en estilo WCF:
Paso 1 - Crear contrato de servicio
public interface IComputingService
{
float AddFloat(float x, float y);
}
Paso 2: Implementar el servicio.
class ComputingService : IComputingService
{
public float AddFloat(float x, float y)
{
return x + y;
}
}
Paso 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>();
}
}
Paso 4 - Invoque 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));