ConvergeERP.Search.Contracts 1.0.0

dotnet add package ConvergeERP.Search.Contracts --version 1.0.0
                    
NuGet\Install-Package ConvergeERP.Search.Contracts -Version 1.0.0
                    
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="ConvergeERP.Search.Contracts" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ConvergeERP.Search.Contracts" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ConvergeERP.Search.Contracts" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ConvergeERP.Search.Contracts --version 1.0.0
                    
#r "nuget: ConvergeERP.Search.Contracts, 1.0.0"
                    
#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.
#:package ConvergeERP.Search.Contracts@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ConvergeERP.Search.Contracts&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ConvergeERP.Search.Contracts&version=1.0.0
                    
Install as a Cake Tool

ConvergeERP.Search.Contracts

Shared contracts and event models for publishing search events to the ConvergeERP Search Service. This package contains all the event definitions, field types, and routing keys needed to integrate any service with the centralized search infrastructure.

Features

  • Event Models: Strongly-typed events for entity CRUD operations
  • Schema Definitions: Field definitions with type information, indexing, and sensitivity markers
  • Routing Constants: Predefined routing keys for message broker integration
  • Search Operators: Standard operators for building search queries

Installation

dotnet add package ConvergeERP.Search.Contracts

Events

EntityCreatedEvent

Published when a new entity is created and should be indexed.

var createdEvent = new EntityCreatedEvent
{
    EntityType = "Product",
    EntityId = product.Id.ToString(),
    TenantId = tenantId,
    SourceService = "ProductService",
    Data = new Dictionary<string, object?>
    {
        ["Name"] = product.Name,
        ["SKU"] = product.SKU,
        ["Price"] = product.Price
    },
    Schema = new Dictionary<string, FieldDefinition>
    {
        ["Name"] = new FieldDefinition { Name = "Name", Type = FieldTypes.String, Searchable = true },
        ["SKU"] = new FieldDefinition { Name = "SKU", Type = FieldTypes.String, Indexed = true },
        ["Price"] = new FieldDefinition { Name = "Price", Type = FieldTypes.Decimal, Sensitive = true }
    },
    // Audit fields
    UserId = currentUser.UserId,
    UserName = currentUser.Name,
    UserEmail = currentUser.Email,
    CompanyId = currentUser.CompanyId
};

EntityUpdatedEvent

Published when an entity is modified.

var updatedEvent = new EntityUpdatedEvent
{
    EntityType = "Product",
    EntityId = product.Id.ToString(),
    TenantId = tenantId,
    SourceService = "ProductService",
    Data = new Dictionary<string, object?>
    {
        ["Name"] = product.Name,
        ["Price"] = product.Price
    },
    Version = product.Version,          // For optimistic concurrency
    ChangedFields = ["Name", "Price"],  // Optional: for partial updates
    UserId = currentUser.UserId
};

EntityDeletedEvent

Published when an entity is removed.

var deletedEvent = new EntityDeletedEvent
{
    EntityType = "Product",
    EntityId = product.Id.ToString(),
    TenantId = tenantId,
    SourceService = "ProductService",
    SoftDelete = true,  // true = mark inactive, false = remove from index
    UserId = currentUser.UserId
};

EntityBulkIndexEvent

Published to trigger bulk indexing (initial sync or recovery).

var bulkEvent = new EntityBulkIndexEvent
{
    EntityType = "Product",
    TenantId = tenantId,
    SourceService = "ProductService",
    ClearExisting = true,  // Clear before indexing
    Items = products.Select(p => new BulkIndexItem
    {
        EntityId = p.Id.ToString(),
        Data = new Dictionary<string, object?>
        {
            ["Name"] = p.Name,
            ["Price"] = p.Price
        }
    }).ToList()
};

Field Definitions

Define field metadata for the search service:

var schema = new Dictionary<string, FieldDefinition>
{
    ["Name"] = new FieldDefinition
    {
        Name = "Name",
        Type = FieldTypes.String,
        Searchable = true,
        Indexed = true,
        DisplayName = "Product Name"
    },
    ["Status"] = new FieldDefinition
    {
        Name = "Status",
        Type = FieldTypes.Enum,
        EnumValues = ["Draft", "Active", "Archived"],
        Operators = [SearchOperators.Equal, SearchOperators.In]
    },
    ["CategoryId"] = new FieldDefinition
    {
        Name = "CategoryId",
        Type = FieldTypes.Guid,
        IsRelationship = true,
        RelatedEntityType = "Category",
        ForeignKeyProperty = "CategoryId",
        EmbedFields = ["Name"],  // Embed category name in product search results
        CascadeUpdates = true    // Update product when category changes
    }
};

Field Types

Type Constant Description
string FieldTypes.String Text fields
int FieldTypes.Integer 32-bit integers
long FieldTypes.Long 64-bit integers
decimal FieldTypes.Decimal Precise decimals
double FieldTypes.Double Floating point
bool FieldTypes.Boolean Boolean values
date FieldTypes.Date Date only
datetime FieldTypes.DateTime Date and time
enum FieldTypes.Enum Enumerated values
guid FieldTypes.Guid Unique identifiers
collection FieldTypes.Collection Arrays/lists
object FieldTypes.Object Nested objects

Routing Keys

Use these constants for message broker integration:

// Exchange
SearchEventRoutingKeys.Exchange        // "search.events"

// Entity Events
SearchEventRoutingKeys.EntityCreated   // "entity.created"
SearchEventRoutingKeys.EntityUpdated   // "entity.updated"
SearchEventRoutingKeys.EntityDeleted   // "entity.deleted"
SearchEventRoutingKeys.EntityBulkIndex // "entity.bulk"

// Subscribe to all entity events
SearchEventRoutingKeys.AllEntityEvents // "entity.*"

Search Operators

Available operators for each field type:

// Get default operators for a field type
var stringOps = SearchOperators.GetDefaultOperators(FieldTypes.String);
// ["equals", "notEquals", "contains", "startsWith", "endsWith", "in", "notIn", "isNull", "isNotNull"]

var numericOps = SearchOperators.GetDefaultOperators(FieldTypes.Integer);
// ["equals", "notEquals", "greaterThan", "lessThan", "between", "in", "notIn"]

Operator Constants

Operator Constant Applicable Types
equals SearchOperators.Equal All
notEquals SearchOperators.NotEqual All
contains SearchOperators.Contains String, Collection
startsWith SearchOperators.StartsWith String
endsWith SearchOperators.EndsWith String
greaterThan SearchOperators.GreaterThan Numeric, Date
lessThan SearchOperators.LessThan Numeric, Date
between SearchOperators.Between Numeric, Date
in SearchOperators.In All
notIn SearchOperators.NotIn All
isNull SearchOperators.IsNull All
isEmpty SearchOperators.IsEmpty String, Collection

Audit Fields

All events include audit information via ISearchableEvent:

Property Type Description
UserId Guid? User who performed the action
UserName string? User's display name
UserEmail string? User's email
CompanyId Guid? Company context (multi-company tenants)
TenantId string Tenant identifier
SourceService string Publishing service name
Timestamp DateTime When the event occurred
CorrelationId string? For distributed tracing

Integration Example

RabbitMQ Publisher

public class RabbitMqSearchPublisher
{
    private readonly IConnection _connection;

    public async Task PublishAsync<T>(string routingKey, T @event) where T : ISearchableEvent
    {
        using var channel = await _connection.CreateChannelAsync();
        
        await channel.ExchangeDeclareAsync(
            SearchEventRoutingKeys.Exchange, 
            ExchangeType.Topic,
            durable: true);

        var body = JsonSerializer.SerializeToUtf8Bytes(@event);
        
        await channel.BasicPublishAsync(
            exchange: SearchEventRoutingKeys.Exchange,
            routingKey: routingKey,
            body: body);
    }
}

MassTransit Consumer

public class EntityCreatedConsumer : IConsumer<EntityCreatedEvent>
{
    private readonly ISearchIndex _searchIndex;

    public async Task Consume(ConsumeContext<EntityCreatedEvent> context)
    {
        var @event = context.Message;
        
        await _searchIndex.IndexAsync(
            entityType: @event.EntityType,
            entityId: @event.EntityId,
            tenantId: @event.TenantId,
            data: @event.Data,
            schema: @event.Schema);
    }
}
  • ConvergeERP.Shared.Search.Interceptors - EF Core interceptor for automatic event publishing
  • ConvergeERP.Shared.Search.Schemas - Schema registration service for startup publishing

License

MIT

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

    • No dependencies.

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
1.0.0 176 2/25/2026