.Net Core에서 WCF를 대체하는 것은 무엇입니까?


101

.Net Framework 콘솔 응용 프로그램을 만들고 Add(int x, int y)클래스 라이브러리 (.Net Framework)를 사용하여 처음부터 WCF 서비스를 통해 함수를 노출하는 데 익숙합니다 . 그런 다음 콘솔 응용 프로그램을 사용하여 서버 내에서이 함수를 프록시 호출합니다.

그러나 콘솔 앱 (.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
대부분의 코드 기반은 Windows 내부 라이브러리에 의존하기 때문에 WCF는 .NET Core로 이식되지 않을 것입니다. ASP.NET Core를 사용할 수 있습니까? 거기 당신은 쉽게 크로스 플랫폼의 HTTP 서버거야
카밀 Terevinto

2
WCF 클라이언트 측은 이미 지원되고 있으며 (얼마나 잘 모르겠습니다), 서버 측은 열띤 논쟁을 벌이고있는 기능 요청입니다.
Henk Holterman

Visual Studio 2017 15.5 이상이 .NET Core 클라이언트 프록시 클래스 생성을 지원 하는 것으로 보입니다 . 지원되는 기능 목록도 있습니다 .
jamiebarrow

5

답변:


35

WCF는 Windows 특정 기술이고 .NET Core는 크로스 플랫폼이어야하므로 .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

2
예, 당신이 놓친 것은 WCF와 같은 IpcServiceFramework를 사용하여 서로 다른 메시징 기술간에 원활하게 전환 할 수 있음을 간략하게 보여 준다는 것입니다.
Chris F Carroll

4
WCF는 추상화하는 일부 프로토콜에서 특정 창으로 간주 될 수 있지만 SOAP 서비스는 그렇지 않습니다. .net 코어에서 SOAP 웹 서비스를 어떻게 생성합니까?
Jeremy

1
WCF는 "Windows 전용 기술"이 아니라 상호 운용 가능한 SOAP / WSDL 스택을 구현하는 .NET 방식입니다. 이를 지원하지 않는 웹 프레임 워크는 이미 구현 된 수천 개의 서비스에 쉽게 연결할 수있는 방법이 없습니다. 확실히 향후 .NET 코어에서 해결해야 할 문제입니다.
Wiktor Zychla

3
참고 :이 프로젝트의 작성자는 "여러분, 개인적인 이유로 몇 달 동안이 프로젝트를 유지할 시간이 없습니다. 그동안 .NET Core 3.0이 gRPC 기능과 함께 출시되었습니다."라는 의견을 작성했습니다. ( github.com/jacqueskang/IpcServiceFramework/issues/… ). gRPC에 대한 두 번째 답변을 참조하십시오.
gerard

68

.NET 핵심 애플리케이션 내에서 웹 서비스를 호스팅하는 데 gRPC를 사용할 수 있습니다.

여기에 이미지 설명 입력

소개

  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
현재로서는 gRPCVS 2019 (16.0.2)의 .net 네이티브 도구 체인에 대해 컴파일되지 않으므로 UWP에서 작동하지 않습니다.
Samuel

2
명명 된 파이프 지원을 찾고 있다면 gRPC 전송을 작성했습니다. github.com/cyanfish/grpc-dotnet-namedpipes
Cyanfish

1
(2020-04-06 기준) grpc-dotnet에는 ARM 용 패키지가 없습니다.
GafferMan2112

23

Microsoft 지원을 통해 .NET Foundation에서 유지 관리 하는 CoreWCF 프로젝트 가있을 것 같습니다 .

.NET Foundation에 Core WCF 환영 에서 자세한 내용

처음에는 netTcp 및 http 전송 만 구현됩니다.


이것은 잘못된 대답입니다. Microsoft는 wcf 클라이언트 만 포팅했습니다. Wcf 호스트 또는 서비스 호스트를 사용할 수 없으며 그렇게 할 의도가 없습니다. 나는 이것을 어려운 방법으로 배웠다. gRPC는 갈 길이
멉니 다

@ user1034912 당신이 맞지 않습니다. CoreWCF는 .NET 코어로 포팅되는 경량 WCF 서버입니다. 한계가 있지만 어떤 경우에는 좋은 선택입니다.
액세스가 거부

예, 사용자 클라이언트 경우에만, 어떤 ServiceHost를 구현 없다
user1034912

@ user1034912 아니요, 서버 측을 사용할 수 있습니다. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/...
액세스가 거부


9

WCF는 많은 일을합니다. 명명 된 파이프를 사용하여 한 시스템에서 두 응용 프로그램 (프로세스) 간의 원격 프로 시저 호출을 쉽게 수행 할 수 있습니다. TCPIP를 통한 이진 직렬화를 사용하는 .NET 구성 요소 간의 대용량 내부 클라이언트-서버 통신 채널이 될 수 있습니다. 또는 SOAP를 통해 표준화 된 교차 기술 API를 제공 할 수 있습니다. MSMQ를 통한 비동기 메시징과 같은 기능도 지원합니다.

.NET Core의 경우 목적에 따라 다른 대체 항목이 있습니다.

크로스 플랫폼 API의 경우이를 ASP.NET을 사용하는 REST 서비스로 대체합니다.

프로세스 간 연결 또는 클라이언트-서버 연결의 경우 gRPC가 좋으며 @Gopi가 제공하는 훌륭한 대답이 있습니다.

따라서 "WCF를 대체하는 항목"에 대한 대답은 사용 용도에 따라 다릅니다.


5

WCF의 일부를 구현 하는 커뮤니티 저장소 https://github.com/CoreWCF/CoreWCF 가 있습니다. 몇 가지 간단한 WCF 서비스를 지원하는 데 사용할 수 있습니다. 그러나 모든 기능이 지원되는 것은 아닙니다.


4

따라서 내 연구에서 최고의 솔루션에는 자동 생성 프록시 클래스가 없습니다. 이 최상의 솔루션은 RESTful 서비스를 만들고 응답 본문을 모델 개체로 직렬화하는 것입니다. 모델은 MVC 디자인 패턴에서 발견되는 일반적인 모델 개체입니다.

귀하의 답변에 감사드립니다



네, 제가 원하는 자동 생성 프록시 클래스였습니다. 이 기능을 위해 RESTful 서비스 / RPC를 사용하고 있습니다
Sigex

이 REPO는 클라이언트 라이브러리입니다
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 코어 웹 API는 wcf와 같은 단일 포트에서 이중 통신을 지원하지 않습니다.
user1034912

0

.NET Core 포트를 사용할 수 있습니다. https://github.com/dotnet/wcf 아직 미리보기 단계이지만 적극적으로 개발 중입니다.


14
이 포트는 Core에서 WCF 로의 통신을위한 것이지만 Core에서 WCF를 작성하기위한 것이 아니라고 생각합니다.
hal9000

7
연결된 github 리포지토리에는 "이 리포지토리에는 .NET Core에 구축 된 애플리케이션이 WCF 서비스와 통신 할 수 있도록하는 클라이언트 지향 WCF 라이브러리가 포함되어 있습니다."
Bahaa

0

오늘날 사용 가능한 모든 WCFCore 셀프 호스트는 설치 및 사용이 쉽지 않습니다.
HostedService에 가장 적합한 것은 gRPC가 이전 답변에서 보여준 것과 같은 대안이 될 것이며 1 년 안에 WCF가 제대로 작동하는 클라이언트로만 Core에서 지원되는지 많은 것을 변경할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.