Skip to content

Commit

Permalink
Add Meilisearch integration (#66)
Browse files Browse the repository at this point in the history
* Add Meilisearch hosting

* Add public api files

* Clean up csproj

* remove configuration schema stuff

* add tests

* fix build

* Fix test by addib Aspire.Hosting.AppHost to Testing proj

* Add test for client package

* fix test on windows

* Add example

* Address PR feedback

* Add logging for tests

* Add readme for packages

* fix xml docs

* rename file

* Remove xunit test classes and use Microsoft.DotNet.XUnitExtensions instead

* Remove polly and use WaitForText instead

* Update codeowners

* Matching the correct naming structure

---------

Co-authored-by: Aaron Powell <[email protected]>
  • Loading branch information
Alirexaa and aaronpowell authored Oct 22, 2024
1 parent 8dd8295 commit 73ed325
Show file tree
Hide file tree
Showing 60 changed files with 2,573 additions and 452 deletions.
9 changes: 9 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@
/examples/golang/_ @tommasodotNET
/src/CommunityToolkit.Aspire.Hosting.Golang/_ @tommasodotNET
/tests/CommunityToolkit.Aspire.Hosting.Golang/_ @tommasodotNET

# CommunityToolkit.Aspire.Meilisearch
# CommunityToolkit.Aspire.Hosting.Meilisearch

/examples/meilisearch/_ @alirexaa
/src/CommunityToolkit.Aspire.Hosting.Meilisearch/_ @alirexaa
/tests/CommunityToolkit.Aspire.Hosting.Meilisearch/_ @alirexaa
/src/CommunityToolkit.Aspire.Meilisearch/_ @alirexaa
/tests/CommunityToolkit.Aspire.Meilisearch/_ @alirexaa
90 changes: 71 additions & 19 deletions CommunityToolkit.Aspire.sln

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
<AspireVersion>8.2.0</AspireVersion>
<AspNetCoreVersion>8.0.7</AspNetCoreVersion>
<OpenTelemetryVersion>1.9.0</OpenTelemetryVersion>

<TestContainersVersion>3.10.0</TestContainersVersion>
<IsPackable>false</IsPackable>
<UsePublicApiAnalyzers>true</UsePublicApiAnalyzers>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<RepoRoot>$(MSBuildThisFileDirectory)</RepoRoot>
</PropertyGroup>

<PropertyGroup>
<ContinuousIntegrationBuild>false</ContinuousIntegrationBuild>
Expand Down
6 changes: 6 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<PackageVersion Include="JsonSchema.Net" Version="7.2.3" />
<!-- AspNetCore packages -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="$(AspNetCoreVersion)" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<!-- .NET packages -->
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="8.7.0" />
Expand All @@ -33,9 +35,13 @@
<PackageVersion Include="xunit" Version="2.9.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.9.1" />
<PackageVersion Include="Microsoft.DotNet.XUnitExtensions" Version="8.0.0-beta.24516.1" />
<!-- External packages -->
<PackageVersion Include="OllamaSharp" Version="3.0.7" />
<PackageVersion Include="MeiliSearch" Version="0.15.3" />
<!-- Build dependencies -->
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
<!-- Testcontainers packages -->
<PackageVersion Include="Testcontainers" Version="$(TestContainersVersion)" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Meilisearch\CommunityToolkit.Aspire.Meilisearch.csproj" />
<ProjectReference Include="..\CommunityToolkit.Aspire.Hosting.Meilisearch.ServiceDefaults\CommunityToolkit.Aspire.Hosting.Meilisearch.ServiceDefaults.csproj" />

</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CommunityToolkit.Aspire.Hosting.Meilisearch.ApiService;
public class Movie
{
public string? Id { get; set; }
public string? Title { get; set; }
public IEnumerable<string>? Genres { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using CommunityToolkit.Aspire.Hosting.Meilisearch.ApiService;
using Meilisearch;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

builder.AddMeilisearchClient("meilisearch");

var app = builder.Build();

app.MapDefaultEndpoints();
app.MapGet("/search", async (MeilisearchClient meilisearch) =>
{
var index = meilisearch.Index("movies");
var result = await index.SearchAsync<Movie>(
"car",
new SearchQuery
{
AttributesToHighlight = ["title"],
});
return result;
});

app.MapGet("/create", async (MeilisearchClient meilisearch) =>
{
// An index is where the documents are stored.
var index = meilisearch.Index("movies");
var documents = new Movie[] {
new() { Id = "1", Title = "Carol", Genres = ["Romance", "Drama"] },
new() { Id = "2", Title = "Wonder Woman", Genres = ["Action", "Adventure"] },
new() { Id = "3", Title = "Life of Pi", Genres = ["Adventure", "Drama"] },
new() { Id = "4", Title = "Mad Max: Fury Road", Genres = ["Adventure", "Science Fiction"] },
new() { Id = "5", Title = "Moana", Genres = ["Fantasy", "Action"] },
new() { Id = "6", Title = "Philadelphia", Genres = ["Drama"] }
};
// If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
var task = await index.AddDocumentsAsync<Movie>(documents);
// Wait for the task to ensure the document is added. this line is necessary for passing tests.
var response = await index.WaitForTaskAsync(task.TaskUid);
return task;
});

app.MapGet("/get", async (MeilisearchClient meilisearch) =>
{
// An index is where the documents are stored.
var index = await meilisearch.GetIndexAsync("movies");
var data = await index.GetDocumentsAsync<Movie>();
return data.Results;
});

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5232",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7042;http://localhost:5232",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>6adfc361-47fd-4c05-88de-c95763714bb0</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Meilisearch\CommunityToolkit.Aspire.Hosting.Meilisearch.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\CommunityToolkit.Aspire.Hosting.Meilisearch.ApiService\CommunityToolkit.Aspire.Hosting.Meilisearch.ApiService.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Projects;

var builder = DistributedApplication.CreateBuilder(args);

var meilisearch = builder.AddMeilisearch("meilisearch");

builder.AddProject<CommunityToolkit_Aspire_Hosting_Meilisearch_ApiService>("apiservice")
.WithReference(meilisearch);

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:18119;http://localhost:12037",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:31475",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:12700"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15073",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19087",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20252"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireSharedProject>true</IsAspireSharedProject>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />

<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ServiceDiscovery;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace Microsoft.Extensions.Hosting;
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
// This project should be referenced by each service project in your solution.
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
builder.ConfigureOpenTelemetry();

builder.AddDefaultHealthChecks();

builder.Services.AddServiceDiscovery();

builder.Services.ConfigureHttpClientDefaults(http =>
{
// Turn on resilience by default
http.AddStandardResilienceHandler();
// Turn on service discovery by default
http.AddServiceDiscovery();
});

// Uncomment the following to restrict the allowed schemes for service discovery.
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
// {
// options.AllowedSchemes = ["https"];
// });

return builder;
}

public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});

builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
//.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation();
});

builder.AddOpenTelemetryExporters();

return builder;
}

private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
{
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

if (useOtlpExporter)
{
builder.Services.AddOpenTelemetry().UseOtlpExporter();
}

// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
//{
// builder.Services.AddOpenTelemetry()
// .UseAzureMonitor();
//}

return builder;
}

public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
// Add a default liveness check to ensure app is responsive
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);

return builder;
}

public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
// Adding health checks endpoints to applications in non-development environments has security implications.
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
if (app.Environment.IsDevelopment())
{
// All health checks must pass for app to be considered ready to accept traffic after starting
app.MapHealthChecks("/health");

// Only health checks tagged with the "live" tag must pass for app to be considered alive
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
}

return app;
}
}
Loading

0 comments on commit 73ed325

Please sign in to comment.