What replaces WCF in .Net Core?
Asked Answered
U

14

140

I am used to creating a .Net Framework console application and exposing a Add(int x, int y) function via a WCF service from scratch with Class Library (.Net Framework). I then use the console application to proxy call this function within the server.

However if I use Console App (.Net Core) and a Class Library (.Net Core) the System.ServiceModel is not available. I have done some Googling but I haven't figured out what "replaces" WCF in this instance.

How do I expose a Add(int x, int y) function within a class library to a console application all within .Net Core? I see System.ServiceModel.Web, and since this is trying to be cross platform do I have to create a RESTful service?

Uncivil answered 30/1, 2018 at 13:40 Comment(7)
do I have to create a RESTful service? - AFAIK yes (or use some 3rd-Party solution I would not know any for .NET Core)Banker
WCF won't likely be ported to .NET Core, because most of the code-base depends on Windows internal libraries. Can you use ASP.NET Core? There you'll have a HTTP server that's readily cross-platformXylotomous
WCF client-side is already supported (I don't know how much), server-side is a hotly debated and votred feature request.Jujitsu
It appears Visual Studio 2017 15.5 and later support generating .NET Core client proxy classes . There is also a list of supported features.Kayne
There is a port for .NET Core: github.com/dotnet/wcfTiepolo
In short : CoreWCFUnexampled
mobilize.net/blog/can-i-use-wcf-in-.net-core-3.1-or-.net5Petronella
D
41

WCF is not supported in .NET Core since it's a Windows specific technology and .NET Core is supposed to be cross-platform.

If you are implementing inter-process communication consider trying the IpcServiceFramework project.

It allows creating services in WCF style like this:

  1. Create service contract

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Implement the service

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Host the service in Console application

    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. Invoke the service from client process

    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));
    
Diadem answered 16/7, 2018 at 8:57 Comment(9)
Nice! Might be worth updating to take advantage of the .Net core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…Uncivil
Sorry am i missing something important here? Isn't pipes supposed to be only for same host communications?Magazine
Yes, what you're missing is that this briefly demonstrates that IpcServiceFramework, like WCF, allows you to switch kind-of-seamlessly between different messaging technologies.Aubarta
WCF might be considered windows specific in some of the protocols that it abstracts, but SOAP services are not. How would one create a SOAP web service in .net core?Prepotency
WCF is not a "windows specific technology" but rather, a .NET way of implementing the interoperable SOAP/WSDL stack. A web framework that doesn't support it has no easy way to connect to thousand of already implemented services. Definitely something that has to be addressed in future .NET core.Gare
Note: the author of this project wrote the following comment: "Guys, for personal reason I do have no time to maintain this project since a few months. Meantime .NET Core 3.0 is released with gRPC feature." (github.com/jacqueskang/IpcServiceFramework/issues/…). See the second answer for gRPC.Gerstner
"WCF is not supported in .NET Core since it's a Windows specific technology while .NET Core is supposed to be cross-platform." And then, there's WPF. :(Steinberg
Why did you decide to use a Lambda for invoke rather than DispatchProxy or even IL Emit? You could construct a transparent Proxy object with either of these options. Since you are going over network the reflection perf hits would be swamped by the latency anyway.Sihun
The client part if supported up to certain extend: mobilize.net/blog/can-i-use-wcf-in-.net-core-3.1-or-.net5Petronella
S
86

You can use gRPC for hosting web services inside .NET core application.

enter image description here

Introduction

  1. gRPC is a high performance, open source RPC framework initially developed by Google.
  2. The framework is based on a client-server model of remote procedure calls. A client application can directly call methods on a server application as if it was a local object.

Example

Server Code

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

Client Code

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

Shared Classes between Client and Server

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

Service descriptors

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

Output

Sample client

Sample client output

Sample Server

Sample Server output

References

  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

Benchmarks

  1. http://csharptest.net/787/benchmarking-wcf-compared-to-rpclibrary/index.html
Sicklebill answered 16/9, 2018 at 20:10 Comment(6)
As of March 2019, this answer is more relevant. See github.com/grpc/grpc-dotnet (and ASP.NET Core updates in .NET Core 3.0).Strychnine
I think this is the closest answer but still, sadly , it doesn't provide any behavior or throttling support.Luzluzader
Be also aware that as of now gRPC does not compile against the .net native tool chain in VS 2019 (16.0.2) and therefore won't work with UWP.Ope
If you're looking for named pipe support, I wrote a gRPC transport: github.com/cyanfish/grpc-dotnet-namedpipesPokeberry
Note that (as of 2020-04-06) grpc-dotnet doesn't have packages for ARM.Spasmodic
Also note, that it makes use of the HTTP/2 protocol. blog.netsil.com/…Horatio
D
41

WCF is not supported in .NET Core since it's a Windows specific technology and .NET Core is supposed to be cross-platform.

If you are implementing inter-process communication consider trying the IpcServiceFramework project.

It allows creating services in WCF style like this:

  1. Create service contract

    public interface IComputingService
    {
        float AddFloat(float x, float y);
    }
    
  2. Implement the service

    class ComputingService : IComputingService
    {
        public float AddFloat(float x, float y)
        {
            return x + y;
        }
    }
    
  3. Host the service in Console application

    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. Invoke the service from client process

    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));
    
Diadem answered 16/7, 2018 at 8:57 Comment(9)
Nice! Might be worth updating to take advantage of the .Net core system.io.pipelines blogs.msdn.microsoft.com/dotnet/2018/07/09/…Uncivil
Sorry am i missing something important here? Isn't pipes supposed to be only for same host communications?Magazine
Yes, what you're missing is that this briefly demonstrates that IpcServiceFramework, like WCF, allows you to switch kind-of-seamlessly between different messaging technologies.Aubarta
WCF might be considered windows specific in some of the protocols that it abstracts, but SOAP services are not. How would one create a SOAP web service in .net core?Prepotency
WCF is not a "windows specific technology" but rather, a .NET way of implementing the interoperable SOAP/WSDL stack. A web framework that doesn't support it has no easy way to connect to thousand of already implemented services. Definitely something that has to be addressed in future .NET core.Gare
Note: the author of this project wrote the following comment: "Guys, for personal reason I do have no time to maintain this project since a few months. Meantime .NET Core 3.0 is released with gRPC feature." (github.com/jacqueskang/IpcServiceFramework/issues/…). See the second answer for gRPC.Gerstner
"WCF is not supported in .NET Core since it's a Windows specific technology while .NET Core is supposed to be cross-platform." And then, there's WPF. :(Steinberg
Why did you decide to use a Lambda for invoke rather than DispatchProxy or even IL Emit? You could construct a transparent Proxy object with either of these options. Since you are going over network the reflection perf hits would be swamped by the latency anyway.Sihun
The client part if supported up to certain extend: mobilize.net/blog/can-i-use-wcf-in-.net-core-3.1-or-.net5Petronella
F
37

It seems, that there will be a CoreWCF project maintained by .NET Foundation with Microsoft support.

More details at Welcoming Core WCF to the .NET Foundation

Initially only netTcp and http transport will be implemented.

Firebreak answered 11/6, 2019 at 12:28 Comment(7)
This is a misleading answer. Microsoft has only ported the wcf client. Wcf host or servicehost is not available and they have no intention to do so. I learned this the hard way. gRPC is the way to goMagazine
@Magazine you are not correct. CoreWCF is lightweight WCF server which is ported to .NET core. It has limitations, but for some cases it is a good choice.Measured
Yes, only if you are a Consuming Client, there is no servicehost implementationMagazine
@Magazine No, server side is available. github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…Measured
github.com/CoreWCF/CoreWCF/blob/master/src/Samples/… and github.com/CoreWCF/CoreWCF/blob/master/src/Samples/…Measured
Wow this is great, didn't knew about this. Thanks, It however doesn't support WebHttpBindingMagazine
to add to this, at BingAds, we leveraged CoreWCF library to serve billions of requests. So, pretty stable now for port.Viscardi
H
16

WCF does many things; it is an easy way to remote procedure calls between two applications (processes) on one machine, using named pipes; it can be a high volume internal client-server communication channel between .NET components, using binary serialization over TCPIP; or it can provide a standardised cross-technology API, e.g. via SOAP. It even has support for things like asynchronous messaging, via MSMQ.

For .NET Core, there are different replacements based on the purpose.

For cross-platform API, you would replace this with a REST service using ASP.NET.

For inter-process connections, or client-server connection, gRPC would be good, with an excellent answer given by @Gopi.

So the answer to "What replaces WCF" depends on what you are using it for.

Halflight answered 20/1, 2020 at 4:59 Comment(0)
P
7

There is a community repo https://github.com/CoreWCF/CoreWCF that implements some parts of WCF. You can use it to support some simple WCF services. However not all features are supported.

Petronella answered 19/11, 2019 at 15:31 Comment(0)
M
5

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

The original implementation of Windows Communication Foundation (WCF) was only supported on Windows. However, there is a client port available from the .NET Foundation. It is entirely open source, cross platform, and supported by Microsoft.

The community maintains the server components that complement the aforementioned client libraries. The GitHub repository can be found at CoreWCF. The server components are not officially supported by Microsoft. For an alternative to WCF, consider gRPC.

Metcalfe answered 12/2, 2021 at 13:38 Comment(0)
U
4

So from my research the best solution does not have the auto-generated proxy classes. This best solution is to create a RESTful service and to serialise the response body into model objects. Where the models are the usual model objects found in the MVC design pattern.

Thank you for your responses

Uncivil answered 22/4, 2018 at 5:6 Comment(3)
See here - learn.microsoft.com/en-us/dotnet/core/additional-tools/…Kayne
Yea it was the auto generated proxy classes that I wanted. I am using RESTful services / RPC for this functionalityUncivil
This repo is just for the client librariesPetronella
L
2

You can also self-host ASP.NET Core Web API.

<!-- SelfHosted.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <!-- see: https://learn.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://learn.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}!";
    }
}
Lenora answered 1/1, 2020 at 2:22 Comment(2)
Asp core web api does not support duplex communications on a single port like how wcf does.Magazine
@user1034912, you are correct. for that, you should probably use a websocket/gRPCLenora
T
1

There is a .NET Core port available: https://github.com/dotnet/wcf It's still in preview, but they are actively developing it.

Tiepolo answered 7/9, 2018 at 7:1 Comment(2)
I believe this port is for communication from Core to WCF but not for writing WCF in Core.Plemmons
The linked github repository clearly says: " This repo contains the client-oriented WCF libraries that enable applications built on .NET Core to communicate with WCF services. "Emersen
G
0

As today all the WCFCore selfhost Available are not that easy to install and use.
The best for HostedService it will be the alternatives as gRPC showed in the previous answer and notice that in 1 year can change many things sure WCF is supported in Core only as a client that works fine.

Gantrisin answered 25/7, 2020 at 16:26 Comment(0)
G
0
// I found a way to implement WCF client proxy in .Net 6.0 (Core):


//--------------------------------------WCF duplex fix------------------------------
// I found a way to fix my problem.. it took me a week of research
// So here it is:
// How to generate WCF Service (.Net Framework 4.8) proxy in client (.Net 6.0):

// If using a callback I need duplex communication

    [ServiceContract(CallbackContract = typeof(IEventsService))]

// Just do as explain here but dont expect it to work for Client .Net 6.0 it will
// only work for client .net Framework 4.8 as Wcf service is .Net Framework 4.8

https://www.codeproject.com/articles/663333/understanding-events-in-wcf#:~:text=Background%20While%20events%20in%20WCF%20are%20nothing%20more,typical%20relationship%20between%20a%20client%20and%20a%20service.

// so here is what I need to do to make it work in .Net 6.0 client:
// Use netHttpBinding for duplex
// Put this on web.config of your Wcf service

    <service name="HomeManagerWcfService.HomeManagerService" behaviorConfiguration="HomeManagerServiceBehavior">
        <host>
            <baseAddresses>
            <add baseAddress="http://localhost:53318/HomeManagerService"/>
            </baseAddresses>
        </host>
    
    <endpoint address="" binding="netHttpBinding" contract="HomeManagerWcfService.IHomeManagerService"/>
    <!--<endpoint address="" binding="wsDualHttpBinding" contract="HomeManagerWcfService.IHomeManagerService"/>-->
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
    </services>
    
    <behaviors>
        <serviceBehaviors>
        <!-- HomeManagerService Behavior -->
        <behavior name="HomeManagerServiceBehavior">
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true "/>
        </behavior>
        </serviceBehaviors>
    </behaviors>

// Generate files for your client proxy on VisualStudio.Tools.Command line.Developer command prompt
// The WCF service must be running

    svcutil http://localhost:53318/HomeManagerService.svc

//copy both files generated in your client project.
// if using the VS UI generator (Managed connected service) it won't work, there is a bug in it I guess.

// I also need System.ServiceModel.Http
// & I need System.ServiceModel.Duplex
// in the client
// use NetHttpBinding for duplex communication
// Use IHomeManagerServiceCallback to implement the callback function 
// where you want it to run the callback

    InstanceContext iCntxt = new InstanceContext(this);// "this" is where i implement the callback for my case
    var endpointAddress = new EndpointAddress("http://localhost:53318/HomeManagerService.svc");
    var binding = new NetHttpBinding();
    var factory = new DuplexChannelFactory<IHomeManagerService>(iCntxt, binding, endpointAddress);
    var clientWCF = factory.CreateChannel();
    
    EmailMessage emailMessage = new EmailMessage();
    emailMessage.Name = "ww23";
    emailMessage.Body = "SSWDDW223";
    emailMessage.EmailAddress = "EMAIL AD dsf2223";
    
    clientWCF.SubscribeCalculatedEvent(); // where we register to the event on the server
    clientWCF.AddEmail(emailMessage);   // the callback event call is in this function on the server

//----------------------------------------------------------------------------------

// for IIS 
// In order to make sure this mapping appears you need to go to control panel
    -> turn windows features on or off
    -> .NET Framework 4.8 Advanced Services
    -> WCF Services -> HTTP Activation
Gutter answered 23/1, 2022 at 19:18 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Holmes
R
0

https://devblogs.microsoft.com/dotnet/corewcf-v1-released/

April 2022, WCF is available on the following .NET core versions .NET Core 3.1 .NET 5 & 6

Rhea answered 27/7, 2022 at 18:8 Comment(0)
B
0

I have found the ServiceWire package to be an excellent replacement for NamedPipes and WCF, especially if you do not need to queue requests.

Boonie answered 5/2, 2023 at 18:45 Comment(0)
G
0

As already mentioned by others, gRPC is a good alternative and is Microsoft's current recommendation. There is a considerable amount of documentation available directly from Microsoft.

However, if all endpoints are .NET applications, gRPC may be unnecessary heavy (not at runtime, but implementation wise). I was missing a really simple solution and ended up creating something myself, called NetMessage. Bear in mind that I'm the author of that library (so my recommendation may be biased).

It supports custom C# classes as communication objects, ensures type safety and enforces request/response contracts. This should give an idea how it works (for more details, see the Readme on GitHub):

// request packet
public class WeatherRequest : IRequest<WeatherResponse>
{
  public string City { get; set; }
  public DateTime Date { get; set; }
}

// corresponding response packet
public class WeatherResponse
{
  public string Forecast { get; set; }
}

// and this is how to use it (compiler enforces correct types):
var response = await client.SendRequestAsync(new WeatherRequest { City = "Bonn" });
Console.WriteLine(response.Forecast);
Gaud answered 11/3, 2023 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.