一般处理程序可以类似路由的_网络核心动作路由处理程序和方法

一般处理程序可以类似路由的

介绍(Introduction)

I am going to discuss four interrelated terms and the code that they represent in this article. These are terms that sometimes get used interchangeably or applied somewhat haphazardly, describing the same block of code. But these terms have specific meanings, intentions, and uses inside your application. These uses are similar across application types and languages, but I am focusing on C# .Net Core Web Applications. Misapplying them is not inherently wrong, but it indicates that you possibly do not understand what the interaction between these terms is and how to use them in your application.

我将讨论四个相互关联的术语以及它们在本文中表示的代码。 这些术语有时会互换使用,或者有些偶然地使用,描述了相同的代码块。 但是这些术语在您的应用程序内部具有特定的含义,意图和用途。 这些用法在应用程序类型和语言之间相似,但是我主要关注C#.Net Core Web应用程序。 错误地使用它们并不是天生的错误,但这表明您可能不了解这些术语之间的相互作用以及如何在应用程序中使用它们。

There are several ways to separate these terms, but in general, Actions and Routes are interface elements that exist purely as the external web interface to your application. Internal to your application, these are not code but attributes and configuration of objects. These provide the communication interface that an external web application uses to communicate with your application.

有几种方法可以分隔这些术语,但是通常,“动作”和“路线”是仅作为应用程序的外部Web界面而存在的界面元素。 在应用程序内部,这些不是代码,而是对象的属性和配置。 这些提供了外部Web应用程序用来与您的应用程序进行通信的通信接口。

Handlers are a less defined area; this is because there is nothing that is directly called a “handler” in .Net Core. There are EventHandlers, Callbacks, Delegates, Events, and their Handling. But handler is used as shorthand for this whole group of objects, methods, events, properties, and variables. In general, if you hear or read handler, be on alert because what you are seeing is that someone does not quite know what they are using but know it is about handling something. Usually, this something ends up being either a delegate passed in as a callback or a method used as an event handler. Again, a delegate, but from your code to the system rather than from external application to your code.

处理程序是一个定义不明确的区域。 这是因为.Net Core中没有任何直接称为“处理程序”的东西。 有事件处理程序,回调,委托,事件及其处理。 但是处理程序用作整个对象,方法,事件,属性和变量的简写。 通常,如果您听到或阅读了处理程序,请保持警惕,因为您看到的是某人不太了解他们在使用什么,而是知道它是在处理某些东西。 通常,这最终要么是作为回调传入的委托,要么是用作事件处理程序的方法。 还是一个委托,但是从您的代码到系统,而不是从外部应用程序到您的代码。

Methods are the best defined and best understood. These are the building blocks of a C# application — you write your code into these. If you do not know what a method is, why are you reading this article? But seriously, all the other terms come down to running one or more methods in the end. These methods may be called handlers, actions, callbacks, endpoints, or routes. But, in the end, you wrote them as methods.

方法是最好的定义和最好的理解。 这些是C#应用程序的构建块-您将代码编写到其中。 如果您不知道什么是方法,那么为什么要阅读本文? 但认真的说,所有其他术语最终归结为运行一个或多个方法。 这些方法可以称为处理程序,操作,回调,端点或路由。 但是,最后,您将它们编写为方法。

So, that was a brief overview. Now I will take a bit of a deeper dive into each term and how to use it.

因此,这是一个简短的概述。 现在,我将对每个术语及其用法进行更深入的探讨。

动作与路线 (Actions and Routes)

These two are closely related enough that many web application developers do not realize they are different things. Or rather that they can be different things. If you are writing a .Net Core MVC application and let the code generator build your initial controllers and views will get a series of matching methods and views. Along with these methods and views, you get a route defined in your Startup method that will correctly route all of these. Because of this, if you follow the pattern set by the code generator — which I will describe below, you can think of action and route as the same.

这两者之间的关系非常密切,以至于许多Web应用程序开发人员都没有意识到它们是不同的东西。 或更确切地说,它们可以是不同的事物。 如果您正在编写.Net Core MVC应用程序,并让代码生成器构建您的初始控制器和视图,则将获得一系列匹配的方法和视图。 除了这些方法和视图之外,您还将在Startup方法中定义一条路由,该路由将正确地路由所有这些路由。 因此,如果遵循代码生成器设置的模式(我将在下面进行描述),则可以将操作和路由视为相同。

The pattern for simple routing in a .NET Core MVC application from the code generator is the following:

通过代码生成器在.NET Core MVC应用程序中进行简单路由的模式如下:

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});

If you have read any of my articles, this should look familiar since I have used it when discussing routing in “.Net Core MVC Request-Routing,” which covers routing in more detail. What this route does, in general, is to say use the base Http address of whatever server the app is running on, then look for a controller it has registered, followed by an action it has registered, followed optionally by some id. If everything is empty, default to the Home Index action. The reason this is simple is that the default controller classes constructed by the code generator have the pattern of:

如果您已经阅读了我的任何文章,这应该看起来很熟悉,因为我在“ .Net Core MVC请求路由”中讨论路由时使用了它,该文章更详细地介绍了路由。 通常,此路由的作用是使用应用程序所运行的任何服务器的基本Http地址,然后查找其已注册的控制器,然后查找其已注册的操作,然后可选地输入一些ID。 如果所有内容均为空,则默认为“主页索引”操作。 这很简单,原因是由代码生成器构造的默认控制器类具有以下模式:

public class HomeController: Controller
{
private StarChartContext _context;public HomeController(StarChartContext context)
{
_context = context;
}public IActionResult Index()
{
// Not default code, actual work
StarMapDataCounts dataCounts = new StarMapDataCounts
{
Charts = await _context.StarCharts.CountAsync(),
Systems = await _context.StarSystems.CountAsync(),
Stars = await _context.Stars.CountAsync(),
Planets = await _context.Planets.CountAsync(),
Satellites = await _context.Satellites.CountAsync(),
Atmospheres = await _context.Atmospheres.CountAsync()
};return View(dataCounts);
}public IActionResult Privacy()
{
_logger.LogInformation($"{_className}.Privacy() Starting...");
return View();
}[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
_logger.LogInformation($"{_className}.Error() Starting...");
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}

The critical thing to note in the above is that the controller name is <NAME>Controller. Each method is public, returns an IActionResult, and most importantly, as shown below, there are a matching <action name>.cshtml in the Views/Controller folder:

上面要注意的关键是控制器名称是<NAME> Controller。 每个方法都是公共的,返回一个IActionResult,最重要的是,如下所示,在Views / Controller文件夹中有一个匹配的<action name> .cshtml:

Image for post

You can see from the code shown above that the methods Index and Privacy have views in the Home folder under Views, while the Error method had a view in the Shared folder. The routing subsystem will look for the View to load when your code calls the View () method starting in the matching controller view folder, then in shared unless you override the view path in the parameter — a more complex topic. So, if you stick with the simple method is an Action is a Route is a View, then you can forget about the rest of the complexities of this section. However, as I found out when I started expanding my applications, no matter how much you want to avoid the complexity, sometimes it jumps out from behind a database and clobbers you. Then you must move on to more complex routing and actions.

您可以从上面显示的代码中看到,“索引”和“隐私”方法在“视图”下的“主”文件夹中有视图,而“错误”方法在“共享”文件夹中有一个视图。 当代码调用匹配的控制器视图文件夹中的View()方法时,然后在共享中,除非您在参数中覆盖视图路径(更复杂的主题),否则路由子系统将寻找要加载的视图。 因此,如果您坚持使用简单的方法是“操作”是“路线”是“视图”,那么您可以忽略本节的其余复杂性。 但是,正如我在开始扩展应用程序时所发现的那样,无论您想避免多少复杂性,有时它都会从数据库后面跳出来,给您带来麻烦。 然后,您必须继续进行更复杂的路由和操作。

The idea with the additional routing information in the controller is to add more routing options to the startup configuration adding sub-actions and optional parameters in the route like this:

控制器中带有附加路由信息的想法是向启动配置添加更多路由选项,从而在路由中添加子操作和可选参数,如下所示:

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "deeper",
pattern: "{controller}/{action}/{subaction}/{id?}");
endpoints.MapControllerRoute(
name: "paging",
pattern: "{controller}/{action}/{id} page={page}");
endpoints.MapControllerRoute(
name: "paging-deeper",
pattern: "{controller}/{action}/{subaction}/{id} page={page}");
});

Again, I go into some additional detail in my earlier article, but generally, this allowed me to add routes that looked like:

同样,我在之前的文章中做了一些其他详细介绍,但是总的来说,这使我可以添加如下所示的路由:

[HttpGet]
[Route("PartialDetailsPlanets/{id}")]
[Route("PartialDetailsPlanets/{id} page={page}")]
public PartialViewResult PartialDetailsPlanets(Guid? id, int? page)

and,

和,

[HttpGet, ActionName("AddStarChart")]
[Route("Edit/AddStarChart")]
[Route("Edit/AddStarChart/{id?}")]
public async Task<IActionResult> AddStarChart(Guid? id)

and,

和,

[HttpPost, ActionName("AddStarChart")]
[ValidateAntiForgeryToken]
[Route("Edit/AddStarChart/{id}")]
public async Task<IActionResult> AddStarChart(Guid? id,
[Bind("StarSystemId, StarSystemName, StarChartIds")]
StarSystemMapsStarChart map)

In the first case, I have a partial view that is part of the Details view, which I called inside the Razor view like this:

在第一种情况下,我有一个局部视图,它是“详细信息”视图的一部分,在“剃刀”视图中我这样调用了它:

@{
_ = @Html.RenderPartialAsync("PartialDetailsPlanets", Model,
ViewData);
}

For anyone who is old enough to remember, this is the equivalent of an asynchronous update panel from back in ASP.Net 3.x, but it works consistently and is easy to use. I should write an article around this fun little construct sometime soon.

对于足够大的人来说,这相当于ASP.Net 3.x中的异步更新面板,但是它始终如一且易于使用。 我应该很快就围绕这个有趣的小结构写一篇文章。

Anyway, the second route, action pair, is a sub-action of the Edit view. I called this sub-action from either the Edit or Index views. In the Edit view, the Razor code looks like this:

无论如何,第二条路线(动作对)是“编辑”视图的子动作。 我从“编辑”或“索引”视图中调用了此子操作。 在“编辑”视图中,Razor代码如下所示:

<a asp-action=”AddStarChart” asp-route-id=”@Model.Id”>Add to Chart</a>

And similarly, in the Index view like this:

同样,在Index视图中如下所示:

<a asp-controller=”StarSystems” asp-action=”AddStarChart” asp-route-id=”@item.Id”>Add to Chart</a>

The main difference is that the second specifies the controller. This property is technically not needed except that there are other actions on the same View related to other controllers. So, for clarity, I include the controller for all the actions in this View.

主要区别在于第二个指定了控制器。 从技术上讲,不需要该属性,只是在同一View上还有其他与其他控制器相关的动作。 因此,为清楚起见,我在该视图中包括了所有动作的控制器。

The Http post action is called only from the AddStarChart View like this:

仅从AddStarChart视图中调用Http post操作,如下所示:

<form asp-action=”AddStarChart”>

In theory, both the get and post routing from above should have found the two actions without the additional information given by the ActionName attribute. In practice, I found that it did not successfully differentiate between the get and post actions, often calling the get when the intent was a post and vis-versa. Adding the action attribute onto the Http message specifier cleared this problem up completely.

从理论上讲,上面的get和post路由都应该找到两个动作,而没有ActionName属性提供的其他信息。 在实践中,我发现它不能成功地区分get和post操作,通常在意图是post时调用get,反之亦然。 将动作属性添加到Http消息说明符上可以彻底解决此问题。

The critical part to remember about route vs. action. The route is how to reach the method defining the Http address path needed by the system to route messages to reach the code that can process them. Action is the external name of your method. It is usually the final part of the route. Unless you have done something wild with your routing, if you have let me know, I want to hear about it!

要记住的关键部分是路线与行动。 路由是如何到达的方法,该方法定义了系统路由消息所需的Http地址路径,以到达可以处理它们的代码。 操作是方法的外部名称。 它通常是路线的最后部分。 除非您对路由做了一些疯狂的事情,否则,如果您让我知道,我想听听!

处理程序 (Handlers)

Okay, this is a big topic. I just spent four pages discussing one form of handler, the Http action handler. If I go into that much detail with all of the other types, this will be a textbook, and I am aiming at article length, not textbook length, so I will give an overview of the other types that you might use.

好的,这是一个大话题。 我只花了四页讨论一种处理程序形式,即Http操作处理程序。 如果我对所有其他类型进行了详细介绍,这将是一本教科书,我的目的是文章长度,而不是教科书长度,因此,我将概述您可能使用的其他类型。

Configuration and startup handlers these are things like the OnModelCreating() from DbContext and ConfigureServices from Startup. Methods that are called by the base class in a defined order on an event or in sequence allowing the descendent class to make changes or updates to the base class or itself. This type is ubiquitous in .Net Core, and you probably use these without even thinking about it.

这些配置和启动处理程序类似于DbContext中的OnModelCreating()和启动中的ConfigureServices。 基类在事件或事件上按定义的顺序调用的方法,允许子代类对基类或其本身进行更改或更新。 在.Net Core中,这种类型无处不在,您可能甚至都没有考虑就使用它们。

Asynchronous callbacks come in a couple of forms. The first and most common is a delegate. Anywhere you create a method with a specific signature and register it to an event on another class is a delegate. Or explicitly pass a variable of type delegate into a method to receive a callback. These are both uses of delegates. Generally, just saying, you write a method, then give a reference to that method to some other block of code along with a signature so they can call it and have something happen in your code.

异步回调有两种形式。 第一个也是最常见的是一个委托。 创建具有特定签名的方法并将其注册到另一个类的事件的任何地方都是委托。 或者将类型为委托的变量显式传递给方法以接收回调。 这些都是委托的用途。 通常,只是说说,您编写了一个方法,然后将该方法的引用与签名一起提供给其他代码块,以便他们可以调用它并使代码中发生某些事情。

There are specialized handlers of all types, hardware event handlers, timer driven handlers that wake up on a timer, and do something, handlers waiting for input from some exotic IoT device. Still, in the end, the essence of handlers is this. They are waiting for something to happen. Then performing the processing, you defined for when that event occurred. No matter what that event is, why the handler triggered, details of that trigger are essential when writing the handler but no just because it is a handler.

有各种类型的专用处理程序,硬件事件处理程序,计时器驱动的处理程序,这些处理程序会在计时器上唤醒,并执行某些操作,这些处理程序正在等待来自某些奇异物联网设备的输入。 最后,处理程序的本质还是这样。 他们正在等待某些事情发生。 然后执行处理,您定义了该事件的发生时间。 无论事件是什么,为什么触发处理程序,在编写处理程序时,该触发器的细节都是必不可少的,而不仅仅是因为它是处理程序。

方法 (Methods)

Okay, I am going to skim this. Methods are the code in a C# program. A method is what all the other terms I discussed today are at their Core. You write a method that can be an action, an event handler, a callback, or another method called by some other method in your application. Methods should be single purpose, but they should have a purpose.

好吧,我将略读一下。 方法是C#程序中的代码。 我今天讨论的所有其他术语都以方法为核心。 您编写的方法可以是动作,事件处理程序,回调或应用程序中其他方法调用的其他方法。 方法应该是单一目的的,但它们应该有目的。

One of my favorite stories from my time as a young programmer was the story of a company that was converting their code from one single monolithic block of code with gotos and if statements as the only flow of control. The department manager had heard that fifty (or seventy, or twenty the number varies on who is telling the story, but fifty is most common) lines if the optimal length for a function in this new-fangled language. So, he had his staff go through and break up their application at exactly fifty-line intervals and make them functions. Without changing anything else, just call the next function down at the bottom…you can probably guess how well that worked out for everyone involved.

在我年轻的程序员时代,我最喜欢的故事之一就是一家公司的故事,该公司正在使用gotos和if语句作为唯一的控制流,将代码从一个单一的整体代码块中转换出来。 部门经理听说,如果使用这种新型语言的功能的最佳长度,则五十行(或七十行或二十行的数字取决于谁在讲故事),而行长则最佳。 因此,他让他的员工每隔五十行检查一次并分解他们的应用程序,并使它们运行。 无需更改其他任何内容,只需在底部调用下一个函数即可……您可能会猜到对每个相关人员而言效果如何。

The moral of this foolish story is that there is no defined length for a method. But if you have trouble remembering what it is supposed to do, it is probably time to break the functionality up into multiple methods. For example, I was recently working on a software project archeology and recovery project for a customer, i.e., the project would not build due to missing source files. While working on this project, I found a method that was many screens long and had many functions, some of which were apparently unrelated. I was able to understand this method without changing functionality by taking code blocks from within inner blocks of loops if statements and switch statements and putting them in appropriate methods with parameters and return values to handle inputs and outputs. After doing this, it was clear that this method was…um painful. I did not change it because that was not my project. But it essentially was a giant do everything that the program had to do and do it on global static variables method. I carefully put everything back the way it was when I started, undoing my checkout to make sure I did not change anything at all because I did not want my fingerprints on that file ever. I then finished reconstructing the missing files and moved on, glad that there had not been any issues in that file or method.

这个愚蠢的故事的寓意是方法没有定义的长度。 但是,如果您不记得应该做什么,可能是时候将该功能分解为多种方法了。 例如,我最近正在为客户从事软件项目考古和恢复项目,即该项目由于缺少源文件而无法构建。 在从事该项目时,我发现了一种方法,该方法有多个屏幕,并且具有许多功能,其中一些功能显然无关。 通过从if语句和switch语句的循环内部块中获取代码块并将它们放入带有参数和返回值的适当方法中以处理输入和输出,我能够在不更改功能的情况下理解该方法。 完成此操作后,很明显,此方法是……非常痛苦。 我没有更改它,因为那不是我的项目。 但是从本质上讲,程序必须做的一切都是巨无霸,并采用全局静态变量方法来完成。 我小心翼翼地将所有内容恢复到开始时的状态,撤消了结帐操作以确保我根本不更改任何内容,因为我从来都不希望该文件上的指纹。 然后,我完成了丢失文件的重建并继续前进,很高兴那个文件或方法没有任何问题。

结论 (Conclusion)

Well, honestly, I do not care what you call your methods. However, having everyone using standardized language helps us understand what other software engineers, programmers, developers, whatever you want to call yourselves are discussing. Standardized terminology also moves us along the transition from an art, to a craft, to an engineering profession. Right now, most of our profession is stuck in the art to craft stage, we are trying hard to reach engineering status, but there are still too many places where a single magic programmer can create art for it to be engineering yet. You do not hear many stories about some super mechanical engineer coming into General Electric and single-handedly designing a new Electric Generator that is X% better than every other on the market. That is because mechanical engineering at that level is engineering. It is well understood, and the people who study it get a similar level of competence coming out of college. Software Engineering still varies widely.

好吧,说实话,我不在乎您所说的方法。 但是,让所有人都使用标准化语言可以帮助我们了解其他软件工程师,程序员,开发人员,无论您想称呼自己在讨论什么。 标准化的术语也使我们朝着从艺术,手Craft.io到工程专业的过渡迈进。 目前,我们的大多数职业都停留在从艺术到Craft.io的阶段,我们正努力达到工程地位,但是仍然有太多的地方可以让一个魔术程序员为之创作艺术。 您不会听到很多关于超级机械工程师加入通用电气并单手设计出比市场上其他产品高出X%的新发电机的故事。 那是因为该级别的机械工程就是工程。 这是众所周知的,学习它的人从大学毕业后也具有类似的能力。 软件工程仍然相差很大。

There is still this vision that a single super programmer can drop in on a project and just make it happen. In some ways, this can occur because software has only existed for less than eighty years. Think about it, mechanical engineering in one form or another has existed since when? The first blacksmith? The first flint knapper? It was not engineering, but these crafts had to have a basic understanding of forces and materials that are the Core of mechanical engineering. So, tens of thousands of years, or at least thousands of years as humanities understanding of mechanical forces evolved from mechanical arts to crafts, to engineering and science. Software and its related computer hardware have had less than one hundred years, sure we are standing on the shoulders of all the other arts, crafts, engineering, and science that came before us, but we are still at the melting tin and copper to see what it does stage. Remember that when you think of how far we have come, we are still crawling. Where will we be when we start walking or running.

仍然有这样的愿景,即单个超级程序员可以加入一个项目并实现它。 在某些方面,这可能会发生,因为软件仅存在不到80年。 想一想,什么时候以一种或另一种形式存在机械工程? 第一个铁匠? 第一个fl石敲打者? 这不是工程,但是这些手Craft.io品必须对作为机械工程核心的力和材料有基本的了解。 因此,随着人类对机械力的理解从机械艺术到手Craft.io品,再到工程学和科学,发展了数万年,或者至少数千年。 软件及其相关的计算机硬件已经使用了不到一百年的时间,可以肯定的是,我们站在摆在我们面前的所有其他艺术,手Craft.io,工程和科学的肩膀上,但是我们仍然处在熔化锡和铜的状态它在舞台上做什么。 请记住,当您想到我们已经走了多远时,我们仍在爬行。 当我们开始走路或跑步时,我们会在哪里。

Good luck, and have fun.

祝好运并玩得开心点。

翻译自: https://medium.com/the-innovation/net-core-actions-routes-handlers-and-methods-aab3ac7a25f3

一般处理程序可以类似路由的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值