【Pro ASP.NET MVC 3 Framework】.学习笔记.11.ASP.NET MVC3的细节:概览MVC项目

时间:2022-01-10 04:59:16

书Adam The Definitive Guide to HTML5

Adam Applied ASP.NET 4 in Context and Pro ASP.NET 4

到此为止,我们已经学了为什么ASP.NET MVC框架会出现,认识了建筑和潜在的设计目标。我们已经做了一个很好的测试驱动的实际的电子商务应哟那个。现在是时候打开钩子,揭示框架机制的所有细节。

在本书的第二部分,我们关注细节。从揭示一个ASP.NET MVC程序的结构,和应用请求处理管道开始。接着关注每个特性个体,如routing,controller,action,MVC view系统,带有领域模型的MVC的工作方式。

在这部分的最后两张,我们会看到如何在MVC程序中使用AJAX和jQuery。

概述MVC项目

在我们探索指定MVC特性之前,要提供一些额外的环境上下文。本章我们概述ASP.NET MVC应用的结构和本质,包括默认项目结构和必须遵循的命名规范。

1 使用VS MVC项目模板

当创建一个新的MVC3项目,VS让你选择Empty,Internet Application,Internet Application。Empty项目模板,会创建相对较少的文件和路径,给你最小的结构。

在这个对话框上,可以使用HTML5,微软已经开始添加HTML5到VS。我们忽略了这个选项,MVC框架。

当使用Internet或Intranet应用模板,可以创建单元测试作为VS解决方案的一部分。这两个模板的不同之处在于身份认证机制。

Folder or File Description Notes
/App_Data 这个路径是放置private data,如XML文件或数据库 IIS不会提供这个路径的环境上下文
/bin MVC程序编译过的装配放在这里,和GAC里没有的引用装配 IIS不会提供这个路径的环境上下文。不会再解决方案浏览器中看到bin路径,除非点击show all files按钮
/Content 存放静态上下的地方,如CSS文件和图片 这是个约定,但不是必须的。你可以把静态上下文放在任何地方
/Controllers 这是controller类的地方 这是约定。你可以把controller类放在任何地方,因为他们都被编译到同一个装配里
/Models 这是放置视图模型和领域模型类的地方,尽管简单的应用受益于在专用的项目中创建领域模型 这是约定。你可以定义你的模型类放在地方或单独的项目中
/Scripts 这个路径是放置JavaScript库。VS默认添加jQuery和Microsoft AJAX helpers 这是约定。你可以吧script文件放在任何位置,它们会作为其他类型的静态环境上下文
/Views 这个路径放置视图和局部视图,一般放置在它controller名字的文件家中 /View/Web.config文件预防IIS提供这些路径的上下文。View必须通过action方法被渲染
/Views/Shared 这个路径放置共享的布局和视图  
/Views/Web.config 这不是应用程序的配置文件。它包含views在ASP.NET中工作所必须的配置,防止IIS直接提供views  
/Global.asax 这是全局ASP.NET应用类,它的后端类Global.asax.cs是注册路由配置的地方。像配置任何代码一样运行一样,能够在程序初始化时运行,关闭,或当未经处理的异常发生 Global.asax文件在MVC应用中,和Web Form应用中的角色一样
/Web.config 这是应用的配置文件。 与Web Form应用中的角色一样

MVC应用部署拷贝文件夹结构到web server。处于安全的原因,IIS不提供Web.config,bin,App_code,App_GlobalResources,App_LocalResources,App_WebReferences,App_Data,App_Browsers这些路径中的文件。IIS也会把.asax ,.ascx,.sitemap,.resx,.mdb,.mdf,.ldf,.csproj过滤掉。如果想要调整项目的结构,必须确保不在URLs中使用这些名字和扩展名。

Folder or File Description
/Areas 区域,是把一个大应用分隔成小片的方法。
/App_GlobalResources
/App_LocalResources
这些文件包含本地化Web Forms页面所需要的资源文件
/App_Browsers 这个文件夹包含.browser XML文件,它是描述如何识别指定的web浏览器,已经这个浏览器能干什么
/App_Thems 这个文件夹包含Web Forms主题,包含.skin文件,影响Web Forms如何控制渲染
   

除了/Areas,表中的其他项是核心ASP.NET平台,和MVC应用不是特别有关。

1.1 使用Internet和Intranet应用控制器

这两个模板都有HomeController,它可以渲染Home页面和About页面。这些页面使用默认布局生成。

Internet应用模板还包含AccountController,它允许访问者注册,登录。它使用表单身份验证,保持用户是否登录的轨迹。它使用ASP.NET核心会员设施,记录注册用户的列表。会员设施会在第一次有人尝试着注册或登录时,在/App_Data文件夹试着创建SQL Server Express基于数据库的文件。如果没有安装并且运行SQL Server,这样会在长时间停顿后失败。AccountController也有actions和views,可以让注册用户改变密码。Intranet Application模板省略AccountController,因为它期望使用Windows domain/Active Directory基础设施管理账户和密码。

1.2 理解MVC约定

在MVC项目中,有两种类型的约定。第一种只是建议你如何设置项目的结构。例如,它惯例地将JavaScript文件放在Scripts文件夹。这是其他MVC开发人员期待找到它的地方,也是VS为新MVC项目放置初始化JavaScript文件的地方。但是你可以重命名Scripts文件夹,甚至完全删除它,放置scripts到任何地方。这不会阻碍MVC框架运行。

另一个类型的约定来自约定大于配置的原理。这意味着不用明确配置controller和views的关联。只需要一个明确的controller名字就行了。

所有约定都能使用自定义视图引擎改变。

1.2.1 以下是控制器类的约定

Controller类的名字必须以Controller结尾,如ProductController。当从MVC route或HTML helper方法参照controller,需要制定名字的第一部分,如Product,DefaultControllerFactory类会自动在名字后附加Controller,并开始寻找controller类。可以通过创建自定义的IControllerFactory接口的实现,改变这个行为。

1.2.2 以下是视图的约定

视图和局部视图应该在它关联的控制器名字的文件夹下,如ProductController类的关联视图应在/View/Product文件夹下。

MVC框架期望action方法的默认视图,应以它的名字命名。例如,List action方法的关联视图应叫List.cshtml,如果使用ASPX视图引擎是List.aspx。

默认视图是用来当你在action方法中调用View方法,返回结果。

return View();

我们指定一个不同的视图,使用名字

return View("MyOtherView");

我们没有包含文件的扩展名,或视图的路径。MVC框架会试着找到这个视图,使用文件名和视图引擎的扩展名,默认是Razor和ASPX视图引擎。

当查找一个视图,MVC框架会查找控制器命名的文件夹,然后找/Views/Shared文件夹。这意味着我们可以在不同的controller中使用/View/Shared文件夹中的同一个view,并依赖框架找到他们。

1.2.3 以下是布局的约定

布局的命名约定,是在文件名前加_下划线前缀,这起源于WebMatrix,另一个使用Razor的。布局文件放在/Views/Shared文件夹。VS创建一个叫做_Layout.cshtml的布局,作为初始化项目模板的一部分。这个不是被默认应用到所有的视图,通过/Views/_ViewStart.cshtml文件。

如果不想让默认布局应用到视图,可以更改_ViewStart.cshtml的设置,指定另一个布局。

@{
Layout ="~/Views/Shared/MyLayout.cshtml";
}
@{
Layout =null;
}

2 调试MVC应用

我们会展示如何设置调试,创建断点,在程序和单元测试中运行调试。

2.1 创建项目

创建新项目,使用Internet应用模板,选中创建单元测试。在编译模式中选择调试模式。调试的快捷方式是F5。如果选择修改Web.config文件,编译选项会更新Web.config文件中的debug属性的值为true。

...
</compilation>

不要在没有禁用debug设置的情况下,部署程序到生产环境。

2.2 调试

一个未处理的异常会导致调试中断。通过使用try..catch块,可以使一个异常变为处理过的。异常处理是非常有用的编码工具。它用来代表一个方案:一个方法无法完成它的任务,需要通知他的调用者。未处理的异常很坏,它代表一个我们意料之外没有处理的条件。

2.3 使用Edit和Continue

VS调试特性中最有意思的一个是编辑和继续。当调试器终端,你可以编辑你的代码,然后继续调试。VS重编译你的程序,重建程序在调试器终端这一刻的状态。

2.4 启用编辑和继续

我们需要在两个地方启用编辑和继续

  • 在VS工具菜单的调试器选项,有编辑和继续的节点,保持启用被选中。
  • 在项目属性中,点击Web节点,确保启用编辑和继续被选中。

2.4.1 编辑并继续

当弹出异常后,在exception helper窗口上点击Enable editing link,改变代码,从调试菜单中选择Continue。

在这时,VS重编译我们的程序,使得我们的改变被包含在构建进程,重新启动执行,重新创建导致异常的状态,然后保持正常。浏览器收到结果的渲染。

没有编辑并继续,我们要停止程序,改变代码,编译横须,重启调试。然后使用浏览器重复导致调试终端的步骤。这是避免这最重要的最后一步。复杂的漏洞可能需要很多步骤,这样可以节省程序员的事件和头脑清醒。

3 项目范围的依赖性注入

在下面的章节,我们会看到多少不同的方式,MVC框架为你的扩展提供支持,自定义如何被请求服务。这些都被定义为接口的实现,或一个基类的派生。

我们已经见过自定义MVC框架的例子。我们创建DefaultControllerFactory类的派生类NinjectControllerFactory,为了能够使用Ninject创建controller,来管理DI。我们最终能够在程序中使用DI,但是比我们理想的,多了一些代码复制和Ninject kernels。

当MVC框架需要创建一个类的实例,它会调用System.Web.Mvc.DependencyResolver类的静态方法。我们可以添加DI贯穿一个MVC程序,通过实现IDependencyResolver接口,并通过DependencyResolver注册偶们的实现。通过这种方式,无论何时框架需要创建一个类的实例,它都会调用我们的类,我们可以调用Ninject来创建这个对象。

我们没有在SpotrsStroe中强化DI,因为我们只想要展示添加DI到控制器。下面展示如何实现IDependencyResolver接口。

publicclass NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel =new StandardKernel();
AddBindings();
}
publicobject GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>()
{
return kernel.Bind<T>();
}
public IKernel Kernel
{
get { return kernel; }
}
privatevoid AddBindings()
{
Bind<IProductRepository>().To<EFProductRepository>();
Bind<IAuthProvider>().To<FormsAuthProvider>();
EmailSettings emailsSettings =new EmailSettings
{
WriteAsFile =bool.Parse(ConfigurationManager.AppSettings["Email.WriteAsFile"] ??"false")
};
Bind<IOrderProcessor>().To<EmailOrderProcessor>().WithConstructorArgument("settings", emailsSettings);
}
}

这个类很简单。前两个方法是当MVC框架需要类的一个新实例时被调用,我们简单地调用Ninject kernel传递给请求。我们添加了Bind方法,所以可以从类外面添加绑定。这完全是可选的,因为我们也包含AddBindings方法,从构造器中被调用。

现在可以删除NinjectControllerFactory类,并在Global.asax中的Application_Start方法注册更一般的NinjectDependencyResolver类。

DependencyResolver.SetResolver(new NinjectDependencyResolver());

通过这些设置,我们将Ninject放到了MVC程序的心脏。偶们可以继续改进MVC框架的这个扩展点,但我们不在需要,因为我们想做的知识介绍DI到请求管道的一些部分。