Initial cut of the AccountingService. Initial cut of the Bootstrapper.

This commit is contained in:
Lynn Orrell 2021-05-05 02:36:36 -05:00
Родитель 0a9c72634e
Коммит 1d8c7fbb3d
23 изменённых файлов: 808 добавлений и 7 удалений

31
.vscode/launch.json поставляемый
Просмотреть файл

@ -99,6 +99,37 @@
"DAPR_GRPC_PORT": "5601"
}
},
{
"name": "Debug AccountingService",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build AccountingService",
"program": "${workspaceFolder}/RedDog.AccountingService/bin/Debug/net5.0/RedDog.AccountingService.dll",
"args": [],
"cwd": "${workspaceFolder}/RedDog.AccountingService",
"stopAtEntry": false,
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "http://127.0.0.1:5700",
"DAPR_HTTP_PORT": "5780",
"DAPR_GRPC_PORT": "5701"
}
},
{
"name": "Debug Bootstrapper",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build Bootstrapper",
"program": "${workspaceFolder}/RedDog.Bootstrapper/bin/Debug/net5.0/RedDog.Bootstrapper.dll",
"args": [],
"cwd": "${workspaceFolder}/RedDog.Bootstrapper",
"stopAtEntry": false,
"env": {
"DAPR_HTTP_PORT": "5880",
"DAPR_GRPC_PORT": "5801"
}
},
],
"compounds": [
{

61
.vscode/tasks.json поставляемый
Просмотреть файл

@ -79,6 +79,32 @@
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "Build AccountingService",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/RedDog.AccountingService",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "Build Bootstrapper",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/RedDog.Bootstrapper",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile",
"group": "build"
},
{
"label": "Build Solution",
"command": "dotnet",
@ -167,6 +193,24 @@
],
"problemMatcher": []
},
{
"label": "Dapr AccountingService",
"command": "dapr",
"args": [
"run",
"--app-id",
"accounting-service",
"--components-path",
"${workspaceFolder}/components/local",
"--app-port",
"5700",
"--dapr-grpc-port",
"5701",
"--dapr-http-port",
"5780"
],
"problemMatcher": []
},
{
"label": "Dapr VirtualWorker",
"command": "dapr",
@ -201,6 +245,22 @@
],
"problemMatcher": []
},
{
"label": "Dapr Bootstrapper",
"command": "dapr",
"args": [
"run",
"--app-id",
"bootstrapper",
"--components-path",
"${workspaceFolder}/components/local",
"--dapr-grpc-port",
"5801",
"--dapr-http-port",
"5880"
],
"problemMatcher": []
},
{
"label": "Dapr (All Services)",
"dependsOn": [
@ -208,6 +268,7 @@
"Dapr MakeLineService",
"Dapr LoyaltyService",
"Dapr ReceiptGenerationService",
"Dapr AccountingService",
"Dapr VirtualWorker",
"Dapr VirtualCustomers"
],

Просмотреть файл

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
namespace RedDog.AccountingModel
{
public class AccountingContext : DbContext
{
public AccountingContext(DbContextOptions<AccountingContext> options) : base(options)
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders {get; set; }
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RedDog.AccountingModel
{
[Table(nameof(Customer))]
public class Customer
{
[Column(TypeName = "nvarchar(36)")]
[Key]
public string LoyaltyId { get; set; }
[Column(TypeName = "nvarchar(50)")]
[Required]
public string FirstName { get; set; }
[Column(TypeName = "nvarchar(50)")]
[Required]
public string LastName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RedDog.AccountingModel
{
[Table(nameof(Order))]
public class Order
{
public Order()
{
OrderItems = new List<OrderItem>();
}
[Key]
public Guid OrderId { get; set; }
[Column(TypeName = "nvarchar(50)")]
[Required]
public string StoreId { get; set; }
[Required]
public DateTime PlacedDate { get; set; }
public DateTime? CompletedDate { get; set; }
[Required]
public Customer Customer { get; set; }
[Required]
public List<OrderItem> OrderItems { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal OrderTotal { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,31 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RedDog.AccountingModel
{
[Table(nameof(OrderItem))]
public class OrderItem
{
[Key]
public int OrderItemId { get; set; }
public int ProductId { get; set; }
[Column(TypeName = "nvarchar(50)")]
[Required]
public string ProductName { get; set; }
public int Quantity { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal UnitCost { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal UnitPrice { get; set; }
public Guid OrderId { get; set; }
public Order Order { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.5" />
</ItemGroup>
</Project>

Просмотреть файл

@ -2,8 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapr;
using Dapr.Client;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using RedDog.AccountingModel;
using RedDog.AccountingService.Models;
namespace RedDog.AccountingService.Controllers
{
@ -11,11 +15,62 @@ namespace RedDog.AccountingService.Controllers
[Route("[controller]")]
public class AccountingController : ControllerBase
{
private const string PubSubName = "reddog.pubsub";
private const string OrderTopic = "orders";
private readonly ILogger<AccountingController> _logger;
private readonly DaprClient _daprClient;
public AccountingController(ILogger<AccountingController> logger)
public AccountingController(ILogger<AccountingController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
}
[Topic(PubSubName, OrderTopic)]
[HttpPost("orders")]
public async Task<IActionResult> UpdateMetrics(OrderSummary orderSummary, [FromServices] AccountingContext dbContext)
{
_logger.LogInformation("Received Order Summary: {@OrderSummary}", orderSummary);
Customer customer = dbContext.Customers.SingleOrDefault(c => c.LoyaltyId == orderSummary.LoyaltyId);
customer ??= new Customer()
{
FirstName = orderSummary.FirstName,
LastName = orderSummary.LastName,
LoyaltyId = orderSummary.LoyaltyId
};
Order order = new Order()
{
OrderId = orderSummary.OrderId,
StoreId = orderSummary.StoreId,
PlacedDate = orderSummary.OrderDate,
Customer = customer,
OrderTotal = orderSummary.OrderTotal
};
foreach(var orderItemSummary in orderSummary.OrderItems)
{
order.OrderItems.Add(new OrderItem()
{
ProductId = orderItemSummary.ProductId,
ProductName = orderItemSummary.ProductName,
Quantity = orderItemSummary.Quantity,
UnitCost = orderItemSummary.UnitCost,
UnitPrice = orderItemSummary.UnitPrice
});
}
dbContext.Add(order);
await dbContext.SaveChangesAsync();
return Ok();
}
[HttpGet("OrderMetrics")]
public async Task<List<OrderMetric>> GetOrderMetricsAsync()
{
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace RedDog.AccountingService.Models
{
public class OrderItemSummary
{
[JsonPropertyName("productId")]
public int ProductId { get; set; }
[JsonPropertyName("productName")]
public string ProductName { get; set; }
[JsonPropertyName("quantity")]
public int Quantity { get; set; }
[JsonPropertyName("unitCost")]
public decimal UnitCost { get; set; }
[JsonPropertyName("unitPrice")]
public decimal UnitPrice { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System;
namespace RedDog.AccountingService.Models
{
public class OrderMetric
{
public string StoreId { get; set; }
public DateTime Date { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace RedDog.AccountingService.Models
{
public class OrderSummary
{
[JsonPropertyName("orderId")]
public Guid OrderId { get; set; }
[JsonPropertyName("orderDate")]
public DateTime OrderDate { get; set; }
[JsonPropertyName("storeId")]
public string StoreId { get; set; }
[JsonPropertyName("firstName")]
public string FirstName { get; set; }
[JsonPropertyName("lastName")]
public string LastName { get; set; }
[JsonPropertyName("loyaltyId")]
public string LoyaltyId { get; set; }
[JsonPropertyName("orderItems")]
public List<OrderItemSummary> OrderItems { get; set; }
[JsonPropertyName("orderTotal")]
public decimal OrderTotal { get; set; }
}
}

Просмотреть файл

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapr.Client;
using Dapr.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
@ -14,6 +16,8 @@ namespace RedDog.AccountingService
{
public class Program
{
private const string SecretStoreName = "reddog.secretstore";
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
@ -44,6 +48,15 @@ namespace RedDog.AccountingService
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureAppConfiguration(config =>
{
var daprClient = new DaprClientBuilder().Build();
var secretDescriptors = new List<DaprSecretDescriptor>
{
new DaprSecretDescriptor("reddog-sql")
};
config.AddDaprSecretStore(SecretStoreName, secretDescriptors, daprClient);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();

Просмотреть файл

@ -6,8 +6,13 @@
<ItemGroup>
<PackageReference Include="Dapr.AspNetCore" Version="1.1.1" />
<PackageReference Include="Dapr.Extensions.Configuration" Version="1.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RedDog.AccountingModel\RedDog.AccountingModel.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -5,11 +5,13 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using RedDog.AccountingModel;
using Serilog;
namespace RedDog.AccountingService
@ -31,6 +33,7 @@ namespace RedDog.AccountingService
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "RedDog.AccountingService", Version = "v1" });
});
services.AddDbContext<AccountingContext>(options => options.UseSqlServer(Configuration["reddog-sql"]));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

131
RedDog.Bootstrapper/Migrations/20210505072819_InitialCreate.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,131 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RedDog.AccountingModel;
namespace RedDog.Bootstrapper.Migrations
{
[DbContext(typeof(AccountingContext))]
[Migration("20210505072819_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.5")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("RedDog.AccountingModel.Customer", b =>
{
b.Property<string>("LoyaltyId")
.HasColumnType("nvarchar(36)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.HasKey("LoyaltyId");
b.ToTable("Customer");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.Property<Guid>("OrderId")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("CompletedDate")
.HasColumnType("datetime2");
b.Property<string>("CustomerLoyaltyId")
.HasColumnType("nvarchar(36)");
b.Property<decimal>("OrderTotal")
.HasColumnType("decimal(18,2)");
b.Property<DateTime>("PlacedDate")
.HasColumnType("datetime2");
b.Property<string>("StoreId")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.HasKey("OrderId");
b.HasIndex("CustomerLoyaltyId");
b.ToTable("Order");
});
modelBuilder.Entity("RedDog.AccountingModel.OrderItem", b =>
{
b.Property<int>("OrderItemId")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<string>("ProductName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitCost")
.HasColumnType("decimal(18,2)");
b.Property<decimal>("UnitPrice")
.HasColumnType("decimal(18,2)");
b.HasKey("OrderItemId");
b.HasIndex("OrderId");
b.ToTable("OrderItem");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.HasOne("RedDog.AccountingModel.Customer", "Customer")
.WithMany()
.HasForeignKey("CustomerLoyaltyId");
b.Navigation("Customer");
});
modelBuilder.Entity("RedDog.AccountingModel.OrderItem", b =>
{
b.HasOne("RedDog.AccountingModel.Order", "Order")
.WithMany("OrderItems")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Order");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.Navigation("OrderItems");
});
#pragma warning restore 612, 618
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace RedDog.Bootstrapper.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Customer",
columns: table => new
{
LoyaltyId = table.Column<string>(type: "nvarchar(36)", nullable: false),
FirstName = table.Column<string>(type: "nvarchar(50)", nullable: false),
LastName = table.Column<string>(type: "nvarchar(50)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Customer", x => x.LoyaltyId);
});
migrationBuilder.CreateTable(
name: "Order",
columns: table => new
{
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
StoreId = table.Column<string>(type: "nvarchar(50)", nullable: false),
PlacedDate = table.Column<DateTime>(type: "datetime2", nullable: false),
CompletedDate = table.Column<DateTime>(type: "datetime2", nullable: true),
CustomerLoyaltyId = table.Column<string>(type: "nvarchar(36)", nullable: true),
OrderTotal = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Order", x => x.OrderId);
table.ForeignKey(
name: "FK_Order_Customer_CustomerLoyaltyId",
column: x => x.CustomerLoyaltyId,
principalTable: "Customer",
principalColumn: "LoyaltyId",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "OrderItem",
columns: table => new
{
OrderItemId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ProductId = table.Column<int>(type: "int", nullable: false),
ProductName = table.Column<string>(type: "nvarchar(50)", nullable: false),
Quantity = table.Column<int>(type: "int", nullable: false),
UnitCost = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
UnitPrice = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrderItem", x => x.OrderItemId);
table.ForeignKey(
name: "FK_OrderItem_Order_OrderId",
column: x => x.OrderId,
principalTable: "Order",
principalColumn: "OrderId",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Order_CustomerLoyaltyId",
table: "Order",
column: "CustomerLoyaltyId");
migrationBuilder.CreateIndex(
name: "IX_OrderItem_OrderId",
table: "OrderItem",
column: "OrderId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrderItem");
migrationBuilder.DropTable(
name: "Order");
migrationBuilder.DropTable(
name: "Customer");
}
}
}

Просмотреть файл

@ -0,0 +1,129 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RedDog.AccountingModel;
namespace RedDog.Bootstrapper.Migrations
{
[DbContext(typeof(AccountingContext))]
partial class AccountingContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.5")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("RedDog.AccountingModel.Customer", b =>
{
b.Property<string>("LoyaltyId")
.HasColumnType("nvarchar(36)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.HasKey("LoyaltyId");
b.ToTable("Customer");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.Property<Guid>("OrderId")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("CompletedDate")
.HasColumnType("datetime2");
b.Property<string>("CustomerLoyaltyId")
.HasColumnType("nvarchar(36)");
b.Property<decimal>("OrderTotal")
.HasColumnType("decimal(18,2)");
b.Property<DateTime>("PlacedDate")
.HasColumnType("datetime2");
b.Property<string>("StoreId")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.HasKey("OrderId");
b.HasIndex("CustomerLoyaltyId");
b.ToTable("Order");
});
modelBuilder.Entity("RedDog.AccountingModel.OrderItem", b =>
{
b.Property<int>("OrderItemId")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<int>("ProductId")
.HasColumnType("int");
b.Property<string>("ProductName")
.IsRequired()
.HasColumnType("nvarchar(50)");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("UnitCost")
.HasColumnType("decimal(18,2)");
b.Property<decimal>("UnitPrice")
.HasColumnType("decimal(18,2)");
b.HasKey("OrderItemId");
b.HasIndex("OrderId");
b.ToTable("OrderItem");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.HasOne("RedDog.AccountingModel.Customer", "Customer")
.WithMany()
.HasForeignKey("CustomerLoyaltyId");
b.Navigation("Customer");
});
modelBuilder.Entity("RedDog.AccountingModel.OrderItem", b =>
{
b.HasOne("RedDog.AccountingModel.Order", "Order")
.WithMany("OrderItems")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Order");
});
modelBuilder.Entity("RedDog.AccountingModel.Order", b =>
{
b.Navigation("OrderItems");
});
#pragma warning restore 612, 618
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Dapr.Client;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using RedDog.AccountingModel;
namespace RedDog.Bootstrapper
{
class Program : IDesignTimeDbContextFactory<AccountingContext>
{
private const string SecretStoreName = "reddog.secretstore";
static async Task Main(string[] args)
{
Program p = new Program();
using AccountingContext context = p.CreateDbContext(null);
await context.Database.MigrateAsync();
}
public AccountingContext CreateDbContext(string[] args)
{
var daprClient = new DaprClientBuilder().Build();
var connectionString = daprClient.GetSecretAsync(SecretStoreName, "reddog-sql").GetAwaiter().GetResult();
DbContextOptionsBuilder<AccountingContext> optionsBuilder = new DbContextOptionsBuilder<AccountingContext>().UseSqlServer(connectionString["reddog-sql"], b =>
{
b.MigrationsAssembly("RedDog.Bootstrapper");
b.EnableRetryOnFailure();
});
return new AccountingContext(optionsBuilder.Options);
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
create user reddog with password = [PASSWORD];
go;
grant create table to reddog;
go;
grant control on schema::dbo to reddog;
go;
Running migrations
DAPR_GRPC_PORT=5801 dotnet ef migrations add InitialCreate

Просмотреть файл

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\RedDog.AccountingModel\RedDog.AccountingModel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapr.Client" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>

Просмотреть файл

@ -16,15 +16,17 @@ namespace RedDog.LoyaltyService.Controllers
private const string PubSubName = "reddog.pubsub";
private const string LoyaltyStateStoreName = "reddog.state.loyalty";
private readonly ILogger<LoyaltyController> _logger;
private readonly DaprClient _daprClient;
public LoyaltyController(ILogger<LoyaltyController> logger)
public LoyaltyController(ILogger<LoyaltyController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
}
[Topic(PubSubName, OrderTopic)]
[HttpPost("orders")]
public async Task<IActionResult> UpdateLoyalty(OrderSummary orderSummary, [FromServices] DaprClient daprClient)
public async Task<IActionResult> UpdateLoyalty(OrderSummary orderSummary)
{
_logger.LogInformation("Received Order Summary: {@OrderSummary}", orderSummary);
@ -34,7 +36,7 @@ namespace RedDog.LoyaltyService.Controllers
StateEntry<LoyaltySummary> stateEntry = null;
try
{
stateEntry = await daprClient.GetStateEntryAsync<LoyaltySummary>(LoyaltyStateStoreName, orderSummary.LoyaltyId);
stateEntry = await _daprClient.GetStateEntryAsync<LoyaltySummary>(LoyaltyStateStoreName, orderSummary.LoyaltyId);
stateEntry.Value ??= new LoyaltySummary()
{
FirstName = orderSummary.FirstName,

Просмотреть файл

@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedDog.VirtualWorker", "Red
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedDog.AccountingService", "RedDog.AccountingService\RedDog.AccountingService.csproj", "{F8E0D2B2-5E21-4763-AC61-0074FA1297F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedDog.Bootstrapper", "RedDog.Bootstrapper\RedDog.Bootstrapper.csproj", "{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedDog.AccountingModel", "RedDog.AccountingModel\RedDog.AccountingModel.csproj", "{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -114,5 +118,29 @@ Global
{F8E0D2B2-5E21-4763-AC61-0074FA1297F9}.Release|x64.Build.0 = Release|Any CPU
{F8E0D2B2-5E21-4763-AC61-0074FA1297F9}.Release|x86.ActiveCfg = Release|Any CPU
{F8E0D2B2-5E21-4763-AC61-0074FA1297F9}.Release|x86.Build.0 = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|x64.ActiveCfg = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|x64.Build.0 = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|x86.ActiveCfg = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Debug|x86.Build.0 = Debug|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|Any CPU.Build.0 = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|x64.ActiveCfg = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|x64.Build.0 = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|x86.ActiveCfg = Release|Any CPU
{B2AE26A4-3A12-4BC8-824C-6C08F04A111F}.Release|x86.Build.0 = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|x64.ActiveCfg = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|x64.Build.0 = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|x86.ActiveCfg = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Debug|x86.Build.0 = Debug|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|Any CPU.Build.0 = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|x64.ActiveCfg = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|x64.Build.0 = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|x86.ActiveCfg = Release|Any CPU
{775EACDA-CD1B-41BC-A1CE-85E7CB8CDB63}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

Просмотреть файл

@ -14,15 +14,15 @@ Content-Type: application/json
"loyaltyId": "42",
"orderItems": [
{
"menuItemId": 1,
"productId": 1,
"quantity": 1
},
{
"menuItemId": 2,
"productId": 2,
"quantity": 1
},
{
"menuItemId": 3,
"productId": 3,
"quantity": 3
}
]