Service Fabric is a powerful tool for scaling any cloud application, but it has one problem. Running the application and debugging can take a lot of time. Also, some of the features of Visual Studio may not work when you are running in a cluster. For example being able to update the JavaScript while the app is running.
In a simple application, it takes a minute to get the app running in the local cluster. I found a way to speed it up by running the services as a standalone application. All you need to do is tweaking the project files and using my implementation of a Standalone Service Fabric.
If you want to see that in action, you can jump to the sample on GitHub: https://github.com/tachev/ServiceFabricStandalone.git
Note: The solution configuration should be either Debug|x64 or Standalone|x64. Switching between those configurations sometimes requires a restart of Visual Studio. For Standalone you need to set WebSite as a start project and for Debug set ServiceFabricApp.
If you want to use that in your project these are the steps:
- Create additional solution configuration for the standalone version.
- Reference ServiceFabricStandalone in the standalone configuration.
- Add conditional compile constant STANDALONE and use it to remove the dependency on Service Fabric in the code (this step is not required in the new VS project if you the name of your configuration is “Standalone”, as it’s creating the constant automatically).
Let’s go on and create a sample app:
- New Project – Service Fabric Application.
- Create 2 services: Stateless ASP.NET Core (WebSite) and Stateful Service (UsersStateService).
- A good practice to keep the things isolated is to create an interface project, to not have a direct reference to the service. Let’s call it UsersStateService.Interfaces.
- Add a reference to UsersStateService.Interfaces from both services.
- Create an interface IUsersStateService and add it to the class UsersStateService.
- Now you have a service fabric application. You can run it in the local cluster. Make sure to run the VisualStudio as an Administrator. You have a debugger and everything you need to do development… but it’s slow. Also debugging of the website is not as advanced as if running the site directly.
Let’s do something with the app. Add a state to the UsersStateService and update it on every call to the website.
I’ll write a separate blog how to do that, to keep this one focused on the standalone solution: How to consume Service Fabric service in an MVC Application?
Now that you have a working app to run, let’s get to the main problem: How to speed the development process up?
- Add to the Project a reference to ServiceFabricStandalone.
- Go to Configuration Manager.
- Create a new Solution Configuration. I used the name Standalone.
- Create a new Configuration “Standalone” for all services’ projects (UsersStateService, UsersStateService.Interfaces, WebSite).
- Exclude ServiceFabricApp from the Build for Standalone configuration.
- I used x64 for all of them, but you can set them up as you like, just make sure to update the conditions.
- Update the project files:
- UsersStateService.Interfaces
Add the following conditions:<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PackageReference Include="Microsoft.ServiceFabric.Services.Remoting" Version="2.8.211" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Standalone|x64'"> <ProjectReference Include="..\ServiceFabricStandalone\ServiceFabricStandalone.csproj" /> </ItemGroup>
- WebSite
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Standalone|x64'"> <Compile Remove="WebSite.cs" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /> <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.0.0" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PackageReference Include="Microsoft.ServiceFabric" Version="6.0.211" /> <PackageReference Include="Microsoft.ServiceFabric.AspNetCore.Kestrel" Version="2.8.211" /> <PackageReference Include="Microsoft.ServiceFabric.Data" Version="2.8.211" /> <PackageReference Include="Microsoft.ServiceFabric.Services" Version="2.8.211" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Standalone|x64'"> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" /> <ProjectReference Include="..\ServiceFabricStandalone\ServiceFabricStandalone.csproj" /> <ProjectReference Include="..\UsersStateService\UsersStateService.csproj" /> </ItemGroup>
- UsersStateService
This one is more complicated, as its project file is still not using the new format. I guess it will change in the future.I removed AssemblyInfo.cs and changed the project file to:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net461</TargetFramework> <Configurations>Debug;Release;Standalone</Configurations> <Platforms>AnyCPU;x64</Platforms> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ProjectGuid>{8DCFD564-316B-42C6-9D79-1D19FA3BC228}</ProjectGuid> <OutputType>Exe</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>UsersStateService</RootNamespace> <AssemblyName>UsersStateService</AssemblyName> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <IsServiceFabricServiceProject>true</IsServiceFabricServiceProject> <OutputPath>bin\x64\Debug\</OutputPath> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Standalone|x64'"> <OutputPath>bin\x64\Standalone\</OutputPath> </PropertyGroup> <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PackageReference Include="Microsoft.ServiceFabric.Services.Remoting" Version="2.8.211" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)|$(Platform)'=='Standalone|x64'"> <ProjectReference Include="..\ServiceFabricStandalone\ServiceFabricStandalone.csproj" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\UsersStateService.Interfaces\UsersStateService.Interfaces.csproj" /> </ItemGroup> </Project>
- UsersStateService.Interfaces
Note: The ServiceFabricStandalone is implemented to include all features that I use. If you are using others, feel free to change the code, send me a pull request, or ask me to add this functionality in the comments below.
Hope you find this helpful and have more fun coding than waiting for compile/deploy.
Let me know if you have any questions or comments on how I can improve the blog and/or the source code.
Thanks,
George