`
mybwu_com
  • 浏览: 177577 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Asp.Net MVC4 系列--进阶篇之Controller(2)

 
阅读更多

调用Action的流程

IIS 接收到一个http请求,进入w3wp进程(如果是webgarden,先找到一个压力小的的w3wp),找到applicationpool,进入global.asax,进入路由,从controllerfactory找到一个controller,如果我们用了默认的controller,会解析出action名称和参数调用action(也可以手动直接在controller处理掉请求),返回并执行result,如图:


自定义controller factory

在上一章节,介绍了如果customize 一个controller(实现IController接口),现在介绍一个如何customizecontroller factory。

接口:


public interface IControllerFactory {
IController  CreateController(RequestContextrequestContext,
string controllerName);
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext,
string controllerName);
void  ReleaseController(IControllercontroller);
}


说明:

CreateController : 接收request context和controller name(不包含”Controller”后缀),返回一个IController对象,用于创建Controller对象

GetControllerSessionBehavior:参数同上,返回一个SessionStateBehavior,控制创建出的controller的sessionstate对象

ReleaseController:

如果controller包含了一些需要手动释放的资源,可以在这个函数里统一释放

代码示例:

  public class CustControllerFactory : IControllerFactory
    {
        private string_nsFind;
        private string_assembly;
        public CustControllerFactory(string namespaceFind, string  assemblyName)
        {
            if(namespaceFind.Last() == '.') namespaceFind =namespaceFind.Remove(namespaceFind.Length - 1);
            _nsFind =namespaceFind;
            _assembly= assemblyName;
        }
        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            var fullName = _nsFind + "." + controllerName + "Controller";
            var type =GetType().Assembly.GetTypes().FirstOrDefault(t => t.FullName == fullName);
            if (type== null)
            {
                return new TestController();
            }
            return (IController)Activator.CreateInstance(_assembly, fullName).Unwrap();
        }
 
        public SessionStateBehavior GetControllerSessionBehavior(RequestContextrequestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }
 
        public void ReleaseController(IController controller)
        {
            var disposable = controller as IDisposable;
            if(disposable != null)
            {
               disposable.Dispose();
            }
        }
    }


代码说明:factory接收一个命名空间名称和assembly名称,在指定的范围内检索controller对象通过反射动态创建对象,如果找不到,返回一个默认的controller。

下一步,在global文件中注册factory:

protected void Application_Start()
        {
           AreaRegistration.RegisterAllAreas();
 
           WebApiConfig.Register(GlobalConfiguration.Configuration);
           FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
           RouteConfig.RegisterRoutes(RouteTable.Routes);
           BundleConfig.RegisterBundles(BundleTable.Bundles);
 
           ControllerBuilder.Current.SetControllerFactory(new
CustControllerFactory("MVCRouteStudy.Controllers","MVCRouteStudy"));
        }


可以看到,在最后一行,我注册了我手动创建的factory。

测试一下这个factory,先访问一个不存在controller:


访问一个存在的:



注意:此例只作为一个简单的实现,甚至没有捕捉异常。现实应用中,场景要复杂的多,自定义的controller工厂在创建controller对象时,一般不仅仅简单的创建一个实例,可能会考虑性能维护一个缓存,手动维护session的状态,异常控制,以及一些安全性的考虑等等。

创建工厂时拿到的两个对象:

HttpContext

当前Http请求对象

RouteData

和当前请求匹配的那条route信息

Controller重置:

当前请求的controller是可以被覆盖的,

requestContext.RouteData.Values["controller"] ="Test";


这样一来,MVC Framework就会去查找新的View并覆盖本来的View名称了。

使用自带的controllerfactory

如果不自己实现controller factory,默认都会使用MVC 自带的factory,但是有几点是需要注意的,为了确保controller会被factory正确找到并实例化:

  • 必须public
  • 不可以是抽象类
  • 不能是泛型类
  • 必须以 ”Controller” 为结尾
  • 必须实现了IController接口(如果继承了Controller就不用了,只针对自定义Controller的情况)

优先查找命名空间

打开global文件,添加:

ControllerBuilder.Current.DefaultNamespaces.Add("MyControllerNamespace");
ControllerBuilder.Current.DefaultNamespaces.Add("MyProject.*");


代码目的很显然,希望MVC framework创建controller时候,添加的这些命名空间中被优先查找,注意最后传递了一个MyProject.*的SearchPattern,而不是正则表达式。另外,被添加的命名空间不会因为先后顺序导致被先后查找,他们的优先顺序是平行的(就像前面章节介绍的限制Route命名空间一样)。

Customize 默认ControllerFactory的行为

Controller Activator

对于一个工厂,最主要的职责就是创建对象,而在MVC Framework中,默认的工厂是支持自己实现创建过程的。

接口:

public interface IControllerActivator {
IController Create(RequestContext requestContext, Type controllerType);
}



参数:

RequestContext 对象:当前http请求的上下文信息,前面章节说了,这个对象包含的信息非常丰富,可以做很多事情(客户端ip,cookie,session,querystring,form, Files, Request ,Response等等)

Controller 类型:和刚才手动创建factory不同,这里我们直接得到了一个Type,这样就不用关心也不用反射出类型了,创建对象方便多了。

示例的实现:

public class CustomControllerActivator :IControllerActivator {
public IController Create(RequestContext requestContext,
Type controllerType) {
if (controllerType == typeof(HomeController)) {
controllerType = typeof(TestController);
}
return (IController)DependencyResolver.Current.GetService(controllerType);
}
}


代码说明:如果进来的是Home,重写为Test ,调用DependencyResolver创建并返回实例。

在global文件的Application_Start方法中配置一下:

ControllerBuilder.Current.SetControllerFactory(new
DefaultControllerFactory(new CustomControllerActivator()));


如果还不能满足需要,继承DefaultControllerFactory,选择的重写以下的函数一个或多个:

public override IController CreateController(RequestContextrequestContext, string controllerName)
        {
            return base.CreateController(requestContext, controllerName);
        }
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return base.GetControllerInstance(requestContext, controllerType);
        }
        protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
        {
            return base.GetControllerSessionBehavior(requestContext, controllerType);
        }
        protected override Type GetControllerType(RequestContext requestContext, string controllerName)
        {
            return base.GetControllerType(requestContext, controllerName);
        }
        public override void ReleaseController(IController controller)
        {
           base.ReleaseController(controller);
        }


Customize Action Invoker

我们知道,MVC 通过controller工厂找到并创建一个controller实例之后,下一步就是查找并调用action了,这一步也是支持customize的。

接口:

public interface IActionInvoker {
bool InvokeAction(ControllerContext controllerContext,string  actionName);
}


示例实现:

public class CustomActionInvoker : IActionInvoker
    {
        public bool InvokeAction(ControllerContext controllerContext,
        string actionName)
        {
            if(actionName == "Index")
            {
               controllerContext.HttpContext.
               Response.Write("I'd like over write all the Index ActionBehavior.");
                return true;
            }
            return false;
        }
}


代码说明:重写所有名称为index的action的行为。

在Controller中指向这个actioninvoker:

public TestController()
        {
            ActionInvoker = new CustomActionInvoker();
        }


查看结果:


发现TestController中的IndexAction的行为已经被重写了。

使用自带的ActionInvoker

  • 方法必须是public
  • 不支持static
  • 方法不能和System.Web.Mvc.Controller中的函数重名
  • 不支持泛型

Customize Action的名字

可以使用[ActionName] 来指定Action的名称:

[ActionName("Enumerate")]
public ViewResult List() {
return View("Result",new Result {
ControllerName ="Customer",
ActionName = "List"
});
}
}


注意:一旦改了名字,旧的名字将被覆盖,意味将不会被找到,如果访问将返回404。

如果有场景需要同样的Action名称出现多次在同一个Controller,例如,支持httppost和httpget的行为想要分在不同的action里面,那么可以使用ActionName属性:

	[ActionName("Index2")]
        [HttpPost]
        public ActionResult Index1()
        {
           
            return Content("FromPost");
        }
 
        [ActionName("Index")]
        [HttpGet]
        public ActionResult Index2()
        {
            return Content("FromGet");
        }


阻止一个Action被访问

[NonAction]
public ActionResult  MyAction() {
return View();
}


访问这个Action,会返回404

Customize Action Selector

可以自定义Selector,来决定这个Action是否被select

抽象类:

[AttributeUsage(AttributeTargets.Method,AllowMultiple = false, Inherited = true)]
public abstract class ActionMethodSelectorAttribute : Attribute {
public abstract bool IsValidForRequest(ControllerContext controllerContext,
MethodInfo methodInfo);
}


说明:

拿到的是ControllerContext和MethodInfo

ControllerContext中包含了http请求的信息

MethodInfo可以取的方法信息

示例实现:

public class LocalAttribute :ActionMethodSelectorAttribute {
public override bool IsValidForRequest(ControllerContext controllerContext,
MethodInfo methodInfo) {
return controllerContext.HttpContext.Request.IsLocal;
}
}


代码目的很明确,限制这个Action只能被本地的请求访问。

使用:

[Local]
public ActionResult  LocalIndex() {
return Content("From Local ");
}


控制unkownAction

如果本次请求向controller要一个不存在的action,可能希望返回到一个特殊的错误页面或者View,这时可以重写Controller中的HandleUnkownAction函数:

protected override void HandleUnknownAction(string actionName) { 
Response.Write(string.Format("You requested the {0} action", actionName)); 
}


查看结果:



Controller性能考虑

1. 考虑设置controller的session为SessionStateLess

如果没必要开启Session,可以考虑把一个Session状态关闭:

[SessionState(SessionStateBehavior.Disabled)]
Public  class FastController :Controller {
Public  ActionResult Index() {
return  View("Result",new Result {
ControllerName = "Fast ",ActionName = "Index"
});
}
}


2. 考虑异步Controller

场景:和第三方系统交互,并且客户端不需要等待这个结果就可以进行当前的活动。可以结合使用TPL完成:

public class RemoteDataController : AsyncController{
public  async Task<ActionResult> Data(){
string  data = await Task<string>.Factory.StartNew(() => {
return new  RemoteService().GetRemoteData();
});
return View((object)data);
}
}


RemoteService模拟实现

public class RemoteService {
public string GetRemoteData() {
Thread.Sleep(2000);
return "Hello from the other side of the world";
}
}


分享到:
评论

相关推荐

    ASP.NET MVC学习笔记-Controller与View传值.

    ASP.NET MVC学习笔记-Controller与View传值.

    ASP.NET MVC 5入门指南(中文PDF+源码)

    ASP.NET MVC 5 - 开始MVC 5之旅 2. ASP.NET MVC 5 - 控制器 3. ASP.NET MVC 5 - 视图 4. ASP.NET MVC 5 - 将数据从控制器传递给视图 5. ASP.NET MVC 5 - 添加一个模型 6. ASP.NET MVC 5 - 创建连接字符串并使用SQL ...

    ASP.NET MVC 身份验证-利用cookie记录登录用户

    ASP.NET MVC 身份验证-利用cookie记录登录用户

    ASP.NET MVC5.pdf

    本系列共11篇文章,翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解,全文最终完成了一个管理影片的小系统,非常适合新手入门ASP.NET MVC 5 (新增、删除、查询、更新) ...

    asp.net MVC4 CMS

    asp.net MVC4 CMS 完整的源代码,学习和提高asp.net mvc4可以参考一下。

    ASP.NET MVC3.0实例-Movies

    ASP.NET MVC3.0实例-Movies

    asp.net mvc demo[25-day]

    asp.net mvc demo 2015-08-25

    ASP.NET MVC 4高级编程(第4版)清晰完整PDF版

    MVC专家“梦之队”对ASP.NET MVC 4的全新诠释 由Microsoft专家和极受敬重的软件开发社区负责人撰写的《ASP.NET MVC 4高级编程(第4版)》将带您学习最前沿的Web框架:ASP.NET MVC 4。本书开篇简要介绍ASP.NET MVC框架...

    ASP.NET MVC MSDN 文档 CHM

    ASP.NET MVC 1.0 MSDN Reference CHM Version ASP.NET MVC 1.0 MSDN 参考及类库,CHM版本,从MSDN 官方网站下载并编译。源分支URL: http://msdn.microsoft.com/en-us/library/dd394709.aspx 内容列表: ASP.NET MVC...

    [ASP.NET MVC] ASP.NET MVC 4 实战 (英文版)

    ASP.NET MVC 4 in Action is a hands-on guide that shows you how to apply ASP.NET MVC effectively. After a high-speed ramp up, this thoroughly revised new edition explores each key topic with a self-...

    ASP.NET MVC 4高级编程 第4版PDF.rar

    ASP.NET MVC 是微软官方提出的一种Web开发框架,通过M是模型(model)-V视图(view)-C控制器(controller)l来设计创建Web应用程序。截至目前最新版本是MVC5,相对于之前的版本MVC5其可扩展性、易用性等方面都不很大的...

    Adam Freeman-Pro ASP.NET Core MVC 2-Apress (2017)

    Adam Freeman-Pro ASP.NET Core MVC 2-Apress (2017) 一如既往的好书!

    ASP.NET MVC4 Web编程

    asp.net mvc4

    【全网首发】ASP.NET MVC4开发指南(附带源码)

    全网首发:ASP.NET MVC4 开发指南(附带源码)版本,ASP.NET MVC4 开发指南 PDF + ASP.NET MVC4 开发指南源码,让你学习起来再也不费劲,轻松高效!

    Asp.Net MVC案例教程

    Asp.Net MVC案例教程 Asp.Net MVC案例教程 Asp.Net MVC案例教程 Asp.Net MVC案例教程 Asp.Net MVC案例教程 Asp.Net MVC案例教程

    asp.net mvc视频1-2

    MVC架构模式是近年来编程世界里最长被提及的模式之一,Model View Controller(模型-视图-控制器,MVC)模式将你的软件组织并分解成三个截然不同的角色: ◆Model封装了你的应用数据、应用流程和业务逻辑。 ◆View从...

    ASP.NET MVC企业实战源代码Chapter12.rar

    本书共分为12章,以符合初学者思维的方式系统地介绍ASP.NET MVC的应用技巧,并结合实际项目详细地介绍如何基于ASP.NET MVC构建企业项目。通过本书的学习,读者可以全面掌握ASP.NET MVC的开发,并从代码中获取软件...

    ASP.NET MVC4

    ASP.NET MVC4,全英文的教程,大家英语好的可以原汁原味的看看

    ASP.NET MVC in Action - Jeffrey Palermo.pdf

    ASP.NET MVC in Action is a comprehensive guide to MVC-based development using this powerful framework. It offers a clearly-written introduction both to the ASP.NET MVC Framework and to the MVC ...

Global site tag (gtag.js) - Google Analytics