asp.net core rc2 with Service Fabric

If you have checked the official site here, you should have seen a warning about the breaking changes in asp.net rc2. It's been about 2-3 weeks since but the template has not yet released.

One of Microsoft's employee has been working on a preview/beta available here. However, I found it to have too many details, confusing at first. The solution included for asp.net 4.6 (previous versions of asp.net) is inside one file, the communication listener. I thought; why not do the same for asp.net core rc2? Well, the file is here. It's all you need but you still need to wire up the project yourself.

internal class AspNetCoreCommunicationListener : ICommunicationListener {  
    private readonly ServiceEventSource eventSource;
    private readonly IWebHostBuilder webHostBuilder;
    private readonly ServiceContext serviceContext;
    private readonly string endpointName;
    private readonly string appRoot;

    private IWebHost webHost;

    public AspNetCoreCommunicationListener(IWebHostBuilder webHostBuilder, ServiceContext serviceContext, ServiceEventSource eventSource, string endpointName)
        : this(webHostBuilder, serviceContext, eventSource, endpointName, null) { }
    public AspNetCoreCommunicationListener(IWebHostBuilder webHostBuilder, ServiceContext serviceContext, ServiceEventSource eventSource, string endpointName, string appRoot) {
        if (webHostBuilder == null) throw new ArgumentNullException(nameof(webHostBuilder));
        if (serviceContext == null) throw new ArgumentNullException(nameof(serviceContext));
        if (eventSource == null) throw new ArgumentNullException(nameof(eventSource));
        if (endpointName == null) throw new ArgumentNullException(nameof(endpointName));

        this.webHostBuilder = webHostBuilder;
        this.serviceContext = serviceContext;
        this.endpointName = endpointName;
        this.eventSource = eventSource;
        this.appRoot = appRoot;
    }

    public Task<string> OpenAsync(CancellationToken cancellationToken) {
        var endpoint = serviceContext.CodePackageActivationContext.GetEndpoint(endpointName);
        int port = endpoint.Port;

        string serverUrl = $"{endpoint.Protocol.ToString().ToLower()}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{port}";

        try
        {
            eventSource.ServiceMessage(serviceContext, "Starting web server on " + serverUrl);

            webHost = webHostBuilder.UseUrls(serverUrl)
                                    .Build();

            webHost.Start();

            eventSource.ServiceMessage(serviceContext, "Listening on " + serverUrl);

            return Task.FromResult(serverUrl);
        }
        catch (Exception ex)
        {
            eventSource.ServiceMessage(serviceContext, "Web server failed to open. " + ex.ToString());

            StopWebServer();

            throw;
        }
    }

    public Task CloseAsync(CancellationToken cancellationToken) {
        eventSource.ServiceMessage(serviceContext, "Closing web server");

        StopWebServer();

        return Task.FromResult(true);
    }

    public void Abort() {
        eventSource.ServiceMessage(serviceContext, "Aborting web server");

        StopWebServer();
    }

    private void StopWebServer() {
        if (webHost != null) {
            try {
                webHost.Dispose();
            } catch (ObjectDisposedException) {
                // no-op
            }
        }
    }
}

That's a modification of OwinCommunicationListener that ships with the SDK template for StatelessWebApi service. To use it, just add it to the communication listeners for the service by overriding the CreateServiceInstanceListeners method as shown below.

/// <summary>
/// The FabricRuntime creates an instance of this class for each service type instance.
/// </summary>
internal class MyService : StatelessService {  
    public MyService(StatelessServiceContext serviceContext) : base(serviceContext) { }
    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners() {
        var webHostBuilder = new WebHostBuilder()
                                    .UseKestrel()
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .UseStartup<Startup>();

        return new ServiceInstanceListener[] {
            new ServiceInstanceListener(
                serviceContext => new KatanaCommunicationListener(webHostBuilder, serviceContext, ServiceEventSource.Current, "ServiceEndpoint"))
        };
    }
}

Since asp.net rc2 is built using NuGet packages, you can run this within a csproj but the list items in your packages.config could end up being very long.
There are two servers available for asp.net rc2, Kestrel and WebListener but both seem to have problems working inside csproj when built with MSBuild directly and not dotnet cli. There is a temporary workaround for Kestrel explained a GitHub issue (#696).

This might change when there is an official template in the SDK in the near future.