0
0

Implement gRPC search service

This commit is contained in:
Serghei Cebotari 2023-10-30 21:49:58 +03:00
parent b91d8fbe99
commit 36cd74a959
9 changed files with 194 additions and 107 deletions

View File

@ -7,7 +7,8 @@ RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:6.0
EXPOSE 5000
EXPOSE 43000
WORKDIR /app
COPY --from=build /app/out .
ENV ASPNETCORE_ENVIRONMENT Production
ENTRYPOINT [ "dotnet", "RhSolutions.Api.dll", "--urls=http://0.0.0.0:5000" ]
ENTRYPOINT [ "dotnet", "RhSolutions.Api.dll" ]

View File

@ -4,7 +4,7 @@ using RhSolutions.Api.Services;
using RhSolutions.Api.Middleware;
using RhSolutions.QueryModifiers;
var builder = WebApplication.CreateBuilder(args);
var builder = WebApplication.CreateBuilder();
string dbHost = builder.Configuration["DB_HOST"],
dbPort = builder.Configuration["DB_PORT"],
@ -23,17 +23,18 @@ builder.Services.AddDbContext<RhSolutionsContext>(opts =>
opts.EnableSensitiveDataLogging(true);
}
});
builder.Services.AddScoped<IPricelistParser, ClosedXMLParser>()
.AddScoped<IProductTypePredicter, ProductTypePredicter>()
.AddSingleton<ProductQueryModifierFactory>();
.AddSingleton<ProductQueryModifierFactory>()
.AddGrpc();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.MapGrpcService<SearchService>();
app.UseMiddleware<QueryModifier>();
var context = app.Services.CreateScope().ServiceProvider
.GetRequiredService<RhSolutionsContext>();
app.Run();

View File

@ -4,7 +4,7 @@
"anonymousAuthentication": true,
"launchBrowser": false,
"iisExpress": {
"applicationUrl": "http://localhost:5000",
"applicationUrl": "http://localhost:5000;http://localhost:43000",
"sslPort": 0
}
},
@ -13,7 +13,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5000",
"applicationUrl": "http://localhost:5000;http://localhost:43000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

View File

@ -0,0 +1,15 @@
syntax = "proto3";
service ProductSearch {
rpc GetProduct (ProductRequest) returns (ProductReply);
}
message ProductRequest {
string query = 1;
}
message ProductReply {
string id = 1;
string name = 2;
double price = 3;
}

View File

@ -9,6 +9,11 @@
<ItemGroup>
<PackageReference Include="ClosedXML" Version="0.100.0" />
<PackageReference Include="Grpc.AspnetCore" Version="2.58.0" />
<PackageReference Include="Grpc.Tools" Version="2.59.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
@ -29,4 +34,9 @@
</None>
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\product.proto" GrpcServices="Server" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,48 @@
using Grpc.Core;
using RhSolutions.Models;
using Microsoft.EntityFrameworkCore;
using RhSolutions.QueryModifiers;
namespace RhSolutions.Api.Services;
public class SearchService : ProductSearch.ProductSearchBase
{
private RhSolutionsContext _dbContext;
private IProductTypePredicter _typePredicter;
private ProductQueryModifierFactory _productQueryModifierFactory;
public SearchService(RhSolutionsContext dbContext, IProductTypePredicter typePredicter, ProductQueryModifierFactory productQueryModifierFactory)
{
_dbContext = dbContext;
_typePredicter = typePredicter;
_productQueryModifierFactory = productQueryModifierFactory;
}
public override async Task<ProductReply?> GetProduct(ProductRequest request, ServerCallContext context)
{
var productType = _typePredicter.GetPredictedProductType(request.Query);
var modifier = _productQueryModifierFactory.GetModifier(productType!);
string query = request.Query;
if (modifier.TryQueryModify(query, out var modified))
{
query = modified;
}
var product = await _dbContext.Products
.Where(p => EF.Functions.ToTsVector(
"russian", string.Join(' ', new[] { p.Name, string.Join(' ', p.ProductLines) }))
.Matches(EF.Functions.WebSearchToTsQuery("russian", query)))
.OrderByDescending(p => p.IsOnWarehouse)
.FirstOrDefaultAsync();
if (product != null)
{
return new ProductReply()
{
Id = product.Id,
Name = product.Name,
Price = (double)product.Price
};
}
return null;
}
}

View File

@ -6,5 +6,17 @@
"Microsoft.EntityFrameworkCore": "Information"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:5000",
"Protocols": "Http1AndHttp2"
},
"gRPC": {
"Url": "http://0.0.0.0:43000",
"Protocols": "Http2"
}
}
}
}