ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

学习MVC项目在7天-第6天

2020-08-08 09:02:32  阅读:202  来源: 互联网

标签:Code 项目 URL 视图 学习 MVC 线程 public 路由


介绍 欢迎来到第6天“学习MVC项目7天”系列。希望你们在第一天到第五天读得愉快。前几天必须在第6天之前完成。 完整的系列 第1天第2天第3天第4天第5天第6天7天奖金第1天奖金第2天 我们很高兴地宣布,这篇文章现在可以从www.amazon.com和www.flipkart.com获得同样的纸质书 议程 实验室27 -添加批量上传选项讲实验室27个问题在上面的解决方案解决方案实验室28 - 29 -异常处理解决线程饥饿问题实验室显示自定义错误页面谈论实验室29以上理解限制在实验室实验室30 -异常处理日志异常实验室30路由了解routetable了解ASP。NET MVC请求周期实验室31 -实现用户友好的url讨论实验室31结论 实验27 -添加批量上传选项 在这个实验室中,我们将创建一个选项,用于从CSV文件中上传多个员工。 我们将在这里学到两件新事情。 如何使用文件上传控制异步控制器。 步骤1 -创建FileUploadViewModel 在ViewModels文件夹中创建一个名为FileUploadViewModel的新类,如下所示。 隐藏,复制Code

public class FileUploadViewModel: BaseViewModel
{
    public HttpPostedFileBase fileUpload {get; set ;}
}

HttpPostedFileBase将提供客户机对上传文件的访问。 步骤2 -创建BulkUploadController和索引操作 创建一个名为BulkUploadController的新控制器和一个名为Index action的操作方法,如下所示。 隐藏,复制Code

public class BulkUploadController : Controller
{
        [HeaderFooterFilter]
        [AdminFilter]
        public ActionResult Index()
        {
            return View(new FileUploadViewModel());
        } 
}

如您所见,索引操作附加了HeaderFooterFilter和AdminFilter属性。HeaderFooterFilter确保将正确的页眉和页脚数据传递给ViewModel,而AdminFilter则限制非admin用户对操作方法的访问。 步骤3 -创建上传视图 为上面的操作方法创建一个视图。 请注意,视图名称应该是index。cshtml,应该放在" ~/Views/BulkUpload "文件夹中。 步骤4 -设计上传视图 在视图中放置以下内容。 隐藏,复制Code

@using WebApplication1.ViewModels
@model FileUploadViewModel
@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
}

@section TitleSection{
    Bulk Upload
}
@section ContentBody{
    <div> 
    <ahref="/Employee/Index">Back</a>
        <formaction="/BulkUpload/Upload"method="post"enctype="multipart/form-data">
            Select File : <inputtype="file"name="fileUpload"value=""/>
            <inputtype="submit"name="name"value="Upload"/>
        </form>
    </div>
}

正如您在FileUploadViewModel中看到的,属性的名称和输入的名称[type="file"]是相同的。这是“类”。我们在模型绑定实验室中谈到了名称属性的重要性。注意:在标签的形式中指定了一个附加属性,即enctype。我们会在实验的最后讨论这个问题。 步骤5 -创建业务层上传方法 在employeebusinesslayer中创建一个名为duploademployees的新方法,如下所示。 隐藏,复制Code

public void UploadEmployees(List<Employee> employees)
{
    SalesERPDAL salesDal = new SalesERPDAL();
    salesDal.Employees.AddRange(employees);
    salesDal.SaveChanges();
}<employee>
</employee>

步骤6 -创建上传动作方法 在BulkUploadController中创建一个名为Upload的新操作方法,如下所示。 隐藏,复制Code

[AdminFilter]
public ActionResult Upload(FileUploadViewModel model)
{
    List<Employee> employees = GetEmployees(model);
    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
    bal.UploadEmployees(employees);
    return RedirectToAction("Index","Employee");
}

private List<Employee> GetEmployees(FileUploadViewModel model)
{
    List<Employee> employees = new List<Employee>();
    StreamReader csvreader = new StreamReader(model.fileUpload.InputStream);
    csvreader.ReadLine(); // Assuming first line is header
    while (!csvreader.EndOfStream)
    {
        var line = csvreader.ReadLine();
        var values = line.Split(',');//Values are comma separated
        Employee e = new Employee();
        e.FirstName = values[0];
        e.LastName = values[1];
        e.Salary = int.Parse(values[2]);
        employees.Add(e);
    }
    return employees;
}

附加到上传操作的AdminFilter限制非管理员用户的访问。 步骤7 -为BulkUpload创建一个链接 AddNewLink开放。从“Views/Employee”文件夹中下载cshtml,并将下面的BulkUpload链接。 隐藏,复制Code

<ahref="/Employee/AddNew">Add New</a>
&nbsp;
&nbsp;
<ahref="/BulkUpload/Index">BulkUpload</a>

步骤8 -执行和测试 步骤8.1 -创建用于测试的样例文件 创建一个示例文件,如下所示,并将其保存在计算机中的某个地方。 步骤8.2 -执行和测试 按F5并执行应用程序。完成登录过程并通过单击链接导航到BulkUpload选项。 选择文件并点击上传。 注意: 在上面的示例中,我们没有在视图中应用任何客户端或服务器端验证。这可能会导致以下错误。 "一个或多个实体验证失败。有关更多细节,请参见“EntityValidationErrors”属性。 要查找错误的确切原因,只需在异常发生时添加一个带有以下手表表达式的手表。 ((System.Data.Entity.Validation.DbEntityValidationException)例外)美元.EntityValidationErrors 监视表达式' $exception '显示当前上下文中抛出的任何异常,即使它没有被捕获并分配给变量。 在27实验室演讲 为什么这里没有验证呢? 向此选项添加客户端和服务器端验证将是读者的一个分配。我给你们一个提示。 对于服务器端验证,使用数据注释。对于客户端,您可以利用数据注释和实现jQuery不显眼的验证。显然,这次您必须手动设置自定义数据属性,因为我们还没有readymade Htmlhelper方法用于文件输入。 注意:如果您还没有理解这一点,我建议您再次完成“在登录视图中植入客户端验证”。对于客户端验证,您可以编写自定义JavaScript并在单击按钮时调用它。这并不困难,因为文件输入说到底是一个输入控件,它的值可以在JavaScript中检索并验证。 HttpPostedFileBase是什么? HttpPostedFileBase将提供对客户机上传的文件的访问。模型绑定器将在发布请求期间更新所有属性FileUploadViewModel类的值。现在我们在FileUploadViewModel中只有一个属性,模型绑定器会将其设置为客户端上传的文件。 有可能提供吗e多文件输入控制? 是的,我们可以通过两种方式实现。 创建多个文件输入控件。每个控件必须有唯一的名称。现在在FileUploadViewModel类中为每个控件创建类型为HttpPostedFileBase的属性。每个属性名称应该与一个控件的名称匹配。剩下的魔术将由ModelBinder完成。☺create多个文件输入控件。每个控件必须具有相同的名称。现在不是创建HttpPostedFileBase类型的多个属性,而是创建一个List< httppostedfilebase>类型的属性。 注:以上情况适用于所有控件。如果属性是一个简单参数,那么当您拥有多个同名控件时,ModelBinder将使用第一个控件的值更新属性。如果属性是列表属性,ModelBinder将把每个控件的值放在列表中。 enctype="multipart/form-data"将做什么? 这不是一个很重要的事情,但是知道这个肯定很好。 此属性指定在发布数据时使用的编码类型。 这个属性的默认值是“application/x-www-form-urlencoded” 示例-我们的登录表单将发送以下post请求到服务器 隐藏,复制Code

POST /Authentication/DoLogin HTTP/1.1
Host: localhost:8870
Connection: keep-alive
Content-Length: 44
Content-Type: application/x-www-form-urlencoded
...
...
UserName=Admin&Passsword=Admin&BtnSubmi=Login

所有输入值都以“&”连接的键/值对的形式作为一部分发送。 当将enctype="multipart/form-data"属性添加到表单标签时,后续的post请求将发送到服务器。 隐藏,复制Code

POST /Authentication/DoLogin HTTP/1.1
Host: localhost:8870
Connection: keep-alive
Content-Length: 452
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywHxplIF8cR8KNjeJ
...
...
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="UserName"

Admin
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="Password"

Admin
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="BtnSubmi"

Login
------WebKitFormBoundary7hciuLuSNglCR8WC--

如你所见,表单是在多个部分张贴。每个部分由Content-Type定义的边界分隔,每个部分包含一个值。 如果表单标签包含文件输入控件,则必须将encType设置为“multipart/form-data”。 注意:边界将在每次请求时随机生成。你可能会看到一些不同的边界。 为什么我们不总是设置encType为“multipart/form-data”? 当encType被设置为“multipart/form-data”时,它会同时做两件事——发布数据和上传文件。那么为什么我们不总是将其设置为“multipart/form-data”呢? 答案是,它还会增加请求的总体大小。请求的大小越大,性能就越差。因此,作为最佳实践,我们应该将其设置为默认值,即“application/x-www-form-urlencoded”。 为什么我们在这里创建ViewModel ? 我们的视图中只有一个控件。我们可以通过直接在Upload操作方法中添加一个名为fileUpload的类型为HttpPostedFileBase的参数来实现相同的结果,而不是创建一个单独的ViewModel。请看下面的代码。 隐藏,复制Code

public ActionResult Upload(HttpPostedFileBase fileUpload)
{
}

那么为什么我们要创建一个单独的类呢? 创建ViewModel是最佳实践。控制器应该总是以ViewModel的形式向视图发送数据,从视图发送的数据应该以ViewModel的形式发送给控制器。 问题在上面解决 您是否曾经想过在发送请求时如何获得响应? 现在不要说,动作方法接收请求等等!!☺ 虽然这是正确的答案,但我希望会有一些不同的答案。 我的问题是一开始会发生什么。 一个简单的编程规则——程序中的一切都是由线程执行的,甚至是一个请求。 在Asp.net的情况下,。net framework维护了一个线程池。 每当一个请求被发送到web服务器时,就会从池中分配一个空闲线程来处理该请求。这个线程将被称为工作线程。 工作线程将被阻塞时,请求正在处理,不能服务于另一个请求。 现在让我们假设一个应用程序接收了太多的请求,并且每个请求将花费很长时间来完全处理。在这种情况下,我们可能会在新请求进入没有工作线程可用来服务该请求的状态时结束。这被称为线程短缺。 在我们的例子中,示例文件有2条员工记录,但在实时情况下,它可能包含数千条或缺少记录。这意味着请求将花费大量的时间来完成处理。它可能会导致线程饥饿。 解决方案 现在,我们到目前为止讨论的请求的类型是synchronous request。 而不是同步,如果客户端做一个异步请求,线程短缺的问题得到解决。 在异步请求的情况下,通常从线程池中分配工作线程来服务请求。工作线程启动异步操作并返回线程池服务另一个请求。异步操作现在将由CLR线程继续。现在的问题是,CLR线程不能返回响应,所以一旦它完成异步操作,它会通知ASP.NET。Webserver再次从线程池中获取工作线程,处理剩余的请求并呈现响应。 在整个场景中,从线程池中检索工作线程两次。它们可能是同一条线,也可能不是。 在我们的示例中,读取文件是一个I/O绑定操作,它不需要由工作线程处理。所以这是变换s的最佳位置同步请求到异步请求。 异步请求是否提高了响应时间? 不,响应时间将保持不变。在这里,线程将被释放以处理其他请求。 实验室28 -解决线程饥饿问题 在ASP。我们可以通过将同步动作方法转换为异步动作方法来将同步请求转换为异步请求。 步骤1 -创建异步控制器 将UploadController的基类从Controller更改为AsynController。 隐藏,复制Code

{
    public class BulkUploadController : AsyncController
    {

步骤2 -将同步操作方法转换为异步操作方法 在两个关键字的帮助下,可以很容易地完成异步和等待。 隐藏,复制Code

[AdminFilter]
public async Task<ActionResult> Upload(FileUploadViewModel model)
{
    int t1 = Thread.CurrentThread.ManagedThreadId;
    List<Employee> employees = await Task.Factory.StartNew<List<Employee>>
        (() => GetEmployees(model));
    int t2 = Thread.CurrentThread.ManagedThreadId;
    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
    bal.UploadEmployees(employees);
    return RedirectToAction("Index", "Employee");
}<actionresult><employee><list<employee>
</list<employee></employee></actionresult>

正如您所看到的,我们在操作方法的开头和结尾将线程id存储在一个变量中。 让我们来理解一下代码。 当客户端单击upload按钮时,新的请求将发送到服务器。Webserver将从线程池中获取一个工作线程,并分配它来服务于请求。工作线程使动作方法执行。Worker方法在Task.Factory的帮助下启动一个异步操作。StartNew方法。可以看到,在async关键字的帮助下,动作方法被标记为异步。它将确保工作线程在异步操作开始时就被释放。从逻辑上讲,异步操作将通过单独的CLR线程在后台继续执行。现在异步操作调用被标记为await关键字。它将确保除非异步操作完成,否则下一行不会执行。一旦异步操作完成,动作方法中的下一个语句就应该执行,为此,同样需要一个工作线程。因此,webserver将从线程池中获取一个新的空闲工作线程,并分配它来服务剩余的请求和呈现响应。 步骤3 -执行和测试 执行应用程序。导航到BulkUpload选项。 现在,在对输出执行更多操作之前,导航到代码并在最后一行放置断点。 现在选择示例文件并单击Upload。 正如您所看到的,开头和结尾的线程id不同。输出和之前的实验一样。 实验29 -异常处理-显示自定义错误页面 一个项目如果没有适当的异常处理,就不会被认为是一个完整的项目。 到目前为止,我们已经讨论了Asp中的两个过滤器。操作过滤器和授权过滤器。现在是第三个例外过滤器的时候了。 什么是异常过滤器? 使用异常过滤器的方式与使用其他过滤器的方式相同。我们将使用它们作为属性。 使用异常筛选器的步骤 使他们。将它们作为属性应用于操作方法或控制器。我们还可以在全局级别应用异常过滤器。 他们会怎么做? 异常过滤器将控制执行,并在操作方法中一旦发生异常,就自动开始执行在其内部编写的代码。 有自动化吗? ASP。NET MVC提供了一个现成的异常过滤器称为HandeError。 如前所述,当操作方法中出现异常时,它将执行。这个过滤器会在“~/Views/[当前控制器]”或“~/Views/Shared”文件夹中找到一个名为“Error”的视图,创建该视图的ViewResult并作为响应返回。 让我们看一个演示,更好地理解它。 在我们项目的最后一个实验室中,我们实现了BulkUpload选项。现在输入文件出错的可能性很大。 步骤1 -创建一个带有错误的示例上传文件 像前面一样创建一个示例上传文件,但是这次放了一些无效的值。 如你所见,工资是无效的。 步骤2 -执行并测试异常 按F5并执行应用程序。导航到批量上传选项。选择上面的文件并点击上传。 步骤3 -启用异常过滤器 在启用自定义异常时启用异常过滤器。要启用自定义异常,请打开web。配置文件,并导航到系统。网络部分。为自定义错误添加一个新的部分,如下所示。 隐藏,复制Code

<system.web>
   <customErrorsmode="On"></customErrors>

步骤4 -创建错误视图 在“~/Views/Shared”文件夹中,你会发现一个名为“Error.cshtml”的视图。这个文件只是在开始时作为mvc模板的一部分创建的。如果没有创建,请手动创建。 隐藏,复制Code

@{
    Layout = null;
}

<!DOCTYPEhtml>
<html>
<head>
    <metaname="viewport"content="width=device-width"/>
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1>Error.</h1>
        <h2>An error occurred while processing your request.</h2>
    </hgroup>
</body>
</html>

& lt; hgroup> 步骤5 -附加异常过滤器 如前所述,启用异常过滤器后,我们将它们附加到操作方法或控制器。 好消息。不需要手动连接它。 从App_Start文件夹中打开FilterConfig.cs文件。在RegisterGlobalFilters方法中,您将看到HandleError过滤器已经在全局级别上附加。 隐藏,复制Code

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());//ExceptionFilter
    filters.Add(new AuthorizeAttribute());
}

如果需要,删除全局过滤器并将其附加在操作或控制器级别,如下所示。 隐藏,复制Code

[AdminFilter]
[HandleError]
public async Task<ActionResult> Upload(FileUploadViewModel model)
{<actionresult>
</actionresult>

不建议这样做。最好是在全球层面上应用。 步骤6 -执行和测试 让我们用与前面相同的方法测试这个应用程序。 步骤7 -在视图中显示错误信息 为了实现这个转换错误视图为类型HandleErrorInfo类的强类型视图,然后在视图中显示错误消息。 隐藏,复制Code

@model HandleErrorInfo
@{
    Layout = null;
}

<!DOCTYPEhtml>
<html>
<head>
    <metaname="viewport"content="width=device-width"/>
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1>Error.</h1>
        <h2>An error occurred while processing your request.</h2>
    </hgroup>
        Error Message :@Model.Exception.Message<br/>
        Controller: @Model.ControllerName<br/>
        Action: @Model.ActionName
</body>
</html>

步骤8 -执行和测试 执行相同的测试,但这一次我们将得到以下错误视图。 我们是不是漏掉了什么? 处理错误属性确保在操作方法中发生异常时显示自定义视图。但是它的功能仅限于控制器和动作方法。它不会处理“资源未找到”错误。 执行应用程序并在URL中添加一些奇怪的内容 步骤9 -创建ErrorController,如下所示 在控制器文件夹中创建一个名为ErrorController的新控制器,并创建一个名为Index的操作方法,如下所示。 隐藏,复制Code

public class ErrorController : Controller
{
    // GET: Error
    public ActionResult Index()
    {
        Exception e=new Exception("Invalid Controller or/and Action Name");
        HandleErrorInfo eInfo = new HandleErrorInfo(e, "Unknown", "Unknown");
        return View("Error", eInfo);
    }
}

HandleErrorInfo构造函数有3个参数——异常对象、控制器名称和操作方法名称。 在无效的URL上显示自定义错误视图 在网络上。配置定义“资源未找到错误”的设置如下。 隐藏,复制Code

<system.web>
    <customErrorsmode="On">
      <errorstatusCode="404"redirect="~/Error/Index"/>
    </customErrors>

步骤11 -让每个人都可以访问ErrorController 将AllowAnonymous属性应用到ErrorController,因为错误控制器和索引操作不应该绑定到经过身份验证的用户。用户可能在登录前输入了无效的URL。 隐藏,复制Code

[AllowAnonymous]
public class ErrorController : Controller
{

步骤12 -执行和测试 执行应用程序并在地址栏中放置一些无效的URL。 在29实验室演讲 是否可以更改视图名称? 是的,不需要将视图名称始终保持为“错误”。 在这种情况下,我们必须在附加HandlError过滤器时指定视图名。 隐藏,复制Code

[HandleError(View="MyError")]
Or
filters.Add(new HandleErrorAttribute()
                {
                    View="MyError"
                });

有可能为不同的异常获得不同的错误视图吗? 是的,这是可能的。在这种情况下,我们必须多次应用处理错误过滤器。 隐藏,复制Code

[HandleError(View="DivideError",ExceptionType=typeof(DivideByZeroException))]
[HandleError(View = "NotFiniteError", ExceptionType = typeof(NotFiniteNumberException))]
[HandleError]

OR

filters.Add(new HandleErrorAttribute()
    {
        ExceptionType = typeof(DivideByZeroException),
        View = "DivideError"
    });
filters.Add(new HandleErrorAttribute()
{
    ExceptionType = typeof(NotFiniteNumberException),
    View = "NotFiniteError"
});
filters.Add(new HandleErrorAttribute());

在上面的例子中,我们添加了三次处理错误过滤器。前两个是特定于异常的,而最后一个是更一般的,它将显示所有其他异常的错误视图。 了解上述实验室的局限性 唯一的限制与上述实验室是我们不记录我们的异常任何地方。 实验30 -异常处理-日志异常 步骤1 -创建记录器类 在项目的根位置创建一个名为Logger的新文件夹。 在Logger文件夹中创建一个名为FileLogger的新类,如下所示。 隐藏,复制Code

namespace WebApplication1.Logger
{
    public class FileLogger
    {
        public void LogException(Exception e)
        {
            File.WriteAllLines("C://Error//" + DateTime.Now.ToString("dd-MM-yyyy mm hh ss")+".txt", 
                new string[] 
                {
                    "Message:"+e.Message,
                    "Stacktrace:"+e.StackTrace
                });
        }
    }
}

步骤2 -创建EmployeeExceptionFilter类 在过滤器文件夹中创建一个名为EmployeeExceptionFilter的新类,如下所示。 隐藏,复制Code

namespace WebApplication1.Filters
{
    public class EmployeeExceptionFilter
    {
    }
}

步骤3 -扩展句柄错误以实现日志记录 从HandleErrorAttribute类继承EmployeeExceptionFilter并覆盖OnException方法,如下所示。 隐藏,复制Code

public class EmployeeExceptionFilter:HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);
    }
}

注意:请务必使用System.Web。MVC在顶部。HandleErrorAttribute类存在于此名称空间中。 步骤4 -定义OnException方法 在OnException方法中包含异常日志代码,如下所示。 隐藏,复制Code

public override void OnException(ExceptionContext filterContext)
{
    FileLogger logger = new FileLogger();
    logger.LogException(filterContext.Exception);
    base.OnException(filterContext);
}

步骤5 -更改默认异常过滤器 打开FilterConfig.cs文件,删除HandErrorAtrribute并附加我们在最后一步中创建的文件,如下所示。 隐藏,复制Code

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    //filters.Add(new HandleErrorAttribute());//ExceptionFilter
    filters.Add(new EmployeeExceptionFilter());
    filters.Add(new AuthorizeAttribute());
}

步骤6 -执行和测试 首先,在C驱动器中创建一个名为“Error”的文件夹,因为这是错误文件将要放置的地方。 注意:如果需要,将路径更改为您想要的路径。 按F5并执行应用程序。导航到批量上传选项。选择上面的文件并点击上传。 这次的输出也不会有什么不同。我们会得到和之前一样的错误视图。唯一的区别是,这次我们还会找到一个在“C:\\Errors”文件夹中创建的错误文件。 关于30号实验室的演讲 当异常发生时,如何返回错误视图作为响应? 在上面的实验室中,我们覆盖了OnException方法并实现了异常日志记录功能。现在的问题是,为什么默认的处理错误过滤器还在工作?这很简单。检查OnException方法的最后一行。 隐藏,复制Code

base.OnException(filterContext);

这意味着,让基类OnException来做重命名工作,基类OnException将返回错误视图的ViewResult。 我们可以在OnException中返回其他结果吗? 是的。请看下面的代码。 隐藏,复制Code

public override void OnException(ExceptionContext filterContext)
{
    FileLogger logger = new FileLogger();
    logger.LogException(filterContext.Exception);
    //base.OnException(filterContext);
    filterContext.ExceptionHandled = true;
    filterContext.Result = new ContentResult()
    {
        Content="Sorry for the Error"
    };
}

当我们想返回自定义响应,我们应该做的第一件事是,通知MVC引擎,我们已经手动处理异常,所以不要执行默认行为,即不显示默认的错误屏幕。这将通过以下语句完成。 隐藏,复制Code

filterContext.ExceptionHandled = true

你可以阅读更多关于ASP中的异常处理。净MVC这里 路由 到目前为止,我们已经讨论了很多概念,我们回答了很多关于MVC的问题,除了一个基本的和重要的问题。 “当最终用户发出请求时,到底会发生什么?” 答案肯定是“行动方法”执行”。但我的确切问题是,如何为特定的URL请求标识控制器和动作方法。 在我们开始我们的实验室“实现用户友好的url”之前,首先让我们找出上面问题的答案。你可能想知道为什么这个话题会出现在结尾。我故意把这个主题放在接近尾声的地方,因为我想让人们在理解内部内容之前就充分了解MVC。 理解RouteTable 在Asp。有一个概念叫做RouteTable,它将为应用程序存储URL路由。简单地说,它包含一个定义应用程序可能的URL模式的集合。 默认情况下,一个路由将作为项目模板的一部分添加到其中。检查它打开全局。asax文件。在Application_Start中,您将发现如下语句。 隐藏,复制Code

RouteConfig.RegisterRoutes(RouteTable.Routes);

您将在App_Start文件夹中找到RouteConfig.cs文件,该文件包含以下代码块。 隐藏,复制Code

namespace WebApplication1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

正如您在RegisterRoutes方法中看到的,已经在route的帮助下定义了一个默认路由。MapRoute方法。 在RegisterRoutes方法中定义的路由将在稍后的asp.net中使用。Net MVC请求周期确定要执行的控制器和动作方法。 如果需要的话,我们可以使用route创建多个路由。MapRoute函数。在内部定义route意味着创建route对象。 MapRoute函数还将RouteHandler附加到route对象上,该对象在ASP中为MVCRouteHandler。NET MVC默认。 了解ASP。NET MVC请求周期 在你开始之前,让我让你清楚,我们不打算解释100%的请求周期在这里。我们只会接触重要的人。 步骤1 - urlrouting模块 当最终用户发出请求时,它首先通过UrlRoutingModule对象传递。UrlRoutingModule是一个HTTP模块。 步骤2 -路由 UrlRoutingModule将从路由表集合中获取第一个匹配的路由对象。现在进行匹配,请求URL将与路由中定义的URL模式进行比较。 匹配时将考虑以下规则。 请求URL(不包括域名)和路由中定义的URL模式中的参数数量 例子: URL模式中定义的可选参数 例子: 在参数中定义的静态参数 步骤3 -创建MVC路由处理程序 选择Route对象后,UrlRoutingModule将从Route对象获得MvcRouteHandler对象。 步骤4 -创建RouteData和RequestContext UrlRoutingModule对象将使用Route对象创建RouteData,然后使用该对象创建RequestContext。 RouteData封装了关于路由的信息,如控制器的名称、操作的名称和路由参数的值。 控制器名称 为了从请求URL获得控制器名称,遵循以下简单规则。"在URL模式中,{controller}是识别控制器名称的关键字"。 例子: 当URL模式为{controller}/{action}/{id},请求URL为“http://localhost:8870/bulkupload / upload/5”时,BulkUpload将是控制器的名称。当URL模式为{action}/{controller}/{id},请求URL为“http://localhost:8870/bulkupload / upload/5”时,Upload将是控制器的名称。 动作方法的名字 为了从请求URL获得动作方法名称,遵循以下简单规则。"在URL模式中,{action}是识别动作方法名称的关键字"。 例子: 当URL模式为{controller}/{action}/{id},请求URL为“http://localhost:8870/bulkupload / upload/5”时,Upload将是动作方法的名称。当URL模式是{action}/{controller}/{id}并且请求URL是“http://localhost:8870/bulkupload / upload/5”时,BulkUpload 将是动作方法的名称。 线路参数 基本上,URL模式可以包含以下四点 {控制器}→标识控制器名称{action} ->标识actionmethod名字。SomeString→示例-“MyCompany/{controller}/{action}”->在此模式中,“MyCompany”成为强制字符串。{一}→示例-“{controller}/{action}/{id}”->在这个模式中,“id”是路由参数。Route参数可用于在请求时获取URL本身的值。 请看下面的示例。 路线模式- >“{控制器}/{行动}/ {id}” 请求URL→http://localhost: 8870 / BulkUpload /上传/ 5 测试1 隐藏,复制Code

public class BulkUploadController : Controller
{
    public ActionResult Upload (string id)
    {
       //value of id will be 5 -> string 5
       ...
    }
}

测试2 隐藏,复制Code

public class BulkUploadController : Controller
{
    public ActionResult Upload (int id)
    {
       //value of id will be 5 -> int 5
       ...
    }
}

测试3 隐藏,复制Code

public class BulkUploadController : Controller
{
    public ActionResult Upload (string MyId)
    {
       //value of MyId will be null
       ...
    }
}

步骤5 -创建MVCHandler MvcRouteHandler将创建传递RequestContext对象的MVCHandler的实例。 步骤6 -创建控制器实例 MVCHandler将在ControllerFactory的帮助下创建控制器实例(默认情况下为DefaultControllerFactory)。 第7步-执行方法 MVCHandler将调用控制器的执行方法。执行方法是在控制器基类内部定义的。 步骤8 -调用动作方法 每个控制器都与一个Cont相关联rollerActionInvoker对象。在执行方法ControllerActionInvoker对象内部调用正确的操作方法。 步骤9 -执行结果。 Action方法接收用户输入并准备适当的响应数据,然后通过返回一个返回类型来执行结果。返回类型可以是ViewResult,也可以是RedirectToRoute Result,也可以是其他类型。 现在我相信您已经很好地理解了路由的概念,所以让我们的项目url在路由的帮助下更加用户友好。 实验室31 -实现用户友好的url 步骤1 -重新定义RegisterRoutes方法 如下所示,在RegisterRoutes方法中包含其他路由。 隐藏,复制Code

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
    name: "Upload",
    url: "Employee/BulkUpload",
    defaults: new { controller = "BulkUpload", action = "Index" }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

正如您现在看到的,我们定义了不止一个路由。 (默认路径保持不变。) 步骤2 -更改URL引用 AddNewLink开放。从“~/Views/Employee”文件夹中的cshtml更改BulkUpload链接,如下所示。 隐藏,复制Code

&nbsp;
<ahref="/Employee/BulkUpload">BulkUpload</a>

步骤3 -执行和测试 执行该应用程序并看到奇迹。 正如你所看到的,URL不再是“控制器/动作”的形式。相反,它更便于用户使用,但输出是相同的。 我建议您定义更多的路由并尝试更多的url。 关于31实验室的演讲 以前的URL现在工作吗? 是的,以前的URL也可以。 现在可以从两个url访问BulkUploadController中的索引操作 “http://localhost: 8870 /员工/ BulkUpload”“http://localhost: 8870 / BulkUpload指数” 默认路由中的“id”是什么? 我们已经说过了。它被称为路由参数。它可用于通过URL获取值。它是查询字符串的替代品。 路由参数和查询字符串之间的区别是什么? 查询字符串有大小限制,而我们可以定义任意数量的路由参数。我们不能向查询字符串值添加约束,但可以向路由参数添加约束。路由参数的默认值是可能的,而查询字符串的默认值是不可能的。查询字符串使URL混乱,而路由参数保持干净。 如何将约束应用到路由参数? 这可以在正则表达式的帮助下完成。 例子:看看下面的路线。 隐藏,复制Code

routes.MapRoute(
    "MyRoute",
    "Employee/{EmpId}",
    new {controller=" Employee ", action="GetEmployeeById"},
    new { EmpId = @"\d+" }
 );

操作方法如下所示。 隐藏,复制Code

public ActionResult GetEmployeeById(int EmpId)
{
   ...
}

现在,当有人用URL“http://..”发出请求时。/员工/ 1”或“http://..。/ employee/111 "时,action方法将被执行,但当有人发出URL为" http://..他/她将得到“资源未找到”的错误。 操作方法中的参数名是否需要与路由参数名相同? 基本上,单个路由模式可以包含一个或多个涉及的路由参数。为了独立地识别每个路由参数,必须将操作方法中的参数名称与路由参数名称保持一致。 序列在定义自定义路由时重要吗? 是的,这很重要。如果你还记得UrlRoutingModule会先取匹配的route对象。 在上面的实验室中,我们定义了两条路线。一个自定义路由和一个默认路由。现在,假设对于一个实例,首先定义默认路由,然后定义自定义路由。 在本例中,当最终用户使用URL“http://..”发出请求时。在比较阶段,UrlRoutingModule会发现所请求的URL与默认路由模式匹配,并将“Employee”作为控制器名,“BulkUpload”作为操作方法名。 因此,序列在定义路由时非常重要。大多数通用路由应该保留在最后。 有没有一种更简单的方法来定义动作方法的URL模式? 我们可以使用基于属性的路由。 让我们试一试。 步骤1 -启用基于属性的路由。 在RegisterRoutes方法中,保持跟随IgnoreRoute语句之后的行。 隐藏,复制Code

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapMvcAttributeRoutes();

routes.MapRoute(
...

步骤2 -定义一个动作方法的路由模式 简单地将路由属性附加到动作方法到EmployeeController的索引动作,如下所示。 隐藏,复制Code

[Route("Employee/List")]
public ActionResult Index()
{

步骤3 -执行和测试 执行应用程序并完成登录过程。 正如您所看到的,我们有相同的输出,但使用了不同的更用户友好的URL。 我们可以用基于属性的路由定义路由参数吗? 是的,看看下面的语法。 隐藏,复制Code

[Route("Employee/List/{id}")]
publicActionResult Index (string id) { ... }

这种情况下的约束条件是什么? 这样就容易多了。 隐藏,复制Code

[Route("Employee/List/{id:int}")]

我们可以有以下约束条件 {x:α}- {x: bool}字符串验证逻辑验证{x: datetime} -日期时间验证{x:小数}-十进制验证{x:双}- 64位浮点值验证{x:浮动}- 32位浮点值验证{x: guid} - guid验证{x:长度(6)}长度验证{x:长度(20)}- Min和Max长度验证{x:长}- 64 int验证{x: Max (10)} - Max整数验证{x:最大长度(10)}- Max长度验证{x: Min(10)} -最小整数验证{x:minlength(10)} -最小长度验证{x:range(10,50)} -整数范围validation {x:regex(SomeRegularExpression)} -正则表达式验证 在RegisterRoutes方法中IgnoreRoutes做什么? 当我们不想为特定的扩展使用路由时,将使用IgnoreRoutes。作为MVC模板的一部分,下面的语句已经在RegisterRoutes方法中写好了。 隐藏,复制Code

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

它的意思是如果最终用户提出一个请求与延期。这样就不会有任何路由操作。请求将直接到达物理资源。 我们也可以定义自己的IgnoreRoute语句。 结论 到第六天,我们已经完成了示例MVC项目。希望您喜欢完整的系列。 等待! !第七天在哪里? 我的朋友们,第七天就到了。在第7天,我们将使用MVC、jQuery和Ajax创建一个单一页面应用程序。这样会更有趣,也更有挑战。请继续关注☺ 你的评论,邮件总是激励我们做更多。把你的想法和评论写在下面,或者发送邮件到SukeshMarla@Gmail.com 在Facebook, LinkedIn或twitter上联系我们,以保持最新的版本。 如果你想开始与MVC 5开始与下面的视频学习MVC 5在2天。 本文转载于:http://www.diyabc.com/frontweb/news1740.html

标签:Code,项目,URL,视图,学习,MVC,线程,public,路由
来源: https://www.cnblogs.com/Dincat/p/13456354.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有