5
votes

I am attempting to upgrade my application like so:

enter image description here

It fails with the following error:

enter image description here

Error details:

2>Test-ServiceFabricApplicationPackage : The BuildLayout of the application in
2>C:\Users\me\AppData\Local\Temp\TestApplicationPackage_2205895293421\4myc2vpp.bdq\Debug is invalid. Code is
2>missing for service MyServicePkg.
2>At C:\Program Files\Microsoft SDKs\Service
2>Fabric\Tools\PSModule\ServiceFabricSDK\Publish-UpgradedServiceFabricApplication.ps1:135 char:38
2>+ ... nSuccess = (Test-ServiceFabricApplicationPackage $AppPkgPathToUse -Im ...
2>+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2> + CategoryInfo : InvalidOperation: (:) [Test-ServiceFabricApplicationPackage], FabricImageBuilderValidati
2> onException
2> + FullyQualifiedErrorId : TestApplicationPackageErrorId,Microsoft.ServiceFabric.Powershell.TestApplicationPackage 2>
2>Finished executing script 'Deploy-FabricApplication.ps1'.
2>Time elapsed: 00:00:40.4035177
2>The PowerShell script failed to execute.
========== Build: 1 succeeded, 0 failed, 46 up-to-date, 0 skipped ==========
========== Publish: 0 succeeded, 1 failed, 0 skipped ==========

Here are my properties for that specific project:

enter image description here

What am I doing wrong? What does this exception mean?

3
Did you rename your project?Munim Munna
The most basic mishap is that the name you used in the ServiceManifest.xml file does not match the name of the .exe that your project generates. We can't see it, "MyServicePkg" sounds so generic that a missing edit smells likely. Notable is that forcing the solution platform to x64 is forever a recipe for trouble, .NET code should be built to target AnyCPU.Hans Passant
If you post your ServiceManifext.xml and the ApplicationManifest.xml might be easier to help you.Diego Mendes

3 Answers

3
votes

I would go with Hans Passant's comment:

The most basic mishap is that the name you used in the ServiceManifest.xml file does not match the name of the .exe that your project generates

It is also visible in your debug output as the build succeeded but the publish failed.

========== Build: 1 succeeded, 0 failed, 46 up-to-date, 0 skipped ========== ========== Publish: 0 succeeded, 1 failed, 0 skipped ==========

It can happen in a number of ways and most probably due to renaming of the project or renaming of the Assembly Name. If you rename the project or the Assembly Name of your project, your build executable will be according to that name. Consider the following case.

Application Properties

I renamed the Assembly Name from "MyService" to "MyRenamedService". So the build executable will be MyRenamedService.exe. So you have to set this in your ServiceManifest.xml.

<CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <ExeHost>
        <Program>MyRenamedService.exe</Program>
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </EntryPoint>
</CodePackage>

The best way to be sure of the build executable path is to build the solution. It will show the full path of the executable in Output window.

1>------ Build started: Project: Web1, Configuration: Debug Any CPU ------
1>Web1 -> C:\.....\Application2\Web1\bin\Debug\net461\win7-x64\MyRenamedService.exe
2>------ Build started: Project: Application2, Configuration: Debug x64 ------
========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Here Web1 is the Project Name I started with, MyRenamedService.exe is the build executable name (because I renamed the Assembly Name), it should be set in the ServiceManifest.xml as shown above.

2
votes

At a higher level, this error happens when the folder named "Code" is missing under the ServiceFabric Project Folder during Publish (after build shows as successfully completed).

Build is the culprit here, not Publish, as Publish is expected to look for assets under Folder Path: {{SFProjectFolder}}\pkg\Release\{{ServiceName}}

Please note that the {{ServiceName}} and "Code" is taken from the ServiceManifest.xml of the corresponding project referenced in the SF application.

ServiceManifest.xml

<ServiceManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="{{ServiceName}}" Version="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <ServiceTypes>
    <StatelessServiceType ServiceTypeName="{{ServiceType}}" />
  </ServiceTypes>
  <CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <ExeHost>
        <Program>{{ServiceName}}.exe</Program>
      </ExeHost>
    </EntryPoint>
  </CodePackage>
  <ConfigPackage
  • What caused the issue: From other answers, it looks like the Build not copying the compiled assets into the right path/folder, could happen due to multiple issues. In our case, we had changed the Configuration Manager settings for Release Configuration from AnyCPU to x64 and deleted the AnyCPU Platform setting from the solution. And for some reason, the Services.csproj still had the AnyCPU Platform setting. We ended up having the build showing as successful, but "Code" folder not being generated under Release folder.

  • Fix: To fix this, we had to manually edit the .csproj and remove the PropertyGroup sections that still used "AnyCPU" like the one below:
    PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "

After this change, Build correctly placed the contents in the right path and Publish worked as expected.

1
votes

This issue occurs when your service's executable .exe path is wrong in ServiceManifest.xml.

<CodePackage> contains .exe path in <Program> just check it out first:

<CodePackage Name="Code" Version="1.0.0">
    <EntryPoint>
      <ExeHost>
        <Program>MyServicePkgHost.exe</Program> // Important
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </EntryPoint>
</CodePackage>

Important References:

For confirming you are not missing anything look at below two tutorials:

Edit 1:-

Your package layout of application directory structure should be:

PS D:\temp> tree /f .\MyServicePkg

D:\TEMP\MYSERVICEPKG
│   ApplicationManifest.xml
│
└───MyServicePkgManifest
    │   ServiceManifest.xml
    │
    ├───MyServicePkg
    │       MyServicePkgHost.exe
    │
    ├───MyServicePkgConfig
    │       Settings.xml
    │
    └───MyServicePkgData
            init.dat

Error:

Why the "Code is missing for service package" occurs?

Reason:

In above directory there is missing a .bat code file from you application directory:

│
├───MyServicePkg
│       MyServicePkgHost.exe
│       MyServicePkgSetup.bat
|

So you have to add that missing file MyServicePkgSetup.bat. And following is a simple service manifest ServiceManifest.xml example that shows the SetupEntryPoint and the main EntryPoint for the service.

<?xml version="1.0" encoding="utf-8" ?>
<ServiceManifest Name="MyServiceManifest" Version="SvcManifestVersion1" xmlns="http://schemas.microsoft.com/2011/01/fabric" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Description>An example service manifest</Description>
  <ServiceTypes>
    <StatelessServiceType ServiceTypeName="MyServiceType" />
  </ServiceTypes>
  <CodePackage Name="Code" Version="1.0.0">
    <SetupEntryPoint>
      <ExeHost>
        <Program>MyServicePkgSetup.bat</Program> // important
        <WorkingFolder>CodePackage</WorkingFolder>
      </ExeHost>
    </SetupEntryPoint>
    <EntryPoint>
      <ExeHost>
        <Program>MyServicePkgHost.exe</Program> // important
      </ExeHost>
    </EntryPoint>
  </CodePackage>
  <ConfigPackage Name="Config" Version="1.0.0" />
</ServiceManifest>

Configure the policy by using a local account

After you configure the service to have a setup entry point, you can change the security permissions that it runs under in the application manifest:

Under the <ServiceManifestImport> section, configure a policy to apply this principal to <SetupEntryPoint>. This tells Service Fabric that when the MyServicePkgSetup.bat file is run, it should be RunAs with administrator privileges. Given that you have not applied a policy to the main entry point, the code in MyServicePkgHost.exe runs under the system NetworkService account. This is the default account that all service entry points are run as.

<?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="MyApplicationType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
   <ServiceManifestImport>
      <ServiceManifestRef ServiceManifestName="MyServiceTypePkg" ServiceManifestVersion="1.0.0" />
      <ConfigOverrides />
      <Policies>
         <RunAsPolicy CodePackageRef="Code" UserRef="SetupAdminUser" EntryPointType="Setup" />
      </Policies>
   </ServiceManifestImport>
   <Principals>
      <Users>
         <User Name="SetupAdminUser">
            <MemberOf>
               <SystemGroup Name="Administrators" />
            </MemberOf>
         </User>
      </Users>
   </Principals>
</ApplicationManifest>

PS: You can verify the package structure locally through PowerShell by using the Test-ServiceFabricApplicationPackage command.


Workaround to add missing file MyServicePkgSetup.bat:

  1. Let's now add the file MyServicePkgSetup.bat to the Visual Studio project to test the administrator privileges. In Visual Studio, right-click the service project and add a new file called MyServicePkgSetup.bat.

  2. Next, ensure that the MyServicePkgSetup.bat file is included in the service package. By default, it is not. Select the file, right-click to get the context menu, and choose Properties. In the Properties dialog box, ensure that Copy to Output Directory is set to Copy if newer. See the following screenshot:

    enter image description here

    **File Path: ** C:\..\YourApplication\

  3. Now open the MyServicePkgSetup.bat file and add the following commands:

    REM Set a system environment variable. This requires administrator privilege
    setx -m TestVariable "MyValue"
    echo System TestVariable set to > out.txt
    echo %TestVariable% >> out.txt
    
    REM To delete this system variable us
    REM REG delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v TestVariable /f
    
  4. Next, build and deploy the solution to a local development cluster. After the service has started, as shown in Service Fabric Explorer, you can see that the MySetup.bat file was successful in a two ways. Open a PowerShell command prompt and type:

    PS C:\ [Environment]::GetEnvironmentVariable("TestVariable","Machine")
    MyValue
    
  5. Then, note the name of the node where the service was deployed and started in Service Fabric Explorer--for example, Node 2. Next, navigate to the application instance work folder to find the out.txt file that shows the value of TestVariable. For example, if this service was deployed to Node 2, then you can go to this path for the MyApplicationType:

    C:\SfDevCluster\Data\_App\Node.2\MyApplicationType_App\work\out.txt