65.9K
CodeProject 正在变化。 阅读更多。
Home

在ASP.NET MVC和jQuery中工作时需要考虑的一些要点

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (2投票s)

2012年4月27日

CC (ASA 3U)

7分钟阅读

viewsIcon

24395

在ASP.NET MVC和jQuery中工作时需要考虑的一些要点

引言

我们知道,ASP.NET MVC提供了

  1. 一种基于模式的方法来构建网站。
  2. 清晰的职责分离
  3. 遵循最新的Web标准

这些功能与jQuery(一个轻量级的JavaScript库,带有一些非常有用的开箱即用函数)一起,极大地改善并在一定程度上简化了Web应用程序开发人员的工作。有关最新的jQuery版本以及相应要包含的“js”文件,请参阅此链接

本文将根据我过去的编码经验,尝试找出一些要点,如果考虑到这些要点,可能会帮助新开发人员更好地利用上述功能。本文也可能有助于修复相当多的错误类型,否则寻找相应的解决方案将非常耗时。

假设

读者了解ASP.NET MVC(例如,模型、视图、控制器等)和jQuery(例如,函数、选择器等)的基本术语。

1. 数据如何在客户端和服务器端之间映射和传递

很多时候,初学者会惊讶于数据是如何如此正确地从客户端映射和传递到服务器,反之亦然。在我们早期的Web应用程序编程实践中,我们很多人一定使用过“HTML隐藏变量”来在客户端和服务器端之间传递数据。ASP.NET MVC框架也考虑了这一概念。

在ASP.NET MVC中,每当我们想使用模型对象实例从客户端向服务器端发送一些数据时,我们在相关视图中使用以下类型的HTML控件(例如,复选框)语法

<% : Html.CheckBoxFor(m => m.SomeBooleanModelProperty,
new { any attributes for the check in the key-value format, e.g. onclick="fnCheckSelection();"
})%> 

其中m表示视图所绑定的模型。请注意是CheckBoxFor,而不仅仅是CheckBox

一旦此控件在客户端浏览器中渲染,如果我们查看HTML源代码(即通过IE中的View-Source),我们会注意到一个同名的隐藏变量也被添加,与复选框同名。此“名称”与视图模型中的属性相同

<input name="SomeBooleanModelProperty " onclick="fnCheckSelection();" type="checkbox" value="true" />
<input name=" SomeBooleanModelProperty " type="hidden" value="false" />

因此,复选框的选择(即表示选中或未选中的布尔值)在回发时传播到服务器端。类似地,我们可以使用Html.TextBoxFor传递文本。

因此,如果您需要传递或分配回模型中未直接链接到某个控件(如上所述)但需要在回发中可用的某些参数,例如,对于某些控制器操作,例如

[HttpPost] 
public ActionResult Save(SomeModelObject model) 
{ 
    //some code here 
}

我们可以使用hidden类型控件,例如

<input name="<%= "ProjectName" %>" type="hidden" value="<%= Model.ProjectName %>" /> 

其中ProjectName是模型中的某个属性。如果我们不这样做,那么在操作参数模型对象中,此属性的值将丢失,即,如果类型是string,则回发后该值将为null。

2. 可选参数必须是可为空类型

假设我们的控制器中有一个动作,例如

public ActionResult Index(string id) 
{
    // do something… 
}

此操作可以由以下任一GET调用无问题地执行

完整的基于REST的URL:https://:portNumber/controllerName/indexhttps://:portNumber/controllerName/index/someID

在第一个选项中,传递给“id”参数的值将为null。因此,我们始终需要确保在这种参数可选的场景中,参数的类型应该是可为空的,否则我们将收到类似以下的错误消息

可选参数必须是引用类型、可为空类型或声明为可选参数。

在上面的示例中,默认情况下,提供的URL仅在操作签名中的变量名为“id”时才有效。如果变量是其他名称,例如identity,例如

public ActionResult Index(string identity) 
{ 
   // do something… 
}

那么GET URL必须是:https://:portNumber/controllerName/index?identity=someValue

否则,即使提供了正确的值,调用操作时参数的值也将为null。在下一点中,我们将看到如何为名称不是“id”的参数也拥有完整的基于REST的GET URL。

3. 完整的基于REST的GET URL,参数不是“id”

默认情况下,当在Visual Studio中创建ASP.NET MVC项目时,在新创建的Web应用程序中,以下方法会添加到Global.asax.cs

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    routes.MapRoute( 
    "Default", // Route name 
    "{controller}/{action}/{id}", // URL with parameters 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
    ); 
}

id更改为更合理的变量名,例如projectCode,然后我们可以在控制器中拥有一个操作签名,例如

public ActionResult Index(string projectCode) 
{ 
// do something… 
}

4. 向GET操作传递多个参数作为完整的基于REST的短URL

Global.asax.cs中上述方法中,更改参数列表为

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    routes.MapRoute( 
    "Default", // Route name 
    "{controller}/{action}/{ projectCode }/{nextParam}", // URL with parameters 
    new { controller = "Home", action = "Index", projectCode = UrlParameter.Optional, 
          nextParam = UrlParameter.Optional } // Parameter defaults 
    ); 
}

其中projectCode = UrlParameter.Optional表示projectCode是可选的,否则我们可以在它不是可选的情况下提供一个默认值。因此我们可以有一个操作签名,例如

public ActionResult Index(string projectCode, string nextParam) 
{ 
    //do something… 
}

然后可以这样访问此操作

https://:portNumber/controllerName/index/someProjectCode/someOtherParam.

通过这种方式,URL可以很短,否则我们将需要遵循基于QueryString的方法,并在URL中也提及参数的名称。

类似地,我们可以在URL中拥有任意数量的级别,但我们需要确保长度永远不会超过所涉及浏览器允许的字符数。例如,对于IE8和IE9,我相信它是2083个字符。检查其他浏览器的情况。一个好的选择是限制在256个字符以内以支持所有浏览器。

5. 模型对象的无参数构造函数

在调用控制器中任何类型的操作期间

[HttpPost] 
public ActionResult Save(SomeModelObject model) 
{ 
  //some code here 
}

ASP.NET MVC框架尝试实例化模型类型的对象,在此过程中,它期望模型定义中有一个无参数构造函数。很多时候我们一定会收到类似以下的错误消息

没有无参数构造函数...

要解决此类错误,我们需要确保模型定义中至少有一个无参数构造函数。

6. jQuery函数未被调用

很多时候,在使用jQuery为某些类型的控件注册事件时,例如“input”HTML元素的点击事件,我们编写函数为

$("input#btnSave").click(function (event) { 
  if ($(this).attr('disabled')) { 
    return false; 
  } 
  // do something… 
});

其中btnSaveinput类型HTML元素的ID。

但在运行时,点击id = btnSave的“input”HTML元素时,点击事件未被调用。这是一个非常常见的问题,HTML元素无法找到正确的事件。为了解决这个问题,作为最佳实践,对于所有此类事件注册,我们应该将上述代码放在document-ready事件中,例如

$(document).ready(function () { 
$("input#btnSave").click(function (event) { 
if ($(this).attr('disabled')) { 
return false; 
} 

// do something… 
});

这有助于避免在文档完成加载之前运行任何jQuery代码。因此,只有在所有控件加载完成后,才会为文档中的特定控件注册事件。

7. JSON未定义

即使在使用预期支持JSON的最新互联网浏览器时,我们也可能会收到类似以下的错误消息

JSON未定义。

对于类似以下的代码

JSON.stringify(someObject)

此类错误在旧版本的互联网浏览器中很常见,即使您在新版本的浏览器中收到任何(可能存在的)应用程序的此类错误,可能的原因是,在视图或母版页的某个地方,代码可能限制了浏览器(尽管是新版本)的执行,使其像旧版本一样。例如,在IE 8浏览器中,我可以在应用程序中配置为模拟并限制为IE 7(即,仅使用IE 7的功能和特性),通过提供

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

在相应的ASPX页面或母版页中。

要解决“JSON未定义..”问题,请务必删除此类标签。但是,如果确实有充分的理由限制使用旧版本的浏览器,但仍需要使用一些新的JSON功能(如上面提到的“stringify”),那么请在视图中显式包含相应的函数,例如

<script type="text/javascript"> 
var JSON = JSON || {}; 
// implement JSON.stringify serialization 
JSON.stringify = JSON.stringify || function (obj) { 
var t = typeof (obj); 
if (t != "object" || obj === null) { 
// simple data type 
if (t == "string") 
obj = '"' + obj + '"'; 
return String(obj); 
} else { 
// recurse array or object 
var n, v, json = [], arr = (obj && obj.constructor == Array); 
for (n in obj) { 
v = obj[n]; 
t = typeof (v); 
if (t == "string") 
v = '"' + v + '"'; 
else if (t == "object" && v !== null) 
v = JSON.stringify(v); 
json.push((arr ? "" : '"' + n + '":') + String(v)); 
} 
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}"); 
} 
}; 
</script>

这样,代码将在新旧浏览器版本中运行。有关上面所示其他JSON函数的定义,请参阅此链接

8. 异步GET和POST控制器动作调用

为了提供更好的用户体验,很多时候我们都需要异步地从服务器获取和发送数据。对于此类需求,基于AJAX的jQuery方法非常有用。

例如,对于GET调用

function fnGetData() { 
$.ajax( 
{ 
    type: "GET", 
    url: "/ControllerName/ActionName", 
    data: "param1=value1" + "&param2=value2" , 
    success: function (data, status) { 
    // do something with "data" 
    }, 
    error: function (req, status, error) { 
    alert("Error occurred while processing your request. Please contact the Administrator."); 
    } 
    }); 
}

其中data是控制器动作返回的对象,可能如下所示

public ActionResult ActionName (string param1, string param2) 
{ 
  //do something… 
}

例如,对于POST调用

function fnPostData() { 

//structure the parameter data to be posted 
$.ajax( 
{ 
    type: "POST", 
    url: "/ControllerName/ActionName", 
    data: "parameter1=parameterData1" + "&parameter2=parameterData2", 
    success: function (data, status) { 
    //do something with the "data" 
    }, 
    error: function (req, status, error) { 
    alert("Error occurred while processing your request. Please contact the Administrator."); 
    } 
    }); 
}

其中data是控制器动作返回的对象,可能如下所示

[HttpPost] 
public ActionResult ActionName (string parameter1, string parameter2) 
{ 
  //do something… 
}

我认为这里最好的部分是,发送到服务器的数据不属于URL字符串的一部分,而是消息正文的一部分。

历史

首次改进版本 - 2012年4月27日

© . All rights reserved.