ASP.NET MVC 学习笔记-7.自定义配置信息
ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如,
1 <appSettings> 2 <add key="LogInfoProvider" value="Cookie" />//登录信息保存方式 3 </appSettings>
但是这些配置都是单个字符串信息,在某些情况下,无法做到灵活配置。
针对这种情况,使用.Net Framework提供的自定义系统配置方式来进行改善。自定义系统配置方式主要使用到以下几个类:
ConfigurationManager:通过该类能够直接获取Web.config的信息。
ConfigurationSection:表示配置文件中的一个配置节的信息。
ConfigurationElement:表示配置节中的单个配置项信息。
ConfigurationElementCollection:表示配置项的集合信息。
ConfigurationPropertyAttribute:对配置信息一些约束信息。
使用自定义配置信息,必须现在web.config配置文件的顶部进行配置声明,否则系统无法识别该配置信息。如下所示:
1 <configuration> 2 <configSections> 3 <section name="TT.appConfiguration" type="TT.Infrastructure.Core.CustomConfiguration.ApplicationConfiguration, TT.Infrastructure.Core" /> 4 <section name="TT.connectionManager" type="TT.Infrastructure.Core.CustomConfiguration.DBConnectionConfiguration, TT.Infrastructure.Core" /> 5 </configSections> 6 <TT.appConfiguration appCode="Location_Management" appName="库位管理系统"/> 7 <TT.connectionManager> 8 …… 9 </TT.connectionManager> 10 …… 11 <configuration>
在知道需要配置什么样的信息后,就需要定义读取配置的实体类信息,本文以ApplicationConfiguration的建立为例,逐步展开。
1) 创建ApplicationConfiguration类,并指定该配置的配置节名称,使用ConfigurationManager.GetSection(SECION_NAME)方法就能够读取到该配置,并将该信息强制转换为ApplicationConfiguration类即可。
1 /// <summary> 2 /// 程序配置信息 3 /// </summary> 4 public class ApplicationConfiguration : ConfigurationSection 5 { 6 private const string SECTION_NAME = "TT.appConfiguration"; 7 8 /// <summary> 9 /// 获取程序配置信息 10 /// </summary> 11 /// <returns></returns> 12 public static ApplicationConfiguration GetConfig() 13 { 14 ApplicationConfiguration config = ConfigurationManager.GetSection(SECTION_NAME) as ApplicationConfiguration; 15 return config; 16 } 17 }
2) 定义自定义配置的属性信息,并使用ConfigurationPropertyAttribute对属性进行约束。约束的信息主要包括:配置节名称Name、是否必须IsRequired、默认值DefaultValue等。
1 /// <summary> 2 /// 应用系统代码 3 /// </summary> 4 [ConfigurationProperty("appCode", IsRequired = false, DefaultValue = "")] 5 public string AppCode 6 { 7 get 8 { 9 return (string)this["appCode"]; 10 } 11 } 12 13 /// <summary> 14 /// 应用系统名称 15 /// </summary> 16 [ConfigurationProperty("appName", IsRequired = false, DefaultValue = "")] 17 public string AppName 18 { 19 get 20 { 21 return (string)this["appName"]; 22 } 23 }
3) 自定义配置信息的获取。
1 var appCode = ApplicationConfiguration.GetConfig().AppCode; 2 var appName = ApplicationConfiguration.GetConfig().AppName;
使用以上方法就可以读取自定义配置信息,并在程序中使用。
ASP.NET MVC 学习笔记-6.异步控制器
1) 异步控制器的由来
对于IIS,它维护了一个.NET线程池来处理客户端请求,这个线程池称为工作线程池,其中的线程称为工作线程。当IIS接收到一个请求时,需要从工作线程池中唤醒一个工作线程,并处理请求,处理完成后,工程线程再被线程池回收。使用线程池回收机制,通过线程的重复使用,避免了每次接受请求都创建一个新的线程,从而避免了服务器发生崩溃的风险。
绝大部分情况下,请求的执行过程都是非常快的。但是在个别情况可能会调用耗时操作(比如,读取文件或调用其他服务),造成工作线程耗用大量时间,这种情况下,线程池可能会没有多余的资源可用,从而发生Thread Starvation线程。当出现这种问题时,后续的客户端请求将会被放入队列,直到有工作线程被释放,但是,当队列也达到一定的数目时,就不会再接受新的请求,直接返回503错误码(服务器忙碌)。
2) 异步控制器的工作步骤
为了避免出现上述问题,可以使用异步控制器方式来操作耗时比较长的操作,它的工作步骤如下:
ASP.NET从线程池获取工作线程来处理请求,异步调用完ASP.NET MVC 操作后,它将工作线程返还给线程池以便处理其他的情况,异步操作在其他线程上执行完成后,通过ASP.NET已完成,然后从线程池获取一个工作线程,调用这个线程处理请求的返回。
3) 异步控制器的创建
平常使用的控制器都是从Controller中派生出来,而异步控制器需要从AsynController派生出来,这个基类提供了异步处理请求的帮助方法。
在ASP.NET MVC4框架之前,遵守下面的开发契约来创建异步控制器的方法,
操作名称Async:
此方法必须返回void,它会开始异步处理过程。
操作名称Completed:
此方法会在异步处理完成后调用,它的返回结果是ActionResult。
1 public class TestController:AsynController 2 { 3 public void TestAsync() 4 { 5 AsyncManager.OutstandingOperations.Increment(); 6 var worker = new BackgroundWorker(); 7 worker.DoWork +=(o,e)=>TestMethod(e); 8 worker.RunWorkerCompleted+=(o,e)=>{ 9 AsyncManager.Parameters["ReturnData"]=e.Result; 10 AsyncManager.OutstandingOperations.Decrement(); 11 }; 12 worker.RunWorkerAsync(); 13 } 14 15 public void TestMethod(DoWorkEventArgs e) 16 { 17 //处理过程 18 e.Result=returnData; 19 } 20 21 public ActionResult TestCompleted(returnData) 22 { 23 return Json(returnData,JsonRequestBehavior.AllowGet); 24 25 } 26 }
Ps:AsyncManager.OutstandingOperations在操作开始前+1,操作完成后减1。它的作用就是通过ASP.NET 框架目前有多少个等待操作,当属性OutstandingOperations为0时,ASP.NET会完成所有的异步请求方法,并且调用XXXCompleted方法。
.Net Framework4.5引入了新的关键字async和await后简化了异步编程模型。上述代码就可以调整为:
1 public class TestController:AsynController 2 { 3 public async Tash<ActionResult> TestMethod() 4 { 5 var returnData = await TestMethod(); 6 return Json(returnData,JsonRequestBehavior.AllowGet); 7 } 8 9 public async Task<Data> TestMethod() 10 { 11 //耗时操作 12 return returnData; 13 } 14 }
ASP.NET MVC 学习笔记-5.Controller与View的数据传递
ViewData属性
ViewData属性是System.Web.Mvc.ControllerBase中的一个属性,它相当于一个数据字典。Controller中向该字典写入数据,ViewData[“Key”]=data;View中从该字典中获取数据 int data=ViewData[“Key”]。从ViewData中获取到的数据是object类型,必须强制类型转换。
1 // 2 // 摘要: Gets or sets the dictionary for view data. 3 // 返回结果: The dictionary for the view data. 4 public ViewDataDictionary ViewData { get; set; }
ViewBag属性
C# 4.0中才提出的ViewBag,在ViewData上引入了动态特性,算是ViewData的语法糖。
ViewData |
ViewBag |
Key/Value字典集合 |
Dynamic类型对象 |
比ViewBag读取速度快 |
比ViewData读取数据慢 |
需要强制类型转换 |
不需要强制类型转换 |
1 // 2 // 摘要: Gets the dynamic view data dictionary. 3 // 返回结果: The dynamic view data dictionary. 4 [Dynamic] 5 public dynamic ViewBag { get; }
实际项目中,使用ViewData和ViewBag在Controller与View中进行数据传递,并不是最佳选择,主要有以下缺点:
1. 性能问题
ViewData中的值都是对象类型,使用之前必须强制转化为需要的类型,增加了额外的性能消耗。
2. 类型不安全
没有类型不安全就不会出现编译错误,调用时转换为其他类型,就会报出运行时错误,良好的编程经验告诉我们,错误最好在编译时铺货。
3. 破坏了Controller与View的松散耦合
MVC模式中,Controller和View是松散耦合的,即Controller不知道View的变化,View也不知道Controller的变化,但是,当使用ViewData或ViewBag进行值传递时,就需要知道写入的是什么值,从而破坏了这种松散的关系。
强类型View方式
ViewData和ViewBag所出现的问题的关键就是数据类型,因此,如果在Controlle和View之间将数据类型固定,所出现的问题就会得到解决。
View方式,是使用Controller基类中的View方法进行值传递。
使用方式为:
- Controller返回值,将返回的值作为View()的参数。
- View视图中,在代码顶部需要添加代码 @model 返回值的数据类型
- View代码中,就可以使用@Model方式来使用返回数据。
Ps:视图顶部添加代码,数据类型必须是全命名空间。也可以在Web.config文件中添加以下命名空间的配置,就可以省略命名空间的信息,只需要添加类名称即可。
1 <system.web.webPages.razor> 2 <pages pageBaseType=”…..”> 3 <namespace> 4 <add namespace=”…..”> 5 …… 6 </namespace> 7 <pages> 8 </system.web.webPages.razor>
View延伸
MVC模式中,M是数据模型,负责业务逻辑,一般都对应着数据库模型,V是数据视图,仅仅是数据展示,不包含数据逻辑。而在使用View()方式传递数据时,将数据模型直接通过Controller传递给View,在一些情况下可能会违反MVC的体系架构规则。
为避免出现类似问题,解决方案是在Model和View中添加一层ViewModel,用来负责在两者间进行数据传递。Controller将Model中数据封装成ViewModel,View根据ViewModel直接展示数据,不处理数据逻辑。
ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用
Ajax的全名为:Asynchronous Javascript And XML(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。Ajax技术首先向Web服务器发送异步请求数据,然后使用返回的内容来更新部分视图页面,而不是整个页面。
Ajax异步请求包含两种类型的内容:一种是服务端生成的HTML代码,直接嵌入到页面里;另一种是原始的序列化数据,客户端JavaScript生成或更新HTML代码。
ASP.NET MVC中关于Ajax的使用主要在以下两个方面:
1. 部分渲染
使用Ajax发送异步请求给服务器,服务器返回包含HTML代码的数据插入到对应的页面区域。
这里可以使用JQuery中的load方法,向指定元素插入HTML代码。
$(“#selectedID”).load(‘fileName’);
2. 渲染部分视图
绝大部分情况下,ASP.NET MVC将渲染部分视图当成其他请求一样看待(请求被路由到特定控制器,控制器执行特定的操作),二者的区别在于请求结束渲染视图时,通常的操作方法时使用View()帮助方法返回ViewResult,而部分视图需要调用Parital()帮助方法来返回PartialViewResult,它只渲染包含视图内容,不渲染外围布局。
3. JavaScript渲染
使用服务端生成HTML文件然后传输这种方法非常浪费资源,因为其中的HTML代码完全可以在客户端上创建,而不需网络传输。
这种方式的改进就是只从服务端获取后原始数据,然后客户端根据数据生成HTML代码。因此,服务端和客户端在数据序列化上需要达成一致,才能准确生成HTML代码。
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式,它使用两种数据结构:名值对集合以及有序值列表。
ASP.NET MVC使用JsonResult对象提供对原生JSON的支持,它可以接受可序列化为JSON的对象模型,直接调用Controller.Json()方法即可创建对应的JsonResult。
默认情况下,ASP.NET MVC不允许对Get方法的HTTP请求返回JSON数据,这样可以避免潜在的JSON劫持风险,但是可以在重载的Json()中传递第二个参数JsonRequestBehavior.AllowGet允许Get方式的HTTP请求,然后返回JSON格式的数据。因此,为了避免风险,不要给不可知的HTTP Get请求返回JSON数据,在非敏感数据时,ASP.NET MVC 框架允许使用JsonRequestBehavior.AllowGet设置来允许这种不安全的方式返回JSON数据。当需要使用JSON传输敏感信息时,可以在控制方法上添加HTTPPostAttribute特性来显示该方法只能通过HTTPPost方法请求。
Ajax跨域请求
默认情况下,浏览器只允许来自本站的请求,这种限制避免了很多安全问题。现实中,有很多需要与外部托管的网站或WebAPI进行交互的情况,这种情况下,Web应用必须能够支持JSONP(Json With Padding)或者CORS(Cross-Origin Resource Sharing 跨站资源共享)。ASP.NET MVC 默认不支持这种情况,需要使用以下两种方式实现:
1. JSONP
它利用跨站请求伪造技术,实现Ajax跨域调用。其交互方式包含以下几步:
1) 客户端创建接受JSONP应答消息的JavaScript函数CallBackMethod()。
2) 客户端动态为DOM添加<script>标签,欺骗浏览器误以为是它正在包含一个真正的脚本,然后利用浏览器允许<script>引用外站资源的“后门”。
3) <script>指定外部的JSONP服务器地址,然后指定第一步里回调的函数名称。<script href=”http://xxx.com/controller/actoin/id?callback=CallBackMethod”/>
4) 服务器像处理JSON请求一样处理请求,区别就是:它不是直接在应该消息里返回JSON对象,而是在客户端回调函数名里包装对象(回调函数中包含原生的JSON数据)。CallBackMethod({JSON对象内容});
JSONP方法是一种完全不同的C/S数据交换方法,它在回调的函数参数里包含原生的JSON数据,而不是像正常的Ajax请求一样返回JSON数据,因此,在客户端访问返回数据的方法只有在JSONP回调函数里实现。
2. CROS
CROS采用特殊的HTTP消息头来告诉浏览器服务允许跨域Ajax调用。为了启用CROS支持,只需要给每个CORS支持的请求消息设置Access-Control-Allow-Origin header值即可。
一般使用配置来给网站的全部请求消息添加HTTP消息头。
<system.webServer> <httpProtocal> <customHeaders> <add name=”Access-Control-Allow-Origin” value=”*” /> </customHeaders> </httpProtocal> </system.webServer>
jsonp方式和cors方式的区别:
jsonp是jquery提供的跨域方式
cors是w3c提供的一个跨域标准
——————————————————————
jsonp只支持get方式的跨域
cors支持get和post方式的跨域
——————————————————————
jsonp支持所有的浏览器(因为所有浏览器都可以使用script标签发送请求)
cors不支持IE10以下的浏览器
ASP.NET MVC 学习笔记-3.面向对象设计原则
在设计程序、系统框架或者类时,最主要考虑的事情就是代码的可扩展性,而不是完成功能即可。因此,提倡使用面向对象设计的最佳实践和基本原则。
1. 单一职责原则(SRP:The Single Responsibility Principle)
对象应承担单一的责任,它们的行为应该关注在它的责任上。比如,视图应该只关注UI的渲染,而不需要任何数据访问逻辑。
通常,代码中要提防的是名称为XXXManager的类,这种类可能包含了更多的职责。
2. 开放封闭原则(OCP:Open Closed Principle)
鼓励对外扩展开发,对修改关闭。尽量通过继承类来扩展其功能,而不是像类中添加更多的行为和责任,这一原则算对SRP原则的补充。
3. 里氏替换原则(LSP:Liskov Substitution Principle)
对象应易于被其子类型的实例替换,而不会影响对象的行为和规则。
4. 接口隔离原则(ISP:Interface Segregation Principle)
鼓励在整个应用程序中使用接口的同时,也需要限制接口的大小。即,接口应该是更小、更多的特定接口,而不是一个包含所有对象行为的超类接口。接口的设计应该遵循SRP原则。
5. 依赖倒置原则(DIP:Dependency Inversion Principle)
互相依赖的组件应该通过抽象来实现交互,而不是直接通过具体来实现。最直接的例子,就是将一切依赖都设置为抽象类或接口,而不是该类的具体实例。
DIP的优点:使用抽象可允许不同的组件进行独立开发、修改和测试。
6. 控制反转(IOC:Inversion of Control)
严格来说,IOC与上面5个设计原则不是对等关系,它应该是将5大原则整合使用的一个原则。
IOC是一种提倡实现松耦合层、组件和类的设计原则,它颠倒了应用程序的控制流程。传统的程序代码显示控制调用的过程,而IOC则使用分离执行特定问题处理代码,它允许独立开发程序的各个组件。
目前,IOC的两个流行实现就是依赖注入(Dependency Injection)和服务定位(Service Location)。这两种方式都是相同的中心容器的概念来管理依赖项的生命周期。而不同的是,服务定位依赖调用者调用依赖,而依赖注入通过类的构造函数、属性或执行方法来实现。
理解依赖关系
减少程序复杂性的关键是了解程序中的依赖关系,并合理地管理其依赖关系。依赖关系有多种形式:程序集引用一个或多个其他程序集,子类必须继承父类。
以一个控制访问数据服务获取数据的例子说明IOC的一步步改进:
直接调用阶段 |
控制器直接创建数据服务的一个实例,因此,控制器与数据服务之间紧密耦合,对数据库层的修改可能会影响到控制器。 |
使用工厂模式 |
为了降低控制器和数据服务的耦合度,使用接口IDataService并把创建服务的代码移动到工厂模式中,控制器和DataService依赖于IDataService接口,接口不变的情况,DataService的修改不会影响到控制器,从而消除了控制器和DataService的紧耦合,但是控制器和工厂类之间存在依赖关系。 |
IOC模式 |
控制器仍使用IDataService接口作为抽象,但是控制器不知道IDataService实例如何创建的,它是由IOC容器负责创建并传递(注入)到控制器的IDataService实例上,程序其他位置需要提供IOC容器的配置来实现类实例的声明周期管理。 |