HotChocolate.Extensions.Tracking.MassTransit 3.0.0-preview.5

This is a prerelease version of HotChocolate.Extensions.Tracking.MassTransit.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package HotChocolate.Extensions.Tracking.MassTransit --version 3.0.0-preview.5                
NuGet\Install-Package HotChocolate.Extensions.Tracking.MassTransit -Version 3.0.0-preview.5                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HotChocolate.Extensions.Tracking.MassTransit" Version="3.0.0-preview.5" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add HotChocolate.Extensions.Tracking.MassTransit --version 3.0.0-preview.5                
#r "nuget: HotChocolate.Extensions.Tracking.MassTransit, 3.0.0-preview.5"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install HotChocolate.Extensions.Tracking.MassTransit as a Cake Addin
#addin nuget:?package=HotChocolate.Extensions.Tracking.MassTransit&version=3.0.0-preview.5&prerelease

// Install HotChocolate.Extensions.Tracking.MassTransit as a Cake Tool
#tool nuget:?package=HotChocolate.Extensions.Tracking.MassTransit&version=3.0.0-preview.5&prerelease                

Reliability Rating Coverage Lines of Code Security Rating

This repository contains features that can be added to your HotChocolate Server to enhance your HotChocolate experience.

HotChocolate.Extensions.Translations

This package uses HotChocolate directives and middlewares to add translations to your HotChocolate server. Easily extend your fields to transform their code-value (for instance "CH") into a more presentable value for your consumer ("Switzerland"/"Schweiz"/"Suisse"...).

The resource strings containing the translations can be provided from any source you like: external microservices, from memory, resx files...

Install

You will need to include the following package on your HotChocolate Server:

dotnet add package HotChocolate.Extensions.Translation

The next step is to register some directives to your GraphQL Schema:

new ServiceCollection()
  .AddGraphQLServer()
  .SetSchema<MySchema>()
  .AddTranslation(
    /* add all translatable types explicitely, except String, which is already added implicitely. */
    c => c.AddTranslatableType<Country>()
          .AddTranslatableType<MyEnum2>()
  );

The last step is to implement and register an IResourcesProvider. This provider will be used to retrieve the string resources in the target language.

services.AddSingleton<IResourcesProvider, MyResourcesProvider>();

The alternative way is to implement IStringLocalizer interfaces. Additionally, we can use resource type marker classes. This approach overrides all logic related to the usage of the IResourcesProvider interface.

namespace Namespace.Namespace1.Namespace2;

[ResourceTypeAlias("SomePath")]
public class CustomResource
{
}

new ServiceCollection()
  .AddGraphQLServer()
  .SetSchema<MySchema>()
  .AddTranslation(    
      /* add all translatable types explicitely, except String, which is already added implicitely. */
      c => c.AddTranslatableType<Country>()
            .AddTranslatableType<MyEnum2>()
  )
  .AddStringLocalizer<CustomLocalizer>(ServiceLifetime.Singleton, typeof(CustomResource))
  .AddStringLocalizer<OtherCustomLocalizer>(ServiceLifetime.Scoped, [ typeof(OtherCustomResource) /* additional resources can share the same localizer logic */ ])
  .AddStringLocalizer(typeof(OpenGenericLocalizer<>), [ typeof(AnyResource), ......]);

If the resource type is not decorated with the ResourceTypeAlias attribute, the default alias is generated from the namespace and name of the resource class. For the case described above, it would generate the alias "Namespace::Namespace1::Namespace2::CustomResource".

With this we have registered the necessary objects to support translation on our fields. Now we can start adding translation support to our fields.

Translating fields

You can translate field values in several ways, listed below.

Translation to a { key label } type

We can also rewrite our string/enum/other field to make it a { key label } field. This can be useful if we also use Array Translations, which use the same typing (see next chapter).

[ResourceTypeAlias("Ref/Aex/Countries"))]
public class CountryResource
{
}

public class AddressType : ObjectType<Query>
{
    protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
    {
        descriptor
            .Field(c => c.Country) // The Country property is a Country enum
            .Translate("Ref/Aex/Countries");
       
       // OR
       // descriptor
       //     .Field(c => c.Country)
       //     .Translate(typeof(CountryResource));
    }
}

Alternatively it is possible to translate the field via an attribute directly on the property:

[ResourceTypeAlias("Ref/Aex/Countries"))]
public class CountryResource
{
}

public class Address
{
    [Translate("Ref/Aex/Countries")]
    public Country Country { get; }
    
    
    // OR
    // [Translate(typeof(CountryResource)]
    // public Country Country { get; }
}

In both cases, this will generate the following Schema:

type Query {
  country: TranslatedResourceOfCountry!
}

type TranslatedResourceOfCountry {
  key: Country!
  label: String!
}

Querying this field will produce the following results:

{
  country {
    key // -> "CH",
    label // -> "Switzerland" if your Thread language is english
  }
}
Translate arrays to { key label } items

We can translate string/enum/other arrays to { key label } arrays.

public class AddressType : ObjectType<Query>
{
    protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
    {
        descriptor.Field(c => c.Countries)
            .TranslateArray<Country>("Ref/Aex/Countries");
    }
}

Alternatively it is possible to translate the field via an attribute directly on the property:

public class Address
{
    [TranslateArray<Country>("Ref/Aex/Countries")]
    public Country[] Countries { get; }
}

This will generate the following Schema:

type Query {
  countries: [TranslatedResourceOfCountry!]!
}

type TranslatedResourceOfCountry {
  key: Country!
  label: String!
}

Querying this field will produce the following results:

{
  countries {
    key
    label 
  }
}
{
  countries: [
    {
      key: "FR",
      label: "France"
    },
    {
      key: "CH",
      label: "Switzerland"
    }
}

FAQ

What language is used by default by this extension?

The language of the thread, which you can for instance initialize via the ASP.NET Core Localization Middleware.

What is the performance impact of translations?

This will depend in large part on your implementation of IResourcesProvider. This provider is registered in the service container and can therefore use any registered service of your applicaton.

In our samples, we usually build our resource strings into our assemblies so that we can retrieve them very quickly from the memory.

If you are retrieving your resource strings from another microservice, you could consider injecting Greendonut DataLoaders or IMemoryCache to reduce calls to the external microservice.

HotChocolate.Extensions.Tracking


This project enables tracking via middlewares on HotChocolate Query and mutation fields. In order to save the tracking items, a custom repository needs to be injected. As for now, the only provided repository is the MassTransitRepository, which essentially sends the tracking item to an azure ServiceBus topic.

Note: In order to not slow down the resolver pipelines of Tracked HotChocolate Fields, the context data of the tracked Field is passed into a System.Threading.Channels.Channel and then persisted asynchonously. As a consequence, some tracking items could be lost if the server were to shut down unexpectedly.

Setting up the depencies and schema

Register the tracking pipeline in the GraphQL Schema.

  Schema schema = await services
            .AddGraphQLServer()
                .AddTrackingPipeline(builder => builder
                    .AddExporter<NotifyOnFirstEntryExporter>()
                        .AddSupportedType<MyTrace>()
                        .AddSupportedType<MyOtherTrace>());

Basic tracking by Tags

The basic field invocation tracking produces a message with the following data:

  • a tag
  • a timestamp

You can add tracking on a field in the following way:

fieldDescriptor.Field("myField").Track(tag:"myFieldWasCalled");

Alternatively, you can also add tracking on the field via an attribute on the field/resolver:

public class Query
{
    [Track("FooInvoked")]
    public string Foo => "bar";
}

Custom tracking

If you want to save custom data fields, you have the possibility to write your own TrackingEntryFactory.

  public sealed class MyTrackingEntryFactory : ITrackingEntryFactory
  {
    public ITrackingEntry CreateTrackingEntry(
        IHttpContextAccessor httpContextAccessor,
        IResolverContext context)
    {
      // Get data from httpContextAccessor or the resolver context and create and return a custom ITrackingEntry from it.
    }

You can then add custom tracking to your fields: fieldDescriptor.Field("myField").Track(new MyTrackingEntryFactory());

Or alternatively via an attribute:

public class Query
{
    [Track<MyTrackingEntryFactory>]
    public string Foo => "bar";
}

Community

This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information, see the Swiss Life OSS Code of Conduct.

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.0.0-rc.1 47 10/17/2024
3.0.0-preview.7 43 10/10/2024
3.0.0-preview.5 47 10/9/2024
3.0.0-preview.4 41 10/9/2024
3.0.0-preview.3 43 10/9/2024
3.0.0-preview.1 41 10/9/2024
2.3.0-preview.6 61 7/25/2024
2.3.0-preview.5 62 7/18/2024
2.3.0-preview.4 60 7/2/2024
2.3.0-preview.3 57 7/1/2024
2.3.0-preview.2 55 6/28/2024
2.3.0-preview.1 60 6/27/2024
2.2.0 7,481 4/4/2023
2.1.0 211 4/3/2023
2.0.0 3,140 2/10/2023
1.0.0 304 2/9/2023
1.0.0-preview.4 3,632 12/2/2022
1.0.0-preview.3 316 11/30/2022
1.0.0-preview.2 103 11/29/2022