隨著 .Net6 的發(fā)布,微軟也改進(jìn)了對之前 ASP.NET Core 構(gòu)建方式,使用了新的 Minimal API 模式。以前默認(rèn)的方式是需要在 Startup 中注冊 IOC 和中間件相關(guān),但是在 Minimal API 模式下你只需要簡單的寫幾行代碼就可以構(gòu)建一個 ASP.NET Core的Web 應(yīng)用,可謂非常的簡單,加之配合 c# 的 global using 和 Program 的頂級聲明方式,使得 Minimal API 變得更為簡潔,不得不說 .NET 團(tuán)隊在 .NET 上近幾年下了不少功夫,接下來我們就來大致介紹下這種極簡的使用模式。
1. 使用方式
使用 Visual Studio 2022 新建的 ASP.NET Core 6 的項目,默認(rèn)的方式就是 Minimal API 模式,整個 Web 程序的結(jié)構(gòu)看起來更加簡單,再i加上微軟對 Lambda 的改進(jìn),使其可以對 Lambda 參數(shù)進(jìn)行 Attribute 標(biāo)記,有的場景甚至可以放棄去定義 Controller 類了。
2. 幾行代碼構(gòu)建Web程序
使用 Minimal API 最簡單的方式就是能通過三行代碼就可以構(gòu)建一個 WebApi 的程序,代碼如下:
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World");
app.Run();
是的你沒有看錯,僅僅這樣運行起來就可以,默認(rèn)監(jiān)聽的 http://localhost:5000 和 https://localhost:5001,所以直接在瀏覽器輸入http://localhost:5000地址就可以看到瀏覽器輸出Hello World字樣。
3. 更改監(jiān)聽地址
如果你想更改它監(jiān)聽的服務(wù)端口,可以使用如下的方式:
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World");
app.Run("http://localhost:6666");
如果想同時監(jiān)聽多個端口的話,可以使用如下的方式:
var app = WebApplication.Create(args);
app.Urls.Add("http://localhost:6666");
app.Urls.Add("http://localhost:8888");
app.MapGet("/", () => "Hello World");
app.Run();
或者是直接通過環(huán)境變量的方式設(shè)置監(jiān)聽信息,設(shè)置環(huán)境變量ASPNETCORE_URLS的值為完整的監(jiān)聽URL地址,這樣的話就可以直接省略了在程序中配置相關(guān)信息了。
ASPNETCORE_URLS=http://localhost:6666
如果設(shè)置多個監(jiān)聽的URL地址的話可以在多個地址之間使用分號;隔開多個值:
ASPNETCORE_URLS=http://localhost:6666;https://localhost:8888
如果想監(jiān)聽本機(jī)所有Ip地址,可以使用如下方式:
var app = WebApplication.Create(args);
app.Urls.Add("http://*:6666");
app.Urls.Add("http://+:8888");
app.Urls.Add("http://0.0.0.0:9999");
app.MapGet("/", () => "Hello World");
app.Run();
同樣的也可以使用添加環(huán)境變量的方式添加監(jiān)聽地址:
ASPNETCORE_URLS=http://*:6666;https://+:8888;http://0.0.0.0:9999
4. 日志操作
日志操作也是比較常用的操作,在Minimal API中微軟干脆把它提出來,直接簡化了操作,如下所示:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddJsonConsole();
var app = builder.Build();
app.Logger.LogInformation("讀取到的配置信息:{content}", builder.Configuration.GetSection("consul").Get<ConsulOption>());
app.Run();
5. 基礎(chǔ)環(huán)境配置
無論我們在之前的.Net Core開發(fā)或者現(xiàn)在的.Net6開發(fā)都有基礎(chǔ)環(huán)境的配置,它包括 ApplicationName、ContentRootPath、 EnvironmentName相關(guān),不過在Minimal API中,可以通過統(tǒng)一的方式去配置:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
ApplicationName = typeof(Program).Assembly.FullName,
ContentRootPath = Directory.GetCurrentDirectory(),
EnvironmentName = Environments.Staging
});
Console.WriteLine($"應(yīng)用程序名稱: {builder.Environment.ApplicationName}");
Console.WriteLine($"環(huán)境變量: {builder.Environment.EnvironmentName}");
Console.WriteLine($"ContentRoot目錄: {builder.Environment.ContentRootPath}");
var app = builder.Build();
或者是通過環(huán)境變量的方式去配置,最終實現(xiàn)的效果都是一樣的。
- ASPNETCORE_ENVIRONMENT
- ASPNETCORE_CONTENTROOT
- ASPNETCORE_APPLICATIONNAME
6. 主機(jī)相關(guān)設(shè)置
我們在之前的.Net Core開發(fā)模式中,程序的啟動基本都是通過構(gòu)建主機(jī)的方式,比如之前的Web主機(jī)或者后來的泛型主機(jī),在Minimal API中同樣可以進(jìn)行這些操作,比如我們模擬一下之前泛型主機(jī)配置Web程序的方式:
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureDefaults(args).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
var app = builder.Build();
如果只是配置Web主機(jī)的話Minimal API還提供了另一種更直接的方式,如下所示:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseStartup<Startup>();
builder.WebHost.UseWebRoot("webroot");
var app = builder.Build();
7. 默認(rèn)容器替換
很多時候我們在使用IOC的時候會使用其他三方的IOC框架,比如大家耳熟能詳?shù)腁utofac,我們之前也介紹過其本質(zhì)方式就是使用UseServiceProviderFactory中替換容器的注冊和服務(wù)的提供,在Minimal API中可以使用如下的方式去操作:
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
//之前在Startup中配置ConfigureContainer可以使用如下方式
builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule()));
var app = builder.Build();
8. 中間件相關(guān)
相信大家都已經(jīng)仔細(xì)看過了WebApplication.CreateBuilder(args).Build()通過這種方式構(gòu)建出來的是一個WebApplication類的實例,而WebApplication正是實現(xiàn)了 IApplicationBuilder接口。所以其本質(zhì)還是和我們之前使用Startup中的Configure方法的方式是一致的,比如我們配置一個Swagger程序為例:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
//判斷環(huán)境變量
if (app.Environment.IsDevelopment())
{
//異常處理中間件
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
}
//啟用靜態(tài)文件
app.UseStaticFiles();
app.UseAuthorization();
app.MapControllers();
app.Run();
常用的中間件配置還是和之前是一樣的,因為本質(zhì)都是IApplicationBuilder
的擴(kuò)展方法,我們這里簡單列舉一下:
中間件名稱 | 描述 | API |
---|---|---|
Authentication | 認(rèn)證中間件 | app.UseAuthentication() |
Authorization | 授權(quán)中間件. | app.UseAuthorization() |
CORS | 跨域中間件. | app.UseCors() |
Exception Handler | 全局異常處理中間件. | app.UseExceptionHandler() |
Forwarded Headers | 代理頭信息轉(zhuǎn)發(fā)中間件. | app.UseForwardedHeaders() |
HTTPS Redirection | Https重定向中間件. | app.UseHttpsRedirection() |
HTTP Strict Transport Security (HSTS) | 特殊響應(yīng)頭的安全增強中間件. | app.UseHsts() |
Request Logging | HTTP請求和響應(yīng)日志中間件. | app.UseHttpLogging() |
Response Caching | 輸出緩存中間件. | app.UseResponseCaching() |
Response Compression | 響應(yīng)壓縮中間件. | app.UseResponseCompression() |
Session | Session中間件 | app.UseSession() |
Static Files | 靜態(tài)文件中間件. |
app.UseStaticFiles() , app.UseFileServer()
|
WebSockets | WebSocket支持中間件. | app.UseWebSockets() |
9. 請求處理
我們可以使用WebApplication中的Map{HTTPMethod}相關(guān)的擴(kuò)展方法來處理不同方式的Http請求,比如以下示例中處理Get、Post、Put、Delete相關(guān)的請求:
app.MapGet("/", () => "Hello GET");
app.MapPost("/", () => "Hello POST");
app.MapPut("/", () => "Hello PUT");
app.MapDelete("/", () => "Hello DELETE");
如果想讓一個路由地址可以處理多種Http方法的請求,可以使用MapMethods方法,如下所示:
app.MapMethods("/multiple", new[] { "GET", "POST","PUT","DELETE" }, (HttpRequest req) => $"Current Http Method Is {req.Method}" );
通過上面的示例我們不僅看到了處理不同Http請求的方式,還可以看到Minimal Api可以根據(jù)委托的類型自行推斷如何處理請求,比如上面的示例,我們沒有寫Response Write相關(guān)的代碼,但是輸出的卻是委托里的內(nèi)容,因為我們上面示例中的委托都滿足Func的形式,所以Minimal Api自動處理并輸出返回的信息,其實只要滿足委托類型的它都可以處理,接下來咱們來簡單一下,首先是本地函數(shù)的形式:
static string LocalFunction() => "This is local function";
app.MapGet("/local-fun", LocalFunction);
還可以是類的實例方法:
HelloHandler helloHandler = new HelloHandler();
app.MapGet("/instance-method", helloHandler.Hello);
class HelloHandler
{
public string Hello()
{
return "Hello World";
}
}
亦或者是類的靜態(tài)方法:
app.MapGet("/static-method", HelloHandler.SayHello);
class HelloHandler
{
public static string SayHello(string name)
{
return $"Hello {name}";
}
}
其實本質(zhì)都是一樣的,那就是將他們轉(zhuǎn)換為可執(zhí)行的委托,無論什么樣的形式,能滿足委托的條件即可。
10. 路由約束
Minimal Api還支持在對路由規(guī)則的約束,這個和我們之前使用UseEndpoints的方式類似,比如我約束路由參數(shù)只能為整型,如果不滿足的話會返回404。
app.MapGet("/users/{userId:int}", (int userId) => $"user id is {userId}");
app.MapGet("/user/{name:length(20)}", (string name) => $"user name is {name}");
經(jīng)常使用的路由約束還有其他幾個,也不是很多大概有如下幾種,簡單的列一下表格:
限制 | 示例 | 匹配示例 | 說明 |
---|---|---|---|
int |
{id:int} |
123456789 , -123456789
|
匹配任何整數(shù) |
bool |
{active:bool} |
true , false
|
匹配 true 或 false . 忽略大小寫 |
datetime |
{dob:datetime} |
2016-12-31 , 2016-12-31 7:32pm
|
匹配滿足DateTime 類型的值 |
decimal |
{price:decimal} |
49.99 , -1,000.01
|
匹配滿足 decimal 類型的值 |
double |
{height:double} |
1.234 , -1,001.01e8
|
匹配滿足 double 類型的值 |
float |
{height:float} |
1.234 , -1,001.01e8
|
匹配滿足 float 類型的值 |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
匹配滿足Guid 類型的值 |
long |
{ticks:long} |
123456789 , -123456789
|
匹配滿足 long 類型的值 |
minlength(value) |
{username:minlength(4)} |
KOBE |
字符串長度必須是4個字符 |
maxlength(value) |
{filename:maxlength(8)} |
CURRY |
字符串長度不能超過8個字符 |
length(length) |
{filename:length(12)} |
somefile.txt |
字符串的字符長度必須是12個字符 |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
字符串的字符長度必須介于8和l6之間 |
min(value) |
{age:min(18)} |
20 |
整數(shù)值必須大于18 |
max(value) |
{age:max(120)} |
119 |
整數(shù)值必須小于120 |
range(min,max) |
{age:range(18,120)} |
100 |
整數(shù)值必須介于18和120之間 |
alpha |
{name:alpha} |
Rick |
字符串必須由一個或多個a -z 的字母字符組成,且不區(qū)分大小寫。 |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
字符串必須與指定的正則表達(dá)式匹配。 |
required |
{name:required} |
JAMES |
請求信息必須包含該參數(shù) |
11. 模型綁定
在我們之前使用ASP.NET Core Controller方式開發(fā)的話,模型綁定是肯定會用到的,它的作用就是簡化我們解析Http請求信息也是MVC框架的核心功能,它可以將請求信息直接映射成c#的簡單類型或者POCO上面。在Minimal Api的Map{HTTPMethod}相關(guān)方法中同樣可以進(jìn)行豐富的模型綁定操作,目前可以支持的綁定源有如下幾種:
- Route(路由參數(shù))
- QueryString
- Header
- Body(比如JSON)
- Services(即通過IServiceCollection注冊的類型)
- 自定義綁定
1) 綁定示例
接下來我們首先看一下綁定路由參數(shù):
app.MapGet("/sayhello/{name}", (string name) => $"Hello {name}");
還可以使用路由和querystring的混用方式:
app.MapGet("/sayhello/{name}", (string name,int? age) => $"my name is {name},age {age}");
這里需要注意的是,我的age參數(shù)加了可以為空的標(biāo)識,如果不加的話則必須要在url的請求參數(shù)中傳遞age參數(shù),否則將報錯,這個和我們之前的操作還是有區(qū)別的。
具體的類也可以進(jìn)行模型綁定,比如咱們這里定義了名為Goods的POCO進(jìn)行演示:
app.MapPost("/goods",(Goods goods)=>$"商品{goods.GName}添加成功");
class Goods
{
public int GId { get; set; }
public string GName { get; set; }
public decimal Price { get; set; }
}
需要注意的是HTTP方法GET、HEAD、OPTIONS、DELETE將不會從body進(jìn)行模型綁定,如果需要在Get請求中獲取Body信息,可以直接從HttpRequest中讀取它。
如果我們需要使用通過IServiceCollection注冊的具體實例,可以以通過模型綁定的方式進(jìn)行操作(很多人喜歡叫它方法注入,但是嚴(yán)格來說卻是是通過定義模型綁定的相關(guān)操作實現(xiàn)的),而且還簡化了具體操作,我們就不需要在具體的參數(shù)上進(jìn)行FromServicesAttribute標(biāo)記了。
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<Person>(provider => new() { Id = 1, Name = "yi念之間", Sex = "Man" });
var app = builder.Build();
app.MapGet("/", (Person person) => $"Hello {person.Name}!");
app.Run();
如果是混合使用的話,也可以不用指定具體的BindSource進(jìn)行標(biāo)記了,前提是這些值的名稱在不同的綁定來源中是唯一的,這種感覺讓我想到了剛開始學(xué)習(xí)MVC4.0的時候模型綁定的隨意性,比如下面的例子:
app.MapGet("/sayhello/{name}", (string name,int? age,Person person) => $"my name is {name},age {age}, sex {person.Sex}");
上面示例的模型綁定參數(shù)來源可以是:
參數(shù) | 綁定來源 |
---|---|
name | 路由參數(shù) |
age | querystring |
person | 依賴注入 |
不僅僅如此,它還支持更復(fù)雜的方式,這使得模型綁定更為靈活,比如以下示例:
app.MapPost("/goods",(Goods goods, Person person) =>$"{person.Name}添加商品{goods.GName}成功");
它的模型綁定的值來源可以是:
參數(shù) | 綁定來源 |
---|---|
goods | body里的json |
person | 依賴注入 |
app.MapPost("/goods",([FromBody]Goods goods, [FromServices]Person person) =>$"{person.Name}添加商品{goods.GName}成功");
很多時候我們可能通過定義類和方法的方式來聲明Map相關(guān)方法的執(zhí)行委托,這個時候呢依然可以進(jìn)行靈活的模型綁定,而且可能你也發(fā)現(xiàn)了,直接通過lambda表達(dá)式的方式雖然支持可空類型,但是它不支持缺省參數(shù),也就是咱們說的方法默認(rèn)參數(shù)的形式,比如:
app.MapPost("/goods", GoodsHandler.AddGoods);
class GoodsHandler
{
public static string AddGoods(Goods goods, Person person, int age = 20) => $"{person.Name}添加商品{goods.GName}成功";
}
當(dāng)然你也可以對AddGoods方法的參數(shù)進(jìn)行顯示的模型綁定處理,十分的靈活。
public static string AddGoods([FromBody] Goods goods, [FromServices] Person person, [FromQuery]int age = 20) => $"{person.Name}添加商品{goods.GName}成功";
在使用Map相關(guān)方法的時候,由于是在Program入口程序或者其他POCO中直接編寫相關(guān)邏輯的,因此需要用到HttpContext、HttpRequest、HttpResponse相關(guān)實例的時候沒辦法進(jìn)行直接操作,這個時候也需要通過模型綁定的方式獲取對應(yīng)實例:
app.MapGet("/getcontext",(HttpContext context,HttpRequest request,HttpResponse response) => response.WriteAsync($"IP:{context.Connection.RemoteIpAddress},Request Method:{request.Method}"));
2) 自定義綁定
Minimal Api采用了一種新的方式來自定義模型綁定,這種方式是一種基于約定的方式,無需提前注冊,也無需集成什么類或者實現(xiàn)什么接口,只需要在自定義的類中存在TryParse和BindAsync方法即可,這兩個方法的區(qū)別如下:
TryParse方法是對路由參數(shù)、url參數(shù)、header相關(guān)的信息進(jìn)行轉(zhuǎn)換綁定
BindAsync可以對任何請求的信息進(jìn)行轉(zhuǎn)換綁定,功能比TryParse要強大
接下來我們分別演示一下這兩種方式的使用方法,首先是TryParse方法:
app.MapGet("/address/getarray",(Address address) => address.Addresses);
public class Address
{
public List<string>? Addresses { get; set; }
public static bool TryParse(string? addressStr, IFormatProvider? provider, out Address? address)
{
var addresses = addressStr?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (addresses != null && addresses.Any())
{
address = new Address { Addresses = addresses.ToList() };
return true;
}
address = new Address();
return false;
}
}
這樣就可以完成簡單的轉(zhuǎn)換綁定操作,從寫法上我們可以看到,TryParse方法確實存在一定的限制,不過操作起來比較簡單,這個時候我們模擬請求:
http://localhost:5036/address/getarray?address=山東,山西,河南,河北
請求完成會得到如下結(jié)果:
["山東","山西","河南", "河北"]
然后我們改造一下上面的例子使用BindAsync的方式進(jìn)行結(jié)果轉(zhuǎn)換,看一下它們操作的不同:
app.MapGet("/address/getarray",(Address address) => address.Addresses);
public class Address
{
public List<string>? Addresses { get; set; }
public static ValueTask<Address?> BindAsync(HttpContext context, ParameterInfo parameter)
{
string addressStr = context.Request.Query["address"];
var addresses = addressStr?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
Address address = new();
if (addresses != null && addresses.Any())
{
address.Addresses = addresses.ToList();
return ValueTask.FromResult<Address?>(address);
}
return ValueTask.FromResult<Address?>(address);
}
}
同樣請求http://localhost:5036/address/getarray?address=山東,山西,河南,河北 地址會得到和上面相同的結(jié)果,到底如何選擇同學(xué)們可以按需使用,得到的效果都是一樣的。如果類中同時存在TryParse和BindAsync方法,那么只會執(zhí)行BindAsync方法。
輸出結(jié)果:
相信通過上面的其他示例演示,我們大概看到了一些在Minimal Api中的結(jié)果輸出,總結(jié)起來其實可以分為三種情況:
IResult 結(jié)果輸出,可以包含任何值得輸出,包含異步任務(wù)Task和ValueTask
string 文本類型輸出,包含異步任務(wù)Task和ValueTask
T 對象類型輸出,比如自定義的實體、匿名對象等,包含異步任務(wù) Task和ValueTask
接下來簡單演示幾個例子來簡單看一下具體是如何操作的,首先最簡單的就是輸出文本類型:
app.MapGet("/hello", () => "Hello World");
然后輸出一個對象類型,對象類型可以包含對象或集合甚至匿名對象,或者是咱們上面演示過的HttpResponse對象,這里的對象可以理解為面向?qū)ο蟮哪莻€對象,滿足Response輸出要求即可。
app.MapGet("/simple", () => new { Message = "Hello World" });
//或者是
app.MapGet("/array",()=>new string[] { "Hello", "World" });
//亦或者是EF的返回結(jié)果
app.Map("/student",(SchoolContext dbContext,int classId)=>dbContext.Student.Where(i=>i.ClassId==classId));
還有一種是微軟幫我們封裝好的一種形式,即返回的是IResult類型的結(jié)果,微軟也是很貼心的為我們統(tǒng)一封裝了一個靜態(tài)的Results類,方便我們使用,簡單演示一下這種操作:
//成功結(jié)果
app.MapGet("/success",()=> Results.Ok("Success"));
//失敗結(jié)果
app.MapGet("/fail", () => Results.BadRequest("fail"));
//404結(jié)果
app.MapGet("/404", () => Results.NotFound());
//根據(jù)邏輯判斷返回
app.Map("/student", (SchoolContext dbContext, int classId) => {
var classStudents = dbContext.Student.Where(i => i.ClassId == classId);
return classStudents.Any() ? Results.Ok(classStudents) : Results.NotFound();
});
上面我們也提到了Results類其實是微軟幫我們多封裝了一層,它里面的所有靜態(tài)方法都是返回IResult的接口實例,這個接口有許多實現(xiàn)的類,滿足不同的輸出結(jié)果,比如Results.File(“foo.text”)方法,本質(zhì)就是返回一個FileContentResult類型的實例。
public static IResult File(byte[] fileContents,string? contentType = null,
string? fileDownloadName = null,
bool enableRangeProcessing = false,
DateTimeOffset? lastModified = null,
EntityTagHeaderValue? entityTag = null)
=> new FileContentResult(fileContents, contentType)
{
FileDownloadName = fileDownloadName,
EnableRangeProcessing = enableRangeProcessing,
LastModified = lastModified,
EntityTag = entityTag,
};
亦或者Results.Json(new { Message=“Hello World” }),本質(zhì)就是返回一個JsonResult類型的實例。
public static IResult Json(object? data, JsonSerializerOptions? options = null, string? contentType = null, int? statusCode = null)
=> new JsonResult
{
Value = data,
JsonSerializerOptions = options,
ContentType = contentType,
StatusCode = statusCode,
};
當(dāng)然我們也可以自定義IResult的實例,比如我們要輸出一段html代碼。
微軟很貼心的為我們提供了專門擴(kuò)展Results的擴(kuò)展類IResultExtensions基于這個類我們才能完成IResult的擴(kuò)展:
static class ResultsExtensions
{
//基于IResultExtensions寫擴(kuò)展方法
public static IResult Html(this IResultExtensions resultExtensions, string html)
{
ArgumentNullException.ThrowIfNull(resultExtensions, nameof(resultExtensions));
//自定義的HtmlResult是IResult的實現(xiàn)類
return new HtmlResult(html);
}
}
class HtmlResult:IResult
{
//用于接收html字符串
private readonly string _html;
public HtmlResult(string html)
{
_html = html;
}
/// <summary>
/// 在該方法寫自己的輸出邏輯即可
/// </summary>
/// <returns></returns>
public Task ExecuteAsync(HttpContext httpContext)
{
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(_html);
return httpContext.Response.WriteAsync(_html);
}
}
定義完成這些我們就可以直接在Results類中使用我們定義的擴(kuò)展方法了,使用方式如下:
app.MapGet("/hello/{name}", (string name) => Results.Extensions.Html(@$"<html>
<head><title>Index</title></head>
<body>
<h1>Hello {name}</h1>
</body>
</html>"));
這里需要注意的是,我們自定義的擴(kuò)展方法一定是基于IResultExtensions擴(kuò)展的,然后再使用的時候注意是使用的Results.Extensions這個屬性,因為這個屬性是IResultExtensions類型的,然后就是我們自己擴(kuò)展的Results.Extensions.Html方法。
12. 總結(jié)
本文我們主要是介紹了ASP.NET Core 6 Minimal API的常用的使用方式,相信大家對此也有了一定的了解,在.NET6中也是默認(rèn)的項目方式,整體來說卻是非常的簡單、簡潔、強大、靈活,不得不說Minimal API卻是在很多場景都非常適用的。當(dāng)然我也在其它地方看到過關(guān)于它的評價,褒貶不一吧,筆者認(rèn)為,沒有任何一種技術(shù)是銀彈,存在即合理。如果你的項目夠規(guī)范夠合理,那么使用Minimal API絕對夠用,如果不想用或者用不了也沒關(guān)系,能最終實現(xiàn)需要的結(jié)果就好。文章來源:http://www.zghlxwxcb.cn/news/detail-476009.html
參考資料:文章來源地址http://www.zghlxwxcb.cn/news/detail-476009.html
- C#教程
- 編程寶庫
到了這里,關(guān)于詳解 .Net6 Minimal API 的使用方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!