อะไรแทนที่ 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.