什么可以替代.Net Core中的WCF?


100

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

但是,如果我使用控制台应用程序(.Net Core)和类库(.Net Core),则System.ServiceModel不可用。我已经做了一些谷歌搜索,但是我还没有弄清楚在这种情况下用什么“替代” WCF。

如何将Add(int x, int y)类库中的函数公开给.Net Core中的控制台应用程序?我看到了System.ServiceModel.Web,由于这是跨平台的,所以我必须创建一个RESTful服务吗?


do I have to create a RESTful service?-AFAIK是的(或使用某些第三方解决方案,.NET Core我将
Christoph Fink,

3
WCF不太可能移植到.NET Core,因为大多数代码库都依赖Windows内部库。可以使用ASP.NET Core吗?在那里你将有一个是容易的跨平台HTTP服务器
卡米洛Terevinto

2
WCF客户端已经受支持(我不知道有多少),服务器端是一个备受争议和质疑的功能请求。
Henk Holterman '18

似乎Visual Studio 2017 15.5和更高版本支持生成.NET Core客户端代理类。还列出了支持的功能
jamiebarrow

5
简而言之:CoreWCF
Ognyan Dimitrov,

Answers:


35

.NET Core不支持WCF,因为它是Windows特定的技术,并且.NET Core应该是跨平台的。

如果要实现进程间通信,请考虑尝试IpcServiceFramework项目。

它允许以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));
    

3
真好!可能是值得升级采取的.Net核心system.io.pipelines的优势 blogs.msdn.microsoft.com/dotnet/2018/07/09/...
Sigex

对不起,我在这里错过了重要的事情吗?管道不应该仅用于同一主机通信吗?
user1034912 '11

2
是的,您所缺少的是,这简要地证明了IpcServiceFramework和WCF一样,允许您在不同的消息传递技术之间无缝切换。
克里斯·卡罗尔

4
WCF在其抽象的某些协议中可能被视为特定于Windows的窗口,但SOAP服务却并非如此。如何在.net核心中创建SOAP Web服务?
杰里米

3
注意:该项目的作者写了以下评论:“伙计们,出于个人原因,自几个月以来,我没有时间来维护该项目。同时,.net Core 3.0具有gRPC功能。” (github.com/jacqueskang/IpcServiceFramework/issues/…)。请参阅gRPC的第二个答案。
杰拉德

68

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

在此处输入图片说明

介绍

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

输出量

客户端输出样本

样本服务器输出

参考文献

  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

7
截至2019年3月,此答案更为相关。请参阅github.com/grpc/grpc-dotnet(以及.NET Core 3.0中的ASP.NET Core更新)。
resnyanskiy

1
我认为这是最接近的答案,但可悲的是,它没有提供任何行为或限制支持。

4
另请注意,截至目前gRPC,VS 2019(16.0.2)中尚无法针对.net本机工具链进行编译,因此不适用于UWP。
塞缪尔

2
如果您正在寻找命名管道支持,我写了一个gRPC传输:github.com/cyanfish/grpc-dotnet-namedpipes
Cyanfish '20

1
请注意(截至2020-04-06),grpc-dotnet没有用于ARM的软件包。
GafferMan2112'4

23

看来,.NET Foundation将在Microsoft支持下维护一个CoreWCF项目。

欢迎使用核心WCF到.NET Foundation的更多详细信息

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


这是一个误导性的答案。Microsoft仅移植了wcf客户端。Wcf主机或servicehost不可用,并且无意这样做。我经过惨痛的教训才学到这个。gRPC是必经之路
user1034912 '20

@ user1034912您不正确。CoreWCF是轻量级的WCF服务器,已移植到.NET Core。它有局限性,但在某些情况下是个不错的选择。
拒绝访问

是的,仅当您是使用客户端时,才没有servicehost实现
user1034912 '20

@ user1034912否,服务器端可用。github.com/CoreWCF/CoreWCF/blob/master/src/Samples/...
拒绝访问


9

WCF做很多事情;这是一种使用命名管道在一台机器上的两个应用程序(进程)之间远程过程调用的简便方法;使用TCPIP上的二进制序列化,它可以是.NET组件之间的大量内部客户端-服务器通信通道;或者它可以提供标准化的跨技术API,例如通过SOAP。它甚至还支持通过MSMQ进行异步消息传递等操作。

对于.NET Core,根据用途有不同的替代品。

对于跨平台API,您可以使用ASP.NET将其替换为REST服务。

对于进程间连接或客户机/服务器连接,gRPC会很好,@ Gopi给出了一个很好的答案。

因此,“用什么代替WCF”的答案取决于您使用它的目的。



4

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

谢谢您的反馈



是的,这是我想要的自动生成的代理类。我正在为此功能使用RESTful服务/ RPC
Sigex

此存储库仅用于客户端库
orellabac

1

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

ASP核心Web API不像wcf那样在单个端口上支持双工通信。
user1034912 '20

0

有可用的.NET Core端口:https : //github.com/dotnet/wcf 它仍处于预览状态,但他们正在积极开发它。


14
我相信此端口用于从Core到WCF的通信,而不用于在Core中编写WCF。
hal9000

7
链接的github存储库明确表示:“此存储库包含面向客户端的WCF库,这些库使基于.NET Core构建的应用程序能够与WCF服务进行通信。”
Bahaa

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.