您的位置:首页 > 编程语言 > ASP

(推荐)第15章 扩展ASP.NET MVC (IModelBinder、过滤器)

2017-11-11 10:54 381 查看
Authorization [ˌɔ:θərəˈzeɪʃn] 授权

一、 模型扩展

1 、把请求数据转换为模型

将请求数据(比如表单数据、查询字符串数据或路由信息)转换为模型的过程称为模型绑定。

模型绑定的过程分为两个阶段:

通过使用值提供器理解数据的来源

使用这些值创建/更新模型对象(通过使用模型绑定器)

(1)、使用值提供器解析请求数据

值提供器:访问能够在模型绑定过程中正确使用的信息。

(2)、创建带有模型绑定器的模型 IModelBinder

从值提供器系统中获取值,并利用获取的值创建新模型或者填充已有模型

ASP.NET MVC中默认模型绑定器可以对传统类、集合类、列表、数组甚至字典进行模型绑定。

不支持不可变对象,对象的初始值必须通过构造函数设置,之后不能改变。

示例1:Point类是不可变的,因此我们必须使用它的值构造一个新实例

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Web.Mvc;

namespace WebApplication3.Areas.ModelBinder.Utility
{
    public class PointModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext,
                                ModelBindingContext bindingContext)
        {
            //值提供器
            var valueProvider = bindingContext.ValueProvider;
            //从值提供器上获取值,创建新模型
            int x = (int)valueProvider.GetValue("X").ConvertTo(typeof(int));
            int y = (int)valueProvider.GetValue("Y").ConvertTo(typeof(int));
            return new Point(x,y);
        }
    }
}


当创建一个新的模型绑定器时,我们需要告知ASP.NET MVC框架存在一个新的模型绑定器以及何时使用它。

可以使用[ModelBinder]特性来装饰绑定类,也可以在ModelBinders.Binders的全局列表中注册新的模型绑定器

using System.Drawing;
using System.Web.Mvc;
using WebApplication3.Areas.ModelBinder.Utility;

namespace WebApplication3.Areas.ModelBinder
{
public class ModelBinderAreaRegistration : AreaRegistration
{
public override string AreaName { get { return "ModelBinder"; } }

public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"ModelBinder_default",
"ModelBinder/{action}/{id}",
new { controller = "ModelBinder", action = "Index", id = UrlParameter.Optional }
);
//ModelBinders.Binders全局列表中注册新的模型绑定器
ModelBinders.Binders.Add(typeof(Point), new PointModelBinder());
}
}
}
控制器、视图如下:

using System;
using System.Drawing;
using System.Web.Mvc;

namespace WebApplication3.Areas.ModelBinder.Controllers
{
public class ModelBinderController : Controller
{
public ActionResult Index()
{
return View(new Point(0, 0));
}

[HttpPost]
public ActionResult Index(Point pt)
{
//在本示例中,默认情况下客户端端验证是关闭的,以便您可以更容易地进入执行服务器端验证的代码。
//你可以在禁用客户端验证的视图中注释该行。显示客户端验证也适用于此示例。
if (ModelState.IsValid)
TempData["Flash"] = String.Format("Bind success! X = {0}, Y = {1}", pt.X, pt.Y);

return View(pt);
}
}
}
@model System.Drawing.Point
@{ ViewBag.Title = "Model Binder Sample"; }
@{ Html.EnableClientValidation(false); } @* 删除/注释此行以显示客户端验证仍然有效。 *@
@using (Html.BeginForm()) {
<p>@Html.ValidationSummary(excludePropertyErrors: true)</p>

<p>
@Html.LabelFor(m => m.X)
@Html.EditorFor(m => m.X)
@Html.ValidationMessageFor(m => m.X)
</p>
<p>
@Html.LabelFor(m => m.Y)
@Html.EditorFor(m => m.Y)
@Html.ValidationMessageFor(m => m.Y)
</p>

<p><input type="submit" /></p>
}

效果:



示例2:验证绑定的值

Get<int>(controllerContext, bindingContext, "X") 由Get方法调用验证

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Web.Mvc;

namespace WebApplication3.Areas.ModelBinder.Utility
{
public class PointModelBinder : IModelBinder
{
//当系统开始模型绑定时,模型参数名称被设置为bindingContext.ModelName中的值(本例控制器参数时pt)
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
//如果值提供器,名称存在(如:找到pt开头),那么使用的值的名称应该是pt.X和pt.Y
//如果名称不存在(如:找不到pt开头),那么名称中只有X或Y的值
if (!String.IsNullOrEmpty(bindingContext.ModelName) &&
!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
{
if (!bindingContext.FallbackToEmptyPrefix)
return null;

bindingContext = new ModelBindingContext
{
ModelMetadata = bindingContext.ModelMetadata,
ModelState = bindingContext.ModelState,
PropertyFilter = bindingContext.PropertyFilter,
ValueProvider = bindingContext.ValueProvider
};
}

//在ModelMetadata中设置一个Point对象的空实例。
//由Get方法调用验证
bindingContext.ModelMetadata.Model = new Point();
return new Point(
Get<int>(controllerContext, bindingContext, "X"),
Get<int>(controllerContext, bindingContext, "Y")
);
}

private TModel Get<TModel>(ControllerContext controllerContext,
ModelBindingContext bindingContext,
string name)
{
//获取完全限定名称
string fullName = name;
if (!String.IsNullOrWhiteSpace(bindingContext.ModelName))
fullName = bindingContext.ModelName + "." + name;

//从值提供程序获取值
ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(fullName);

//在模型状态中记录,以便用户可以看到他们输入的值
ModelState modelState = new ModelState { Value = valueProviderResult };
bindingContext.ModelState.Add(fullName, modelState);

//获得属性模型元数据的副本
ModelMetadata metadata = bindingContext.PropertyMetadata[name];

//使用模型元数据来决定是否将空字符串转换为null
string attemptedValue = valueProviderResult.AttemptedValue;
if (metadata.ConvertEmptyStringToNull && String.IsNullOrWhiteSpace(attemptedValue))
attemptedValue = null;

TModel model;
bool invalidValue = false;

try
{
//尝试将值转换为正确的类型
model = (TModel)valueProviderResult.ConvertTo(typeof(TModel));
metadata.Model = model;
}
catch (Exception)
{
//转换失败,因此返回该类型的默认值。并将尝试的值设置为模型元数据。
model = default(TModel);
metadata.Model = attemptedValue;
invalidValue = true;
}

//运行所有验证器,并在模型状态的错误集合中记录每一个验证错误
IEnumerable<ModelValidator> validators = ModelValidatorProviders.Providers.GetValidators(metadata, controllerContext);
foreach (var validator in validators)
foreach (var validatorResult in validator.Validate(bindingContext.Model))
modelState.Errors.Add(validatorResult.Message);

//记录数据类型转换错误,如果发生失败并且没有其他验证规则失败,就返回该值
if (invalidValue && modelState.Errors.Count == 0)
modelState.Errors.Add(
String.Format(
"The value '{0}' is not a valid value for {1}.",
attemptedValue,
metadata.GetDisplayName()
)
);

return model;
}
}
}

效果:



https://www.cnblogs.com/SkySoot/p/6050251.html

Asp.net MVC的Model Binder工作流程以及扩展方法(1) - Custom Model Binder

2 、用元数据描述模型

ASP.NET MVC2中引入了模型元数据系统,用来帮助描述用于协助HTML生成模型验证的模型元数据信息

ASP.NET MVC支持通过应用于类和属性的特性所表示的模型元数据。

这些特性主要包含在System.ComponetModel(.NET 1.0中引入)和System.ComponetModel.DataAnnotations(.NET 3.5 SP1和ASP.NET Dynamic Data一起被引入)中。

实现一个元数据提供器意味着需要继承类ModelMetadataProvider,并实现其中的3个抽象方法:

A. GetMetadataForType             返回关于整个类的元数据。

B. GetMetadataForProperty      返回类上单个属性的元数据。

C. GetMetadataForProperties  返回类上所有属性的元数据。

还有一个名为AssociatedMetadataProvider的派生类,可以被计划通过特性提供元数据的元数据提供器使用。它把上述三个方法的调用压缩到对CreateMetadata方法的调用,并传递附加到模型和模型属性的特性列表。由于简化了API和对元数据“兄弟类”的自动支持,因此如果要编写用特性装饰模型的元数据提供器,那么使用AssociatedMetadataProvider作为提供器的基类就是一个不错的选择。

https://book.2cto.com/201301/13269.html

3 、验证模型

实现验证器需要继承基类 ModelValidatorProviders,并实现返回给定模型的验证器的方法,给定模型有ModelMetadata的一个实例和ControllerContext表示。我们可以通过使用ModelValidatorProviders.Providers来注册自定义的模型验证器提供器。

ModelValidatorProviders.Providers.Add

二、 视图扩展

视图是操作返回结果的最常见类型。视图通常是带有一些代码的模板,可以用来根据输入(模型)自定义输出。

ASP.NET MVC默认安装了两个视图引擎:即在MVC 1.0中的WebForms视图引擎和Razor视图引擎(MVC3)。

ASP.NET MVC第三方视图引擎包括Spark、NHaml和NVelocity等。

1 、自定义视图引擎 

2、 编写HTML辅助方法

3、 编写Razor辅助方法

三、 控制器扩展

通过数据访问层与模型对话,对如何实现用户要求的活动作出初步决定,并决定如何使用视图、JSON、XML等做出响应。

1 、操作选择

(1)、操作名称选择

示例1:为Action重命一个新的名称

//为Action定义一个新的名称
[ActionName("B")]
public ActionResult A()
{
return View("a");
}


使用:注意不能通过地址使用 http://localhost:4405/index/B

@{Html.RenderAction("B");}


示例2:Action方法名以Product-开头

public class MyActionName : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
{
return actionName.StartsWith("Product-");
}
}
[MyActionName]
public ActionResult A()
{
return View("a");
}
http://localhost:4405/Home/Product-A

(2)、方法选择器

示例1:请求只能是Ajax请求

public class AjaxOnly : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
[AjaxOnly]
public ActionResult A()
{
return View("a");
}


2、 操作过滤器

(1)、身份验证过滤器

(2)、授权过滤器

需要实现IAuthorizationFilter接口,授权过滤器在身份验证过滤器之后执行。

有些类实现了该接口,其中包括[Authorize]、[ChildActionOnly]、[RequireHttps]、[ValidateAntiForgeryToken]和[ValidateInput]

推荐阅读:MVC 拦截器之授权 AuthorizeAttribute

认识ASP.NET MVC的5种AuthorizationFilter

深入理解ASP.NET MVC(7)

(3)、异常过滤器

(4)、过滤器重写

推荐阅读:MVC 自定义拦截器 IActionFilter(或ActionFilterAttribute)、IExceptionFilter(或HandleErrorAttribute)

过滤器接口类型(IActionFilter、IAuthenticationFilter、IAuthorizationFilter、IExceptionFilter和IResultFilter)

3 、提供自定义结果 

public ActionResult Index()
{
var model = new Person {
FirstName="Brad",
LastName="Wilson",
Blog="http;//www.aa.com"
};
//将类序列化xml表示
return new XmlResult(model);
}
public class XmlResult : ActionResult
{
private object data;
public XmlResult(object data)
{
this.data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var seralizer = new XmlSerializer(data.GetType());
var response = context.HttpContext.Response.OutputStream;
context.HttpContext.Response.ContentType = "text/xml";
seralizer.Serialize(response,data);
}
}


四、 小结
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: