Skip to content

Defining Services

Oleg Karasik edited this page Dec 4, 2019 · 4 revisions

The stateful service is defined using DefineStatefulService(...) method:

new HostBuilder()
  .DefineStatefulService(serviceBuilder => { ... })
  .Build()
  .Run()

The stateless service is defined using DefineStatelessService(...) method:

new HostBuilder()
  .DefineStatelessService(serviceBuilder => { ... })
  .Build()
  .Run()

You can define more than one service using the same HostBuilder instance. This is done using multiple calls to DefineStatefulService(...) and DefineStatelessService(...) methods:

new HostBuilder()
  .DefineStatefulService(serviceBuilder => { ... })
  .DefineStatefulService(serviceBuilder => { ... })
  .DefineStatelessService(serviceBuilder => { ... })
  .DefineStatelessService(serviceBuilder => { ... })
  .Build()
  .Run()

Warning

When configuring multiple services within the same assembly and these services use shared process hosting model then all statics are shared between services. More information about shared hosting process model can be found https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-hosting-model

Linking service configuration to service declaration

All services has to be linked to the one of the service types declared in ServiceManifest.xml.

<ServiceManifest Name="ServicePkg" Version="1.0.0">
  <ServiceTypes>
    <!-- @ServiceTypeName is the service type name. -->
    <StatefulServiceType 
      ServiceTypeName="StatefulServiceType" 
      HasPersistedState="true" />
  </ServiceTypes>
</ServiceManifest>

The linkage is done using UseServiceType(...) method:

...

.DefineStatefulService(
  serviceBuilder => 
  {
    // The value matches the @ServiceTypeName in ServiceManifest.xml
    serviceBuilder.UseServiceType("StatefulServiceType");
  })

...

Reconfiguring service's Event Source

ETW (Event Tracing for Windows) - is the recommended way to log service events. During initialization infrastructure creates an instance of self-descriptive EventSource identified as AppType-ServiceType. This instance is then used to support ILogger<T> event redirection scenario (please see Understanding Logging).

The default behavior can be overridden using SetupEventSource(...) method:

.DefineStatefulService(
  serviceBuilder =>
  {
    serviceBuilder.SetupEventSource(eventSourceBuilder => { ... });
  })

The re-configuration is done by overriding the implementation of the event source. This is done using UseImplementation(...) method:

.DefineStatefulService(
  serviceBuilder =>
  {
    serviceBuilder
      .SetupEventSource(
        eventSourceBuilder =>
        {
          eventSourceBuilder
            .UseImplementation(() => ServiceEventSource.Current);
        })
  })

The UseImplementation(...) method allows to specify a factory function used to create an instance of event source.

Information

The event source class should implement IServiceEventSource interface. This is required to support ILogger<T> event redirection.

Here is the example of event source class implementation:

[EventSource(Name = "App-Service")]
internal sealed class ServiceEventSource 
  : EventSource, IServiceEventSource
{
  public static class Keywords
  {
      public const EventKeywords ApiController = (EventKeywords) 0x4L;
  }

  private const int ServiceMessageEventId = 2;

  private const int GetValueMethodInvokedId = 7;

  public static readonly ServiceEventSource Current = new ServiceEventSource();

  [Event(GetValueMethodInvokedId, 
    Level = EventLevel.Informational, 
    Message = "GetValueMethodInvoked", 
    Keywords = Keywords.ApiController)]
  public void GetValueMethodInvoked()
  {
    this.WriteEvent(GetValueMethodInvokedId);
  }

  public void WriteEvent<T>(
    ref T eventData)
    where T : ServiceEventSourceData
  {
    this.ServiceMessage(
      eventData.ServiceName,
      eventData.ServiceTypeName,
      eventData.ReplicaOrInstanceId,
      eventData.PartitionId,
      eventData.ApplicationName,
      eventData.ApplicationTypeName,
      eventData.NodeName,
      eventData.EventMessage);
  }

  [Event(ServiceMessageEventId, 
    Level = EventLevel.Informational, 
    Message = "{7}")]
  private void ServiceMessage(
    string serviceName,
    string serviceTypeName,
    long replicaOrInstanceId,
    Guid partitionId,
    string applicationName,
    string applicationTypeName,
    string nodeName,
    string message)
  {
    this.WriteEvent(
      ServiceMessageEventId,
      serviceName,
      serviceTypeName,
      replicaOrInstanceId,
      partitionId,
      applicationName,
      applicationTypeName,
      nodeName,
      message);
  }
}

This implementation has two events defined: ServiceMessage and GetValueMethodInvoked:

  • The ServiceMessage event is used to write all entries redirected from ILogger<T>.
  • The GetValueMethodInvoked method is intended to be used directly in code: ServiceEventSource.Current.GetValueMethodInvoked(...).

Specialized Interfaces

Writing events through ILogger<T> doesn't allow you to leverage all the benefits of the EventSource implementation. Thus infrastructure provides support for so called specialized interfaces. These interfaces are derived from IServiceEventSourceInterface interface and allow you to setup a logging API surface for particular use cases.

public interface IApiServiceEventSource : IServiceEventSourceInterface
{
  void GetValueMethodInvoked();
}

When event source class implements a specialized interface then during initialization the same instance of event source is automatically registered in all dependency injection containers as interfaces, type and as IServiceEventSource interface.

[EventSource(Name = "App-Service")]
internal sealed class ServiceEventSource 
  : EventSource, 
    IServiceEventSource, 
    IApiServiceEventSource
{
  ...
}

Usage of specialized interfaces allows to hide the implementation behind the specifically designed interface and leverage benefits of interface segregation and usage of EventSource's methods.

Defining Delegates

Please see Defining Delegates documentation for a complete guide.

Defining Listeners

Please see Defining Listeners documentation for a complete guide.