อะไรแทนที่ WCF ใน. Net Core


96

ฉันคุ้นเคยกับการสร้างแอปพลิเคชันคอนโซล. Net Framework และเปิดเผยAdd(int x, int y)ฟังก์ชันผ่านบริการ WCF ตั้งแต่เริ่มต้นด้วย Class Library (.Net Framework) จากนั้นฉันใช้แอปพลิเคชันคอนโซลเพื่อพร็อกซีเรียกใช้ฟังก์ชันนี้ภายในเซิร์ฟเวอร์

อย่างไรก็ตามหากฉันใช้ Console App (.Net Core) และ Class Library (.Net Core) System.ServiceModel จะไม่พร้อมใช้งาน ฉันได้ทำ Googling ไปบ้างแล้ว แต่ยังไม่ทราบว่า 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 ที่สามารถข้ามแพลตฟอร์มได้อย่างง่ายดาย
— Camilo Terevinto

2
ฝั่งไคลเอ็นต์ WCF ได้รับการสนับสนุนแล้ว (ฉันไม่รู้ว่าเท่าไหร่) ฝั่งเซิร์ฟเวอร์เป็นคำขอคุณลักษณะที่มีการถกเถียงกันอย่างมากและได้รับการโหวต
— Henk Holterman

มันจะปรากฏ Visual Studio 2017 15.5 และต่อมาสนับสนุนการสร้าง .NET คอร์พร็อกซี่ลูกค้าชั้นเรียน นอกจากนี้ยังมีรายชื่อของคุณสมบัติที่รองรับ
— jamiebarrow

5
ในระยะสั้น: CoreWCF
— Ognyan Dimitrov

คำตอบ:


35

ไม่รองรับ WCF ใน. NET Core เนื่องจากเป็นเทคโนโลยีเฉพาะของ 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 core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…
— Sigex

ขอโทษนะที่นี่ฉันพลาดของสำคัญไปหรือเปล่า? ไม่ควรไปป์สำหรับการสื่อสารโฮสต์เดียวกันหรือไม่?
— user1034912

2
ใช่สิ่งที่คุณขาดหายไปคือสิ่งนี้แสดงให้เห็นสั้น ๆ ว่า IpcServiceFramework เช่น WCF ช่วยให้คุณสามารถสลับชนิดของเทคโนโลยีการส่งข้อความที่แตกต่างกันได้อย่างราบรื่น
— Chris F Carroll

4
WCF อาจถูกพิจารณาว่าเป็น windows เฉพาะในบางโปรโตคอลที่เป็นนามธรรม แต่บริการ SOAP ไม่ใช่ เราจะสร้างบริการเว็บ SOAP ใน. net core ได้อย่างไร?
— Jeremy

3
หมายเหตุ: ผู้เขียนโครงการนี้เขียนความคิดเห็นต่อไปนี้: "Guys ด้วยเหตุผลส่วนตัวฉันไม่มีเวลาดูแลโครงการนี้ตั้งแต่สองสามเดือนขณะเดียวกัน. NET Core 3.0 ได้รับการเผยแพร่พร้อมคุณสมบัติ gRPC" ( github.com/jacqueskang/IpcServiceFramework/issues/… ) ดูคำตอบที่สองสำหรับ gRPC
— เจอราร์ด

64

คุณสามารถใช้ gRPC สำหรับโฮสต์บริการเว็บภายในแอปพลิเคชันหลัก. NET

ป้อนคำอธิบายภาพที่นี่

บทนำ

  1. gRPC เป็นเฟรมเวิร์ก RPC โอเพ่นซอร์สประสิทธิภาพสูงที่พัฒนาโดย Google
  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));
}

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

เอาต์พุต

ตัวอย่างผลลัพธ์ของไคลเอ็นต์

เอาต์พุตเซิร์ฟเวอร์ตัวอย่าง

อ้างอิง

  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 มีความเกี่ยวข้องมากขึ้น ดูที่github.com/grpc/grpc-dotnet (และการอัปเดต ASP.NET Core ใน. NET Core 3.0 )
— resnyanskiy

1
ฉันคิดว่านี่เป็นคำตอบที่ใกล้เคียงที่สุด แต่ยังน่าเศร้าที่มันไม่ได้ให้การสนับสนุนพฤติกรรมหรือการควบคุมปริมาณใด ๆ
— โจ

4
โปรดทราบด้วยว่า ณ ตอนนี้gRPCไม่สามารถคอมไพล์กับห่วงโซ่เครื่องมือ. net แบบเนทีฟใน VS 2019 (16.0.2) ดังนั้นจึงใช้ไม่ได้กับ UWP
— ซามูเอล

2
หากคุณกำลังมองหาการสนับสนุนท่อที่มีชื่อฉันเขียนการขนส่ง gRPC: github.com/cyanfish/grpc-dotnet-namedpipes
— Cyanfish

1
โปรดทราบว่า (ณ วันที่ 2020-04-06) grpc-dotnet ไม่มีแพ็คเกจสำหรับ ARM
— GafferMan2112

23

ดูเหมือนว่าจะมีโครงการCoreWCF ที่ดูแลโดย. NET Foundation พร้อมการสนับสนุนของ Microsoft

รายละเอียดเพิ่มเติมที่Welcoming Core WCF to the .NET Foundation

ในขั้นต้นจะดำเนินการเฉพาะการขนส่ง netTcp และ http เท่านั้น


นี่เป็นคำตอบที่ทำให้เข้าใจผิด Microsoft มีพอร์ตเฉพาะไคลเอ็นต์ wcf เท่านั้น โฮสต์ Wcf หรือโฮสต์บริการไม่พร้อมใช้งานและไม่มีความตั้งใจที่จะทำเช่นนั้น ฉันเรียนรู้วิธีนี้ยาก gRPC คือหนทางที่จะไป
— user1034912

@ user1034912 คุณไม่ถูกต้อง CoreWCF เป็นเซิร์ฟเวอร์ WCF ที่มีน้ำหนักเบาซึ่งพอร์ตไปยัง. NET core มันมีข้อ จำกัด แต่สำหรับบางกรณีก็เป็นทางเลือกที่ดี
— การเข้าถึงถูกปฏิเสธ

ใช่เฉพาะในกรณีที่คุณเป็นลูกค้าที่ใช้งานอยู่จะไม่มีการใช้งาน
— โฮสต์บริการ

@ user1034912 ไม่ฝั่งเซิร์ฟเวอร์ใช้ได้ github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…
— การเข้าถึงถูกปฏิเสธ


9

WCF ทำหลายอย่าง มันเป็นวิธีง่ายๆในการเรียกโพรซีเดอร์ระยะไกลระหว่างสองแอพพลิเคชั่น (กระบวนการ) ในเครื่องเดียวโดยใช้ชื่อไปป์ อาจเป็นช่องทางการสื่อสารไคลเอนต์เซิร์ฟเวอร์ภายในปริมาณมากระหว่างคอมโพเนนต์. NET โดยใช้ไบนารีอนุกรมผ่าน TCPIP หรือสามารถให้ API ข้ามเทคโนโลยีที่เป็นมาตรฐานเช่นผ่าน SOAP มันยังรองรับสิ่งต่างๆเช่นการส่งข้อความแบบอะซิงโครนัสผ่าน MSMQ

สำหรับ. NET Core มีการเปลี่ยนที่แตกต่างกันตามวัตถุประสงค์

สำหรับ API ข้ามแพลตฟอร์มคุณจะแทนที่สิ่งนี้ด้วยบริการ REST โดยใช้ ASP.NET

สำหรับการเชื่อมต่อระหว่างกระบวนการหรือการเชื่อมต่อไคลเอนต์เซิร์ฟเวอร์ gRPC จะดีด้วยคำตอบที่ยอดเยี่ยมจาก @Gopi

ดังนั้นคำตอบของ "สิ่งที่แทนที่ WCF" ขึ้นอยู่กับว่าคุณใช้มันเพื่ออะไร


5

มีชุมชน repo https://github.com/CoreWCF/CoreWCFที่ใช้บางส่วนของ WCF คุณสามารถใช้เพื่อสนับสนุนบริการ WCF ง่ายๆ อย่างไรก็ตามไม่รองรับคุณสมบัติทั้งหมด


4

ดังนั้นจากการวิจัยของฉันทางออกที่ดีที่สุดไม่มีคลาสพร็อกซีที่สร้างขึ้นโดยอัตโนมัติ ทางออกที่ดีที่สุดนี้คือการสร้างบริการ RESTful และทำให้เนื้อหาการตอบสนองเป็นแบบ โดยที่โมเดลเป็นวัตถุโมเดลทั่วไปที่พบในรูปแบบการออกแบบ MVC

ขอบคุณสำหรับการตอบกลับของคุณ



ใช่มันเป็นคลาสพร็อกซีที่สร้างขึ้นโดยอัตโนมัติที่ฉันต้องการ ฉันใช้บริการ RESTful / RPC สำหรับฟังก์ชันนี้
— Sigex

repo นี้มีไว้สำหรับไลบรารีไคลเอ็นต์เท่านั้น
— orellabac

Restful ไม่รองรับการสื่อสารแบบดูเพล็กซ์
— user1034912

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 core web api ไม่รองรับการสื่อสารแบบดูเพล็กซ์บนพอร์ตเดียวเหมือนกับวิธีที่ wcf ทำ
— user1034912

0

มีพอร์ต. NET Core ให้ใช้งาน: https://github.com/dotnet/wcf ยังอยู่ในการแสดงตัวอย่าง แต่พวกเขากำลังพัฒนาอย่างต่อเนื่อง


14
ฉันเชื่อว่าพอร์ตนี้มีไว้สำหรับการสื่อสารจาก Core ถึง WCF แต่ไม่ใช่สำหรับการเขียน WCF ใน Core
— hal9000

7
ที่เก็บ github ที่เชื่อมโยงระบุไว้อย่างชัดเจนว่า: "repo นี้มีไลบรารี WCF สำหรับไคลเอนต์ที่เปิดใช้งานแอปพลิเคชันที่สร้างบน. NET Core เพื่อสื่อสารกับบริการ WCF"
— Bahaa

0

ณ วันนี้ WCFCore selfhost Available ทั้งหมดไม่ใช่เรื่องง่ายที่จะติดตั้งและใช้งาน
สิ่งที่ดีที่สุดสำหรับ HostedService จะเป็นทางเลือกอื่นตามที่ gRPC แสดงไว้ในคำตอบก่อนหน้านี้และสังเกตว่าใน 1 ปีสามารถเปลี่ยนแปลงหลายสิ่งได้อย่างแน่นอนว่า WCF รองรับใน Core เป็นไคลเอนต์ที่ทำงานได้ดีเท่านั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.