Porting from .NET Framework 4.8 to .NET Core 8

Good morning,
I am porting from .NET Framework 4.8 to .NET Core 8.0. I have not changed the code, I have only used different libraries.
I start the server without errors, but it does not listen on the ports I specify in Start().
What am I doing wrong? Do I need to adapt the code for .NET Core?

Thank you!

I couldn’t tell you how to upgrade an unknown project to a completely different framework, that’s a whole migration effort.

Start with the closest .NET Project template, then move over your project slowly, ensuring that it still works along the way.

Thank you for your prompt reply.

I notice that in all project templates, the service is started using WebApplication.CreateBuilder(). In the mode I am starting from (version for .NET Framework), I did not use that method.
Has it become necessary, or can I continue to use new AppHost().Init().Start(listeningUrls)?

You start the App when you run it:

It runs on https://localhost:5001 by default, which can be changed in launchSettings.json

Thank you, but I was referring to the fact that a web application is always created in the templates. I need to have a Windows service. Is there a way to use it as a Windows service (like an HttpListener, so to speak) and not as a web application?

That’s not really a thing in .NET, the closest template for a background service are Background MQ Workers.

To see if I understand correctly. In .NET Framework, I could do new AppHost().Init().Start(listeningUrls) and start a server listening on the specified ports. Now, with .NET Core 8, I can no longer do that and must follow the example of the Background MQ Workers template?

All .NET Projects are self-hosting, here are the different ways to run it on different endpoints

Thank you for the explanation.

I am integrating the ‘Single project’ template into my application. Is there a way to set the listening ports programmatically and in the format ‘http://+8080’ instead of using the launchSettings.json file?

I linked to the docs to configure the endpoints, .NET doesn’t use HttpListener, so you can’t use HttpListener URLs.

I downloaded the RabbitMQ template, and as soon as I launch it, I get this error:

ServiceStack.RabbitMq.RabbitMqServer[0]
      Exception in Rabbit MQ Server: None of the specified endpoints were reachable
      RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable
       ---> System.AggregateException: One or more errors occurred. (Connection failed)
       ---> RabbitMQ.Client.Exceptions.ConnectFailureException: Connection failed
       ---> System.Net.Sockets.SocketException (11001): Host sconosciuto.
         at System.Net.NameResolutionPal.ProcessResult(SocketError errorCode, GetAddrInfoExContext* context)
         at System.Net.NameResolutionPal.GetAddressInfoExCallback(Int32 error, Int32 bytes, NativeOverlapped* overlapped)
      --- End of stack trace from previous location ---
         at System.Net.Dns.<GetAddrInfoWithTelemetryAsync>g__CompleteAsync|35_0[T](Task task, String hostName, Int64 startingTimeStamp)
         at RabbitMQ.Client.TcpClientAdapter.ConnectAsync(String host, Int32 port)
         at RabbitMQ.Client.Impl.TaskExtensions.TimeoutAfter(Task task, TimeSpan timeout)
         at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectOrFail(ITcpClient socket, AmqpTcpEndpoint endpoint, TimeSpan timeout)
         --- End of inner exception stack trace ---
         at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectOrFail(ITcpClient socket, AmqpTcpEndpoint endpoint, TimeSpan timeout)
         at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectUsingAddressFamily(AmqpTcpEndpoint endpoint, Func`2 socketFactory, TimeSpan timeout, AddressFamily family)
         at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectUsingIPv4(AmqpTcpEndpoint endpoint, Func`2 socketFactory, TimeSpan timeout)
         at RabbitMQ.Client.Impl.SocketFrameHandler..ctor(AmqpTcpEndpoint endpoint, Func`2 socketFactory, TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout)
         at RabbitMQ.Client.Framing.Impl.IProtocolExtensions.CreateFrameHandler(IProtocol protocol, AmqpTcpEndpoint endpoint, ArrayPool`1 pool, Func`2 socketFactory, TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout)
         at RabbitMQ.Client.ConnectionFactory.CreateFrameHandler(AmqpTcpEndpoint endpoint)
         at RabbitMQ.Client.EndpointResolverExtensions.SelectOne[T](IEndpointResolver resolver, Func`2 selector)
         --- End of inner exception stack trace ---
         at RabbitMQ.Client.EndpointResolverExtensions.SelectOne[T](IEndpointResolver resolver, Func`2 selector)
         at RabbitMQ.Client.Framing.Impl.AutorecoveringConnection.Init(IEndpointResolver endpoints)
         at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver, String clientProvidedName)
         --- End of inner exception stack trace ---
         at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver, String clientProvidedName)
         at RabbitMQ.Client.ConnectionFactory.CreateConnection(String clientProvidedName)
         at RabbitMQ.Client.ConnectionFactory.CreateConnection()
         at ServiceStack.RabbitMq.RabbitMqServer.get_Connection() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.RabbitMq/RabbitMqServer.cs:line 144
         at ServiceStack.RabbitMq.RabbitMqServer.Init() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.RabbitMq/RabbitMqServer.cs:line 267
         at ServiceStack.RabbitMq.RabbitMqServer.Start() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.RabbitMq/RabbitMqServer.cs:line 339

What am I doing wrong?
Thanks for your help.

It’s saying it couldn’t connect to your RabbitMQ broker?

Using your templates and following your advice, I’ve managed to start an AppHostBase server that exposes my responses.
I do have one question, though: should the JsonServiceClient I was using before still work now?
I’m asking because I’m having trouble retrieving the public key.

 using (JsonServiceClient jsonServiceClient = new JsonServiceClient($"http://{IpAddress}:{PortHttp}/"))
 {
     var publicKey = jsonServiceClient.Get(new GetPublicKey());
     ....
}

Is there another way to obtain the public key needed to instantiate an IEncryptedClient?

Thank you

It’s recommended to use AddJsonApiClient to register a HttpClient factory:

builder.Services.AddJsonApiClient(BaseUrl);

Then you can use JsonApiClient in your services:

class MyService(JsonApiClient client)
{
    public async Task<object>(MyRequest requset)
    {
        var api = await client.ApiAsync(new GetPublicKey());
        var key = api.Response;
    }
}

You should use Api and ApiAsync so it uses the primary HTTP Method.

Thank you for your reply and the example.
I used your code and I got this error message: “The operation does not exist for this service”.

On the server side, I added the EncryptedMessagesFeature plugin as follows:

public override void Configure()
{
    Plugins.Add(new EncryptedMessagesFeature
    {
        PrivateKeyXml = RsaUtils.CreatePublicAndPrivateKeyPair().PrivateKey,
    });

    // Configure ServiceStack, Run custom logic after ASP.NET Core Startup
    SetConfig(new HostConfig
    {
        WriteErrorsToResponse = true,
        EnableOptimizations = true,
    });
}

Am I missing something else?

You can’t use Plugins.Add anymore, plugins need to be registered before the App and AppHost is created with services.AddPlugin, e.g:

public class AppHost() : AppHostBase("MyApp"), IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureServices(services => {
            // Configure ASP.NET Core IOC Dependencies
            services.AddPlugin(...);
        });
}

I did this way:

public class AppHost() : AppHostBase("MyApp"), IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureServices(services =>
        {
            services.AddPlugin(new EncryptedMessagesFeature
            {
                PrivateKeyXml = RsaUtils.CreatePublicAndPrivateKeyPair().PrivateKey,
            });

            // Configure ASP.NET Core IOC Dependencies
        });

    public override void Configure()
    {
        // Configure ServiceStack, Run custom logic after ASP.NET Core Startup
        SetConfig(new HostConfig
        {
            WriteErrorsToResponse = true,
            EnableOptimizations = true,
        });
    }
}

but I still get the error “The operation does not exist for this service”-
What else did I miss?

Thank you.

Show me the c# client code you’re using, I’m expecting you to use what I posted above.

Unfortunately, for backward compatibility reasons, I have to use JsonServiceClient here. I know it would be better to use JsonApiClient. If necessary, I could write some custom code.

This is how I implemented your suggestion above:

private class MyService
{
    private readonly JsonServiceClient _client;
    public MyService(JsonServiceClient client)
    {
        _client = client;
    }

    public async Task<GetCertificateResponse> GetCertificate(GetCertificateRequest request)
    {
        var api = await _client.ApiAsync(new GetPublicKey());
        var publicKey = api.Response;

        IEncryptedClient encryptedClient = _client.GetEncryptedClient(publicKey);
        var response = encryptedClient.Post(new GetCertificateRequest());
        return response;
    }
}

Used as follows:

using (JsonServiceClient jsonServiceClient = new JsonServiceClient($"https://{IpAddress}:{PortHttp}/"))
{
    MyService myService = new MyService(jsonServiceClient);
    var certificate = myService.GetCertificate(new GetCertificateRequest()).Result;
    ....

Am I doing something wrong?

If I ask you to try something, please don’t ignore it and then just say you’re getting the same error. If you’re not going to try it, I need to know exactly what you’re trying instead. Please don’t let me believe you’re getting the same error but are not trying what I’ve said.

The only efficient way to use a HttpClient is with the IOC, using JsonServiceClient uses WebServiceClient which is deprecated and an inefficient wrapper over HttpClient. You also shouldn’t use .Result; which is sync over async.

By showing dependency injection:

class MyService(JsonApiClient client) 
{
}

I mean that you need to use dependency injection to resolve the JsonApiClient instance, and not to dispose it since the life cycle is handled by the IOC.

Note both JsonApiClient and JsonServiceClient implements the same IServiceClient so you could use that, otherwise pass the public key string in instead.

Now can you let me know if a Service that uses AddJsonApiClient and JsonApiClient works?

public class GetKey : IGet, IReturn<string> {}

class MyService(JsonApiClient client) : Service
{
    public async Task<object> Any(GetKey request)
    {
        var api = await client.ApiAsync(new GetPublicKey());
        return api.Response;
    } 
}