第一个MVC应用程序

r01cn 2011-09-24 10:45:07
C H A P T E R 3

Your First MVC Application
第一个MVC应用程序


The best way to appreciate a software development framework is to jump right in and use it. In this chapter, you’ll create a simple data-entry application using the ASP.NET MVC Framework. We’ll take things a step at a time so you can see how an ASP.NET MVC application is constructed. To keep things simple, we’ll skip over some of the technical details for the moment; but don’t worry—if you are new to MVC, you’ll find plenty to keep you interested. Where we use something without explaining it, we provide a reference to the chapter where you can find all the details.
鉴赏一个软件开发框架最好的方法是投入其中并使用它。本章中,你将用ASP.NET MVC框架生成一个简单的“数据-实体”应用程序。我们将把事情分为一个个步骤,以使你能明白ASP.NET MVC应用程序是如何构造的。为简化起见,这里我们将跳过某些技术细节,但是不必着急 — 如果你是MVC新手,你将会发现大量让你感兴趣的东西。在我们不加解释地使用某些东西的地方,我们会提供参考章节,在那里,你会找到所有细节。

Creating a New ASP.NET MVC Project
生成一个新ASP.NET MVC项目


We are going to start by creating a new MVC project in Visual Studio. Select New Project from the File menu to open the New Project dialog. If you select the Web templates, you’ll see that the MVC 3 installer has created a new item called ASP.NET MVC 3 Web Application, as shown in Figure 3-1.
我们打算从生成一个新的MVC项目开始。在Visual Studio的“文件”菜单中选择“新建项目”,以打开新项目对话框。如果你选择“Web”模板,你会看到MVC 3安装程序已经生成了一个新条目,叫做“ASP.NET MVC 3 Web应用程序”,如图3-1所示。

http://hi.csdn.net/attachment/201108/31/1430687_1314790781gmQW.png
Figure 3-1. The Visual Studio MVC 3 project template
图3-1. Viusal Studio MVC 3项目模板

n Caution The MVC 3 installer doesn’t remove MVC version 2, so you’ll also see the old templates available alongside the new. When creating a new project, be careful to select the right one.
小心:MVC 3安装程序并未删除MVC 2版本,因此你也会在这个新模板的旁边看到老版本的模板。在生成一个新项目时,要小心选择正确的模板。

Set the name of the new project to PartyInvites and click the OK button to continue. You will see another dialog box, shown in Figure 3-2, which asks you to choose between three different types of MVC project templates.
将这个新项目的名字设置为PartyInvites,并点击OK按钮。你将看到另一个对话框。如图3-2所示,它让你在三个不同的MVC项目模板之间进行选择。

http://hi.csdn.net/attachment/201108/31/1430687_1314790797YmZM.png
Figure 3-2. Selecting a type of MVC 3 project
图3-2. 选择MVC 3项目的类型

The Empty option creates a project with only the minimum files and folders required for an MVC 3 application. The Internet Application option creates a small example application that you can modify and build on. It includes user registration and authentication, navigation, and a consistent visual style. The Intranet Application option is similar to Internet Application, but is designed for use in environments that authenticate users through a domain/Active Directory infrastructure. For this chapter, we are going to keep things simple. Select the Empty option, leave the Use HTML5 semantic markup option unchecked, and click OK to create the new project.
“空模板(Empty)”选项只生成一个MVC 3应用程序所需要的最少文件和文件夹。“Internet应用程序”选项生成一个小型的例子应用程序,你可以在它上面进行修改,并建立其它功能。它包括了用户注册与认证、导航,以及一个和谐的可视化样式。Intranet应用程序选项比Internet应用程序更小些,但它是设计用于通过一个域/活动目录(domain/Active Directory)体系结构进行用户认证的环境。现在选择“空模板”选项,让“使用HTML 5语义标记”复选框为不选,点击OK以生成这个新项目。

n Note Under the template options in Figure 3-2, you can see a drop-down menu that lets you specify the view engine for the project. As we mentioned in Chapter 1, MVC 3 includes a new and improved view engine called Razor, which we’ll be using Razor throughout this book. We recommend that you do the same. But if you want to use the regular ASP.NET view engine (known as the ASPX engine), this is where you select it.
注:在图3-2的模板选项下,你可以看到一个下拉菜单,它让你指定项目的视图引擎。正如我们在第1章所提到的,MVC包括了一个新的、叫做Razor的改善了的视图引擎,我们在本书中都使用这个Razor。我们建议你也这样做。但如果你想使用老式的ASP.NET视图引擎(称为ASPX引擎),你可以在这里选择。

Once Visual Studio creates the project, you’ll see a number of files and folders displayed in the Solution Explorer window. This is the default structure for an MVC 3 project. You can try to run the application now by selecting Start Debugging from the Debug menu (if it prompts you to enable debugging, just click the OK button). You can see the result in Figure 3-3. Since we started with the empty project template, the application doesn’t contain anything to run, so we see a 404 Not Found Error.
一旦Visual Studio生成了这个项目,你将在“解决方案浏览器”窗口中看到一些文件和文件夹。这是MVC 3项目默认的结构。现在,通过选择“调试”菜单中的“启动调试”,你可以试着运行一下这个应用程序(如果出现 “能够调试”提示,点一下OK按钮)。你会看到图3-3所示的结果。因为我们是从空项目模板开始的,此应用程序尚未含有任何可以运行的东西,因此我们会看到“404未找到错误”的提示屏幕。


Figure 3-3. Trying to run an empty project
图3-3. 试运行一个空项目

When you’re finished, be sure to stop debugging by closing the browser window that shows the error, or by going back to Visual Studio and selecting Stop Debugging from the Debug menu.
做完上述事情之后,要确保停止调试,这可以通过关闭显示错误消息的浏览器窗口,或返回Visual Studio,在调试菜单上选择“停止调试”。

Adding the First Controller
添加第一个控制器


In MVC architecture, incoming requests are handled by controllers. In ASP.NET MVC, controllers are just simple C# classes (usually inheriting from System.Web.Mvc.Controller, the framework’s built-in controller base class). Each public method in a controller is known as an action method, meaning you can invoke it from the Web via some URL to perform an action. The MVC convention is to put controllers in a folder called Controllers, which Visual Studio created for us when it set up the project. You don’t need to follow this or most other MVC conventions, but we recommend that you do—not least because it will help you make sense of the examples in this book.
在MVC体系结构中,传入的请求是由控制器处理的。在ASP.NET MVC中,控制器只是简单的C#类(通常继承于System.Web.Mvc.Controller,这是.NET框架内建的基类)。在控制器中的每一个public方法称为一个动作方法,意即,你可以通过某个URL从Web来调用它,以执行一个动作。MVC约定,把控制器放在一个名为Controllers的文件夹中,这是Visual Studio在建立项目时为我们自动生成的。你不一定要遵循这一约定以及其它大多数MVC约定,但我们建议你还是遵循它 — 至少因为它有助于你搞清本书例子的意思。

To add a controller to our project, right-click the Controllers folder in the Visual Studio Solution Explorer window and choose Add and then Controller from the pop-up menus, as shown in Figure 3-4.
要把一个控制器添加到我们的项目,右击Controllers文件夹,并从弹出菜单中选择“添加” — “控制器”,如图3-4所示。


Figure 3-4. Adding a controller to the MVC project
图3-4. 在MVC项目上添加控制器

When the Add Controller dialog appears, set the name to HomeController, as shown in Figure 3-5. This is another convention: the names we give to controllers should be descriptive and end with Controller.
当“添加控制器”对话框出现时,将其命名为HomeController,如图3-5所示。这是另一个约定:我们给控制器的命名应该是描述性的,并以Controller结尾。


Figure 3-5. Setting the name for the controller
图3-5. 设置控制器的名字

The Scaffolding options section of the dialog allows us to create a controller using a template with common functions. We aren’t going to use this feature, so ensure that the Empty controller item is selected in the Template menu, as shown in the figure.
这个对话框的辅助选项(Scaffolding Options)部分允许我们用一个带有常规功能的模板生成一个控制器。我们暂不打算使用这一特性,因此,确保在“模板(Template)”菜单中选择了“空(Empty)”条目,如图3-5所示。

n Note If you don’t see the Add Controller dialog as it is shown in Figure 3-5, you have probably forgotten to install the MVC 3 Tools Update. See Chapter 2 for details.
注:如果你没看到如图3-5所示的添加控制器对话框,你可能忘记了安装MVC 3工具更新。详见第2章。

Click the Add button to create the controller. Visual Studio will create a new C# code file in the Controller folder called HomeController.cs and open it for editing. You can see that the class is called HomeController and it is derived from System.Web.Mvc.Controller. Edit the code in this file so that it matches Listing 3-1.
点击添加按钮以生成这个控制器。Visual Studio将在Controller文件夹中生成一个名为HomeController.cs的新的C#代码文件,并打开它进行编辑。你可以看到这个类的名字为HomeController,而且它派生于System.Web.Mvc.Controller。编辑这个文件中的代码,使其内容如清单 3-1。

Listing 3-1. Modifying the HomeController Class

using System.Web.Mvc;
namespace PartyInvites.Controllers {
public class HomeController : Controller {
public string Index() {
return "Hello, world";
}
}
}


We haven’t created anything exciting, but this is a good way of getting started with MVC. We’ve created an action method called Index, which returns the string “Hello, world”. Run the project again by selecting Start Debugging from the Visual Studio Debug menu. The browser will display the result of the Index action method, as shown in Figure 3-6.
我们还没有生成任何让人兴奋的东西,但这是MVC的一个良好的开端。我们已经生成了一个名为Index的动作方法,它返回字符串“Hello, world”。再次运行这个项目,浏览器将显示Index动作方法的结果,如图3-6所示。


Figure 3-6. The output form of our controller action method
图3-6. 控制器动作方法的输出
...全文
9919 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
codepat 2013-07-26
  • 打赏
  • 举报
回复
楼上狂妄自大,不知所云
MSDNXGH 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 moneysoft 的回复:]
引用 8 楼 msdnxgh 的回复:
建议,你先用一下MVC,如果你用过的话

在微软推出asp.netMVC之前,我们就拥有自己的MVC系统了,而且覆盖整个软件生产过程,而不仅仅局限在代码层面,为了避免不必要的误解,我们还修改了命名空间
另一方面,在计算机发明之前,人类也早就拥有不计其数的MVC设计和应用了
[/Quote]

那请问,你们拥有自己的编程语言吗?只能说,有自主开发基于MVC的应用系统

你说一了些没用的话,另一方面,在计算机发明之前,人类也早就拥有不计其数的MVC设计和应用了
这当然是,没有谁说,MVC就指定是.NETMVC。

只能说.NETMVC的推广比其它慢而己,
r01cn 2011-09-25
  • 打赏
  • 举报
回复
Completing the Example
完成示例


The last requirement for our sample application is to e-mail completed RSVPs to our friend, the party organizer. We could do this by adding an action method to create and send an e-mail message using the e-mail classes in the .NET Framework. Instead, we are going to use the WebMail helper method. This isn’t part of the MVC framework, but it does let us complete this example without getting mired in the details of setting up other forms of sending e-mail.
这个示例应用程序的最后需求是把完成了RSVP的电子邮件发给我们的朋友,该晚会的组织者。我们可以通过添加一个动作方法用.NET框架的e-mail类来生成并发送一份邮件消息的办法来完成这一任务。这里,我们打算使用WebMail辅助方法。这不是MVC框架的一部分,但它确实能让我们完成这个例子而不必陷入要建立另一个发送邮件的表单这样的麻烦。

n Note We used the WebMail helper because it lets us demonstrate sending an e-mail message with a minimum of effort. Typically, however, we would prefer to put this functionality in an action method. We’ll explain why when we describe the MVC architecture pattern in Chapter 4.
注:我们使用WebMail辅助方法是因为它让我们以最少的努力就可以发送一封邮件。然而,典型地,我们更喜欢把这个功能放在一个动作方法中。我们将在第4章中描述MVC体系结构模式时解释这是为什么。

We want the e-mail message to be sent as we render the Thanks view. Listing 3-16 show the changes that we need to apply.
我们希望,当我们渲染Thanks视图时发送这超过计划邮件消息。清单3-16显示了我们需要进行的修改。

Listing 3-16. Using the WebMail Helper
@model PartyInvites.Models.GuestResponse
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Thanks</title>
</head>
<body>
@{
try {
WebMail.SmtpServer = "smtp.example.com";
WebMail.SmtpPort = 587;
WebMail.EnableSsl = true;
WebMail.UserName = "mySmtpUsername";
WebMail.Password = "mySmtpPassword";
WebMail.From = "rsvps@example.com";
WebMail.Send("party-host@example.com", "RSVP Notification",
Model.Name + " is " + ((Model.WillAttend ?? false) ? "" : "not")
+ "attending");
} catch (Exception) {
@:<b>Sorry - we couldn't send the email to confirm your RSVP.</b>
}
}
<div>
<h1>Thank you, @Model.Name!</h1>
@if (Model.WillAttend == true) {
@:It's great that you're coming. The drinks are already in the fridge!
} else {
@:Sorry to hear that you can't make it, but thanks for letting us know.
}
</div>
</body>
</html>

We have added a Razor code block that uses the WebMail helper to configure the details of our e-mail server, including the server name, whether the server requires SSL connections, and account details. Once we’ve configured all of the details, we use the WebMail.Send method to send the e-mail.
我们已经添加了一段Razor代码块,它用WebMail辅助器来配置邮件服务器的细节,包括服务器名、服务器是否需要SSL连接,以及帐号细节。一旦我们已经配置了所有这些细节,我们就可以用WebMail.Send方法来发送这封邮件。

We have enclosed all of the e-mail code in a try...catch block so that we can alert the user if the e-mail isn’t sent. We do this by adding a block of text to the output of the Thanks view. A better approach would be to display a separate error view when the e-mail message can’t be sent, but we wanted to keep things simple in our first MVC application.
我们把所有邮件代码封闭在一个try…catch块中,这样,如果不能发送邮件,我们可以向用户发出告警。我们把一个文本块添加到thanks视图的输出。一个更好的办法是当不能发送邮件消息时显示一个独立的错误视图,但我们希望在我们的第一个MVC应用程序中保持事物简单。

Summary
摘要


In this chapter, we created a new MVC project and used it to construct a simple MVC data-entry application, giving you a first glimpse of the MVC Framework architecture and approach. We skipped over some key features (including Razor syntax, routing, and automated testing), but we’ll come back to these topics in depth in later chapters.
本章我们生成了一个新的MVC项目,并用它构造了一个简单的MVC数据-实体应用程序,让你概览了MVC框架的体系结构和方法。我们跳过了一些关键特性(包括Razor语法、路由,以及自动测试),但我们将在之后的章节中深入讨论这些主题。

In the next chapter, we’ll explore the MVC architecture, design patterns, and techniques that we’ll use throughout the book.
下一章我们考察MVC体系结构、设计模式,以及在本书中要运用的技术。
r01cn 2011-09-25
  • 打赏
  • 举报
回复
Adding Validation
添加验验


We are now in a position to add validation to our application. If we didn’t do this, our users could enter nonsense data or even submit an empty form.
现在到了我们把验证添加到我们的应用程序的时候了。如果我们不这样做,我们的用户可能输入无意义的数据,甚至递交一个空的表单。

In an MVC application, validation is typically applied in the domain model, rather than in the user interface. This means that we define our validation criteria in one place, and it takes effect in any place the model class is used. ASP.NET MVC supports declarative validation rules defined with attributes from the System.ComponentModel.DataAnnotations namespace. Listing 3-13 shows how these attributes can be applied to the GuestResponse model class.
在一个MVC应用程序中,验证典型地用于域模型中,而不是在用户界面。这意味着我们在一个地方定义验证条件,它会在模型运用的任何地方生效。ASP.NET MVC支持验证规则声明,验证规则是以System.ComponentModel.DataAnnotations命名空间中的属性进行定义的。清单3-13演示了这些属性如何才能用于GuestResponse模型类。

Listing 3-13. Applying Validation to the GuestResponse Model Class
using System.ComponentModel.DataAnnotations;
namespace PartyInvites.Models {
public class GuestResponse {
[Required(ErrorMessage="Please enter your name")]
public string Name { get; set; }
[Required(ErrorMessage="Please enter your email address")]
[RegularExpression(".+\\@.+\\..+",
ErrorMessage="Please enter a valid email address")]
public string Email { get; set; }
[Required(ErrorMessage="Please enter your phone number")]
public string Phone { get; set; }
[Required(ErrorMessage="Please specify whether you'll attend")]
public bool? WillAttend { get; set; }
}
}

The validations rules are shown in bold. MVC detects the validation attributes and uses them to validate data during the model-binding process. Notice that we have imported the namespace that contains the validations, so we can refer to them without needing to qualify their names.
验证规则显示为黑体。MVC侦测这些验证属性,并把它们用于验证模型绑定过程中的数据。注意,我们已经引入了含有验证的命名空间,因此我们不需要用限定名来引用它们。

n Tip As noted earlier, we used a nullable bool for the WillAttend property. We did this so we could apply the Required validation attribute. If we used a regular bool, the value we received through model binding could be only true or false, and we wouldn’t be able to tell if the user had selected a value. A nullable bool has three possible values: true, false, and null. The null value will be used if the user hasn’t selected a value, and this causes the Required attribute to report a validation error.
提示:正如之前说明的,我们对WillAttend属性使用了一个可空的布尔型。因此这样做我们可以运用Required验证属性。如果我们使用一个规则的布尔型,那么我们通过模型绑定能够使用的只能是true或false,则我们就不能说明用户是否已选择了一个值。一个可空的布尔型有三个可能的值:true、false、和null。如果用户尚未选择一个值,将用null来表示,这样可使Required属性来报告一个验证错误。

We can check to see if there has been a validation problem using the ModelState.IsValid property in our controller class. Listing 3-14 shows how to do this in our POST-enabled RsvpForm action method.
我们可以用控件类中的ModelState.IsValid属性来查看是否有验证问题。清单3-14演示了在可以POST的RsvpForm动作方法中如何做这件事。

Listing 3-14. Checking for Form Validation Errors
[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse) {
if (ModelState.IsValid) {
// TODO: Email guestResponse to the part organizer
return View("Thanks", guestResponse);
} else {
// there is a validation error - redisplay the form
return View();
}
}

If there are no validation errors, we tell MVC to render the Thanks view as we did previously. If there are validation errors, we rerender the RsvpForm view by calling the View method without any parameters.
如果没有验证错误,就像我们之前做的那样,告诉MVC来渲染Thanks视图。如果有验证错误,我们通过调用不带参数的视图方法来重新渲染这个RsvpForm视图。

We need to display the validation errors to the user, and we can do this by using the Html.ValidationSummary helper method in the RsvpForm view, as shown in Listing 3-15.
我们需要把验证错误显示给用户,而我们可以通过使用RsvpForm视图中的Html.ValidationSummary辅助方法来实现,如清单3-15所示。

Listing 3-15. Using the Html.ValidationSummary Help Method
...
<body>
@using (Html.BeginForm()) {
@Html.ValidationSummary()
<p>Your name: @Html.TextBoxFor(x => x.Name) </p>
<p>Your email: @Html.TextBoxFor(x => x.Email)</p>
...

If there are no errors, the Html.ValidationSummary method creates a hidden list item as a placeholder in the form. MVC makes the placeholder visible and adds the error messages defined by the validation attributes. You can see how this appears in Figure 3-18.
如果没有错误,Html.ValidationSummary方法在表单中生成一个隐藏的列表条目占位符。MVC使这个占位符成为可见的,并添加根据验证属性所定义的错误消息。在图3-18中你可以看到这是如何出现的。


Figure 3-18. The validation summary

The user won’t be shown the Thanks view until all of the validation constraints we applied to the GuestResponse class have been satisfied. Notice that the data we entered into the form was preserved and displayed again when the view was rendered with the validation summary. This is a benefit we get from model binding.
直到我们用于GuestResponse类的所有验证约束都得到满足,才会显示Thanks视图。注意,我们在表单中输入的数据是保留的,并且当带有验证摘要的视图被重新渲染时被再次显示出来。这是我们通过模型绑定所得到的好处。
(总结:验证规则是在模型中设置的,而验证过程和对验证的处理是在视图中进行的。 — 译者注)

n Note If you’ve worked with ASP.NET Web Forms, you’ll know that Web Forms has a concept of “server controls” that retain state by serializing values into a hidden form field called __VIEWSTATE. ASP.NET MVC model binding is not related to the Web Forms concepts of server controls, postbacks, or View State. ASP.NET MVC doesn’t inject a hidden __VIEWSTATE field into your rendered HTML pages.
注:如果你曾经用过ASP.NET Web表单,你应该知道Web表单有一个“服务器控件”的概念,服务器控件通过把值序列化到一个叫做__VIESTATE的隐含字段的方法来保持状态。ASP.NET MVC模型绑定与web表单的服务器控件、回递、或视图状态等概念无关。ASP.NET MVC不会把一个隐含字段__VIEWSTATE注入到你渲染的HTML页面之中。

Highlighting Invalid Fields
高亮无效字段


The HTML helper methods that create text boxes, drop-downs, and other elements have a very handy feature that can be used in conjunction with model binding. The same mechanism that preserves the data that a user entered in a form can also be used to highlight individual fields that failed the validation checks.
生成文本框、下拉列表、以及其它元素的HTML辅助方法有一个十分灵活的特性,可以用来与模型绑定相关联。与保留用户在表单中输入的数据同样的机制也可以用来高亮验证检查失败的字段。

When a model class property has failed validation, the HTML helper methods will generate slightly different HTML. As an example, here is the HTML that a call to Html.TextBoxFor(x => x.Name) generates when there is no validation error:
当一个模型类属性验证失败时,HTML辅助方法可以生成稍有不同的HTML。例如,以下是Html.TextBoxFor(x => x.Name)在没有验证错误时生成的HTML:

<input data-val="true" data-val-required="Please enter your name" id="Name" name="Name"
type="text" value="" />

And here is the HTML the same call generates when the user doesn’t provide a value (which is a validation error because we applied the Required attribute to the Name property in the GuestResponse model class):
而以下是同样的调用在用户未提供一个值(这是一个验证错误,因为我们对GuestResponse模型类中的Name属性运用了Required属性)时所生成的HTML:

<input class="input-validation-error" data-val="true" data-val-required="Please enter your name" id="Name" name="Name" type="text" value="" />

We have highlighted the difference in bold. This helper method added a CSS class called input-validation-error. Different helper methods apply different CSS classes, but they can all be found in the ~/Content/Site.css style sheet that Visual Studio adds to all MVC projects. To use this style sheet, we add a new reference to the head section of RsvpForm view, like this:
我们已经以黑体高亮了其差异。这个辅助方法添加了一个名为input-validation-error的CSS类。不同的辅助方法运用不同的CSS类,但它们都可以在Visual Studio给MVC项目添加的~/Content/Site.css样式表中找到。要使用这个样式表,我们可以在RsvpForm视图的头部添加一个新的引用,像这样:

<link rel="Stylesheet" href="@Href("~/Content/Site.css")" type="text/css"/>

n Tip If you’ve used the ASPX view engine, you may be used to specifying paths directly using the tilde (~) (like this: href="~/Content/Site.css") and relying on the view engine to convert this into a URL that the browser can follow (such as ../Content/Site.css). The Razor View Engine takes a different approach. It requires the Href operator to convert URLs (like this: href="@Href("~/Content/Site.css")"). You can find more details about Razor in Chapter 5.
提示:如果你使用ASPX视图引擎,你可能习惯于用波浪号(~)直接指定路径(如,href=”~/Content/Site.css”)并依靠视图引擎把它转换成一个浏览器可以采用的URL(如,../Content/Site.css)。Razor视图引擎采用一种不同的方式。它需要Href操作符来转换URL(如,href=”@Href(“~/Content/Site.css”)”)。第5章你可以了解Razor的更多细节。

Now when the user submits data that causes a validation error, he will see a more useful indication of the cause of the problems, as shown in Figure 3-19.
现在,当用户递交会引发验证错误的数据时,他会看到引起这个错误的更多有用的提示,如图3-19所示。


Figure 3-19. Automatically highlighted validation errors
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 msdnxgh 的回复:]
建议,你先用一下MVC,如果你用过的话
[/Quote]
在微软推出asp.netMVC之前,我们就拥有自己的MVC系统了,而且覆盖整个软件生产过程,而不仅仅局限在代码层面,为了避免不必要的误解,我们还修改了命名空间
另一方面,在计算机发明之前,人类也早就拥有不计其数的MVC设计和应用了
r01cn 2011-09-25
  • 打赏
  • 举报
回复
Using Model Binding
使用模型绑定


The first overload of the RsvpForm action method renders the same view as before. It generates the form shown in Figure 3-15. The second overload is more interesting because of the parameter, but given that the action method will be invoked in response to an HTTP POST request, and that the GuestResponse type is a C# class, how are the two connected?
第一个过载的RsvpForm动作方法渲染和前面同样的视图。它生成如图3-15所示的表单。第二个过载方法由于其参数变得更有趣,但已经给定了这个动作方法的调用以响应HTTP POST请求,而GuestResponse类型是一个C#类,这两者是如何连接的呢?

The answer is model binding, an extremely useful MVC feature whereby incoming data is parsed and the key/value pairs are used to populate properties of domain model types. This process is the opposite of using the HTML helper methods; that is, when creating the form data to send to the client, we generated HTML input elements where the values for the id and name attributes were derived from the model class property names. In contrast, with model binding, the names of the input elements are used to set the values of the properties in an instance of the model class, which is then passed to our POST-enabled action method.
答案是模型绑定,这是一个非常有用的MVC特性,以解决如何解析数据,以及“键/值”对如何组装域模型类型属性等问题。这一过程与使用HTML辅助方法是反向的,即,当生成表单数据以便把它们发送到客户端时,我们(用HTML辅助方法)生成了HTML输入元素,在这里,id和name属性的值是从模型类的属性名派生而来的。反过来,利用模型绑定,输入元素的名字用来设置模型类实例的属性值,这些值然后由POST动作方法进行传递。

Model binding is a powerful and customizable feature that eliminates the grind and toil of dealing with HTTP requests, letting us work with C# objects rather than dealing with Request.Form[] and Request.QueryString[] values. The GuestResponse object that is passed as the parameter to our action method is automatically populated with the data from the form fields. We’ll dive into the detail of model binding, including how it can be customized, in Chapter 17.
模型绑定是一个功能强大并可定制的特性,它消除了处理HTTP请求的折磨和辛苦,使我们能够用C#对象进行工作,而不是处理Request.Form[]和Request.QuertyString[]值。作为参数被传递给动作方法的GuestResponse对象自动发布了表单字段的数据。我们将在第17章研究模型绑定,包括如何定制它的细节。

Rendering Other Views
渲染其它视图


The second overload of the RsvpForm action method also demonstrates how we can tell MVC to render a specific view in response to a request. Here is the relevant statement:
第二个过载的RsvpForm动作方法也演示了我们如何才能告诉MVC去渲染一个指定的视图。以下是相关语句:

return View("Thanks", guestResponse);

This call to the View method tells MVC to find and render a view called Thanks and to pass our GuestResponse object to the view. To create the view we’ve specified, right-click inside one of the HomeController methods and select Add View from the pop-up menu. Set the name of the view to Thanks, as shown in Figure 3-16.
这个对View方法的调用告诉MVC找到并渲染一个名为Thanks的视图,并把我们的GuestResponse对象传递给这个视图。要生成我们指定的这个视图,右击HomeController中的一个方法,并从弹出菜单中选择“添加视图”。将视图名设为Thanks,如图3-16所示。


Figure 3-16. Adding the Thanks view

We are going to create another strongly typed view, so check that box in the Add View dialog. The data class we select for the view must correspond with the class we pass to the view using the View method, so select GuestResponse from the drop-down list. Ensure that the Select master page option is not checked, that View engine is set to Razor, and the view content is set to Empty. Click Add to create the new view. Since the view is associated with the Home controller, MVC creates the view as ~/Views/Home/Thanks.cshtml. Edit the new view so that it matches Listing 3-12.
我们打算生成另一个强类型视图,因此选中“生成强类型”复选框。我们为这个视图所选择的数据类,必须与我们用View方法传递给这个视图的类相对应,故从下拉列表中选择GrestResponse。确保“选择母板页”选项未选,视图引擎设置为Razor,视图内容设置为“空模板”。点击“添加”以生成这个新视图。因为这个视图与Home控制器相对应,MVC将此视图生成为~/Views/Home/thanks.cshtml。把这个新视图的内容编辑为如清单3-12所示。

Listing 3-12. The Thanks View
@model PartyInvites.Models.GuestResponse
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Thanks</title>
</head>
<body>
<div>
<h1>Thank you, @Model.Name!</h1>
@if (Model.WillAttend == true) {
@:It's great that you're coming. The drinks are already in the fridge!
} else {
@:Sorry to hear that you can't make it, but thanks for letting us know.
}
</div>
</body>
</html>

The Thanks view uses Razor to display content based on the value of the GuestResponse properties that we passed to the View method in the RsvpForm action method. The Razor @model operator specifies the domain model type that the view is strongly typed with. To access the value of a property in the domain object, we use Model.PropertyName. For example, to get the value of the Name property, we call Model.Name. Don’t worry if the Razor syntax doesn’t make sense—we’ll explain Razor in Chapter 5.
Thanks视图使用Razor基于我们在RsvpForm动作方法中传递给View方法的GuestResponse对象的属性的值来显示内容。Razor的@model操作符指示域模型类型是此视图的强类型。为了访问这个域对象中的属性值,我们使用Model.PropertyName(Model.<属性名>)。例如,要获得Name属性的值,我们调用Model.Name。如果Razor语法没有智能感应,不用着急 — 我们将在第5章解释Razor。

Now that we have created the Thanks view, we have a working example. Start the application in Visual Studio, click the RSVP Now link, add some data to the form, and click the Submit RSVP button. You’ll see the result shown in Figure 3-17 (although it might differ if your name isn’t Joe and you said you couldn’t attend).
现在,我们已经生成了Thanks视图,我们有了一个工作示例。在Visual Studio中启动这个应用程序,现在点击RSVP连接,在表单上添加一些信息,然后点击递交RSVP按钮。你将看到显示在图3-17中的结果(如果你的名字不是Joe,而你说不参加这个晚会,显示也许会有不同)。


Figure 3-17. The rendered Thanks view

r01cn 2011-09-25
  • 打赏
  • 举报
回复
Building the Form
建立表单


Now that we’ve created the strongly typed view, we can build out the contents of RsvpForm.cshtml to make it into an HTML form for editing GuestResponse objects. Edit the view so that it matches Listing 3-10.
现在,我们已经生成了这个强类型视图,我们可以扩建RsvpForm.cshtml的内容,把它制作成编辑GuestResponse对象的HTM表单。编辑这个视图,使它如清单3-10。

Listing 3-10. Creating a Form View
@model PartyInvites.Models.GuestResponse
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>RsvpForm</title>
</head>
<body>
@using (Html.BeginForm()) {
<p>Your name: @Html.TextBoxFor(x => x.Name) </p>
<p>Your email: @Html.TextBoxFor(x => x.Email)</p>
<p>Your phone: @Html.TextBoxFor(x => x.Phone)</p>
<p>
Will you attend?
@Html.DropDownListFor(x => x.WillAttend, new[] {
new SelectListItem() {Text = "Yes, I'll be there", Value = bool.TrueString},
new SelectListItem() {Text = "No, I can't come", Value = bool.FalseString}
}, "Choose an option")
</p>
<input type="submit" value="Submit RSVP" />
}
</body>
</html>

For each property of the GuestResponse model class, we use an HTML helper method to render a suitable HTML input control. These methods let you select the property that the input element relates to using a lambda expression, like this:
对GuestResponse模型类的每个属性,我们用一个HTML辅助方法来渲染一个适当的HTML输入控件。这些方法让你选择将输入元素与一个lambda表达式相关联的属性,像这样:

@Html.TextBoxFor(x => x.Phone)

Don’t worry if you aren’t familiar with C# lambda expressions. We provide an overview in Chapter 5.
如果你不熟悉C#的lambda表达式,不用着急。我们在第5章提供了一个概览。
The HTML helper method generates the HTML that creates an input element, sets the type parameter to text, and sets the id and name attributes to Phone, the name of the selected domain class property, as follows:
HTML辅助方法生成HTML输入元素,把type参数设置为text,并把id和name属性设置为Phone,Phone是所选域类属性的名字,如下所示:

<input id="Phone" name="Phone" type="text" value="" />

This handy feature works because our RsvpForm view is strongly typed, and we have told MVC that GuestResponse is the type that we want to render with this view.
这种方便的特性会起作用,是因为我们的RsvpForm视图是强类型的,并且我们已经告诉了MVC,我们想用这个视图来渲染的类型是GuestResponse。

An alternative to using lambda expressions is to refer to name of the model type property as a string, like this:
代替运用lambda表达式的一种方法是,把模型类型的属性名引用为一个字符串,像这样:

@Html.TextBox("Email")

We find that the lambda expression technique prevents us from mistyping the name of the model type property. This is because Visual Studio IntelliSense pops up and lets us pick the property automatically, as shown in Figure 3-14.
我们发现lambda表达式可以防止我们把模型类型的属性输错。这是因为Visaul Studio智能感应会弹出,并让我们自动地选取属性,如图3-14。


Figure 3-14. Visual Studio IntelliSense for lambda expressions in HTML helper methods

Another convenient helper method is Html.BeginForm, which generates an HTML form element configured to postback to the action method. Since we haven’t passed any parameters to the helper method, it assumes we want to postback to the same URL. A neat trick is to wrap this in a C# using statement, like this:
另一个方便的辅助方法是Html.BeginForm,它生成一个HTML表单元素,它被配置用来回递给动作方法。因为我们还没传递任何参数给这个辅助方法,它假设我们是想回递到同样的URL。一个灵活的窍门是把它包装在一个C#的using语句中,像这样:

@using (Html.BeginForm()) {
...form contents go here...
}

Normally, when applied like this, the using statement ensures that an object is disposed of when it goes out of scope. It is commonly used for database connections, for example, to make sure that they are closed as soon as a query has completed. (This application of the using keyword is different from the kind that brings classes in a namespace into scope in a class.) Instead of disposing of an object, the HtmlBeginForm helper closes the HTML form element when it goes out of scope. This means that the Html.BeginForm helper method creates both parts of a form element, like this:
正常情况下,当像这样运用时,using语句在对象超出范围时确保对这个对象作了清理(清理意指收回对象所占用的内存 — 译者)。例如,这通常用于数据库连接,以确保查询完成后尽快关闭连接。(本应用程序的using关键词与在一个类中引用命名空间的那种using不同。)这里不是清理一个对象,而是Html.BeginForm辅助方法在它超出范围时关闭HTML表单。这意味着,Html.BeginForm辅助方法生成form元素的两部分(指<form>元素的开标签和闭标签 — 译者),像这样:

<form action="/Home/RsvpForm" method="post">
...form contents go here...
</form>

Don’t worry if you are not familiar with disposing of C# objects. The point here is to demonstrate how to create a form using the HTML helper method.
如果你不熟悉C#对象的清理,不用着急。这里会演示如何用HTML辅助方法生成一个表单。

n Tip ASP.NET Web Forms supports only one server-side form in a web page, usually expressed as <form runat=“server”>, which is a container for the View State data and postback logic. MVC doesn’t user server-side forms. All forms are expressed using regular HTML, and you can have as many of them as you like in a single view. There are no View State or other hidden form elements, and the ID values you assign to IDs don’t get mangled.
提示:ASP.NET Web表单仅支持一个web页面中的服务器端表单,通常表达成<form runat=”server”>,它是视图状态数据和回递逻辑的一个容器。MVC并不使用服务器端表单。所有表单都表示成规则的HTML,你在一个视图中可以用任意多个表单。没有视图状态和其它隐藏的表单元素,而且你赋给IDs的值不会被混乱。

You can see the form in the RsvpForm view when you run the application and click the RSVP Now link. Figure 3-15 shows the result.
当运行这个应用程序时,你可以看到RsvpForm视图中的这个表单,点击RSVP连接,图3-15显示了这一结果。


Figure 3-15. The RspvForm view

n Note This isn’t a book about CSS or web design. For the most part, we will be creating examples whose appearance might be described as dated (although we prefer the term classic, which feels less disparaging). MVC views generate very clean and pure HTML, and you have total control over the layout of elements and the classes they are assigned to, so you’ll have no problems using design tools or off-the-shelf templates to make your MVC project pretty.
注:这不是一本关于CSS或web设计的书。大部分内容,我们将把例子生成流行的样式(虽然我们更喜欢古典这一说法,这样让人感觉少一些蔑视)。MVC视图生成很纯净的HTML,并使你对元素布局和所赋值的类有完全的控制,因此你采用设计工具或它所提供的模板使你的MVC项目很美观是没有问题的。

Handling Forms
处理表单


We haven’t told MVC what we want to do when the form is posted to the server. As things stand, clicking the Submit RSVP button just clears any values you’ve entered into the form. That’s because the form posts back to the RsvpForm action method in the Home controller, which just tells MVC to render the view again.
我们还没有告诉MVC,当表单被递交给服务器时,我们要做什么。在目前情况下,点击Submit RSVP按钮只是清除你在表单中已经输入的任何值。这是因为回递给Home控制器中的RsvpForm动作方法,它只是告诉MVC再次渲染这个视图。

n Caution You might be surprised that the input data is lost when the view is rendered again. If so, you have probably been developing applications with ASP.NET Web Forms, which automatically preserves data in this situation. We’ll show you how to achieve the same effect with MVC shortly.
注意:你也许奇怪,视图再次渲染时,输入的数据丢失了。如果是这样,你可能正在用ASP.NET Web表单开发应用程序,它在这种情况下自动地保留数据。我们将很快给你演示如何用MVC取得同样的效果。

To receive and process submitted form data, we’re going to do a clever thing. We will add a second RsvpForm action method in order to create the following:
为了获得并处理递交表单的数据,我们打算做一件聪明的事情。我们将添加第二个RsvpForm动作方法以生成如下作用:

 •A method that responds to HTTP GET requests: A GET request is what a browser issues normally each time someone clicks a link. This version of the action will be responsible for displaying the initial blank form when someone first visits /Home/RsvpForm.
一个方法用来响应HTTP的 GET请求:GET请求是某人点击一个连接,浏览器发出的请求。这个动作将负责某人最初访问/Home/RsvpForm时显示空白表单。
 •A method that responds to HTTP POST requests: By default, forms rendered using Html.BeginForm() are submitted by the browser as a POST request. This version of the action will be responsible for receiving submitted data and deciding what to do with it.
一个方法用来响应HTTP的 POST请求:默认地,用Html.BeginForm()渲染的表单是由浏览器作为一个POST请求递交的。这个动作负责获得所递交的数据,并决定用它做什么。
(其实,GET请求和POST请求的区别很简单:GET请求是获取(GET)一个页面,而POST请求是递交(POST)一个页面(当然要包括在表单中输入的数据)。— 译者注)

Handing GET and POST requests in separate C# methods helps to keep our code tidy, since the two methods have different responsibilities. Both action methods are invoked by the same URL, but MVC makes sure that the appropriate method is called, based on whether we are dealing with a GET or POST request. Listing 3-11 shows the changes we need to apply to the HomeController class.
在不同的C#方法中分别处理GET和POST请求,这有助于保持代码整洁,因为这两种方法有不同的职责。两种方法都是由同样的URL调用的,但MVC确保会根据我们是处理GET还是POST请求来调用合适的方法。清单3-11显示了我们要对HomeController类进行的修改。

Listing 3-11. Adding an Action Method to Support POST Requests
using System;
using System.Web.Mvc;
using PartyInvites.Models;
namespace PartyInvites.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
int hour = DateTime.Now.Hour;
ViewData["greeting"] = hour < 12 ? "Good morning" : "Good afternoon";
return View();
}
[HttpGet]
public ViewResult RsvpForm() {
return View();
}
[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse) {
// TODO: Email guestResponse to the part organizer
return View("Thanks", guestResponse);
}
}
}

We have added the HttpGet attribute to our existing RsvpForm action method. This tells MVC that this method should be used only for GET requests. We then added an overloaded version of RsvpForm, which takes a GuestResponse parameter and applies the HttpPost attribute. The attribute tells MVC that the new method will deal with POST requests. Notice that we have imported the PartyInvites.Models namespace. This is so we can refer to the GuestResponse model type without needing to qualify the class name.
我们已经把HttpGet属性加到了现在的RsvpForm动作方法上。这告诉MVC,这个方法应该仅用于GET请求。然后我们添加了一个过载的RsvpForm方法,它带有一个GuestResponse参数,并运用了HttpPost属性。此属性告诉MVC,这个新方法将处理POST请求。注意,这里我们已经引入了PartyInvites.Modes命名空间。这样,我们可以直接使用GuestResponse模型类型而不需要使用这个类的限定名。

MSDNXGH 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 sp1234 的回复:]
不知道各位注意到了没有,这些例子的界面你稍微看一下就会发现,都是简单得特别幼稚的界面应用。为什么不演示一下如何开素开发复杂的应用界面呢?因为它根本不是做那个的料。
[/Quote]

不是吧,P哥,我想问一下,作为教程,你做些复杂的应用界面,读者,要把大些的心思,去了解你的例子应用,还有那个想不明白设计模式,思路,而不是去了解MVC如何工作了。
  • 打赏
  • 举报
回复
不知道各位注意到了没有,这些例子的界面你稍微看一下就会发现,都是简单得特别幼稚的界面应用。为什么不演示一下如何开素开发复杂的应用界面呢?因为它根本不是做那个的料。
MSDNXGH 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 moneysoft 的回复:]
楼主,你这个不是MVC,而是asp.netMVC,
在整个MVC设计模式中,充其量能算作一个视图解决方案,
也就是说:
MVC系统,可以使用webform,winform,SL,html+js,作为view方案,
asp.netMVC只是其中一种View而已
[/Quote]

建议,你先用一下MVC,如果你用过的话

MVC一个模式,很多编程语言都支持MVC,比如.ENT,JAVA,等。
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 r01cn 的回复:]
ASP.NET的MVC中,视图一样可以重用 —— 部分视图(Partial View)就可以作为其它视图的搭建块。
[/Quote]
重用是指你的一个view可以用在不同的项目中,也可以用在呈现不同的业务,
你所说的viewpart组装对于任何现有的常见的开发工具都是最基本的能力
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 r01cn 的回复:]
ASP.NET的MVC中,视图一样可以重用 —— 部分视图(Partial View)就可以作为其它视图的搭建块。

我觉得你对ASP.NET MVC并不十分了解,所以别妄加批评。若大一个微软公司推出MVC,而且正在不断发展和改善,足以说明其MVC有它的特点和长处,也会不断改进和提高。
[/Quote]
asp.netMVC刚发明的时候,我们第一时间就进行了评估,希望能应用到我们的MVC设计中去,
我知道如何利用asp.netMVC去构造真正符合MVC设计模式的视图,而不是像你贴出的那些代码,
但是,如果asp.netMVC连最起码的控件都不提供,
我们宁可使用html+js作为web客户端平台,反正也是要自己开发控件,还不如搞个能跨平台的

我最后再次强调,我从来没有批评过asp.netMVC,
这个东西只不过是一种view方案,和winform,webform以及其他view方案一样可以选择,
微软出于商业目的给它起了个带有MVC字样的名字,
无论如何不能把MVC和这个混为一谈
r01cn 2011-09-25
  • 打赏
  • 举报
回复

ASP.NET的MVC中,视图一样可以重用 —— 部分视图(Partial View)就可以作为其它视图的搭建块。

我觉得你对ASP.NET MVC并不十分了解,所以别妄加批评。若大一个微软公司推出MVC,而且正在不断发展和改善,足以说明其MVC有它的特点和长处,也会不断改进和提高。
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
看到这些代码,你只能看出来跟查询有关,但是不知道具体是查询什么对象,
这才是有重用价值的视图,它可以用在任何项目,任何需要这种外观的业务
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
如何创建视图,举例如下:
public virtual void CreateView_Search() {
this.div_1_1.Controls.Add(ViewDrv.MethodViewDrv.CreateView(this.Model.MethodSearch));
}//end CreateView_Search
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
这些代码到处都是,楼主的就是:
[Quote=引用 2 楼 r01cn 的回复:]
<div>
@ViewBag.Greeting, world (from the view)
</div>
[/Quote]
这个视图根本就没有重用价值
MVC模式下,这个div的内容是在运行时刻动态渲染的,甚至这个div也是动态渲染的,
就好比,显示器本身没有图像,显卡输出信号的时候才呈现千变万化的内容,
有些熟悉操作的人,甚至不需要显示器,也可以操作电脑,

而且,在web开发中,使用asp.net的代理人机制,有个很大的作用,
那就是"动态生成静态视图",一直到Model的定义发生变化,才重绘这个视图,
这样可以避免每次呈现都渲染相同的视图带来的性能问题,
不过这需要开发组织有动态装载Model的能力,比如像这样:
protected virtual AppCenter4.IModel.IOrdinaryModel Model {
get {
if(this.ViewState[m_ModelName] == null) {
string _FormName = this.FileName.Replace(".aspx", "");
this.ViewState[m_ModelName] = new AppCenter4.Models.OrdinaryModel(MyApp.AppKey, _FormName);
}
return (AppCenter4.IModel.IOrdinaryModel)this.ViewState[m_ModelName];
}
set { this.ViewState[m_ModelName] = value; }
}
MSDNXGH 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 moneysoft 的回复:]
那我只能说,你心目中的MVC就是:asp.netMVC
不是说他的名字里有MVC或者view这些字样,就可以叫MVC设计模式的
实现MVC的各层职责的组件的可替换性极强,重用价值极高,可以无限扩展和细分,

比如,你设计一个View,它可以承载各种不同的业务实现,
并且这个view通过不同的viewController可以推送到winform,webform,html+js,SL等多种U……
[/Quote]

这当然就是啊,.NETMVC也是这样啊

view通过不同的viewController可以推送到winform,webform,html+js,SL等多种UI平台

你说:asp.netMVC的样板程序连视图都没有动态渲染,UI中居然还写着数据相关的代码,
说个例子看看。
r01cn 2011-09-25
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 moneysoft 的回复:]

那我只能说,你心目中的MVC就是:asp.netMVC
不是说他的名字里有MVC或者view这些字样,就可以叫MVC设计模式的
实现MVC的各层职责的组件的可替换性极强,重用价值极高,可以无限扩展和细分,

比如,你设计一个View,它可以承载各种不同的业务实现,
并且这个view通过不同的viewController可以推送到winform,webform,html+js,SL等多种……
[/Quote]

sigh...,云里雾里的,不知你都说些什么...

你多次提View,视图(View)只不过是MVC模式中的一部分,用来做页面表现的
qq2013 2011-09-25
  • 打赏
  • 举报
回复
学习,学习班
--缪军-- 2011-09-25
  • 打赏
  • 举报
回复
那我只能说,你心目中的MVC就是:asp.netMVC
不是说他的名字里有MVC或者view这些字样,就可以叫MVC设计模式的
实现MVC的各层职责的组件的可替换性极强,重用价值极高,可以无限扩展和细分,

比如,你设计一个View,它可以承载各种不同的业务实现,
并且这个view通过不同的viewController可以推送到winform,webform,html+js,SL等多种UI平台
在真正的企业应用里,
相同的View承载不同的业务,或者相同的view同时出现在桌面客户端和web客户端,是家常便饭,
当客户需要订单登记同时提供桌面版和web版,难不成你们还要设计2遍吗?
那采用MVC模式又意义何在呢?
就算是提供手机版,也仅仅是设计一个新的view
加载更多回复(11)

62,041

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧