зеркало из https://github.com/Azure/reddog-code.git
Initial cut of the AccountingService. Initial cut of the Bootstrapper.
This commit is contained in:
Родитель
0a9c72634e
Коммит
1d8c7fbb3d
|
@ -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": [
|
||||
{
|
||||
|
|
|
@ -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
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,
|
||||
|
|
28
RedDog.sln
28
RedDog.sln
|
@ -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
|
||||
}
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче