是什么取代了.Net Core中的WCF?

时间:2018-01-30 13:40:28

标签: c# .net wcf service .net-core

我习惯于创建一个.Net Framework控制台应用程序,并通过WCF服务从头开始使用类库(.Net Framework)公开Add(int x, int y)函数。然后我使用控制台应用程序在服务器内代理调用此函数。

但是,如果我使用Console App(.Net Core)和类库(.Net Core),则System.ServiceModel不可用。我做了一些谷歌搜索,但我还没有弄清楚"取代"在这种情况下的WCF。

如何在类库中将Add(int x, int y)函数公开到.Net Core中的控制台应用程序?我看到System.ServiceModel.Web,因为这是尝试跨平台,我是否必须创建一个RESTful服务?

9 个答案:

答案 0 :(得分:19)

您可以使用gRPC在.NET核心应用程序中托管Web服务。

enter image description here

简介

  1. gRPC是最初由Google开发的高性能,开源RPC框架。
  2. 该框架基于远程过程调用的客户端-服务器模型。客户端应用程序可以直接调用服务器应用程序上的方法,就像它是本地对象一样。

示例

服务器代码

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

客户代码

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

客户端和服务器之间的共享类

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

服务描述符

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

序列化器/反序列化器

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

输出

Sample client output

Sample Server output

参考

  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

基准

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

答案 1 :(得分:16)

.NET Core不支持WCF,因为它是Windows特定技术,而.NET Core应该是跨平台的。 如果要实现进程间通信,请考虑尝试this project。 它允许以WCF样式创建服务:

第1步-创建服务合同

public interface IComputingService
{
    float AddFloat(float x, float y);
}

第2步:实施服务

class ComputingService : IComputingService
{
    public float AddFloat(float x, float y)
    {
        return x + y;
    }
}

第3步-在控制台应用程序中托管服务

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步-从客户端进程调用服务

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

答案 2 :(得分:5)

似乎,.NET Foundation将在Microsoft支持下维护一个Core WCF项目。此处有更多详细信息:https://www.dotnetfoundation.org/blog/2019/06/07/welcoming-core-wcf-to-the-net-foundation

最初仅将实现netTcp和http传输。

答案 3 :(得分:4)

因此,根据我的研究,最佳解决方案没有自动生成的代理类。这个最佳解决方案是创建RESTful服务并将响应主体序列化为模型对象。模型是MVC设计模式中常见的模型对象。

感谢您的回复

答案 4 :(得分:3)

<块引用>

What's new in .NET 5 / Windows Communication Foundation

Windows Communication Foundation (WCF) 的原始实现仅在 Windows 上受支持。但是,.NET Foundation 提供了一个客户端端口。它是完全开源的、跨平台的,并由 Microsoft 提供支持。

社区维护补充上述客户端库的服务器组件。 GitHub 存储库可以在 CoreWCF 中找到。 Microsoft 不正式支持服务器组件。对于 WCF 的替代方案,请考虑 gRPC

答案 5 :(得分:1)

有一个实现WCF某些部分的社区仓库https://github.com/CoreWCF/CoreWCF。您可以使用它来支持一些简单的WCF服务。但是,并非所有功能都受支持。

答案 6 :(得分:0)

有一个可用的.NET Core端口:https://github.com/dotnet/wcf 它仍在预览中,但是他们正在积极开发它。

答案 7 :(得分:0)

您还可以自托管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}!";
    }
}

答案 8 :(得分:0)

今天,所有可用的WCFCore自托管主机都不容易安装和使用。
对于HostedService来说,最好的方法是gRPC在上一个答案中显示的替代方法,并请注意,在1年内可以更改许多功能,确保仅在工作正常的客户端上,Core中支持WCF。