1.Action中返回值 :
return this.Json(new { success = true, redirect = returnUrl });
[AllowAnonymous]
[HttpPost]
public JsonResult JsonLogin(LoginModel model, string returnUrl) {
if (this.ModelState.IsValid) {
if (Membership.ValidateUser(model.UserName, model.Password)) {
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return this.Json(new { success = true, redirect = returnUrl });
} else {
this.ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed
return this.Json(new { errors = this.GetErrorsFromModelState() });
}
大家都很少用到这个ActionResult,因为它的基本用法是返回文本,也许下面这段代码可以说服你
public ContentResult RSSFeed()
{
Story[] stories = GetAllStories(); // Fetch them from the database or wherever
// Build the RSS feed document
string encoding = Response.ContentEncoding.WebName;
XDocument rss = new XDocument(new XDeclaration("1.0", encoding, "yes"),
new XElement("rss", new XAttribute("version", "2.0"),
new XElement("channel", new XElement("title", "Example RSS 2.0 feed"),
from story in stories
select new XElement("item",
new XElement("title", story.Title),
new XElement("description", story.Description),
new XElement("link", story.Url)
)
)
)
);
return Content(rss.ToString(), "application/rss+xml");
}
上面的代码返回了一个RSS。值得注意的是,Content的第二个参数是个contentType(MIME类型,参见www.iana.org/assignments/media-types),如果不指定这个参数将使用text/html的contentType。
事实上我们的action可以返回一个非ActionResult,MVC在执行action的返回结果前,会确保将返回值转换成一个ActionResult,其中一步,就是对非空和非ActionResult的结果转换成string,并包装成ContentResult:
protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) {
if (actionReturnValue == null) {
return new EmptyResult();
}
ActionResult actionResult = (actionReturnValue as ActionResult) ??
new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };
return actionResult;
}
Json():返回JsonResult
Controller的Json方法能返回一个JsonResult,出于安全性的考虑JsonResult只支持POST方式,设置response.ContentType = "application/json";并利用JavaScriptSerializer序列化对象,并返回给客户端。像下面这样使用JsonResult:
class CityData { public string city; public int temperature; }
[HttpPost]
public JsonResult WeatherData()
{
var citiesArray = new[] {
new CityData { city = "London", temperature = 68 },
new CityData { city = "Hong Kong", temperature = 84 }
};
return Json(citiesArray);
}
JavaScript():返回JavaScriptResult
JavaScript方法实例化一个JavaScriptResult,JavaScriptResult只是简单的设置response.ContentType = "application/x-javascript";
File():返回二进制数据或文件
FileResult是个抽象类,File方法的多个重载返回不同的FileResult:
FilePathResult:直接将一个文件发送给客户端
public FilePathResult DownloadReport()
{
string filename = @"c:\files\somefile.pdf";
return File(filename, "application/pdf", "AnnualReport.pdf");
}
FileContentResult:返回byte字节给客户端比如图片
public FileContentResult GetImage(int productId)
{
var product = productsRepository.Products.First(x => x.ProductID == productId);
return File(product.ImageData, product.ImageMimeType);
}
<img src="<%: Url.Action("GetImage", "Products", new { Model.ProductID }) %>" />
FileStreamResult:返回流
public FileStreamResult ProxyExampleDotCom()
{
WebClient wc = new WebClient();
Stream stream = wc.OpenRead("http://www.example.com/");
return File(stream, "text/html");
}
2.跳转:
return RedirectToAction("Index");
return RedirectToAction("Index", "Login");
return RedirectToAction("Index", "Login", new { searchCode = TraceCode });
return RedirectToAction("Index", new { searchCode = TraceCode });
3.Action中添加cookie:
HttpCookie _cookie = new HttpCookie("User");
_cookie.Values.Add("UserName", login.UserName);
_cookie.Values.Add("Password", Common.Text.Sha256(login.Password));
Response.Cookies.Add(_cookie);
4 异步请求
异步处理请求的意义
大伙儿都知道,ASP.NET通过线程池处理请求,对于每个请求从线程池中请求一个可用的线程来处理请求,当请求处理完毕之后,线程资源将被归还到线程池。然而,线程池中的线程是互斥资源,当网站在同一时刻的请求量达到一定数量的话,必然会导致这种资源不够耗尽,新来的请求只能等待有新的线程归还才能被处理。当然这不是最糟糕的,通常每个请求只需要很短的时间就可以了,新的请求不会等待太长的时间,但是,如果处理请求需要花费较长的时间呢?比如一次耗时的数据库查询、一次外部web service请求这类的IO操作。注意这里特指的IO操作,指的是不会占用ASP.NET线程池线程的,甚至不占用本机CPU资源的操作。正因为如此,异步处理请求在这种情况下尤其适用。当异步处理请求时,占用的线程会在耗时的IO操作开始前,将线程归还给线程池,直到IO操作完成后,再从线程池中请求一个线程,并恢复当时的HttpContext,处理IO操作的结果。这样就不会占用宝贵的线程资源了。
MVC支持异步地处理请求。可以通过下面的三种方式:
1.实现一个自定义的RouteHandler,并为GetHttpHandler方法返回一个实现IHttpAsynHandler的对象。
2.创建一个自定义的基类Controller,并实现IAsyncController,IAsyncController是IController的异步版本。
3.MVC内置了一个AsyncController,它实现了上述的IAsyncController,通过简单的继承AsyncController,即可实现异步。
下面仅对第三种方法作简单介绍。假设某个Action需要调用一个web service,并处理结果后返回:
public ContentResult GetPhotoByTag(string tag)
{
...
using (var response = WebRequest.Create(url).GetResponse())
{
// Parse the response as XML
var xmlDoc = XDocument.Load(XmlReader.Create(response.GetResponseStream()));
...
}
...
}
显然,如果这个web request消耗2s,那么这个请求将hold这个线程至少2s。这种同步的处理方式显然不合理,想要异步处理,只需按如下步骤进行:
1、替换基类Controller为AsyncController
2、创建两个配对的Action:ActionNameAsync和ActionNameCompleted。ActionNameAsync方法必须返回void,在内部启动一个耗时的IO操作前,需要使用AsyncManager.OutstandingOperations.Increment()向MVC框架“注册启动”,在IO方法返回后,可以在AsyncManager.Parameters字典中保存希望传给ActionNameCompleted方法的参数。最后调用AsyncManager.OutstandingOperations.Decrement()通知MVC框架操作完成,此时,MVC框架会自动调用ActionNameCompleted。ActionNameCompleted需要向通常的Action一样,返回一个ActionResult。因此上面的代码需要改写成如下这样:
public void GetPhotoByTagAsync(string tag)
{
//向MVC中注册启动
AsyncManager.OutstandingOperations.Increment();
...
WebRequest request = WebRequest.Create(url);
//启动一个异步的web request
request.BeginGetResponse(asyncResult =>
{
using (WebResponse response = request.EndGetResponse(asyncResult))
{
var xml = XDocument.Load(XmlReader.Create(response.GetResponseStream()));
...
//将结果photoUrls,保存在AsyncManager.Parameters中
AsyncManager.Parameters["photoUrls"] = photoUrls;
//通知MVC框架操作完成 ,准备调用Completed
AsyncManager.OutstandingOperations.Decrement();
}
}, null);
}
//像通常的Action一样,这里的参数photoUrls将在AsyncManager.Parameters中匹配
public ContentResult GetPhotoByTagCompleted(IEnumerable<string> photoUrls)
{
return Content(string.Format("<img src='{0}'/>", photoUrls.First()));
}
当然,可以设置异步操作的超时时间:
[AsyncTimeout(10000)] // 10000 milliseconds equals 10 seconds
public void GetPhotoByTagAsync(string tag) { ... }
上面的代码如果超时了,将抛出TimeoutException异常,我们可以用希望的方式处理它。
当使用类似BeginGetResponse这类的异步方法,并提供回调函数参数时,你无法控制回调函数调用在哪个线程上。大多数情况下,甚至不在ASP.NET的工作线程上。所以回调函数无法关联原始的HttpContext对象。
幸好,AsyncManager提供了一个Sync()方法,它会将一个委托在ASP.NET的工作线程上启动,并关联原始的HttpContext对象。而且它保证线程安全:
BeginAsyncOperation(asyncResult => {
var result = EndAsyncOperation(asyncResult);
// Can't always access System.Web.HttpContext.Current from here...
Action doSomethingWithHttpContext = () => {
// ... but can always access it from this delegate
};
if (asyncResult.CompletedSynchronously) // Already on an ASP.NET thread
doSomethingWithHttpContext();
else // Must switch to an ASP.NET thread
AsyncManager.Sync(doSomethingWithHttpContext);
AsyncManager.OutstandingOperations.Decrement();
}, null);
5. 全局过滤器
ASP.NET MVC 支持通过过滤机制来描述性地应用“横切”逻辑。 你可以使用属性语法为控制器和执行函数指定过滤器,如下所示image
但在使用中,我们常常希望将一些过滤器逻辑应用于程序中的所有控制器上,如Authorize过滤器。
现在ASP.NET MVC3 能够让你指定一个全局的过滤器,这个过滤器可以应用于程序中的所有控制器上。
如下图所示:在Global文件中将自定义过滤器加入GlobalFliterCollection中就可以了
在MVC3中,这个过滤器的判定逻辑非常灵活,你可以配置一个全局过滤器,使它只在某些条件符合的时候才启用。
如下图所示,我实现了一个全局权限过滤器,在任何页面如果没有登录的话则跳转到LogOn页面。因为是全局的,当跳转到LogOn页面时,
也要判断是否有权限,所以最终页面上什么都不显示。
那如何解决这个问题呢,让LogOn页面不应用该全局权限呢?
如下图所示:我们实现一个IFilterProvider,在里面过滤掉LogOn页面而应用于其他的页面。代码如下:
在使用Authorize过滤器时,发现了一个bug,就是当没有权限时,系统会自动跳到“Account/LogIn”页面,而不是跳转到webconfig中设置的页面。
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
这个设置好像不起作用了,通过查看ScottGu’s Blog,知道这是一个bug,解决方案就是在Configuration配置节下加入
<appSettings>
<add key="autoFormsAuthentication" value="false" />
</appSettings>
我想在正式版中不会再有这个问题了。
6.Rozar
7.Action 在方法里面获取参数:
[HttpGet]
pulbic ActionResult Login()
{
string name = Request.QueryString("name");// get 方式的请求
string pass = Request.QueryString("pass");
}
string name = Request.Form["name"]; form 表单的请求
string pass = Request.Form["pass"];
string name = Request.Parems["name"]; // get,post方式的请求都能获取到参数
string pass = Request.Parems["pass"];
public ActionResult Login(string name,string pass)
{
}
8.RoteData
Action 中获请求参数的方式:
Action 在方法里面获取参数:
[HttpGet]
pulbic ActionResult Login()
{
string name = Request.QueryString("name");// get 方式的请求
string pass = Request.QueryString("pass");
}
string name = Request.Form["name"]; form 表单的请求
string pass = Request.Form["pass"];
string name = Request.Parems["name"]; // get,post方式的请求都能获取到参数
string pass = Request.Parems["pass"];
public ActionResult Login(string name,string pass)
{
}