diff --git "a/\351\231\210\346\200\235\347\235\277/20241122-(\344\274\240\345\217\202).md" "b/\351\231\210\346\200\235\347\235\277/20241122-(\344\274\240\345\217\202).md" index 438a391f9f5a01a6b37592476c63ac23b1ae1bb0..923298d0b74f521d0b73ba50d910753613da4381 100644 --- "a/\351\231\210\346\200\235\347\235\277/20241122-(\344\274\240\345\217\202).md" +++ "b/\351\231\210\346\200\235\347\235\277/20241122-(\344\274\240\345\217\202).md" @@ -9,6 +9,7 @@ - **维护软件的兼容性** - **获取新功能和改进** + ## 更新软件和补丁 执行命令:`apt upgrade -y` - **了解这一步的实际用处意义**:确保系统和软件包是最新的,以修复已知的安全漏洞和提升性能。 diff --git "a/\351\231\210\346\200\235\347\235\277/20241125-(\346\216\247\345\210\266\345\231\250\344\274\240\345\217\202Action).md" "b/\351\231\210\346\200\235\347\235\277/20241125-(\346\216\247\345\210\266\345\231\250\344\274\240\345\217\202Action).md" new file mode 100644 index 0000000000000000000000000000000000000000..fb07a916c358138a7a7f1569cd66e49051416f63 --- /dev/null +++ "b/\351\231\210\346\200\235\347\235\277/20241125-(\346\216\247\345\210\266\345\231\250\344\274\240\345\217\202Action).md" @@ -0,0 +1,261 @@ +## 课堂笔记 + +## Action 的返回值类型 + +### 1. **Action 定义与修饰符** + +在 ASP.NET Core 中,**Action** 是指被 `public` 修饰的控制器方法,通常用于处理 HTTP 请求。Action 的返回值类型可以多种多样,具体取决于你想要返回的数据类型或者响应状态。 + +### 2. **常见的返回数据类型** + +#### 基本数据类型 + +- **基本数据类型**:你可以在 Action 中返回如 `int`、`string`、`bool` 等基本数据类型。例如,返回一个整型的 ID 或者一个字符串消息: + +```cs +public int GetId() +{ + return 1; +} + +public string GetMessage() +{ + return "Hello, World!"; +} +``` + +- **集合类型**:Action 也可以返回集合类型,如 `IList<>`,例如: + +```cs +public IList GetBlogs() +{ + return Db.Blog; +} +``` + +#### `IActionResult` + +`IActionResult` 是 ASP.NET Core 控制器中最常见的返回类型。它表示一个通用的 HTTP 响应,你可以根据具体需求返回不同的响应类型。常见的状态码包括: + +- **200 OK**:请求成功,返回请求的数据或信息。 +- **301 Moved Permanently**:请求的资源已被永久移动,未来应使用返回的 URI。 +- **401 Unauthorized**:资源需要身份验证,客户端未提供有效的认证凭证。 +- **404 Not Found**:请求的资源未找到。 +- **500 Internal Server Error**:服务器遇到错误,无法完成请求。 + +#### 视图返回 (`ViewResult`) + +返回一个视图是 ASP.NET Core 中常见的做法。你可以在 Action 中返回一个视图,这将自动渲染视图页面: + +```cs +public IActionResult Index() +{ + return View(); +} +``` + +视图通常返回 `IActionResult` 类型,但其具体实现是 `ViewResult`。 + +#### 重定向返回 (`RedirectToAction`) + +有时你需要将用户重定向到另一个 Action 方法。这可以通过 `RedirectToAction` 实现: + +```cs +public IActionResult RedirectToIndex() +{ + return RedirectToAction("Index"); +} +``` + +这种重定向操作返回一个 `RedirectResult`,该结果会发送一个 302 状态码的响应,指示浏览器重定向到指定的 URL。 + +#### **ActionResult<>** + +`ActionResult<>` 是一个更灵活的返回类型,它允许你在同一个返回值中既返回状态码也返回常规数据类型。例如,你可以返回一个包含数据的 200 状态码,或者返回错误状态码: + +```cs +public ActionResult GetBlog(int id) +{ + var blog = Db.Blog.FirstOrDefault(b => b.Id == id); + if (blog == null) + { + return NotFound(); // 返回 404 状态码 + } + return Ok(blog); // 返回 200 和数据 +} +``` + +这种方式为响应提供了更大的灵活性,可以同时控制状态码和返回数据。 + +#### `JsonResult` 与 `ContentResult` + +- **JsonResult**:如果你需要返回纯粹的数据,可以使用 `JsonResult`,它将数据序列化为 JSON 格式并返回。例如,返回一个对象或集合时: + +```cs +public JsonResult GetBlogsJson() +{ + var blogs = Db.Blog; + return new JsonResult(blogs); +} +``` + +- **ContentResult**:如果你希望直接返回原始文本内容,可以使用 `ContentResult`: + +```cs +public ContentResult GetMessageContent() +{ + return Content("Hello, this is a content response."); +} +``` + +这将直接返回字符串数据。 + +--- + +### 3. **POCO 对象的返回** + +POCO(Plain Old CLR Object)对象是没有继承自任何特定基类的普通对象。当你将 POCO 对象作为返回值时,ASP.NET Core 会自动将它序列化为 JSON 格式返回。反之,当客户端发送 JSON 请求时,数据会被反序列化为 POCO 对象。 + +例如,返回一个博客对象: + +```cs +public Blog GetBlog(int id) +{ + return Db.Blog.FirstOrDefault(b => b.Id == id); +} +``` + +在浏览器中,`Blog` 对象会被自动序列化为 JSON 格式: + +```json +{ + "Id": 1, + "Title": "Blog Title", + "Content": "Blog content", + "Author": "Author Name" +} +``` + +- **序列化**:将对象的状态信息转换为可存储或传输的格式的过程。通常是将对象转化为 JSON 或 XML 格式。 +- **反序列化**:是序列化的逆过程,将传输的数据(如 JSON)转换为对象。 + +### 4. **常用状态码和返回类型总结** + +| 状态码 | 含义 | 返回类型 | +| ------- | ------------------------ | ---------------------- | +| 200 | 请求成功,数据返回 | `IActionResult` / `ViewResult` / `JsonResult` | +| 301 | 永久重定向,资源已移动 | `RedirectResult` | +| 401 | 未授权,身份验证失败 | `UnauthorizedResult` | +| 404 | 资源未找到 | `NotFoundResult` | +| 500 | 服务器内部错误 | `StatusCodeResult` | + +## 课后作业 +### 作业一 +```cs +// 生成一个随机整数,范围[0,100],注意是否包含 +public IActionResult Index() +{ + Random random = new Random(); + // 101是因为Next方法生成的是min到max-1之间的数 + int randomNumber = random.Next(0, 101); + return View(randomNumber); +} +``` + +### 作业二 +```cs +// 生成一个随机整数,范围(0,100],注意是否包含 +public IActionResult Index_2() +{ + Random random = new Random(); + int randomNumber = random.Next(1, 101); + return View(randomNumber); +} +``` + +### 作业三 +```cs +// 生成10个随机整数,范围[5,80],注意是否包含 +public IActionResult Index_3() +{ + Random random = new Random(); + List randomNumbers = new List(); + for (int i = 0; i < 10; i++) + { + int randomNumber = random.Next(5, 81); + randomNumbers.Add(randomNumber); + } + return View(randomNumbers); +} +``` + +### 作业四 +```cs +// 定义一个字符串,字符串中有100个中文字符,需要从中随机取1个字符串 +public IActionResult Index_4() +{ + string str = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两去但事报需必请强置设及度年日识自约就千次么照海统技质六水办除业据期业点权些备员革又员好厂列宁员广听府美质再量方五头深响知万全具上半办八入吗"; + + // 创建Random对象 + Random random = new Random(); + char oneChinese = str[random.Next(str.Length)]; + + return View(oneChinese); +} +``` + +### 作业五 +```cs +//定义一个字符串,字符串中有100个中文字符,需要从中随机取5-50个字符,组成新的字符 +public ActionResult Index_5() +{ + string str = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两去但事报需必请强置设及度年日识自约就千次么照海统技质六水办除业据期业点权些备员革又员好厂列宁员广听府美质再量方五头深响知万全具上半办八入吗"; + Random random = new Random(); + int length = random.Next(5, 51); + // 随机选择字符并组成新的字符串 + string newStr = ""; + for (int i = 0; i < length; i++) + { + int index = random.Next(str.Length); + newStr += str[index]; + } + ViewBag.NewStr = newStr; + + return View(); +} +``` + +### 作业六 +```cs +// 定义2个字符串,第一个字符串中放百家姓,第二个字符串中放中文字符,要求从第一个字符串随机取得一个姓, +// 再从第二个字符串中随机获得1到2个字符组成新字符串,和第一个字符串取得的姓组成一个姓名 +public IActionResult Index_6() +{ + // 定义包含百家姓的字符串 + string names = "赵,钱,孙,李,周,吴,郑,王,冯,陈,褚,卫,蒋,沈,韩,杨,朱,秦,尤,许,何,吕,施,张,孔,曹,严,华,金,魏,陶,姜,戚,谢,邹,喻,柏,水,窦,章,云,苏,潘,葛,奚,范,彭,郎,鲁,韦,昌,马,苗,凤,花,方,俞,任,袁,柳,酆,鲍,史,唐,费,廉,岑,薛,雷,贺,倪,汤,滕,殷,罗,毕,郝,邬,安,常,乐,于,时,傅,皮,卞,齐,康,伍,余,元,卜,顾,孟,平,黄,和,穆,萧,尹,姚,邵,湛,汪,祁"; + // 定义包含中文字符的字符串 + string chineseChars = "一二三四五六七八九十上下左右多少口耳目手足心山水土日月风雨霜雪花草树木鸟兽虫鱼江河湖海金银铜铁丝竹筋角羽齿革羽毛"; + Random random = new Random(); + + // 随机选择一个姓 + // 将字符串分割成姓的列表 + string[] arrNames = names.Split(','); + string surname = arrNames[random.Next(arrNames.Length)]; + // 随机选择1到2个中文字符 + int count = random.Next(1, 3); + string givenName = ""; + for (int i = 0; i < count; i++) + { + int index = random.Next(chineseChars.Length); // 假设每个字符占两个字符 + givenName += chineseChars[index]; + } + // 组成姓名 + string name = surname + givenName; + ViewBag.name = name; + + return View(); +} +``` + + + diff --git "a/\351\231\210\346\200\235\347\235\277/20241127-(Razor\351\232\217\346\234\272\346\225\260).md" "b/\351\231\210\346\200\235\347\235\277/20241127-(Razor\351\232\217\346\234\272\346\225\260).md" new file mode 100644 index 0000000000000000000000000000000000000000..25b5269dced5a5d51fe48dc044fbc6b3e89687b3 --- /dev/null +++ "b/\351\231\210\346\200\235\347\235\277/20241127-(Razor\351\232\217\346\234\272\346\225\260).md" @@ -0,0 +1,208 @@ +## 课堂笔记 + +## Razor 语法概述 +Razor 是一种将 C# 代码嵌入到 HTML 中的语法,通过 `@` 符号实现 C# 与 HTML 的无缝转换。以下是 Razor 表达式和代码块的使用说明: + +### 隐式 Razor 表达式 + +隐式表达式以 `@` 开头,后接 C# 代码。常见示例: + +```cshtml +

@DateTime.Now

+

@DateTime.IsLeapYear(2016)

+``` + +**注意事项:** +- 隐式表达式中不能包含空格,C# 的 `await` 关键字除外。例如: + + +### 显式 Razor 表达式 + +显式表达式由 `@` 符号和圆括号 `()` 包裹。它允许执行复杂的计算或表达式: + +```cshtml +

Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))

+``` + +### Razor 代码块 + +Razor 代码块以 `@` 开头并被 `{}` 括起来。代码块内的 C# 代码不会直接输出到页面,而是用于变量或逻辑操作,代码块与表达式共享同一作用域。示例: + +```cshtml +@{ + var quote = "The future depends on what you do today. - Mahatma Gandhi"; +} + +

@quote

+ +@{ + quote = "Hate cannot drive out hate, only love can do that. - Martin Luther King, Jr."; +} + +

@quote

+``` + +--- + +## 定位点标记帮助程序 + +Razor 还支持通过 `asp-` 前缀扩展 HTML 标记,使其支持动态生成 URL。常见的标记包括: + +### `asp-controller` + +`asp-controller` 属性指定用于生成 URL 的控制器名称。例如,列出所有发言人的链接可以写作: + +```cshtml +All Speakers +``` + +### `asp-action` + +`asp-action` 属性指定生成的 URL 中的控制器操作。例如,跳转到发言人评估页: + +```cshtml +Speaker Evaluations +``` + +### `asp-route-{value}` + +`asp-route-{value}` 用于动态生成带有路由参数的 URL。`{value}` 会被替换为实际的路由参数值。例如: + +```cshtml +Speaker Details +``` + +如果匹配不到路由模板,`asp-route-{value}` 会被当作请求参数附加到生成的 URL。 + +## 课后作业 + +## 渲染(展示)简单数据类型到视图 +```cs +public string Index() +{ + return "我是简单数据类型"; +} +``` + +## 渲染(展示)对象数据到视图 +```cs +public IActionResult Index_2() +{ + var list = new BlogCreateDto + { + Title="今天星期三", + Author="张三", + Content="明天星期四,明天没有课,可以睡一天" + }; + + return View(list); +} +``` + +## 渲染(展示)集合数据到视图 +```cs +public IActionResult Index_3() +{ + var list = new List + { + new BlogCreateDto + { + Title="今天星期三", + Author="张三", + Content="明天星期四,明天没有课,可以睡一天", + }, + new BlogCreateDto + { + Title="明天星期四", + Author="张三", + Content="今天星期四,没有课,好爽", + }, + new BlogCreateDto + { + Title="后天星期五", + Author="张三", + Content="今天上午上完课就可以放假,开心", + }, + }; + return View(list); +} +``` +```cshtml + + + + + + + + @foreach(var item in @Model) + { + + + + + + + } +
标题作者内容操作
@item.Title@item.Author@item.Content + + +
+``` + +## 渲染(展示)包含集合数据的对象数据到视图 +```cs +public IActionResult Index_4() +{ + var blog = new Blog + { + Title = "今天周四", + Author = "张三", + Content = "今天怎么这么快就过完了,啊啊啊啊啊,不想上早八", + BlogCreateDto = new List + { + new BlogCreateDto + { + Title="明天天星期五", + Author = "张三", + Content = "上午上完课就可以放假,开心" + }, + new BlogCreateDto + { + Title="明天星期五", + Author = "张三", + Content = "上午上完课就可以放假,开心" + }, + } + }; + return View(blog); +} +``` + +```cshtml +

@Model.Title

+

@Model.Author

+

@Model.Content

+ +

BlogCreateDto:

+ + + + + + + + @foreach(var item in @Model.BlogCreateDto) + { + + + + + + + } +
标题作者内容操作
@item.Title@item.Author@item.Content + + +
+``` \ No newline at end of file diff --git "a/\351\231\210\346\200\235\347\235\277/20241129-(\345\242\236\346\223\215\344\275\234).md" "b/\351\231\210\346\200\235\347\235\277/20241129-(\345\242\236\346\223\215\344\275\234).md" new file mode 100644 index 0000000000000000000000000000000000000000..6d5d75ddeb45aa53277aa9a82517a2b94b6e8772 --- /dev/null +++ "b/\351\231\210\346\200\235\347\235\277/20241129-(\345\242\236\346\223\215\344\275\234).md" @@ -0,0 +1,265 @@ +## 课堂笔记 +## 实现增操作 + +### 1. 定义模型并模拟数据库 + +我们首先定义一个模拟的数据库,使用静态类来模拟数据表。这个数据库将包含一个 `Blog` 类列表,该列表用于存储博客文章。 + +#### 创建数据库模型 +```cs +public static class Db +{ + public static List Blog { get; set; } + + // 静态构造函数,确保初始化只执行一次 + static Db() + { + Blog = new List(); + + for (int i = 0; i < 15; i++) + { + var tmp = new Blog + { + Id = i + 1, + Title = "Title " + (i + 1), + Content = "Content of blog post " + (i + 1), + Author = "Author " + (i + 1) + }; + Blog.Add(tmp); + } + } +} +``` + +- **静态构造函数**:`Db` 类的静态构造函数会在第一次访问类时执行,并初始化 `Blog` 集合。 +- **延迟初始化**:这确保了 `Blog` 集合只有在需要时才被初始化。 +- **数据填充**:通过静态构造函数,模拟的数据库会自动填充 15 条数据。 + +--- + +### 2. 创建视图来展示内容 + +#### 展示博客列表并提供增、删、改功能 +使用 `` 标签和 Razor 的 `asp-` 属性来生成控制器操作的链接。以新增博客为例: + +```html +新增 +``` + +- `asp-controller`:指定表单提交的目标控制器。 +- `asp-action`:指定表单提交时调用控制器中的动作方法。 + +#### 编辑链接示例 + +```html +编辑 +``` + +- `asp-route-id`:传递给控制器的路由参数,通常是编辑项的 ID。 + +--- + +### 3. 跳转至增加页面并创建表单 + +#### 创建新增博客的表单 +在 `Create` 动作对应的视图中,使用 `form` 表单来提交数据: + +```html +@model Blogs.Models.Blog + +
+
+
+
+ +
+``` + +- `@model` 声明:指定当前视图使用的模型类型。 +- `asp-for`:为表单控件指定与模型属性的绑定。 +- `asp-action="Create"`:表单提交后将调用 `Create` 动作方法。 + +--- + +### 4. 使用 POST 请求添加数据 + +#### 处理新增请求 +在控制器的 `Create` 动作中,我们将接收表单数据并将其添加到模拟数据库中。 + +```cs +[HttpPost] +public IActionResult Create(Blog input) +{ + // 获取表单中最大 ID 数,确保新添加的博客有唯一 ID + var maxId = Db.Blog.Select(t => t.Id).Max(); + input.Id = maxId + 1; // 设置新的 ID + + // 将新增的博客添加到数据库 + Db.Blog.Add(input); + + // 重定向到博客列表页面 + return RedirectToAction("Index"); + // 测试:return Content(JsonSerializer.Serialize(input)); 可返回提交的内容 +} +``` + +- **获取最大 ID**:使用 `Max()` 方法来找到当前 `Blog` 集合中的最大 ID,以便新博客的 ID 能自动递增。 +- **重定向**:数据添加后,页面会重定向回博客列表页 (`Index`),确保用户可以看到最新的博客列表。 + +## 课后作业 +```c# +using Microsoft.AspNetCore.Mvc; +namespace Blog.Controllers +{ + public class BodyController : Controller + { + // 1. 生成一个随机整数,范围[0,100],包含0和100 + public IActionResult Random1() + { + Random random = new Random(); + int randomNumber = random.Next(0, 101); // 生成0到100之间的随机数 + ViewBag.RandomNumber = randomNumber; // 将随机数传递到视图 + return View(); + } + + // 2. 生成一个随机整数,范围(0,100],不包含0,包含100 + public IActionResult Random2() + { + Random random = new Random(); + int randomNumber = random.Next(1, 101); // 生成1到100之间的随机数 + ViewBag.RandomNumber = randomNumber; // 将随机数传递到视图 + return View(); + } + + // 3. 生成10个随机整数,范围[5,80] + public List Random3() + { + Random random = new Random(); + var list = new List(); + + for (int i = 0; i < 10; i++) + { + int randomNumber = random.Next(5, 81); // 生成5到80之间的随机数 + list.Add(randomNumber); // 将随机数加入列表 + } + + return list; + } + + // 4. 从100个中文字符中随机选择一个字符 + public IActionResult Random4() + { + string str = "阳光普照万物生机盎然人间烟火为理想哈奔波心怀激情燃烧血脉中流淌时间如梭不等人紧握双手勇往直前冲不畏艰难险阻勇攀高峰誓创未来新篇章书写人生真辉煌展现自我力量铸就传奇啊"; + Random random = new Random(); + int randomIndex = random.Next(0, str.Length); // 随机索引 + char randomChar = str[randomIndex]; // 获取随机字符 + return Content(randomChar.ToString()); // 返回字符内容 + } + + // 5. 从100个中文字符中随机选取5-50个字符组成一个新字符串 + public IActionResult Random5() + { + string str = "阳光普照万物生机盎然人间烟火为理想哈奔波心怀激情燃烧血脉中流淌时间如梭不等人紧握双手勇往直前冲不畏艰难险阻勇攀高峰誓创未来新篇章书写人生真辉煌展现自我力量铸就传奇啊"; + Random random = new Random(); + int length = random.Next(5, 51); // 随机生成5到50个字符 + string randomText = ""; + + for (int i = 0; i < length; i++) + { + int index = random.Next(str.Length); // 从字符串中随机选择一个字符 + randomText += str[index]; // 拼接字符 + } + + return Content(randomText); // 返回生成的字符串 + } + + // 6. 从姓氏和名字字符串中生成随机姓名 + public IActionResult Random6() + { + string surnames = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹孟高林何马陶冯程严唐"; + string names = "阳光普照万物生机盎然人间烟火为理想哈奔波心怀激情燃烧血脉中流淌时间如梭不等人紧握双手勇往直前冲不畏艰难险阻勇攀高峰誓创未来新篇章书写人生真辉煌展现自我力量铸就传奇啊"; + + Random random = new Random(); + char surname = surnames[random.Next(surnames.Length)]; // 随机选取姓氏 + int nameLength = random.Next(1, 3); // 随机选择名字的字数(1或2个字) + string firstName = ""; + + for (int i = 0; i < nameLength; i++) + { + firstName += names[random.Next(names.Length)]; // 拼接名字字符 + } + + string fullName = surname + firstName; // 拼接姓名 + return Content(fullName); // 返回生成的姓名 + } + + // 7. 随机生成100个 BlogCreateDto 类型的数据 + public IActionResult Random7() + { + string surnames = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹孟高林何马陶冯程严唐"; + string names = "阳光普照万物生机盎然人间烟火为理想哈奔波心怀激情燃烧血脉中流淌时间如梭不等人紧握双手勇往直前冲不畏艰难险阻勇攀高峰誓创未来新篇章书写人生真辉煌展现自我力量铸就传奇啊在这个快节奏的时代 时间仿佛成了一种奢侈 每个人都在忙碌中度过 追逐着心中的梦想和生活的琐碎 然而 在这无尽的奔波中 我们是否曾停下脚步 去感受那些被忽视的美好 一缕温暖的阳光 一声亲切的问候 一杯香浓的咖啡 都是生活赋予我们的礼物 让我们在忙碌之余 不忘珍惜这些微小而真实的瞬间 让心灵得到片刻的宁静与满足 因为 正是这些点点滴滴 汇聚成了我们丰富多彩的人生"; + + Random random = new Random(); + var blogList = new List(); + + for (int i = 0; i < 100; i++) + { + // 随机生成标题 + int titleLength = random.Next(6, 16); // 标题长度随机在6到15字之间 + string title = GenerateRandomString(names, titleLength); + + // 随机生成作者 + string author = GenerateRandomAuthor(surnames, names); + + // 随机生成内容 + int contentLength = random.Next(100, 201); // 内容字数随机在100到200字之间 + string content = GenerateRandomString(names, contentLength); + + var blog = new BlogCreateDto + { + Title = title, + Author = author, + Content = content + }; + + blogList.Add(blog); // 将生成的博客对象加入列表 + } + + return View(blogList); // 返回包含100个博客的视图 + } + + // 辅助方法:生成指定长度的随机字符串 + private string GenerateRandomString(string source, int length) + { + Random random = new Random(); + string result = ""; + + for (int i = 0; i < length; i++) + { + result += source[random.Next(source.Length)]; + } + + return result; + } + + // 辅助方法:生成随机作者 + private string GenerateRandomAuthor(string surnames, string names) + { + Random random = new Random(); + char surname = surnames[random.Next(surnames.Length)]; + int nameLength = random.Next(1, 3); // 名字长度为1或2 + string firstName = GenerateRandomString(names, nameLength); + return surname + firstName; + } + } + + // BlogCreateDto 数据传输对象 + public class BlogCreateDto + { + public string Title { get; set; } = null!; + public string Author { get; set; } = null!; + public string Content { get; set; } = null!; + } +} +``` + \ No newline at end of file