Service Definition and Types of Services

Each Manager Service API service must have a unique definition within a single project or system.

Various service properties are used to:

  • Start and run services on the server
  • Correctly address services on the client

All services are distinguished based on the following aspects:

  • System (only on client):

    • The name of the WinCC OA system.
    • This is implicit information on the server, as the system in which the manager and service are running is known.
    • It is an optional argument on the client and is not needed for the 'local' system.
  • Name:

    • The service name is the primary identifier to differentiate services.
    • It is recommended to use prefixes on the customer side to avoid name collisions with services provided by WinCC OA.
    • While the name is used internally in a case-insensitive manner, it is recommended to use PascalCase in the definition.
    • Only alphanumeric characters and / are allowed. This follows the ppath definition of the URL specification for PROSPERO URLs.
    • See service suffix examples for how the name is used regularly, and see the manager-specific examples for advanced naming techniques.
  • There are two hosting types:
    • Global: The default case. Global Services are intended for situations where the client and the required functionality do not need to know which specific manager is hosting the service. From the client's point of view, the focus is on accessing the service, no matter where it is located. This service behaves as a singleton within a single WinCC OA project. In summary, the scope of global services covers the entire WinCC OA project.

    • Manager-specific: Manager-Specific Services are limited to the scope of a single manager within the project. In this case, the client interacts with a service that is hosted by a particular manager. This structure is useful when you need to deploy the same service on multiple managers, such as manager-specific diagnostic tools or utilities that are specific to each manager or driver. This approach allows each manager to have its own instance of the service, tailored to its individual requirements.

      • Service Hosting Manager: This information is implicit on the server side because the manager type of the service hosting manager is already known. On the client side, this is a required argument for manager-specific services, but it is not used for global services. The following distinctions are made:
        • Manager Type: The ManagerType of the service hosting manager.
        • Manager Number: The number assigned to the service hosting manager.
        • Replica: The replica of the service hosting manager. There are three possible cases:
          • None: No replica is present. For example, this applies to any service in a single system or a global service in a redundant system.
          • Left: The logical left (primary) replica in a redundant system.
          • Right: The logical right (secondary) replica in a redundant system.

Manager-specific Services

By default, services are defined as global services. The following code shows how manager-specific services are used.

Example codes for a server: Options objects (CTRL: VrpcServiceOptions, C++: ::vrpc::ServiceOptions, C#: VrpcServiceDefinitionOptions, TS: Vrpc.ServiceOptions) are used to change the defaults. The following code examples show how this can be achieved.

  public void registerManSpecificService(VrpcServiceContainer &serviceContainer, shared_ptr<VrpcServiceBase> &service)
  {
    VrpcServiceOptions options;

    // Register service as manager-specific service
    options.withManagerSpecificService();

    serviceContainer.registerService(service, options);
  }
 void registerManSpecificService(::vrpc::ServiceContainer& serviceContainer, std::shared_ptr<::vrpc::ServiceBaseBase> service)
  {
    ::vrpc::ServiceOptions options;

    // Register service as manager-specific service
    options.withManagerSpecificService();

    serviceContainer.registerService(service, options);
  }       
   public void RegisterManSpecificService<Service>(IServiceCollection services)
    where Service : VrpcServiceBase
  {
    services.AddOaVrpcManagerService<Service>(options =>
    {
      // Register service as manager-specific service
      options.WithManagerSpecificService();
    });
  }        
   public registerManSpecificService(
    serviceContainer: Vrpc.ServiceContainer,
    service: Vrpc.ServiceBase,
  ) {
    const options = new Vrpc.ServiceOptions();

    // Register service as manager-specific service
    options.withManagerSpecificService();

    serviceContainer.registerService(service, options);
  }

Example codes for a client: Options objects (CTRL / C#: VrpcStubOptions, C++: ::vrpc::StubOptions, TS: Vrpc.StubOptions) are used to change the default settings. By default, services are addressed as global services. The following example shows how to address a manager-specific service. In the example we assume the service is hosted in a CTRL manager with number 1 in a single system.

  public shared_ptr<VrpcStub> createStubForManSpecificService()
  {
    VrpcStubOptions options = VrpcStubOptions();

    // Create a stub for a manager-specific service
    options.withManagerSpecificService(CTRL_MAN, 1);

    return VrpcStub::createAndInitialize("SomeServiceName", options);
  }
  std::unique_ptr<::vrpc::Stub> createStubForManSpecificService()
  {
    ::vrpc::StubOptions stubOptions;

    // Create a stub for a manager-specific service
    stubOptions.withManagerSpecificService(CTRL_MAN, 1);

    return std::make_unique<::vrpc::Stub>("SomeServiceName", stubOptions);
  }         
  public VrpcStub CreateStubForManSpecificService(IOaManager manager)
  {

    return new VrpcStub(manager, "SomeServiceName", options =>
    {
      // Create a stub for a manager-specific service
      options.WithManagerSpecificService(ManagerIdentifier.OaManagerType.Ctrl, 1);
    });
  }           
  public createStubForManSpecificService(): Vrpc.Stub {
    const options = new Vrpc.StubOptions();

    // Create a stub for a manager-specific service
    options.withManagerSpecificService(CTRL_MAN, 1);

    return new Vrpc.Stub('SomeServiceName', options);
  }
Note:
For the client, you must specify the manager number, the manager type and, in a redundant system, the replica.

Service Suffix

The service name is defined in the service implementation and stub declaration. See also How to implement a service and How to implement a client.

In order to use the same service implementation multiple times, it is necessary to have unique names. This can be achieved by using a special suffix option during service registration:

Example codes for a server:

  public void registerServiceWithSuffix(VrpcServiceContainer &serviceContainer, shared_ptr<VrpcServiceBase> &service)
  {
    VrpcServiceOptions options;

    // Register service as manager-specific service
    options.setServiceNameSuffix("_Some_Suffix");

    serviceContainer.registerService(service, options);
  }
 void registerServiceWithSuffix(::vrpc::ServiceContainer& serviceContainer, std::shared_ptr<::vrpc::ServiceBaseBase> service)
  {
    ::vrpc::ServiceOptions options;
    // Set service name suffix
    options.setServiceNameSuffix("_SomeSuffix");

    serviceContainer.registerService(service, options);
  }
  public void RegisterServiceWithSuffix<Service>(IServiceCollection services)
    where Service : VrpcServiceBase
  {
    services.AddOaVrpcManagerService<Service>(options =>
    {
      // Register service with name suffix
      options.ServiceNameSuffix = "_SomeSuffix";
    });
  }
  public registerServiceWithSuffix(
    serviceContainer: Vrpc.ServiceContainer,
    service: Vrpc.ServiceBase,
  ) {
    const options = new Vrpc.ServiceOptions();

    // Set service name suffix
    options.serviceNameSuffix = '_SomeSuffix';

    serviceContainer.registerService(service, options);
  } 

For symmetric behavior, the stub also supports such an option:

Example codes for a client:

  public shared_ptr<VrpcStub> createStubWithSuffix()
  {
    VrpcStubOptions options = VrpcStubOptions();

    // Set service name suffix
    options.setServiceNameSuffix("_SomeSuffix");

    return VrpcStub::createAndInitialize("SomeServiceName", options);
  }
  std::unique_ptr<::vrpc::Stub> createStubWithSuffix()
  {
    ::vrpc::StubOptions stubOptions;

    // Set service name suffix
    stubOptions.setServiceNameSuffix("_SomeSuffix");

    return std::make_unique<::vrpc::Stub>("SomeServiceName", stubOptions);
  }  
  public VrpcStub CreateStubWithSuffix(IOaManager manager)
  {
    return new VrpcStub(manager, "SomeServiceName", options =>
    {
      // Set service name suffix
      options.ServiceNameSuffix = "_SomeSuffix";
    });
  }
  public createStubWithSuffix(): Vrpc.Stub {
    const options = new Vrpc.StubOptions();

    // Set service name suffix
    options.serviceNameSuffix = '_SomeSuffix';

    return new Vrpc.Stub('SomeServiceName', options);
  }