# DDD, C#, ### 課程jamboard * https://jamboard.google.com/d/1tExzdJz67TyKzBTz4h07BJA_C2a-tTwyjGkHPEYIeS8/edit?usp=sharing ### 可以參考的 * https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures * ### 預先安裝工具 #### dotnet SDK * https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-6.0.402-windows-x64-installer * ### 測試方式, 打開cmd * `dotnet --version` #### Visual Studio Code * https://code.visualstudio.com/ * 順便安裝C# extension * link: ``` 名稱: C# 識別碼: ms-dotnettools.csharp 描述: C# for Visual Studio Code (powered by OmniSharp). 版本: 1.25.0 發行者: Microsoft VS Marketplace 連結: https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp ``` ![](https://i.imgur.com/dQVOep4.png) #### git * git --version * https://github.com/git-for-windows/git/releases/download/v2.38.1.windows.1/Git-2.38.1-64-bit.exe * 順便安裝git extension * gitgraph: ``` 名稱: Git Graph 識別碼: mhutchie.git-graph 描述: View a Git Graph of your repository, and perform Git actions from the graph. 版本: 1.30.0 發行者: mhutchie VS Marketplace 連結: https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph ``` ![](https://i.imgur.com/6h8zwNo.png) #### db-browser * https://sqlitebrowser.org/dl/ * https://download.sqlitebrowser.org/DB.Browser.for.SQLite-3.12.2-win64.msi ![](https://i.imgur.com/VXYY2oe.png) ### 額外使用的 #### Figma * https://www.figma.com/ # 建立目錄用VSCode開 ``` \DDD_C#_2022_Oct_21 ``` ### 安裝的plugin * Rest Client ``` 名稱: REST Client 識別碼: humao.rest-client 描述: REST Client for Visual Studio Code 版本: 0.25.1 發行者: Huachao Mao VS Marketplace 連結: https://marketplace.visualstudio.com/items?itemName=humao.rest-client ``` * nuget reverse ![](https://i.imgur.com/4LPHDry.png) ``` 名稱: NuGet Reverse Package Search ("Add Package" support) 識別碼: jesschadwick.nuget-reverse-package-search 描述: Adds reverse .NET package lookup support like the "Add Package" context menu item in full Visual Studio 版本: 0.1.68 發行者: Jess Chadwick VS Marketplace 連結: https://marketplace.visualstudio.com/items?itemName=jesschadwick.nuget-reverse-package-search ``` ## Lab1 * dotnet 能夠有的版型 ``` dot net --list dotnet dev-certs https --trust ``` * https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215 * https://zh.wikipedia.org/zh-tw/%E7%BB%9F%E4%B8%80%E5%BB%BA%E6%A8%A1%E8%AF%AD%E8%A8%80 * https://app.diagrams.net/ # https://zh.wikipedia.org/zh-tw/%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91 ## lab1 ``` dotnet new sln -o lab1_nunit_unit_test cd lab1_nunit_unit_test git init ``` * .gitignore ``` bin/ obj/ Migrations/ ``` # 注意在lab1*下 ``` dotnet new classlib -o PrimeService dotnet new nunit -o PrimeService.Tests ``` # 複製.gitignore ![](https://i.imgur.com/LoIOekr.png) ![](https://i.imgur.com/2H6Ua9f.png) ![](https://i.imgur.com/IAW0QVo.png) # 在加入方案前 ``` dotnet build ``` ![](https://i.imgur.com/t5F8qaR.png) # add projects to solution ``` dotnet sln add .\PrimeService\PrimeService.csproj dotnet build dotnet sln add .\PrimeService.Tests\PrimeService.Tests.csproj dotnet build dotnet test ``` # 加入一個專案 ![](https://i.imgur.com/ynKIHfh.png) # 加入兩個專案 ![](https://i.imgur.com/YK7HfjG.png) # 加入後 ![](https://i.imgur.com/teglvmA.png) ``` dotnet add PrimeService.Tests\PrimeService.Tests.csproj reference PrimeService\PrimeService.csproj ``` # `ctrl+P` find file quickly # PrimeService下新增Class1.cs ```csharp using System; namespace Prime.Services; public class PrimeService { public bool IsPrime(int c){ if (c == 1) { return false; } throw new NotImplementedException("程式還沒寫"); } } ``` # https://docs.nunit.org/articles/nunit/writing-tests/attributes/apartment.html # PrimeService.Test.cs ```csharp namespace Prime.Services.Tests; public class PrimeTest1 { [OneTimeSetUp] public void init() { Console.WriteLine("只啟動一次"); TestContext.Progress.WriteLine("只啟動一次"); } [OneTimeTearDown] public void final() { Console.WriteLine("一次性的清除"); TestContext.Progress.WriteLine("一次性的清除"); } [TearDown] public void cleanUp() { Console.WriteLine("儲存資料清理環境"); } [Test] public void checkCondition() { Console.WriteLine("測試前置作業"); Assert.Pass(); } [Test] [Ignore("尚未實作完成")] public void checkCondition2() { Console.WriteLine("檢查資料"); Assert.Fail("意料中的失敗"); } [SetUp] public void prepare() { Console.WriteLine("測試前的準備"); service = new PrimeService(); } private PrimeService service = null!; [Test] public void test1IsPrime() { bool result = service.IsPrime(1); Assert.False(result, "1應該不是質數"); } } ``` ![](https://i.imgur.com/YHF8s2p.png) ## ctrl+click點擊 ![](https://i.imgur.com/ZOv8Vkq.png) # git graph ![](https://i.imgur.com/tHFFdvW.png) # ![](https://i.imgur.com/XuzOIXa.png) # https://drive.google.com/file/d/1kh8vvj8GFuulOQO8pmEt4vWW_Y05WXdk/view?usp=sharing # 生成lab2的方案 ``` dotnet new sln -o lab2_rest_client cd lab2_rest_client dotnet new webapi -o lab2_rest_api git init ``` ![](https://i.imgur.com/GgQDBoH.png) ![](https://i.imgur.com/cY0OfWG.png) ``` dotnet run --project lab2_rest_api ``` ![](https://i.imgur.com/xmR8tul.png) # https://localhost:7175 # https://localhost:7175/WeatherForecast # https://petstore.swagger.io/?_ga=2.57332200.33774714.1666337891-701740915.1666337891#/pet/uploadFile ![](https://i.imgur.com/J3TcWFf.png) ## 創建檔名為`GetWeatherForecast.http` ``` @REQUEST_SERVER = https://localhost:7175 GET {{REQUEST_SERVER}}/WeatherForecast ### 可以再測試另一組 GET {{REQUEST_SERVER}}/WeatherForecast ``` # 完成的lab2 * thttps://drive.google.com/file/d/1HCJuTTT8jDjDHtqVGCuoDQuMI40HFSzV/view?usp=sharing # https://ithelp.ithome.com.tw/articles/10220739 # day2 ``` 名稱: NuGet Reverse Package Search ("Add Package" support) 識別碼: jesschadwick.nuget-reverse-package-search 描述: Adds reverse .NET package lookup support like the "Add Package" context menu item in full Visual Studio 版本: 0.1.68 發行者: Jess Chadwick VS Marketplace 連結: https://marketplace.visualstudio.com/items?itemName=jesschadwick.nuget-reverse-package-search ``` ``` dotnet new console -o lab3_di_package_search ``` # `DI.cs` ```csharp! namespace Lab3; public static class DependencyInjuection { public static IServiceCollection Sample(this IServiceCollection services){ } } ``` # ctrl+P ==> 找檔案 # ctrl+shift+P ==> 啟動功能 ![](https://i.imgur.com/bd2Cvd6.png) ``` <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="1.0.0" /> ``` ``` <ItemGroup> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /> </ItemGroup> ``` ``` dotnet add . package Microsoft.Extensions.DependencyInjection.Abstractions ``` ```xml! <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /> </ItemGroup> </Project> ``` # `ctrl+.` ![](https://i.imgur.com/Pt4Bqbt.png) ```csharp! using Microsoft.Extensions.DependencyInjection; namespace Lab3; public static class DependencyInjuection { public static IServiceCollection Sample(this IServiceCollection services){ return services; } } ``` ```csharp! using Microsoft.Extensions.DependencyInjection; namespace Lab3 { public static class DI { public static IServiceCollection Sample(this IServiceCollection services) { return services; } } } ``` # https://drive.google.com/file/d/1-5Eg67ZUl5wwFtsY_2qeRiU_P2qOOJgu/view?usp=sharing ![](https://i.imgur.com/uiirfBc.png) # https://www.martinfowler.com/books/eaa.html # lab4 (EFCore) ``` dotnet new console -o lab4_entity_framework cd lab4_entity_framework ``` # 刪除 ``` package reference... dotnet add package Microsoft.EntityFrameworkCore.Sqlite ``` ## sqlite ```xml! <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.10" /> </ItemGroup> </Project> ``` # 加上一個.gitignore ``` bin/ obj/ Migrations/ ``` # 創建git ``` git init ``` # 建立Model模型 ## `Blog.cs` ```csharp namespace Model; public class Blog { public int BlogId { get; set; } public String? Url { get; set; } } ``` ## `Post.cs` ```csharp namespace Model; public class Post { public int PostId { get; set; } public String? Title { get; set; } public String? Content { get; set; } } ``` ## `BlogContext.cs` ## 注意建構子要public * `ctrl+.` ```csharp! using Microsoft.EntityFrameworkCore; namespace Model; public class BlogContext : DbContext { public BlogContext() { var folder = Environment.SpecialFolder.LocalApplicationData; var path = Environment.GetFolderPath(folder); DbPath = System.IO.Path.Join(path, "lab4.db"); } public DbSet<Blog>? Blogs { get; set; } public DbSet<Post>? Posts { get; set; } public string DbPath { get; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite($"Data Source={DbPath}"); } ``` ![](https://i.imgur.com/hp0uk9F.png) ``` dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design ``` ``` dotnet ef migrations add InitialCreate dotnet ef migrations remove dotnet ef database update ``` # 進入家目錄下的`\AppData\Local` ## 應該有lab4.db # for MSSQL ## https://learn.microsoft.com/zh-tw/ef/core/dbcontext-configuration/ ## https://sqlitebrowser.org/ ## Program.cs ```csharp using Model; using var db = new BlogContext(); Console.WriteLine($"目前資料庫的路徑:{db.DbPath}"); Console.WriteLine($"新增數筆資料"); db.Add(new Blog { Url = "https://www.uuu.com.tw/" }); db.Add(new Blog { Url = "https://www.tibame.com/" }); db.Add(new Blog { Url = "https://hahow.in/" }); db.Add(new Blog { Url = "https://www.iii.org.tw/" }); db.SaveChanges(); Console.WriteLine("把資料讀回來"); var blogs = db.Blogs!.OrderBy(b => b.BlogId); foreach (var b in blogs) { Console.WriteLine($"blog id:{b.BlogId}, url是{b.Url}"); } ``` # Blog ```csharp namespace Model; public class Blog { public int BlogId { get; set; } public String? Url { get; set; } public List<Post> Posts { get; } = new(); } ``` # Post ```csharp! namespace Model; public class Post { public int PostId { get; set; } public String? Title { get; set; } public String? Content { get; set; } public int BlogId {get;set;} public Blog Blog {get;set;}=null!; } ``` # dotnet build ``` dotnet ef migrations add BlogAddPost dotnet ef database update ``` # 創建PK-->FK ```csharp using Model; using var db = new BlogContext(); Console.WriteLine($"目前資料庫的路徑:{db.DbPath}"); Console.WriteLine($"新增數筆資料"); db.Add(new Blog { Url = "https://www.uuu.com.tw/" }); db.Add(new Blog { Url = "https://www.tibame.com/" }); db.Add(new Blog { Url = "https://hahow.in/" }); db.Add(new Blog { Url = "https://www.iii.org.tw/" }); db.SaveChanges(); Console.WriteLine("把資料讀回來"); var blogs = db.Blogs!.OrderBy(b => b.BlogId); foreach (var b in blogs) { Console.WriteLine($"blog id:{b.BlogId}, url是{b.Url}"); } Console.WriteLine("準備修改"); var blog = db.Blogs!.OrderBy(b => b.BlogId).Last(); blog.Url = "https://www.cwb.gov.tw"; blog.Posts.Add(new Post { Title = "urgent news!", Content = "Typhoon is coming" }); db.SaveChanges(); Console.WriteLine("修改完成"); // 從主table往下讀 blogs = db.Blogs!.OrderBy(b => b.BlogId); foreach (var b in blogs) { Console.WriteLine($"Blog ID={b.BlogId}, URL={b.Url}"); foreach (var p in b.Posts) { Console.WriteLine($"* title:{p.Title}, content:{p.Content}"); } } ``` # lab4 * https://drive.google.com/file/d/1o8blhnca1pTbnE_Q2Do7Q7Q-6S7elMqx/view?usp=sharing ``` dotnet new mvc -o lab5_webmvc dotnet build dotnet run ``` ## 在Controllers目錄下: * `HelloWorldController.cs` ```csharp! using Microsoft.AspNetCore.Mvc; namespace lab5_webmvc; public class HelloWorldController : Controller { public string Index() { return "Index是預設的, 所以會對應到Controller類別的名稱"; } public string Welcome() { return "在Controller的後面可以接上welcome"; } } ``` ## https://localhost:7003/HelloWorld ## https://localhost:7003/HelloWorld/Welcome ```csharp using Microsoft.AspNetCore.Mvc; namespace lab5_webmvc; public class HelloWorldController : Controller { public IActionResult Index() { return View(); } public string Welcome() { return "在Controller的後面可以接上welcome"; } } ``` ## Views\HelloWorld ### Index.cshtml ```htmlembedded <H2>Index</H2> <p>直接讀取樣板</p> ``` # lab5 * https://drive.google.com/file/d/1Kykfe5VEQKDYRc0rSR9XVQcxnJucpReU/view?usp=sharing # Day3 ## 解決方案建立 ``` dotnet new sln -o lab6_clean_architecture cd lab6_clean_architecture copy ../.gitignore . git init ``` ## 建立五個專案 (pp.8) ``` dotnet new webapi -o Together.Api dotnet new classlib -o Together.Contract dotnet new classlib -o Together.Infrastructure dotnet new classlib -o Together.Domain dotnet new classlib -o Together.Application ``` ![](https://i.imgur.com/m1gFC6Y.png) ## 試著建置 ``` cd Together.Api dotnet build ``` ![](https://i.imgur.com/cUO5jNW.png) # 把專案加到方案 ``` cd lab6_clean_architecture dotnet sln add (ls -r **\*.csproj) ``` # 增露api的相依性 ## 在lab6根目錄 ``` dotnet add .\Together.Api reference .\Together.Contract .\Together.Application .\Together.Infrastructure ``` ``` cd lab6_clean_architecture\Together.Api dotnet build ``` # Infrastructure <-- Application ``` dotnet add .\Together.Infrastructure reference .\Together.Application ``` # application <-- domain ``` dotnet add .\Together.Application reference .\Together.Domain ``` # step1 建立了DDD/clean architecture * https://drive.google.com/file/d/1g8cpMG6ehZ3n8uVY2okIsSm985laoy48/view?usp=sharing # 從方案執行某特定專案 ``` dotnet run --project Together.Api ``` * https://localhost:7026/WeatherForecast # 建立Rest下面的Sample目錄 ## sample.http ``` GET https://localhost:7026/WeatherForecast ``` # clean up webapi的code ```csharp var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // builder.Services.AddEndpointsApiExplorer(); // builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. // if (app.Environment.IsDevelopment()) // { // app.UseSwagger(); // app.UseSwaggerUI(); // } app.UseHttpsRedirection(); // app.UseAuthorization(); app.MapControllers(); app.Run(); ``` # alt+shift+F 乾淨化程式 ```csharp var builder = WebApplication.CreateBuilder(args); { builder.Services.AddControllers(); } var app = builder.Build(); { app.UseHttpsRedirection(); app.MapControllers(); app.Run(); } ``` ```xml <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\Together.Contract\Together.Contract.csproj" /> <ProjectReference Include="..\Together.Application\Together.Application.csproj" /> <ProjectReference Include="..\Together.Infrastructure\Together.Infrastructure.csproj" /> </ItemGroup> </Project> ``` # step2 clean architecture, clean code * https://drive.google.com/file/d/16Tmp8cZAJxcQRNFy435onQJ7WFLrYupi/view?usp=sharing ## Together.Api ### Controllers * EventController.cs ```csharp! using Microsoft.AspNetCore.Mvc; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController:ControllerBase { } ``` ``` code . ``` ![](https://i.imgur.com/9WbpSX8.png) # ctrl+. ![](https://i.imgur.com/o4ldUWa.png) # EventControllers.cs ```csharp using Microsoft.AspNetCore.Mvc; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController : ControllerBase { [Route("add-event")] public IActionResult AddEvent() { return Ok(); } [Route("query-event")] public IActionResult QueryEvent() { return Ok(); } } ``` # sample.http ``` @REQUEST_SERVER = https://localhost:7026 ### QUERY EVENT GET GET {{REQUEST_SERVER}}/api/query-event ### ADD EEVENT GET GET {{REQUEST_SERVER}}/api/add-event ``` # 應該看到的是200 ``` HTTP/1.1 200 OK Content-Length: 0 Connection: close Date: Thu, 03 Nov 2022 03:34:03 GMT Server: Kestrel ``` # Together.Contract.Controller ``` AddEventRequest.cs ``` # ctrl+P ![](https://i.imgur.com/wMmCMv3.png) ```csharp namespace Together.Contract.Controller; public record QueryEventRequest( float lat, float len, float length ); ``` ![](https://i.imgur.com/pbXPOBR.png) # EventController.cs ```csharp using Microsoft.AspNetCore.Mvc; using Together.Contract.Controller; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController : ControllerBase { [Route("add-event")] public IActionResult AddEvent(AddEventRequest request) { return Ok(); } [Route("query-event")] public IActionResult QueryEvent(QueryEventRequest request) { return Ok(); } } ``` # https://drive.google.com/file/d/1bQWZA_Mi-fXF_IkJiPfHZE63wQPf2mIp/view?usp=sharing # sample.http ``` @REQUEST_SERVER = https://localhost:7026 ### QUERY EVENT GET GET {{REQUEST_SERVER}}/api/query-event Content-Type: application/json { "lat":20.4, "lng":130.5, "length":0.5 } ### ADD EEVENT GET GET {{REQUEST_SERVER}}/api/add-event Content-Type: application/json { "name":"拳擊有氧", "coordinator":"Mark Ho", "place":"星巴克三創", "lat":20.4, "lng":130.5, "fee":500 } ``` # EventController.cs ```csharp using Microsoft.AspNetCore.Mvc; using Together.Contract.Controller; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController : ControllerBase { [Route("add-event")] public IActionResult AddEvent(AddEventRequest request) { return Ok(request); } [Route("query-event")] public IActionResult QueryEvent(QueryEventRequest request) { return Ok(request); } } ``` # AddEventResponse ```csharp namespace Together.Contract.Controller; public record AddEventResponse( Guid Id, string name, string coordinator, string place, float lat, float lng, int fee ); ``` # QueryEventResponse.cs ```csharp namespace Together.Contract.Controller; public record QueryEventResponse ( string name, string coordinator, string place, float lat, float lng, int fee ); ``` # EventController.cs ```csharp= using Microsoft.AspNetCore.Mvc; using Together.Contract.Controller; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController : ControllerBase { [HttpPost("add-event")] public IActionResult AddEvent(AddEventRequest request) { AddEventResponse response = new AddEventResponse( Guid.NewGuid(), request.name, request.coordinator, request.place, request.lat, request.lng, request.fee); return Ok(response); } [HttpPost("query-event")] public IActionResult QueryEvent(QueryEventRequest request) { QueryEventResponse response = new QueryEventResponse("name", "coord", "tpe", 0.5f, 1.0f, 300); QueryEventResponse[] events = new QueryEventResponse[]{response, response, response}; return Ok(events); } } ``` ![](https://i.imgur.com/xHG83BG.png) # step4 * https://drive.google.com/file/d/191iIQEPDS8nk-wBtQb16j25dRN2Vx-TT/view?usp=sharing # Application層 # EventAddResult.cs ```csharp namespace Together.Application.Services; public record EventAddResult ( Guid Id, string name, string coordinator, string place, float lat, float lng, int fee ); ``` # EventQueryResult.cs ```csharp= namespace Together.Application.Services; public record EventQueryResult( string name, string coordinator, string place, float lat, float lng, int fee ); ``` # IEventService.cs ```csharp= namespace Together.Application.Services; public interface IEventService { EventAddResult add(String name, String coordinator, String place, float lat, float lng, int fee); EventQueryResult[] query(float lat, float lng, float len); } ``` ![](https://i.imgur.com/rlwp0zi.png) # EventService.cs ```csharp= namespace Together.Application.Services; public class EventService : IEventService { public EventAddResult add(string name, string coordinator, string place, float lat, float lng, int fee) { return new EventAddResult(Guid.NewGuid(), name, coordinator, place, lat, lng, fee); } public EventQueryResult[] query(float lat, float lng, float len) { EventQueryResult r = new EventQueryResult("name", "coord", "tpe", 0.5f, 0.5f, 300); EventQueryResult[] results = new EventQueryResult[] { r, r, r, r }; return results; } } ``` ![](https://i.imgur.com/TS1EMY5.png) # https://drive.google.com/file/d/1JyUfA4dpdC3crMvaDBxzkVne4onLXrmN/view?usp=sharing ## Program.cs ```csharp= using Together.Application.Services; var builder = WebApplication.CreateBuilder(args); { builder.Services.AddControllers(); builder.Services.AddScoped<IEventService, EventService>(); } var app = builder.Build(); { app.UseHttpsRedirection(); app.MapControllers(); app.Run(); } ``` # EventController.cs ```csharp using Microsoft.AspNetCore.Mvc; using Together.Application.Services; using Together.Contract.Controller; namespace Together.Api.Controllers; [ApiController] [Route("api")] public class EventController : ControllerBase { private readonly IEventService eventService; public EventController(IEventService eventService) { this.eventService = eventService; } [HttpPost("add-event")] public IActionResult AddEvent(AddEventRequest request) { var result = eventService.add(request.name, request.coordinator, request.place, request.lat, request.lng, request.fee); AddEventResponse response = new AddEventResponse(result.Id, result.name, result.coordinator, result.place, result.lat, result.lng, result.fee); return Ok(response); } [HttpPost("query-event")] public IActionResult QueryEvent(QueryEventRequest request) { var result = eventService.query(request.lat, request.length, request.length); List<QueryEventResponse> events = new List<QueryEventResponse>(); foreach (var r in result) { QueryEventResponse response = new QueryEventResponse(r.name, r.coordinator, r.place, r.lat, r.lng, r.fee); events.Add(response); } return Ok(events.ToArray()); } } ``` # step6 * https://drive.google.com/file/d/1pPVzQJrgi1GnhbxyYbTzbd4F9WuWkLFC/view?usp=sharing # DependencyInjection.cs ```csharp= using Microsoft.Extensions.DependencyInjection; using Together.Application.Services; namespace Together.Application; public static class DependencyInjection { public static IServiceCollection AddApplication(this IServiceCollection services) { services.AddScoped<IEventService, EventService>(); return services; } } ``` ``` dotnet add .\Together.Application package Microsoft.Extensions.DependencyInjection ``` # Program.cs ```csharp using Together.Application; var builder = WebApplication.CreateBuilder(args); { builder.Services.AddControllers(); builder.Services.AddApplication(); } var app = builder.Build(); { app.UseHttpsRedirection(); app.MapControllers(); app.Run(); } ``` # step 7 * https://drive.google.com/file/d/1GbpHQSF3zOo06gEJc5NPFr_6N2j22pPE/view?usp=sharing # Event.cs 在Domain的Entity下 ```csharp= namespace Together.Domain.Entity; public class Event { public Guid Id { get; set; } = Guid.NewGuid(); public String? Name { get; set; } = null; public String? Coordinator { get; set; } = null; public String? Place { get; set; } = null; public float Lat; public float Lng; public int Fee; } ``` ![](https://i.imgur.com/dzazH7p.png) # Application\Common\Interfaces ## IEventRepository.cs ```csharp using Together.Domain.Entity; namespace Together.Application.Common.Interfaces; public interface IEventRepository { Event[] GetAll(); void AddEvent(Event e); } ``` # Infrastructure\Persistence ## EventMemoryRepository.cs ```csharp! using Together.Application.Common.Interfaces; using Together.Domain.Entity; namespace Together.Infrastructure.Persistence; public class EventMemoryRepository : IEventRepository { private static readonly List<Event> _events = new(); public void AddEvent(Event e) { _events.Add(e); } public Event[] GetAll() { return _events.ToArray(); } } ``` # step 8 * https://drive.google.com/file/d/1yFYWannKSGxYgmbNdohbDh3_Fub3vJTZ/view?usp=sharing # Infrastructure下的DependencyInjection ```csharp dotnet add .\Together.Infrastructure package Microsoft.Extensions.DependencyInjection ``` ``` using Microsoft.Extensions.DependencyInjection; using Together.Application.Common.Interfaces; using Together.Infrastructure.Persistence; namespace Together.Infrastructure; public static class DependencyInjection { public static IServiceCollection AddInfrastructure(this IServiceCollection services) { services.AddScoped<IEventRepository, EventMemoryRepository>(); return services; } } ``` # EventService.cs ```csharp using Together.Application.Common.Interfaces; using Together.Domain.Entity; namespace Together.Application.Services; public class EventService : IEventService { private readonly IEventRepository repository; public EventService(IEventRepository repository) { this.repository = repository; } public EventAddResult add(string name, string coordinator, string place, float lat, float lng, int fee) { var event1 = new Event { Name = name, Coordinator = coordinator, Place = place, Lat = lat, Lng = lng, Fee = fee }; repository.AddEvent(event1); return new EventAddResult(Guid.NewGuid(), name, coordinator, place, lat, lng, fee); } public EventQueryResult[] query(float lat, float lng, float len) { List<EventQueryResult> results = new(); foreach (var r in repository.GetAll()) { EventQueryResult result = new EventQueryResult(r.Name, r.Coordinator, r.Place, r.Lat, r.Lng, r.Fee); results.Add(result); } return results.ToArray(); } } ``` # Program.cs ```csharp using Together.Application; using Together.Infrastructure; var builder = WebApplication.CreateBuilder(args); { builder.Services.AddControllers(); builder.Services.AddApplication(); builder.Services.AddInfrastructure(); } var app = builder.Build(); { app.UseHttpsRedirection(); app.MapControllers(); app.Run(); } ``` # step9 * https://drive.google.com/file/d/1JXQVNqu9WqonOZ-g0QytNFFh3xqiCIP-/view?usp=sharing # EventQueryResult.cs ```csharp namespace Together.Application.Services; public record EventQueryResult( string? name, string? coordinator, string? place, float lat, float lng, int fee ); ``` # QueryEventResponse ```csharp namespace Together.Contract.Controller; public record QueryEventResponse ( string? name, string? coordinator, string? place, float lat, float lng, int fee ); ``` ``` dotnet add package Microsoft.EntityFrameworkCore.Sqlite cd .. dotnet build ``` # EventContext.cs ```csharp using Microsoft.EntityFrameworkCore; using Together.Domain.Entity; namespace Together.Infrastructure.Persistence; public class EventContext : DbContext { public string DbPath { get; } public EventContext() { var folder = Environment.SpecialFolder.LocalApplicationData; var path = Environment.GetFolderPath(folder); DbPath = System.IO.Path.Join(path, "lab6.db"); } public DbSet<Event>? Events { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite($"Data Source={DbPath}"); } ``` # cd Together.Infrastructure ``` dotnet add package Microsoft.EntityFrameworkCore.Design ``` ``` dotnet ef migrations add InitialCreate dotnet ef database update ``` # 進入`YOUR_HOME\AppData\Local` # dir *.db # EventEFCoreRepository ```csharp! using Together.Application.Common.Interfaces; using Together.Domain.Entity; namespace Together.Infrastructure.Persistence; public class EventEFCoreRepostiory : IEventRepository { private readonly EventContext db = new EventContext(); public void AddEvent(Event e) { db.Add(e); db.SaveChanges(); } public Event[] GetAll() { return db.Events!.ToArray(); } } ``` # step10 * https://drive.google.com/file/d/1N_WxBirKoKif2cI-Xppd9X2Bw5VKehgr/view?usp=sharing