Commit:
8d5a3e2Parent:
6c646c4Send content to receipt-printer gRPC service
.gitignore
+0
-2
diff --git a/.gitignore b/.gitignore
index ab8b75c..e7495bb 100644
@@ -6,8 +6,6 @@
# dotenv files
.env
receipt_printer.proto
# User-specific files
*.rsuser
*.suo
Receipt.Web/Components/Pages/Home.razor
+15
-3
diff --git a/Receipt.Web/Components/Pages/Home.razor b/Receipt.Web/Components/Pages/Home.razor
index 5aa62c9..62489dd 100644
@@ -1,6 +1,8 @@
@page "/"
@using Grpc.Core
@using Microsoft.Extensions.Logging
@inject ILogger<Home> logger
@using Receipt.Web.Services
@inject ReceiptPrinterService receiptPrinter
<PageTitle>Receipt Printer</PageTitle>
@@ -18,17 +20,27 @@
</p>
</EditForm>
@if (Status is not null)
{
<p>@Status</p>
}
@code {
[SupplyParameterFromForm]
public PrintForm? Model { get; set; }
public string? Status { get; set; }
protected override void OnInitialized() => Model ??= new();
private async Task OnSubmit()
{
logger.LogInformation("Printing receipt with content: {Content}", Model!.Content);
Status = await receiptPrinter.Print(Model!.Content);
Model = new();
if (Status is null)
{
Model = new();
}
}
public sealed record PrintForm
Receipt.Web/Program.cs
+3
-0
diff --git a/Receipt.Web/Program.cs b/Receipt.Web/Program.cs
index 7afc79d..8eab0c3 100644
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Receipt.Web.Components;
using Receipt.Web.Services;
var builder = WebApplication.CreateBuilder(args);
@@ -10,6 +11,8 @@ builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddRazorComponents();
builder.Services.AddReceiptPrinterService();
var app = builder.Build();
// Configure the HTTP request pipeline.
Receipt.Web/Receipt.Web.csproj
+11
-0
diff --git a/Receipt.Web/Receipt.Web.csproj b/Receipt.Web/Receipt.Web.csproj
index 46103f2..1e34890 100644
@@ -8,4 +8,15 @@
<ItemGroup>
<ProjectReference Include="..\Receipt.ServiceDefaults\Receipt.ServiceDefaults.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.Net.ClientFactory" />
<PackageReference Include="Grpc.Tools">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\protos\receipt_printer.proto" GrpcServices="Client" />
</ItemGroup>
</Project>
Receipt.Web/Services/ReceiptPrinterService.cs
+68
-0
diff --git a/Receipt.Web/Services/ReceiptPrinterService.cs b/Receipt.Web/Services/ReceiptPrinterService.cs
new file mode 100644
index 0000000..83145da
@@ -0,0 +1,68 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ReceiptPrinter;
using static ReceiptPrinter.ReceiptPrinter;
namespace Receipt.Web.Services;
public sealed partial class ReceiptPrinterService(ILogger<ReceiptPrinterService> logger, ReceiptPrinterClient client)
{
public async Task<string?> Print(string content)
{
LogPrintingContent(content);
var request = new PrintRequest() { Typst = new() { Content = content } };
try
{
await client.PrintAsync(request);
return null;
}
catch (RpcException ex)
{
LogPrintingException(ex);
return ex.Status.Detail;
}
}
[LoggerMessage(Message = "Printing content: {Content}", Level = LogLevel.Debug)]
private partial void LogPrintingContent(string content);
[LoggerMessage(Message = "Printer failed", Level = LogLevel.Warning)]
private partial void LogPrintingException(Exception ex);
}
public sealed class ReceiptPrinterOptions
{
[Required]
public required Uri Address { get; set; }
}
[OptionsValidator]
public sealed partial class ReceiptPrinterOptionsValidator : IValidateOptions<ReceiptPrinterOptions>;
public static class ReceiptPrinterServiceCollectionExtensions
{
public static IServiceCollection AddReceiptPrinterService(this IServiceCollection services)
{
services.AddOptions<ReceiptPrinterOptions>().BindConfiguration("ReceiptPrinter").ValidateOnStart();
services.AddTransient<IValidateOptions<ReceiptPrinterOptions>, ReceiptPrinterOptionsValidator>();
services.AddGrpcClient<ReceiptPrinterClient>(
"ReceiptPrinter",
(sp, options) =>
{
options.Address = sp.GetRequiredService<IOptions<ReceiptPrinterOptions>>().Value.Address;
}
);
services.AddTransient<ReceiptPrinterService>();
return services;
}
}
Receipt.Web/appsettings.Development.json
+4
-1
diff --git a/Receipt.Web/appsettings.Development.json b/Receipt.Web/appsettings.Development.json
index 0c208ae..a9fb2cf 100644
@@ -1,8 +1,11 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Default": "Debug",
"Microsoft.AspNetCore": "Warning"
}
},
"ReceiptPrinter": {
"Address": "http://localhost:50051"
}
}
Receipt.Web/packages.lock.json
+42
-0
diff --git a/Receipt.Web/packages.lock.json b/Receipt.Web/packages.lock.json
index fd92f4e..066d656 100644
@@ -8,12 +8,54 @@
"resolved": "1.2.6",
"contentHash": "KMSJG+jfk7vjP52QkWB99qWespXCPAzG/IaMCMRHYWumJEAGKQYm2HtyWG6eqnOwDitH96i1cqq5EVesyOtPmg=="
},
"Google.Protobuf": {
"type": "Direct",
"requested": "[3.34.1, )",
"resolved": "3.34.1",
"contentHash": "212vdYxRuVopGE5bess6Jg5oXWyizA6hcLPTI7G+qA4PthQEvfeof3njT+7VSY5v/+O0P22xTydiP5fSJJpGEA=="
},
"Grpc.Net.ClientFactory": {
"type": "Direct",
"requested": "[2.76.0, )",
"resolved": "2.76.0",
"contentHash": "XI+kO69L9AV8B9N0UQOmH911r6MOEp9huHiavEsY56DJYuzJ9KAxNGy37dpV6CLbgCaN2uKmpOsZ9Pao6bmpVQ==",
"dependencies": {
"Grpc.Net.Client": "2.76.0"
}
},
"Grpc.Tools": {
"type": "Direct",
"requested": "[2.78.0, )",
"resolved": "2.78.0",
"contentHash": "6jPG2gHon+w2PczW8jjrCRnW/g9eEfCdd7aK6mDooptWtuPsV3ZxAwKKEx7LGEDVoT4c2SViRl8Yu3L1XiWIIg=="
},
"Microsoft.AspNetCore.App.Internal.Assets": {
"type": "Direct",
"requested": "[10.0.4, )",
"resolved": "10.0.4",
"contentHash": "M942X5Vy726SlvFBuoAC4cDczEMlPAFt1mmyFlrkw/QcpdVwVU0DkF4P9JabxX6eWNm9RvaYZHe25FN7oXoxpQ=="
},
"Grpc.Core.Api": {
"type": "Transitive",
"resolved": "2.76.0",
"contentHash": "cSxC2tdnFdXXuBgIn1pjc4YBx7LXTCp4M0qn+SMBS35VWZY+cEQYLWTBDDhdBH1HzU7BV+ncVZlniGQHMpRJKQ=="
},
"Grpc.Net.Client": {
"type": "Transitive",
"resolved": "2.76.0",
"contentHash": "K1oldmqw2+Gn69nGRzZLhqSiUZwelX1GrBu/cUl9wNf1C0uB61vFS6JcxUUv9P8VoUJhFsmV44JA6lI2EUt4xw==",
"dependencies": {
"Grpc.Net.Common": "2.76.0"
}
},
"Grpc.Net.Common": {
"type": "Transitive",
"resolved": "2.76.0",
"contentHash": "bZpiMVYgvpB44/wBh1RotrkqC7bg2FOasLri2GhR3hMKyzsiTxCoDE49YjPrJeFc4RW0wS8u+EInI09sjxVFRA==",
"dependencies": {
"Grpc.Core.Api": "2.76.0"
}
},
"Microsoft.Extensions.AmbientMetadata.Application": {
"type": "Transitive",
"resolved": "10.4.0",
protos/receipt_printer.proto
+20
-0
diff --git a/protos/receipt_printer.proto b/protos/receipt_printer.proto
new file mode 100644
index 0000000..05e4c05
@@ -0,0 +1,20 @@
syntax = "proto3";
package receipt_printer;
service ReceiptPrinter {
rpc Print(PrintRequest) returns (PrintResponse);
}
message PrintRequest {
oneof content {
TypstContent typst = 1;
}
}
message TypstContent {
optional string content = 1;
}
message PrintResponse {
}