[转载]HttpClient + ASP.NET Web API WCF之外的另一个选择

mikel阅读(1029)

[转载]HttpClient + ASP.NET Web API, WCF之外的另一个选择 – dudu – 博客园.

WCF的野心造成了它的庞大复杂,HTTP的单纯造就了它的简单优美。为了实现分布式Web应用,我们不得不将两者凑合在一起 —— WCF服务以HTTP绑定宿主于IIS。

于是有了让人晕头转向的配置、让人郁闷不已的调试,还有那ServiceContract, DataContract, EnumMember…还有还有,不要在using语句中调用WCF服务

于是经常自问:拿着牛刀削苹果有必要吗?废话,当然没有必要,水果刀在哪里?

微软看着这么多人拿着牛刀削苹果,自己也看不下去了,于是,一种水果刀横空出世 —— ASP.NET Web API。

最近我们在实际开发中有个地方用WCF太麻烦,就小试了一下水果刀,感觉还不错。

下面用一个简单的示例分享一下ASP.NET Web API水果刀的用法。

服务端ASP.NET Web API的实现

需要准备的工具:Visual Studio 2010, NuGet

1. 新建一个空的ASP.NET Web Application项目。

2. 通过NuGet添加ASP.NET Web API的引用,在NuGet中搜索时要用“AspNetWebApi”(用“ASP.NET Web API”是搜索不到的),然后选择ASP.NET Web API(Beta)进行安装。

3. 添加Global.asax,在Application_Start中注册Web API的路由,在Global.asax.cs中添加如下代码:

protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute("WebApi", "api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
}

4. 添加Controllers文件夹,在其中添加类文件DemoController.cs,并让DemoController继承自ApiController。代码如下:

namespace CNBlogsWebApiDemo.Controllers
{
public class DemoController : ApiController
{
}
}

5. 添加ViewModels文件夹,在其中添加Site.cs,并定义Site。

namespace CNBlogsWebApiDemo.ViewModels
{
public class Site
{
public int SiteId { get; set; }
public string Title { get; set; }
public string Uri { get; set; }
}
}

6. 给DemoController添加一个方法SiteList,并写上我们的示例代码。代码如下:

public class DemoController : ApiController
{
public IList SiteList(int startId, int itemcount)
{
var sites = new List();
sites.Add(new Site { SiteId = 1, Title = "test", Uri = "www.cnblogs.cc" });
sites.Add(new Site { SiteId = 2, Title = "博客园首页", Uri = "www.cnblogs.com" });
sites.Add(new Site { SiteId = 3, Title = "博问", Uri = "q.cnblogs.com" });
sites.Add(new Site { SiteId = 4, Title = "新闻", Uri = "news.cnblogs.com" });
sites.Add(new Site { SiteId = 5, Title = "招聘", Uri = "job.cnblogs.com" });

var result = (from Site site in sites
where site.SiteId > startId
select site)
.Take(itemcount)
.ToList();
return result;
}
}

7. 配置一下Web项目的启动设置Specific Page与Specific port

8. Ctrl+F5运行项目,结果如下:

结果是我们期望的,用浏览器直接可以查看Web API的运行结果,测试时会很方便。

好了,服务端Web API就这么轻松搞定了!

客户端通过HttpClient调用服务端Web API

1. 新建一个WebApiTest的类库项目。

2. 在NuGet中添加System.Net.Http(HttpClient就在这里), Json.NET, xUnit.net。

3. 添加类文件WebApiClientTest.cs,添加测试方法WebApi_SiteList_Test:

namespace WebApiClientTest
{
public class WebApiClientTest
{
[Fact]
public void WebApi_SiteList_Test()
{

}
}
}

4. WebApi_SiteList_Test() 的代码实现

4.1 首先,要确定三个东西:

a) 客户端调用WebAPI的方式是Http Get,还Http Post,我们这里选用Http Post;

b) 客户端调用WebAPI时传递的参数格式,我们这里选用的是Json。

c) WebAPI返回的数据格式,我们这里选用的也是Json(这也是之前添加Json.NET引用的原因)。

4.2 用到的类

System.Net.Http.HttpClient
System.Net.Http.httpContent
System.Net.Http.StringContent
System.Net.Http.Headers.MediaTypeHeaderValue
Newtonsoft.Json.JsonConvert

4.3 准备需要传递给WebAPI的参数

需要传递的两个参数是startId ,itemcount,传递的格式是Json。这里可没有JavaScript中的JSON.stringify(),但我们有Json.NET,再加上匿名类型,有点用js的感觉,代码如下:

var requestJson = JsonConvert.SerializeObject(new { startId = 1, itemcount = 3 });

代码的运行结果:{“startId”:1,”itemcount”:3}

然后用System.Net.Http.StringContent把它打个包:

HttpContent httpContent = new StringContent(requestJson);

然后设置一下ContentType:

httpContent.Headers.ContentType = new MediaTypeHeaderValue(“application/json”);

4.4 通过Http Post调用WebAPI得到返回结果

HttpClient闪亮登场,调用它的PostAsync()方法轻松搞定:

var httpClient = new HttpClient();
var responseJson = httpClient.PostAsync(“http://localhost:9000/api/demo/sitelist”, httpContent)
.Result.Content.ReadAsStringAsync().Result;

看一下responseJson的结果:

[{“SiteId”:2,”Title”:”博客园首页”,”Uri”:”www.cnblogs.com”},{“SiteId”:3,”Title”:”博问”,”Uri”:”q.cnblogs.com”},{“SiteId”:4,”Title”:”新闻”,”Uri”:”news.cnblogs.com”}]

正宗的Json!你注意到没有,服务端WebAPI的代码未作任何修改,我们只是在Http Headers中将ContentType设置为了application/json,返回的就是Json格式的数据。而我们通过浏览器访问,得到的还是标准的XML。这里就是ASP.NET Web API的魅力之一 —— 一次实现,按需服务。

4.5 将Json格式返回的结果反序列化为强类型

Json.NET又登场:

var sites = JsonConvert.DeserializeObject>(responseJson);

展示一下返回结果:

代码

sites.ToList().ForEach(x => Console.WriteLine(x.Title + “:” + x.Uri));

结果

博客园首页:www.cnblogs.com
博问:q.cnblogs.com
新闻:news.cnblogs.com

4.6 WebApi_SiteList_Test() 完整实现代码

public class WebApiClientTest
{
[Fact]
public void WebApi_SiteList_Test()
{
var requestJson = JsonConvert.SerializeObject(new { startId = 1, itemcount = 3 });

HttpContent httpContent = new StringContent(requestJson);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

var httpClient = new HttpClient();
var responseJson = httpClient.PostAsync("http://localhost:9000/api/demo/sitelist", httpContent)
.Result.Content.ReadAsStringAsync().Result;

var sites = JsonConvert.DeserializeObject>(responseJson);

sites.ToList().ForEach(x => Console.WriteLine(x.Title + ":" + x.Uri));
}
}

注:运行这里的代码之前,要先运行WebAPI项目,先把服务跑起来,客户端才能享受到服务。

JQuery ajax调用代码比较一下:

var requestJson = JSON.stringify({ startId: 1, itemcount: 3 });
$.ajax({
url: '/api/demo/sitelist',
data: requestJson,
type: "post",
dataType: "json",
contentType: "application/json; charset=utf8",
success: function (data) {
jQuery.each(data, function (i, val) {
$("#result").append(val.Title + ': ' + val.Uri +'
');
});
}
});

注:上面的代码是可真实运行的哦,代码在示例代码WebApiDemo项目的AjaxWebApi.htm文件中。这也是ASP.NET Web API “一次实现,按需服务”的体现。

小结 

水果刀(ASP.NET Web API)用下来感觉还不错,不仅可以削苹果,还可以削梨子,切西瓜也不在话下。用不用牛刀(WCF),还得多考虑考虑。

示例代码下载

http://files.cnblogs.com/dudu/CNBlogsWebApiDemo.rar

[转载]分享14个jQuery插件开发人员易犯的错误

mikel阅读(1147)

[转载]分享14个jQuery插件开发人员易犯的错误 – gbin1 – 博客园.

分享14个jQuery插件开发人员易犯的错误

随着越来越多的开发人员开始开发JQuery插件,所以我们随时都有可能遇到很烂的插件开发“成果”。没有在线演示,没有文档,或者插件没有遵循最 佳编码实 践。但是对于阅读这篇文章的朋友来说,你很幸运,因为这里我们将介绍14个JQuery插件开发中最容易犯的错误。希望大家会觉得有帮助!

随着JQuery的广泛使用,每天都出现很多新的插件 ,但是问题在于很多插件真不怎么样。

以前我们介绍过10个帮助你创建超棒jQuery插件的小技巧,在今天这篇文章中,我们将专注于jQuery插件的最佳开发实践,希望对于大家有帮助,如果你喜欢我们的文章,请给我们留言,谢谢!

错误一:不是在开发一个jQuery插件

总的来说,这里有很多大家接受的jQuery开发的模式。 如果你没有遵从这些设计模式,你开发的插件有可能很“垃圾“。看看如下最常用的模式:

(function($, window, undefined){
$.fn.myPlugin = function(opts) {
var defaults = {
// 设置你的选项缺省值
}

// 使用用户的选项缺省值来扩展缺省选项
var options = $.extend(defaults, opts || {});

return this.each(function(){ // jQuery链式操作
// 插件的相关内容
});
})(jQuery, window);

首先呢,我们创建了一个自调用的匿名方法来将我们插件中的参数和外部全局参数隔离开。我们传递$,window,和undefined三个变量参数。这些变 量和自调用的方法将和jQuery和window一起调用。对于undefined来说没有传递任何值,因此如果我们决定在插件中使用undefined 关键字的话,其实”undefined“并没有被定义。

使用这种方法可以有效的保证外部脚本被隔离而无法给undefined变量赋值,例如,将无法赋值undefined为true。

$被作为jQuery来传递;我们使用这种方法来保证在匿名方法的外部,$仍旧可以参考为其它内容,例如,prototype。

传递变量给全局性访问的window对象能允许更多经过压缩最小化(minification)处理的代码(当然,压缩是应该做的)

下 一步,我们将使用jQuery插件的模式, $.fn.PluginName。这用来登记你的插件使得其能被应用到 $(selector).method()格式中。简单使用new来扩展jQuery的prototype。如果你想创建一个jQuery的方法的话,只 需要直接添加如下代码:

$.PluginName = function(options){
// 扩展选项,执行插件功能
}

这种类型的插件不可以执行链式操作,因为方法在jQuery对象中定义为属性,不能返回jQuery对象,例如如下代码:

$.splitInHalf = function(stringToSplit){
var length = stringToSplit.length;
var stringArray = stringToSplit.split(stringToSplit[Math.floor(length/2)]);
return stringArray;
}

这个我们返回了一个字符串数组。直接返回array比较合理,因为这有可能是用户需要的返回类型(当然如果需要的话,直接使用jQuery对象来封装也很容易)。对比以上代码,我们看看如下代码:

$.getOddEls = function(jQcollection){ //
return jQcollection.filter(function(index){
var i = index+1;
return (index % 2 != 0);
});
}

在这个例子中,我们得到奇数数值,用户可能需要jQuery对象返回$.getOddEls;因此我们返回了filter方法,这个方法通过传递的方法返回了jQuery的collection定义。一个比较好的原则是封转返回的元素到一个jQuery方法中,特别是如果用户希望它可以进行链式操作;如果你返回数组,字符串,数据,方法或者其它类型,则不需要封装。
错误二:不书写文档或者不正确的书写文档来注释你的代码

无可厚非,对于发布代码来说最重要的是书写很好的文档。这是帮助你的使用者更好的了解代码功能及其能够实现功能的而一个很好的方式。用户可不愿意花大量时间研究你的代码输入输出。

文档书写没有什么强制的规则,理论来说你给的文档越多,肯定越好。

这个过程包括了代码内部注释说明及其外部的使用API文档或者应用演示。
错误三:没有提供足够的灵活性和自定义

最受欢迎的插件提供了对于参数(即用户使用的插件选项)完整的访问。他们可以提供很多不同的配置,这样可以应用到不同的场景中。例如,我们这里看看一个简单幻灯插件。可以控制的选项包括了速度,类型和动画的延迟。

比较好的实践是提供用户访问class或者ID名称。更好的话,你可能想调用幻灯过渡后的callback方法,或者是幻灯恢复到最初的状态的callback。

你需要考虑所有插件的可能使用场景和需求。

这里我们在看看另外一个例子:一个调用API的插件应该提供对于返回对象的访问。看看如下这个例子:

$.fn.getFlickr = function(opts) {
return this.each(function(){ // jQuery chainability
var defaults = { // setting your default options
cb : function(data){},
flickrUrl : // some default value for an API call
}
// extend the options from defaults with user's options
var options = $.extend(defaults, opts || {});

// call the async function and then call the callback
// passing in the api object that was returned
$.ajax(flickrUrl, function(dataReturned){
options.cb.call(this, dataReturned);
});
});
}

这个插件允许我们执行如下代码行:

$(selector).getFlickr(function(fdata){ // flickr data is in the fdata object });

另 外一个执行类似公开化的方法是提供一个”hooks”作为选项。在jQuery1.7.1及其以上版本中,我们可以在插件调用后使 用.on(eventName, function(){})方法以便分开自己独立的方法行为。例如,使用上面的插件,我们可以修改代码如下:

$.fn.getFlickr = function(opts) {
return this.each(function(i,el){
var $this = el;
var defaults = { // setting your default options
flickrUrl : "http://someurl.com" // some default value for an API call
}
var options = $.extend(defaults, opts || {});

// call the async function and then call the callback
// passing in the api object that was returned
$.ajax(flickrUrl, function(dataReturned){
// do some stuff
$this.trigger("callback", dataReturned);
}).error(function(){
$this.trigger("error", dataReturned);
});
});
}

这样允许我们调用getFilckr插件并且链式其它行为的处理。

$(selector).getFlickr(opts).on(“callback”, function(data){ // do stuff }).on(“error”, function(){ // handle an error });

你可以看到提供这种灵活方式是绝对重要的,插件拥复杂的操作越多,那么控制就会越复杂。
错误四:要求太多的配置

上面的错误三我们介绍了越复杂的插件,要求控制就越复杂。一个很大的错误在于,插件创建了太多的选项。例如,对于UI插件来说比较理想的方式是不设置缺省的选项。

$(selector).myPlugin();

当然,有时候这不太现实(例如,插件中用户需要指定RSS Feed来源)。在这里例子中,你应该尽量为用户设置初始的选项。

例如你开发一个需要从Tweet取得内容的插件。你可以要求用户输入一个用户名,如下:

$(selector).fetchTweets(“gbin1”);

你可以提供缺省的展示方法,例如,feed个数,显示在<p>标签中。大多数的开发人员都希望是这样的。

错误五:将外部的CSS和行内的CSS混淆

如 果你处理UI的话,不可避免的需要在你的插件中包含CSS文件。一般来说,这是一个可接受的解决方式。多数的插件都带有图片和CSS。但是不要忘了错误 二,文档需要包含如何使用这些CSS和图片的内容。开发人员可没有时间来搜索你的代码来找到答案(况且,很多人可能并不会真正开发jQuery代码,特别 是在国内)。

无论如何,我们都需要保证插件能正常工作。

对于插件来说,最好的方式是使用基于Class/ID的CSS样式或者行内注入CSS(使用插件选项)。行内CSS会覆盖外部CSS,但是混合使用俩者会非常不舒服。开发人员可能会花一定时间来搞清楚为什么代码中的样式不好使。所以最好你自己决策如何处理这些问题。

作为一个规则来说,行内的CSS非常不好 –  除非它影响非常小,不会干扰外部的CSS样式定义。

错误六:没有提供任何在线演示

这绝对是很恶心的一件事,开发人员必须自己动手才能看到效果,往往发现不是自己期望的那样。其实作为插件开发来说,添加一些在线演示还是很简单的,如下是一些不错的演示模板:

A good template for examples:

  • A “hello world” example – usually the plugin call with the minimum configuration/options passed, and it’s accompanying html/css
  • A few more involved examples – usually with examples of full functionality of multiple options
  • An integration example – if someone might use another plugin with your plugin, here is where you can show how to do that. (This gets you bonus points in the open-source development world, too. Kudos.)

错误七:代码没有匹配正确的jQuery版本

jQuery 和其它的代码类库类似,也有不同的版本。大多数的方法即使被遗弃也会被保留。但是新的方法会被添加。一个非常典型的例子是.on方法。它是jQuery新 版本中事件处理的一个全新的all-in-one解决方案。如果你书写使用到.on()方法的插件的话,需要使用到jQuery1.6或者以上版本。

一 个比较好的习惯是在你的文档中说明,你要求的jQuery版本,例如,1.7或者以上,作为我个人来说,在使用jQuery插件中也有类似不愉快的体验。 所以为了让更多的开发人员喜欢你的插件,一定要很好的说明。并且提供一个不再支持的旧版本下载也是一个相当不错的方法。

问题。

鼓励大家使用新的jQuery类库,但是不要让你的插件失效的太频繁了!提供一个不再支持的旧版本下载也是一个相当不错的选择。

错误八:找不到修正说明

除了保证你的jQuery版本的支持和兼容性,你还需要版本控制(例如,Github)。 如果你希望你开发的jQuery插件最后能够公开发布的话,你最好保存在Github中。使用版本控制有诸多的好处,具体就不在这篇文章中详细说明。但是 最重要的在于允许使用你的插件的开发人员看到相关的修改,提升或者兼容性的bug修正。这同时能够帮助你扩展/提高你的插件的用户体验。

更多资源:

错误九:开发的插件并没有人使用

这里我们得提一下,很多插件都很简单,或者说是肤浅,没有任何理由来称之为插件。这个世界不再需要幻灯插件了!

我们不需要闭门造车,很多已经存在的不错的插件,为什么还需要再去开发呢?

这个世界不再需要幻灯插件了。

错误十:没有提供一个压缩最小化版本

这个问题非常简单明显,如果是一个可供使用的插件,意味着是ready to use的代码,试问如何在产品环境中使用一个超大的js代码呢?

请参考错误十三来寻找自动处理解决方案。

错误十一:把代码写的太“聪明”

当你书写一个插件的时候,你是不是打算给别人使用的呢?如果你书写的代码晦涩难懂,大家如何能够Debug

如果你给变量起名gbin1,x,y,z,你绝对犯了一个大错。

错误十二:不需要使用jQuery

我 们都很喜欢使用jQuery,但是要知道它是一个类库,肯定会有些性能代价的。一般来说,你不会太在意jQuery选择器的性能。当然jQuery是被很 好的优化过的。 但是如果你只需要一些简单的DOM查询的话,你可能可以考虑使用别的技术,例如,vanilla,Zepto。

不要为了jQuery而使用jQuery,如果你使用其它技术例如,vanilla JavaScript,你需要注意兼容性,你有可能需要书写一些polyfill来适应新API。

错误十三:没有自动化整个过程

Grunt是一个基于任务的JavaScript命令行编译工具。如果有兴趣可以看看这篇文章。

grunt init:jquery

运行这个命令,将会提示你一系列问题,例如,title,描述,版本,git repository,许可等。

Grunt功能不止于此。它可以帮助你自定义boilerplate代码,并且内建很多工具,例如,JSHint Qunit 还有 PhantomJS

定期使用Grunt做编译工作。

错误十四:没有做过测试

你是不是认真测试过你的代码?那你怎么保证代码正常工作?只靠刷新浏览器吗?还是考虑使用一些工具吧: QUnit, Jasmine, 或者 Mocha

如果测试jQuery插件对你来说比较新的话,可以考虑多留意一些测试工具和方法。

一些有用的资源

希望大家喜欢我们带来的这篇文章,如果你有任何问题和意见,请给我们留言,谢谢!

[转载]ASP.NET MVC三个重要的描述对象:ControllerDescriptor

mikel阅读(1041)

[转载]ASP.NET MVC三个重要的描述对象:ControllerDescriptor – Artech – 博客园.

ASP.NET MVC应用的请求都是针对某个Controller的某个Action方法,所以对请求的处理最终体现在对目标Action方法的执行。而Action方 法具有相应的参数,所以在方法执行之前必须根据相应的规则从请求中提取相应的数据并将其转换为Action方法参数列表,我们将这个过程称为Model绑 定。在ASP.NET MVC应用编程接口中,Action方法某个参数的元数据通过ParameterDescriptor表示,而两个相关的类型ControllerDescriptorActionDescriptor则用于描述Controller和Action方法。[本文已经同步到《How ASP.NET MVC Works?》中]

一、ControllerDescriptor

ControllerDescriptor 包含了用于描述某个Controller的元数据信息。如下面的代码片断所示,ControllerDescriptor具有三个属性,其中 ControllerName和ControllerType分别表示Controller的名称和类型,前者来源于路由信息;字符串类型的 UniqueId表示ControllerDescriptor的唯一标识,该标识由自身的类型Controller的类型以及Controller的名称三者派生。

1: public abstract class ControllerDescriptor : ICustomAttributeProvider

2: {

3: public virtual object[] GetCustomAttributes(bool inherit);

4: public virtual object[] GetCustomAttributes(Type attributeType, bool inherit);

5: public virtual bool IsDefined(Type attributeType, bool inherit);

6: public virtual IEnumerableGetFilterAttributes(bool useCache);

7:

8: public abstract ActionDescriptor FindAction(ControllerContext controllerContext, string actionName);

9: public abstract ActionDescriptor[] GetCanonicalActions();

10:

11: public virtual string ControllerName { get; }

12: public abstract Type ControllerType { get; }

13: public virtual string UniqueId { get; }

14: }

15:

16: public interface ICustomAttributeProvider

17: {

18: object[] GetCustomAttributes(bool inherit);

19: object[] GetCustomAttributes(Type attributeType, bool inherit);

20: bool IsDefined(Type attributeType, bool inherit);

21: }

ControllerDescriptor实现了ICustomAttributeProvider接 口,意味着我们可以通过调用GetCustomAttributes和GetCustomAttributes方法获取应用在Controller类型上 的所有自定义特性或者给定类型的特性,也可以调用IsDefined方法判断指定的自定义特性类型是否应用在对应的Controller类型上。

另一个方法GetFilterAttributes用于获取应用在Controller上的所有筛选器特性(继承自抽象类FilterAttribute)。筛选器是一种基于AOP的设计,它使我们可以一些基于横切关注点相关逻辑的执行动态的注入到Action方法的执行前后,我们会在“Action方法的执行”中对筛选器进行详细地介绍。

ControllerDescriptor的FindAction方法根据指定的Controller上下文和名称得到相应的Action方法,返 回的是用于描述Action方法的ActionDescriptor对象。而GetCanonicalActions得到当前Controller的所有 Action方法,返回类型为ActionDescriptor数组。

二、ReflectedControllerDescriptor

ASP.NET MVC应用编程接口中定义了抽象类ControllerDescriptor的唯一继承类型ReflectedControllerDescriptor。 顾名思义,ReflectedControllerDescriptor通过反射的机制解析用于描述Controller的元数据。如下面的代码片断所 示,表示Controller类型的ControllerType属性在构造函数中指定。ReflectedControllerDescriptor通 过反射的方式获取应用在Controller类型上的相关特性以提供针对ICustomAttributeProvider接口的实现。

1: public class ReflectedControllerDescriptor : ControllerDescriptor

2: {

3: public ReflectedControllerDescriptor(Type controllerType);

4:

5: public override object[] GetCustomAttributes(bool inherit);

6: public override object[] GetCustomAttributes(Type attributeType, bool inherit);

7: public override IEnumerableGetFilterAttributes(bool useCache);

8: public override bool IsDefined(Type attributeType, bool inherit);

9:

10: public override ActionDescriptor FindAction( ControllerContext controllerContext, string actionName);

11: public override ActionDescriptor[] GetCanonicalActions();

12:

13: public sealed override Type ControllerType { get; }

14: }

对于GetCanonicalActions方法返回的用于描述所有Action方法的ActionDescriptor数组,仅限于公有实例方法,但是从.Controller中继承下来的方法除外。当我们调用FindAction方法根据Action名称获取对应ActionDescriptor的时候,在默情况下会将方法名称视为Action名称进行匹配。如果方法上应用了具有如下定义的ActionNameSelectorAttribute特性,会传入相应的参数调用其IsValidName方法,如果该返回值为True,目标方法会被认为是匹配的Action方法。

1: [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]

2: public abstract class ActionNameSelectorAttribute : Attribute

3: {

4: public abstract bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo);

5: }

顾名思义,抽象类ActionNameSelectorAttribute是一个用于辅助选择目标Action方法的特性,在ASP.NET MVC应用编程接口中具有一个类型为ActionNameAttribute的 继承者。ActionNameAttribute特性应用于Action方法通过参数值指定一个Action别名,在实现的IsValidName方法中 会比较指定的别名是否和当前的Action名称相匹配。如果具有不同 的Action选择规则,我们也可以通过自定义ActionNameSelectorAttribute特性的方式来实现。

1: [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]

2: public sealed class ActionNameAttribute : ActionNameSelectorAttribute

3: {

4: public ActionNameAttribute(string name);

5: public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo);

6: public string Name { get; }

7: }

对于FindAction方法,如果找不到与指定Action名称的Action方法,则返回Null,而最终会导致一个状态码为404的HttpException异常的抛出;如果具有多个匹配的Action方法,则直接抛出AmbiguousMatchException异常。也就是说对于每一次请求,要求有且只有一个匹配的Action方法

三、ReflectedAsyncControllerDescriptor

ReflectedAsyncControllerDescriptor类 型为ReflectedControllerDescriptor的异步版本。如下面的代码片断所 示,ReflectedAsyncControllerDescriptor和ReflectedControllerDescriptor具有类似的成 员定义,实际上除了FindAction和GetCanonicalActions两个方法,其他方法的实现逻辑(即对应用在Controller类型上 的相关特性的解析)与ReflectedControllerDescriptor完全一致。

1: public class ReflectedAsyncControllerDescriptor : ControllerDescriptor

2: {

3: public ReflectedAsyncControllerDescriptor(Type controllerType);

4:

5: public override object[] GetCustomAttributes(bool inherit);

6: public override object[] GetCustomAttributes(Type attributeType, bool inherit);

7: public override IEnumerableGetFilterAttributes( bool useCache);

8: public override bool IsDefined(Type attributeType, bool inherit);

9:

10: public override ActionDescriptor FindAction( ControllerContext controllerContext, string actionName);

11: public override ActionDescriptor[] GetCanonicalActions();

12:

13: public sealed override Type ControllerType { get; }

14: }

ReflectedAsyncControllerDescriptor的GetCanonicalActions总是返回一个空的 ActionDescriptor数组。对于继承自AsyncController的Controller类型,一个异步Action方法由两个匹配的方 法({ActionName}Async和{ActionName}Completed)构成,ReflectedAsyncControllerDescriptor在根据指定的Action名称对方法成员进行匹配的时候会自动忽略掉方法名称的“Async”和“Completed”后缀。

ASP.NET MVC三个重要的描述对象:ControllerDescriptor
ASP.NET MVC三个重要的描述对象:ActionDescriptor
ASP.NET MVC三个重要的描述对象:ControllerDescriptor与ActionDescriptor的创建机制
ASP.NET MVC三个重要的描述对象:ParameterDescriptor

[转载]MVC与三层架构的区别

mikel阅读(1449)

[转载]MVC与三层架构的区别 – 小孤狼 – 博客园.

在此之前对MVC和三层架构没有一个太明确的认识,不知道它们之间有什么异同点,今天仔细研究了一下。

首先说三层架构:

1、表现层(UI):通俗讲就是展现给用户的界面,即用户在使用一个系统的时候他的所见所得。

2、业务逻辑层(BLL):针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。

3、数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增添、删除、修改、更新、查找等。

它们之间存在一种引用依赖关系:

再说说MVC

MVC是 Model-View-Controller M是指数据模型,V是指用户界面,C则是控制器。

视图V
视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序 中,HTML依旧在视图中扮演着重要的角色,但一些新的技术已层出不穷,它们包括Macromedia Flash和象XHTML,XML/XSL,WML等一些标识语言和Web services.如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理 发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。
模型M
模型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
控制器C
控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

举一个简单的例子来说明MVC

MVC就像我们小时候玩的那种卡带式游戏机,Control是主机,一般来说我只要买一个主机就行了,只要它不坏,我可以一直玩这类的游戏。 View则是电视机和游戏手柄,电视机是可以独立工作的,它不管输入的是电视信号,影碟机信号,还是游戏信号,它只管显示,而且它决定显示的效果,如果我 想要一个尺寸更大的或者显示效果更好的,我只需要换一个电视机可以了,游戏手柄也可以换的,是普通的还是带震动的。Model则是游戏机的卡带。它决定我 玩什么游戏,是魂斗罗还是超级玛丽。而且游戏机的主机和电视机的生产厂家永远不知道将来在上面会运行什么游戏。卡带中可能会有游戏代码和存储单元,都根据 游戏的需要而设计。

最后在说说他们之间存在的区别

1.三层架构中,DAL(数据访问层)、BLL(业务逻辑层)、WEB层各司其职,意在职责分离。

2.MVC是 Model-View-Controller,严格说这三个加起来以后才是三层架构中的WEB层,也就是说,MVC把三层架构中的WEB层再度进行了分 化,分成了控制器、视图、实体三个部分,控制器完成页面逻辑,通过实体来与界面层完成通话;而C层直接与三层中的BLL进行对话。

3.MVC三个事物之间并不存在明显的层次结构,没有明显的向下依赖关系,相反View和Model往往比较独立,而Control是两者之间的桥 梁,它们更像是横向切分,因此MVC中每个块都是可以独立测试的,而三层结构中,上层模块的运行测试势必要提供下层代码或提供相同接口桩。

为什么要使用 MVC
首先,最重要的一点是多个视图能共享一个模型,现在需要用越来越多的方式来访问你的应用程序。对此,其中一个解决之道是使用MVC,无论你的用户想要 Flash界面或是 WAP 界面;用一个模型就能处理它们。由于你已经将数据和业务规则从表示层分开,所以你可以最大化的重用你的代码了。
由于模型返回的数据没有进行格式化,所以同样的构件能被不同界面使用。例如,很多数据可能用HTML来表示,但是它们也有可能要用Adobe Flash和WAP来表示。模型也有状态管理和数据持久性处理的功能,例如,基于会话的购物车和电子商务过程也能被Flash网站或者无线联网的应用程序 所重用。
因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变你的应用程序的数据层和业务规则。如果你想把你的数据库从MySQL移植到Oracle, 或者改变你的基于RDBMS数据源到LDAP,只需改变你的模型即可。一旦你正确的实现了模型,不管你的数据来自数据库或是LDAP服务器,视图将会正确 的显示它们。由于运用MVC的应用程序的三个部件是相互独立,改变其中一个不会影响其它两个,所以依据这种设计思想你能构造良好的松耦合的构件。
拿一个简单的登陆模块说,需求是你输入一个用户名、密码,如果输入的跟预先定义好的一样,那么就进入到正确页面,如果不一样,就提示个错误信息“你Y别在这儿蒙我,输入的不对!”。
V 这个小小的模块中,起始的输入用户名密码的页面跟经过校验后显示的页面就相当于View
C 而这里还需要一个controller页面,就是用于接收输入进来的用户名密码,还有经过校验后返回的一个flg(此flg就是用于判断你输入的是否正确,而跳转到相应的页面的)
M 最后还缺一个Model,那么就是你那个用于校验的类了,他就是处理你输入的是否跟预先订好的一样不一样的,之后返回一个flg。
这样就完全实现了逻辑跟页面的分离,我页面不管你咋整,反正我就一个显示,而controller呢也不管你Model咋判断对不对,反正我给你了用户名跟密码,你就得给我整回来一个flg来,而Medol呢,则是反正你敢给我个用户名跟密码,我就给你整过去个flg

m 提供数据,数据之间的关系,转化等。并可以通知视图和控制器自己哪些地方发生了变化。
v 提供显示,能根据m的改变来更新自己
c 比如视图做了点击一个按钮,会先发给这个视图的控制器,然后这个控制器来决定做什么操作(让模型更新数据,控制视图改变)

以上是本人对mvc和三层结构的认识,有不对的地方希望大家多提意见,共同进步!

[转载]使用IE控件与Firefox扩展的页面打印解决方案

mikel阅读(1053)

[转载]使用IE控件与Firefox扩展的页面打印解决方案 – 无心的专栏 – 博客频道 – CSDN.NET.

for IE:  MeadCo’s ScriptX ActiveX control

 

for Firefox:  JS Print Setup (extention)

 

by search “printer ” in firefox addons site, these extentions was found:

CustomPrint :   Allows JS-developpers to define specific printer settings to use when printing a page from JavaScript

PrinterMagic :  This extension allows web content to control printer settings such as headers, footers, and page orientation.

官方网址:http://www.meadroid.com/scriptx/index.asp

MeadCo’s ScriptX控件有两种使用方式,一种是做为免费版本使用,一种是做为收费版本使用,免费版本支持的功能要少些,不过最重要也是最常用的页面设置,它还 是提供的,因此使用免费版本即可。不过这两个版本用的都是同一个cab文件,只不过在代码设置中有一些不同。

http://www.meadroid.com/scriptx/sxdownload.asp这里下载smsx.cab文件。

页面调用示例:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>
<html xmlns=”http://www.w3.org/1999/xhtml“>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<object id=factory viewastext style=”display:none” classid=”clsid:1663ed61-23eb-11d2-b92f-008048fdd814″ codebase=”smsx.cab#Version=6,5,439,12″></object>
<title></title>
<style media=”print”>
.noprint {
display:none;
}
</style>
<script type=”text/JavaScript”>
<!–
function SetPrintSettings() {
// — advanced features
//factory.printing.SetMarginMeasure(2); // measure margins in inches
//factory.printing.printer = “HP DeskJet 870C”;
//factory.printing.paperSize = “A4”;
//factory.printing.paperSource = “Manual feed”;
//factory.printing.collate = true;
//factory.printing.copies = 2;
//factory.printing.SetPageRange(false, 1, 3); // need pages from 1 to 3

//注意,如果页面报了JS错误,可以先将以上advanced features全部去掉,只留下面的basic features,这里我将上面的全部注释掉

// — basic features
factory.printing.header = “”;
factory.printing.footer = “”;
factory.printing.portrait = false;
factory.printing.leftMargin = 1.0;
factory.printing.topMargin = 1.0;
factory.printing.rightMargin = 1.0;
factory.printing.bottomMargin = 1.0;
}

function Print(frame) {
factory.printing.Print(true, frame) // print with prompt
}

//–>
</script>
</head>

<body onload=”SetPrintSettings()”>
<table border=”1″ width=”100%”>
<tr>
<td>a</td>
<td>b</td>
</tr>
<tr>
<td>c</td>
<td>d</td>
</tr>
</table>
<center class=”noprint”>
<input type=button value=”打印本页” onclick=”factory.printing.print(false)”>
<input type=button value=”页面设置” onclick=”factory.printing.PageSetup()”>
<input type=button value=”打印预览” onclick=”factory.printing.Preview()”>
</center>
</body>
</html>

官方说明文档:http://www.meadroid.com/scriptx/docs/printdoc.asp,建议看看这个。

[转载]HTML5 WebSocket 技术介绍

mikel阅读(1105)

[转载]HTML5 WebSocket 技术介绍 – twaver – 博客园.

WebSocket是html5规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用WebSocket技术,后台可以随时向前端推送消息,以保证前后台状态统一,在传统的无状态HTTP协议中,这是“无法做到”的。

传统服务端推(server push)技术

WebSocket提出之前,为了解决后台推送消息到前台的需求,提出了一些解决方案,这些方案使用已有的技术(如ajax,iframe,flashplayer,java applet …),通过一些变通的处理来实现。

简单轮询

最简单的是前台轮询,每隔一段时间去请求后台,以获取最新状态,这种方式最容易实现,但效果也最差,频繁盲目的调用后台,带来不必要的开销,且实时性无法保障,后台出现更新,前端需要在下一次轮询时才知道。

长轮询

为了解决这些弊端,进化出长轮询技术,轮询请求会在后台阻塞,相当于保持一个长连接,直到后台出现更新或者超时才返回,这样就可以保证更新的及时性,前端得到请求后,重新建立轮询连接,等待后台的更新通知。

其他方案

其他解决方案无外乎保持一个长连接(如Iframe及htmlfile流),实时的从后台获取信息,或者借助第三方插件(flashPlayer, jre),使用的是flash xmlsocket或者java applet socket技术,这些方式都不够纯html,所以这里就不过多介绍了,更多传统server push 技术可参考IBM的文章:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

WebSocket介绍

webSocket是html5新引入的技术,允许后台随时向前端发送文本或者二进制消息,WebSocket是一种全新的协议,不属于http无 状态协议,协议名为”ws”,这意味着一个websocket连接地址会是这样的写法:ws://twaver.com:8080 /webSocketServer。ws不是http,所以传统的web服务器不一定支持,需要服务器与浏览器同时支持, WebSocket才能正常运行,目前的支持还不普遍,需要特别的web服务器和现代的浏览器。

浏览器对WebSocket的支持

Google Chrome浏览器最先支持WebSocket,随后是Safari,Firefox,此外最新版本的Opera和IE(Opera11,IE10)也支持WebSocket。
下面是主要浏览器的支持情况,Opera11中默认关闭了WebSocket支持,所以这里没有列出,更多信息可参考:http://en.wikipedia.org/wiki/WebSocket http://caniuse.com/#search=websockets

客户端WebSocket的主要方法

浏览器支持程度各有区别,前面wiki中关于WebSocket的“Browser support”章节有介绍,遵循w3c关于WebSocket API的相关规范,浏览器提供了WebSocket类型,在Firefox中为MozWebSocket,检测浏览器是否支持WebSocket可以使用 下面的脚本代码:

检测浏览器是否支持WebSocket

1
2
3
4
5
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket){
    alert("WebSocket not supported by this browser");
    return;
}

构造函数 – WebSocket#constructor(url, optional protocols)
第一个参数是请求地址,第二个参数选填,表示协议名
使用示例:

1
var websocket = new WebSocket("ws://127.0.0.1:8080/alarm/alarmServer");

事件 – open/message/close/error
WebSocket#onopen, onmessage, onclose, onerror
连接打开时,回调onopen方法,接收到后台消息时会触发到onmessage事件,后台关闭时调用onclose,出现连接异常时可在onerror中捕获
使用示例:

1
2
3
websocket.onmessage = function(evt){
    var data = evt.data;
}

方法 – send/close
发送消息 – WebSocket#send(data)
关闭连接 – WebSocket#close(optional code, optional reason)
使用示例:

1
websocket.send(JSON.stringify({action: "node.remove", id: "001"}));

服务器对WebSocket的支持

WebSocket不同于http协议,传统的web服务器通常不支持WebSocket,比如tomcat目前就不支持(tomcat 7.0.26 支持WebSocket了),反倒是一些小众的或者更活跃的web server率先支持WebSocket,如jetty,以及基于node.js的WebSocket-Node扩展,基本上各种编程语言都有相应的服务 器可以选择,下图是我列举的几种,详细情况参阅:http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations

服务器端编程语言各不相同,具体实现自然也不相同,即使是同一种语言,实现类和接口函数也有很大的差别,比如jetty和netty都是基于 java语言,但他们的实现类几乎没有相同命名的,下面我以jetty(http://www.eclipse.org/jetty)为例,简单介绍 WebSocket相关的类和方法:

jetty对WebSocket的实现

WebSocketServlet基于servlet标准,增加了doWebSocketConnect(…)方法,为客户端请求创建一个后台对应的WebSocket实例

1
2
3
4
org.eclipse.jetty.websocket.WebSocketServlet
{
WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
}

后台WebSocket类,与客户端WebSocket类对应,能监听open, message, close等状态变化事件,并包含一个Connection属性,用于向客户端发送消息

1
2
3
4
5
6
7
org.eclipse.jetty.websocket.WebSocket
org.eclipse.jetty.websocket.WebSocket.OnTextMessage
{
void onOpen(Connection connect);
void onClose(int code, String message);
void onMessage(String message);
}

WebSocket.Connection 后台连接类,包含于WebSocket对象中,用于向客户端推送消息

1
2
3
4
org.eclipse.jetty.websocket.WebSocket.Connection
{
void sendMessage(String message);
}

本篇先做介绍,后续将介绍一个WebSocket与TWaver组件结合的实例…

[转载]利用正则表达式排除特定字符串

mikel阅读(1019)

[转载]利用正则表达式排除特定字符串 – 薰衣草的旋律 – 博客园.

1.例子,查找不以baidu开头的字符串。
baidu.com
sina.com.cn

正则:^(?!baidu).*$  匹配结果就是第2行,也就是第1行被排除了
这里使用了零宽度断言(?!exp),注意,我们有一个向前查找的语法(也叫顺序环视)  (?=exp)
(?=exp) 会查找exp之前的【位置】如果将等号换成感叹号,就变成了否定语义,也就是说查找的位置的后面不能是exp
一般情况下?!要与特定的锚点相结合,例如^行开头或者$行结尾,那么上面的例子的意思如下:
^(?!baidu).*$ 先匹配一个行开头的位置,并且要求接下来的位置的后面不是baidu这个字符串。这样由于第一行^之后的位置后面是baidu所以匹配失败,被排除在外了。

2.例子,查找不以com结尾的字符串。
www.sina.com.cn
www.educ.org
www.hao.cc
www.baidu.com
www.123.com

正则 ^.*?(?<!com)$  匹配前3行结果。
如果查找以com结尾的字符串则使用正则 ^.*?(?<=com)$或者 ^.*?com$
对正则表达式的解释:^.*?(?<!com)$
首 先匹配行开头,让后是 .*? 这个是忽略优先,也就是优先忽略不匹配任何字符,(?<!com) 这个是一个逆序环视的否定形式,意思是匹配一个位置此位置的前面不能是字符串com,最后是一个行结束。对于www.123.com来说,首先匹配行首, 接着匹配w后面的位置,发现前面不是com,所以成功但紧接着要匹配行尾,失败,回溯让.*? 匹配一个w符号,接着(?<com)匹配第二个w后面的位置,发现前面也不是com匹配成功,紧接着要匹配$对应的行尾失败,一直到.*?匹配了 www.baidu.com的时候,此时(?<!com)匹配m后面的位置,此时此位置的前面是com匹配直接失败,接着.*?匹配行末尾, (?<!com)匹配$后面的位置,显然这次也失败了,所以整个全局匹配都失败。  www.123.com被排除到匹配之外。这里的.*后面加不加问号结果都一样。

3.例子查找不含有if的行
if (a>b)
printf(“hello”);
else if(a<b)
printf(“hello2”);
else
printf(“hello3”);

正则 ^([^f]|[^i]f)+$
其实这个匹配也是一个排除型字符串的匹配,但是不同于上面两种,因为这里的if可能既不在行开头,也不在行结尾,而是在字符串中间这样就给匹配带来了麻烦,在正则表达式中没有提供类似排除的功能。我们最容易想到的就是下面的正则:
^[^if]+$ 这种写法看起来是那么回事,但是排除型字符组排除的是i和f两个字符,而不是if这个字符串,所以这个正则表达式匹配的是那些既没有i字符也不包含f字符 的字符串。但是如果字符串中有一个i或多个i或者有一个或多个f,或者i和f字符都有只不过没有连在一起。这些情况都是我们需要匹配的情况,而我们不能匹 配的情况是那些包含if字符串的行,而不是包含i或f字符的行,所以这种写法漏洞很大。

^.*(?!if).*$ 这种写法使用了零宽度断言,表面意思看起来好像是说 任意字符+非if+任意字符 组成了整个字符串,但是仔细研究匹配过程就知道这个是错的,(?if)匹配的是一个位置,所以对于字符串aifb他也是可以匹配到的,而实际上这样的字符 正是我们不要的。按照这个正则表达式,对于aifb 首先匹配行首,其次.*是贪婪模式(匹配优先),会一直匹配到字符串的末尾(此时传动装置定位在$位置前面),此时(?!if)需要匹配一个位置,这个位 置的后面不能是if,这个时候正好位置在b字符的后面,符合匹配条件,紧接着匹配行尾,到这里整个全局匹配成功。

也就是说对于一个字符串 例如我要排除abc这个字串,那么对于任意一个字符串   helloworld abc helloworld 在匹配的时候(?!abc)可以匹配h、e、l、l、o、w、o、r、l、d等这些字符后面的位置,都是成功的。所以匹配根本还没有进行到abc这个地 方,(?!abc)就会匹配成功。这个时候根本起不到排除的作用,为什么上面的第1和第2个例子可以呢,因为他们的位置有行首和行尾限定。例如我要匹配行 首不是abc的话,那么此时^(?!abc) 这个时候(?!abc)实际上在匹配的时候其传动装置的位置被行首进行了限定,所以对于那些以abc开头的字符串来说就会匹配失败了。

对于正则表达式^.*(?!abc).*$怎么能让第一个.*匹配到 helloworldabcxxx中的helloworld的问题。

对 于上面的题目,我们的答案是^([^f]|[^i]f)+$  起始就将所有的匹配分成了2种情况,一种情况是假设字符串中没有f字符,    自然就不可能有if字符串了,这种情况下匹配的字符串中是不可能有if的。第二种情况就是有f字符,但是我们要求此时f的前面不能是i,所以在有f和没 有f两种情况都考虑到的情况下,这个正则就应该可以满足所有的情况了。

其实这个问题的解答是不完美的,对于排除的字符串if只有2个字符i和f字符,我们可以使用这种方式,但是如果我们要排除的是字符串helloworld,这种方法显然就不实用了,那要考虑到多少总情况呢?

在 这种情况下我们使用  ^(?!.*helloworld).*$  正则表达式  我们将第一个.*移到了零宽度断言的里面。在匹配的时候首先匹配行首的位置,然后接下来是匹配行首后面的位置,要求此位置的后面不能是    .*helloworld 匹配的字符串,说白了要求此位置的后面不能是xxxxxxxxxxxxxxxxxxhelloworld 类似的字符串,这样就排除了从行首开始后面含有helloworld的情况了。

[转载]说说.NET中被我忽视的方法

mikel阅读(1003)

[转载]嘿,原来不认识你,想不到你这么好用—说说.NET中被我忽视的方法 – Gyoung – 博客园.

NET中有些方法以前没有接触过,但用过了之后让人眼前一亮,哇,原来你这么好用。

下面就说说被我忽视过的方法。当然,每个人的编程经历,涉猎面及对.NET的认知程度都不一样。所以,这只是一家之言,肯定有很多不足之处,欢迎大家批评指正。

1. ADO.NET类

DataTable.Merge()

如何合并两张表?自己以前写的方法:

复制代码
private void UniteTable(DataTable sourceTable, DataTable targetTable) { foreach (DataRow row in sourceTable.Rows) { DataRow newRow = targetTable.NewRow(); //将sourceTable中row的值赋给对应的targetTable中的row
                newRow["column1"] = row["column1"]; //...
 targetTable.Rows.Add(newRow); } }
复制代码

哎,这个方法很傻很天真吧,其实DataTable中早就提供了合并两张表的方法,就是DataTable.Merge()。合并两张表,只要一条语句就行:

targetTable.Merge(sourceTable);

DataRow.ItemArray

结构相同的情况下,如何将一行的值赋给另一行?自己以前都这样写:

            DataRow row1 = table1.Rows[0]; DataRow row2 = table2.Rows[0]; row1["column1"] = row2["column1"]; row1["column2"] = row2["column2"]; //...

老天,要是有30多个列我可怎么办。其实DataRow有个ItemArray属性,只要一句话就完成了:

row1.ItemArray = row2.ItemArray;

SQLCommand.Parameters.AddWithValue()

SQLCommand执行存储过程的时候怎么增加参数,类似这样做就可以了:

复制代码
 //设置参数名和类型
                cmd.Parameters.Add("@Target", SqlDbType.NChar); cmd.Parameters.Add("@Description", SqlDbType.NChar); cmd.Parameters.Add("@Actor", SqlDbType.NChar); //给参数赋值
                cmd.Parameters[0].Value = "ATarget"; cmd.Parameters[1].Value = "Description"; cmd.Parameters[2].Value = "Actor";
复制代码

上面都分了两步,增加参数,然后再给参数赋值,其实我们可以一步到位的:

                cmd.Parameters.AddWithValue("@Actor", "Actor"); cmd.Parameters.AddWithValue("@Target", "Target"); cmd.Parameters.AddWithValue("@Description", "Description");

 2. 集合类

List.AddRange()

怎么在List中怎样添加多个值,曾经的我是这样子的:

List<int> list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); list.Add(4);

其实完全可以用一个方法就搞写,它就是AddRange().(在很多类中都有AddRange(),这里我只是用LIST来举例)

list.AddRange(new int[] { 1,2,3,4});

List.Find()与List.FindAll()

在List中查找特定值?以前我都是这样做:

复制代码
 foreach (int i in list) { if (i == 3) { Console.Write(i); } }
复制代码

其实完全可以不用foreach循环,用Find()就可以很好的解决:(FindAll()与Find()用法相似)

int result = list.Find(delegate(int i) { return i == 3; });

 3 控件类

DataGridView.HitTest()

DataGridView中如何获取当前鼠标位置所在的行数与列数?我认为DataGridView会有这样的方法,但找了很久都没找到。终于工夫 不负有心人,在VS智能提示下点点终于找到了。只怪这坑爹的命名HitTest?为毛不是Get,Find,Index之类开头啊。返回值还是一个内部 类:DataGridView.HitTestInfo

 //捕获鼠标点击区域的信息
            DataGridView.HitTestInfo hitTestInfo= this.sourceGrid.HitTest(e.X, e.Y); //获取所在行数
            int rowIndex = hitTestInfo.RowIndex; //获取所在列数
            int columnIndex = hitTestInfo.ColumnIndex;

ListBox.IndexFromPoint()

同样的,ListBox也有一个根据Point来获取行数的方法,即IndexFromPoint().你看,这个命名好多了:

 

 // Get the index of the item the mouse is below.
           indexOfItemUnderMouseToDrag = ListDragSource.IndexFromPoint(e.X, e.Y);

4.其它

进制转换.

以前做进制转换,比如十六进制转八进制,还自己写过一个独立的方法。坑爹的,其实远不用这么麻烦,Convert.ToInt32()与string.Format()都有提供重载方法来实现:

 //将十六进制“10”转换为十进制i
            int i = Convert.ToInt32("10", 16); //将十进制i转换为十六进制s
            string s = string.Format("{0:X}", i);

PS.我这里只提供示例,关于上面提到方法的详细应用大家可以自行百度。

[转载]ASP.NET MVC Razor视图引擎攻略

mikel阅读(1172)

[转载]ASP.NET MVC Razor视图引擎攻略 – 菊花台泡茶 – 博客园.

一,创建基于Razor的Web程序

  首先你的开发环境必须安装.NET Framework4.0,然后在VS中新建项目时选择ASP.NET MVC 3 应用程序,在选项页面中选择视图引擎为Razor,如图1:

图1

 

然后创建项目,就会得到一个基于Razor的Web项目了,如图2。

 图2

相信熟悉MVC的看官们对此结构并不陌生。注意红框部份,Razor的页面是以cshtml为后缀的,下面我们来讲下如何使用Razor来进行页面布局。

 

二,使用Razor来进行页面布局

UI设计师们现在也讲究页面设计的语义化和结构化,把一个页面分成很多个模块,使用语义化的类名或id来标识这些模块。Razor推出了新的布局解决方案来迎合这一潮流。

这里涉及到Razor的一些语法,大家可以不深究“@”后面的内容,讲到页面布局,你只要专注与HTML代码就可以了。语法会在后面补充。

 1.指定母版与加载机制

首先我们来看_ViewStart.chhtml页面,它的内容很简单:

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

这句代码指定了默认的母版的位置: 当前应用程序根目录下<“~”的含义>的Views/Shared/_Layout.cshtml

除非特殊情况,比如视图是Partial视图,或显示的在视图中添加以下代码指示不使用母版:

@{ Layout = null; }

其他情况下,该指定页就是视图的母版页。

然后我们来看看Razor母版页_Layout.cshtml的内容:

View Code

@ViewBag.Title
<script type="text/javascript" src="@Url.Content("></script>

<div class="page">

<div id="header">

<div id="title">

<h1>我的 MVC 应用程序</h1>

&nbsp;
</div>

  

<div id="logindisplay">欢迎 <strong>@User.Identity.Name</strong>!</div>

  

<div id="menucontainer">
<ul>
<ul>
<ul>
	<li>@Html.ActionLink("主页", "Index", "Home")</li>
</ul>
</ul>
</ul>

&nbsp;

&nbsp;

<ul>
<ul>
	<li>@Html.ActionLink("关于", "About", "Home")</li>
</ul>
</ul>

&nbsp;

     
</div>
</div>

  

<div id="main">@RenderBody()<!--一般视图内容的占位符--></div>

  

<div id="footer"></div>
</div>

注意@RenderBody()这个方法相当于一个占位符,假如我们的首页视图Index.cshtml是这样,

 View Code @{ ViewBag.Title = "主页"; } 

<h2>@ViewBag.Message</h2>

若要了解有关 ASP.NET MVC 的更多信息,请访问 <a title="ASP.NET MVC 网站" href="http://asp.net/mvc">http://asp.net/mvc</a>。 

一般的视图处理,比如当服务器响应一个HomeController.Index()请求的时候,需要返回Index视图,

      • 首先会加载母版页_Layout.cshtml的内容,

 

 

    • 遇到@RenderBody()时,就用首页视图的内容置换到这里,最后处理完成返回静态页面。

 

      2.使用Partial视图   MVC 2.0中,你需要使用<asp:Content></asp:Content>标签来进行页面分割,太多的话自己都忘记了哪个对应的是哪个部份。   在Razor中,可以将需要剥离出来的部份作为一个单独的Partial视图,比如网站的头部(Logo,导航等等..),底部(友情链接,版权声明等等..),或是某个功能模块(登陆框等等..)。   比如上面的母版页,我们可以把它的头部和底部剥离出来,在Share文件夹下右键添加/视图,选择创建为分部视图,如图3:   图3     依照上述步骤创建”_HeaderPartial.cshtml“和”_FooterPartial.cshtml”两个视图:

 <!--_HeaderPartial.cshtml--> 

<div id="header">

<div id="title">

<h1>我的 MVC 应用程序</h1>

&nbsp;
</div>

  

<div id="logindisplay">欢迎 <strong>@User.Identity.Name</strong>!</div>

  

<div id="menucontainer">
<ul>
<ul>
<ul>
	<li>@Html.ActionLink("主页", "Index", "Home")</li>
</ul>
</ul>
</ul>

&nbsp;

&nbsp;

<ul>
<ul>
	<li>@Html.ActionLink("关于", "About", "Home")</li>
</ul>
</ul>

&nbsp;

     
</div>
</div>

     可以看出,提取Partial视图很简单,就是把需要的内容提取出来,放在新建的Partial视图中。然后,我们还需要干一件事情,   类似于一般视图,Partial视图使用自己特有的占位符来替换原内容。我们这么干之后,原_Layout.cshtml页就变成了这样:

 @ViewBag.Title<script type="text/javascript" src="@Url.Content("></script>
<div class="page">@Html.Partial("_HeaderPartial")<!--_HeaderPartial视图占位符--></div>
<div id="main">@RenderBody()</div>
@Html.Partial("_FooterPartial")<!--_FooterPartial视图占位符-->

这样,页面的布局是不是更清爽简洁了?如同一般视图,返回请求时会先加载母版页然后遇到占位符时加载相应的Partial视图,最后返回处理完成的静态页面。

 

三,Razor语法简介与应用

 

     1.语法简介

  如果我们希望在HTML代码中绑定数据,比如说我们有一个产品的对象Product,需要绑定产品的名称Product.Name,只需要在变量前面加“@”即可,

  也可以使用“@(expression)”绑定一个表达式:

<p>@Product.Name</p>
<p>@(Product.Price*0.8)</p>

Razor中使用”@{code}“来标识一段C#代码,代码段可以出现在任何位置,并且支持与HTML混写:

@{
var product=new product();
product.Name="pen";
product.Price=1.00;

@product.Name

@product.Price

}

使用循环或条件语句时直接加”@”前缀,可以控制页面逻辑:

@foreach(var product in products)

@item.Name

Razor中注释是”@**@”,即可以注释Html代码,也可以注释C#代码,在代码块中仍可使用C#的注释方式:
复制代码

@{
var product=new product();
product.Name=”pen”;
//product.Price=1.00;

@product.Name

@*

@product.Price

*@
}

2.ASP.NET MVC3.0 Web中的应用

假设我们有一个Product类位于JohnConnor.Data命名空间下,有Name和Price两个属性,HomeController.Index()方法返回一个List对象给Index视图,

打印所有产品名称,并且点击产品名称时,弹出产品价格。

HomeController.Index()方法如下:

View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JohnConnor.Data;

namespace JohnConnor.Web.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var products = new List()
{
new Product{ Name="钢笔", Price=11.55M},
new Product{ Name="铅笔", Price=2.17M},
new Product{ Name="圆珠笔", Price=5.98M},
};
return View(products);
}
}
}

我们来改一下Index视图演示一下Razor的简单应用。

@using JohnConnor.Data;
@model List @{
ViewBag.Title = "主页";//母版中ViewBag.Title用于绑定Title标签,这里进行赋值。
}
<h2>Razor</h2>
@foreach (var product in Model)
{
//遍历所有的产品
<input onclick="alert(@product.Price)" type="button" name="@product.Name" value="@product.Name" />
}

在一般视图中,首先声明视图模型,即Action返回的ViewResult对象的类型<也可以不声明,如果有返回对象建议声明>

这里的视图模型是一个List<Product>集合,因为Product位于using JohnConnor.Data命名空间,所以先添加了引用。

母版中ViewBag.Title用于绑定Title标签,在一般视图中就可以进行赋值来绑定页面的Title 。

  如果你不想使用母版,就在代码块中添加”Layout = null;”。

  最后是就是一些数据绑定,或者是逻辑的处理。

  

  Razor的基本内容大概就讲这些了,当然它还有很丰富的底蕴,需要在实际的运用过程中去学习,一篇短文是无法涵盖所有信息的。

  最后提一点,Razor暂时没有设计视图,这是比较悲摧的一点。相信之后会有的。如果对Razor的使用有任何问题,可以在此提出,能力范围内的问题我都可以提供帮助。

  希望大家多多支持。

[转载]如何在asp.net mvc3中使用HttpStatusCode

mikel阅读(932)

[转载]如何在asp.net mvc3中使用HttpStatusCode – Nic Pei – 博客园.

下载了ASP.NET mvc 4的源码看了看,没怎么看清楚。不过个人觉得MVC4 beta中Web API这个是比较不错的,虽然说它是往传统回归。 web api最好的莫过于它更加适合使用JQuery的ajax调用。

 

我这里主要给大家说明下如何在ASP.NET mvc 3中借鉴Web API的特性来让AJAX调用更加酷。

首先给大家看个例子,传统的ASP.NET mvc 3中异步调用的Response:

Action如下:

 

image

 

相应的JQuery ajax请求代码(只是简单的代码,):

image

 

我们来运行看一下Response的信息:

Response Header信息:

image

 

状态码是200 OK。绿色,Smile 

返回的JSON数据:

image

 

现在我们想使用http.net定义好的Status来根据不同的操作来返回不同的状态码,比如当创建一条记录成功时,我们返回201成功,当没有权限时,我们返回没有权限。

 

现在我们试着修改Action如下:

image

 

只是添加一行代码: Response.StatusCode,也就是说这个Action是创建人员信息,当信息创建成功时,返回给浏览器说:Hi,创建成功了。以前你可能是 去通过JQuery的ajaxSuccess来去进行后续操作,好吧,现在你可以通过判断客户端获得的状态码来判断是该进行哪步操作了。

 

试着运行下:

image

 

这时你可以看到我们得到的状态码是201,对应的Response Header的信息:

image

 

它也不再是200 OK,而是201 Created。

 

在Asp.net http.net命名空间中,定义了很多Status Code:

image

 

这里你可能会想到,对于AJAX请求 这种方式,安全方面就可以使用这种方式来统一处理啦。 当一个请求没有权限时,我们使用一个Filter来告诉它,Hi 你这个请求不可以,返回上图红色框内的状态码:400。那么对应的如果是Web请求,你就可以不冤枉它的把这个请求者转到登陆页面,巴拉巴拉巴拉。。。

 

首先我们需要定义一个Filter:

image

 

在PostPerson的Action中使用这个Filter:

image

 

编译后,运行:

image

 

可以看到,Status Code是400,Bad Request。 对应的Response当然也不会有数据啦,我们可以在jQuery的ajax请求中,判断当status code是400时,location.href=”any where ha”:

 

Cheers