Sunday, April 8, 2018

Convert Dot net Core application to Service Fabric application

How to convert my existing dot.net Core Web API application to Azure service fabric web api.

I've dot.net core web api already been built and deployed in the azure web app. Now, I'm trying to deploy the same application in the azure service fabric. Also I want run the service fabric web api individually on IIS express without SF cluster.

Here is the steps, I followed to modify the existing dot.net core to SF application

1. Add Service Fabric Project into existing solution (Either existing solution or new solution)
2. Add the following Service fabric packages to the existing web api project

    <PackageReference Include="Microsoft.ServiceFabric" Version="6.1.472" />
    <PackageReference Include="Microsoft.ServiceFabric.AspNetCore.Kestrel" Version="3.0.472" />
    <PackageReference Include="Microsoft.ServiceFabric.Data" Version="3.0.472" />
    <PackageReference Include="Microsoft.ServiceFabric.Services" Version="3.0.472" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="2.3.0" />


3. Add the following folders to the existing web api project

    Add PackageRoot folder and config folder. Settings.xml and ServiceManifest.xml



4. In Settings.xml, add the following default content

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <!-- Add your custom configuration sections and parameters here -->
  <!--
  <Section Name="MyConfigSection">
    <Parameter Name="MyParameter" Value="Value1" />
  </Section>
  -->
</Settings>
5. In ServiceManfiest.xml, add the following content

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Caterpillar.Application.WebApi"
                 Version="1.0.0"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
    <!-- This is the name of your ServiceType.
         This name must match the string used in RegisterServiceType call in Program.cs. -->
    <StatefulServiceType ServiceTypeName="existingWebApiType" HasPersistedState="true" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <ExeHost>
        <Program>exisitingWebApi.exe</Program>
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </EntryPoint>
  </CodePackage>

  <!-- Config package is the contents of the Config directoy under PackageRoot that contains an
       independently-updateable and versioned set of custom configuration settings for your service. -->
  <ConfigPackage Name="Config" Version="1.0.0" />

</ServiceManifest>


Here,

  •  I've used StatefulService, It can also be StatelessService. Just change the serviceType based on the need 
  • existingWebApiType - is the name of the service type (change based on your application name)
  • exisitingWebApi.exe - is the dot.net core application exe name

4. In general, Dot.net Core application is created and run on 32 bit(x86), whereas  ServiceFabric application needs to run on 64 bit. Convert your existing project runtime as x64.


5. Changes in Program.cs

Remove the existing webHostBuilder and add the following code

using Microsoft.ServiceFabric.Services.Runtime;       
         ServiceRuntime.RegisterServiceAsync("existingWebApiType", context => new WebApi(context)).GetAwaiter().GetResult();
                Thread.Sleep(Timeout.Infinite);

6. Add WebApi.cs to the existing application with following content

using System;
using System.Collections.Generic;
using System.Fabric;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
using Microsoft.ServiceFabric.Data;

namespace existingApplication
{
    /// <summary>
    /// The FabricRuntime creates an instance of this class for each service type instance.
    /// </summary>
    internal sealed class WebApi : StatefulService
    {
        public WebApi(StatefulServiceContext context)
            : base(context)
        { }

        /// <summary>
        /// Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
        {
            return new ServiceReplicaListener[]
            {
                new ServiceReplicaListener(serviceContext =>
                    new KestrelCommunicationListener(serviceContext, (url, listener) =>
                    {
                        //ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                        return new WebHostBuilder()
                       
                                    .UseKestrel()
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton<StatefulServiceContext>(serviceContext)
                                            .AddSingleton<IReliableStateManager>(this.StateManager))
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
                                    .UseUrls(url)
                                    .Build();
                    }))
            };
        }
    }
}



7. Add existing project reference to service fabric project

8. Add ApplicationManifest.xml in Service fabric project

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ConvertingServiceFabricAppType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="existingWebApi_TargetReplicaSetSize" DefaultValue="3" />
    <Parameter Name="existingWebApi_MinReplicaSetSize" DefaultValue="1" />
    <Parameter Name="existingWebApi_PartitionCount" DefaultValue="3" />
  </Parameters>
  <!-- Import the ServiceManifest from the ServicePackage. The ServiceManifestName and ServiceManifestVersion
       should match the Name and Version attributes of the ServiceManifest element defined in the
       ServiceManifest.xml file. -->
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="existingWebApi" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides />
  </ServiceManifestImport>
  <DefaultServices>
    <!-- The section below creates instances of service types, when an instance of this
         application type is created. You can also create one or more instances of service type using the
         ServiceFabric PowerShell module.
       
         The attribute ServiceTypeName below must match the name defined in the imported ServiceManifest.xml file. -->
    <Service Name="existingWebApi">
      <StatefulService ServiceTypeName="existingWebApiType" TargetReplicaSetSize="[existingWebApi_TargetReplicaSetSize]" MinReplicaSetSize="[existingWebApi_MinReplicaSetSize]">
        <UniformInt64Partition PartitionCount="[existingWebApi_PartitionCount]" LowKey="-9223372036854775808" HighKey="9223372036854775807" />
      </StatefulService>
    </Service>
  </DefaultServices>
</ApplicationManifest>





No comments:

Post a Comment