广告
返回顶部
首页 > 资讯 > 精选 >自定义的ControllerFactory接口如何实现支持Area
  • 218
分享到

自定义的ControllerFactory接口如何实现支持Area

2023-06-17 23:06:32 218人浏览 安东尼
摘要

这篇文章将为大家详细讲解有关自定义的ControllerFactory接口如何实现支持Area,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。几个星期之前,有个朋友对我说,他的项目中需要将前后

这篇文章将为大家详细讲解有关自定义的ControllerFactory接口如何实现支持Area,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

几个星期之前,有个朋友对我说,他的项目中需要将前后台区分开来,也就是类似分Area的功能。不过Area只在mvc 2中出现,因此现在想在1.0版本中先实现类似的功能了。他打算,根据Route中捕获的内容(如“area”),然后去找对应命名空间下的Controller。这样看来不难,似乎只要在Route上做点配置,而默认的DefaultControllerFactory已经对命名空间的查询提供支持了(可惜有线程安全的问题)。

不过他说,发现似乎这块功能不是他想象的那样,因此希望我可以看看到底是什么问题。由于当时没有扩展asp.net MVC的需求,后来我事情一多就忘了,现在先说声抱歉。最近开始对ASP.net MVC动手动脚了,发现这样一个Area的功能非常有用,而且巧合的是,我也打算把Area和命名空间对应起来。

只是我选择的路和那位兄弟不一样,我打算自己写一个简单的ControllerFactory来替换掉默认的DefaultControllerFactory。这么做的主要原因是:我不知道DefaultControllerFactory已经提供对命名空间的支持了,微软默默地实现了却没有对外公开过,我也是后来阅读代码时才发现的。同时又意识到线程安全的问题,于是就还是打算自己写了。

好在ASP.NET MVC从设计之初就提供了扩展的能力,每个组件粒度都很小,大部分组件都是可以独立拔插的(Controller类除外,如果你使用自己的IController实现,就会发现大部分功能,如各Filter都失效了)。而要实现一个Controller Factory,只要实现一个简单的IControllerFactory就可以了(我喜欢接口):

public interface IControllerFactory  {      IController CreateController(RequestContext requestContext, string controllerName);      void ReleaseController(IController controller);  }

于是构建一个AreaControllerFactory也大致只需要以下一些代码:

public class AreaControllerFactory : IControllerFactory  {      public IController CreateController(RequestContext requestContext, string controllerName)      {          ...      }       public void ReleaseController(IController controller)      {          IDisposable disposable = controller as IDisposable;          if (disposable != null)          {              disposable.Dispose();          }      }  }

然后按照惯例,还是一步步谈起。首先是构造函数,我们的策略是根据不同的Area加载不同命名空间下的Controller类型。方便起见,我选择“基础命名空间”和“扩展部分”两块,它们从构造函数中传入:

private Dictionary<string, string> m_areaPartMapping = new Dictionary<string, string>();   public string NamespaceBase { get; private set; }   public AreaControllerFactory(string namespaceBase)      : this(namespaceBase, null)  { }   public AreaControllerFactory(string namespaceBase, IDictionary<string, string> areaPartMapping)  {      this.NamespaceBase = namespaceBase.EndsWith(".") ? namespaceBase : namespaceBase + ".";       if (areaPartMapping != null)      {          foreach (var pair in areaPartMapping)          {              this.m_areaPartMapping.Add(pair.Key.ToLowerInvariant(), pair.Value);          }      }  }

于是我们就可以这样使用:

var controllerFactory = new AreaControllerFactory("MyApp.Controllers");  ControllerBuilder.Current.SetControllerFactory(controllerFactory);

如果在需要的时候,还可以指定Area与特定命名空间“部分”的映射关系。因此,我们需要从Area来获取这个“Part”:

private string GetNamespacePart(string area)  {      if (String.IsNullOrEmpty(area)) return "";       string part;      if (this.m_areaPartMapping.TryGetValue(area.ToLowerInvariant(), out part))      {          return part;      }       return area;  }

这里我选择“配置”和“约定”相结合的方式。得到一个Area之后,我们会在映射表里进行查找Part,如果没有,则Area本身便是Part。根据Part和Controller名称,我们便可以获得Controller的类型:

private ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();  private Dictionary<string, Type> m_controllerTypes = new Dictionary<string, Type>();   private Type GetControllerType(string area, string controllerName)  {      string part = this.GetNamespacePart(area);       string typeName = String.IsNullOrEmpty(part) ?          this.NamespaceBase + controllerName.ToLowerInvariant() + "Controller" :          this.NamespaceBase + part + "." + controllerName.ToLowerInvariant() + "Controller";       Type type;       this.m_rwLock.EnterReadLock();      try     {          if (this.m_controllerTypes.TryGetValue(typeName, out type))          {              return type;          }      }      finally     {          this.m_rwLock.ExitReadLock();      }       type = Type.GetType(typeName, false, true);       if (type != null)      {          this.m_rwLock.EnterWriteLock();          try         {              this.m_controllerTypes[typeName] = type;          }          finally         {              this.m_rwLock.ExitWriteLock();          }      }       return type;  }

由于我选择在应用程序中使用同一个AreaControllerFactory对象,因此线程安全是一定要有保证的。这里我们用到了读写,不过请注意,红色那句话并不保证对于每个相同的typeName只执行一次,也不保证相同的typeName对于m_controllerTypes字典只会进行一次写操作(所以我没有Add,而是使用了下标操作)。不过,由于这些“重复”不会造成问题,因此就没有去涉及太多这方面的考虑。

***,便是那CreateControlle方法:

public IController CreateController(RequestContext requestContext, string controllerName)  {      Type controllerType;      object area;      if (requestContext.RouteData.Values.TryGetValue("area", out area))      {          controllerType = this.GetControllerType(area.ToString(), controllerName);      }      else     {          controllerType = this.GetControllerType(null, controllerName);      }       if (controllerType == null)      {          throw new HttpException(404,              String.FORMat(                  "Controller of path {0} not found.",                  requestContext.HttpContext.Request.Path));      }       try     {          return (IController)Activator.CreateInstance(controllerType);      }      catch (Exception ex)      {          string message = String.Format("Error creating controller {0}" + controllerType);          throw new InvalidOperationException(message, ex);      }  }

似乎没有什么可谈的:我们从RouteData中获取出area对应的值,并且调用GetControllerType方法获得Controller的类型,并使用Activator.CreateInstance创建对象。在不合法的情况下,抛出合适的异常即可。

至此,AreaControllerFactory就完成了,很容易,不是吗?很显然,这个组件的功能非常有限,例如为什么所有的Controller一定要在同一个命名空间下?没错,它其实只是符合“我要求”的一个东西。但是,在项目中很多东西都是如此,我只实现我够用的功能。例如,我可能不会向对外公开的api那样,严格检查每个问题,抛出严谨的异常。我可能倾向于在项目中使用接口,而不是使用抽象类。因为是我的项目,我可以快速反馈,需要修改的时候就修改吧。

同样的,如果DefaultControllerFactory真在某些特别情况下有问题,或者支持的有些复杂。那么不如我们就自己动手吧。一次性投入,而且这样的小组件也花不了多少时间。

关于自定义的ControllerFactory接口如何实现支持Area就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 自定义的ControllerFactory接口如何实现支持Area

本文链接: https://www.lsjlt.com/news/294372.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 自定义的ControllerFactory接口如何实现支持Area
    这篇文章将为大家详细讲解有关自定义的ControllerFactory接口如何实现支持Area,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。几个星期之前,有个朋友对我说,他的项目中需要将前后...
    99+
    2023-06-17
  • Flask如何利用自定义接口实现mock应用
    这篇文章主要介绍了Flask如何利用自定义接口实现mock应用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Flask如何利用自定义接口实现mock应用文章都会有所收获,下面我们一起来看看吧。问题:后端接口已提...
    99+
    2023-07-05
  • PHP接口如何定义与实现
    这篇文章主要讲解了“PHP接口如何定义与实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP接口如何定义与实现”吧!一、PHP接口的定义首先我们来了解一下PHP接口的定义,下面是一个非常...
    99+
    2023-07-05
  • SpringBoot如何使用自定义注解实现接口限流
    目录使用自定义注解实现接口限流1、自定义限流注解2、限流类型枚举类3、限流 Lua 脚本4、限流切面处理类 5、使用与测试SpringBoot工程中限流方式1、google...
    99+
    2022-11-13
  • MyBatis如何实现自定义持久层框架
    这篇“MyBatis如何实现自定义持久层框架”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MyBatis如何实现自定义持久层...
    99+
    2023-06-30
  • 如何通过ECharts和php接口实现自定义样式的统计图
    如何通过ECharts和PHP接口实现自定义样式的统计图引言:统计图是数据可视化的重要工具之一,能够直观地展示大量的数据。ECharts 是一款优秀的数据可视化库,它提供了丰富的图表类型和灵活的配置选项。在本文中,我们将介绍如何使用ECha...
    99+
    2023-12-17
    echarts PHP接口 自定义样式
  • 如何在SpringBoot项目中的自定义配置添加IDE支持
    这篇文章将为大家详细讲解有关如何在SpringBoot项目中的自定义配置添加IDE支持,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Application.java:application....
    99+
    2023-06-06
  • win10系统如何实现窗口自定义调整
    这篇文章主要为大家展示了“win10系统如何实现窗口自定义调整”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“win10系统如何实现窗口自定义调整”这篇文章吧。按win+r打开运行窗口,输入reg...
    99+
    2023-06-28
  • Spring MVC如何实现接口Controller定义控制器
    目录实现接口Controller定义控制器方法一:实现接口Controller定义控制器方法二:使用注解@Controller定义控制器详谈Controller(控制器)一、cont...
    99+
    2022-11-13
  • Android 自定义圆形头像CircleImageView支持加载网络图片的实现代码
    在Android开发中我们常常用到圆形的头像,如果每次加载之后再进行圆形裁剪特别麻烦。所以在这里写一个自定义圆形ImageView,直接去加载网络图片,这样的话就特别的方便。 ...
    99+
    2022-06-06
    网络图 自定义 图片 Android
  • Android Compose自定义TextField如何实现自定义的输入框
    这篇文章主要介绍Android Compose自定义TextField如何实现自定义的输入框,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!简单自定义BasicTextField示例代码 var&n...
    99+
    2023-06-29
  • QT中如何实现自定义quick-Popup弹出窗口
    小编给大家分享一下QT中如何实现自定义quick-Popup弹出窗口,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.Popup介绍Popup是一个弹出窗口的控件...
    99+
    2023-06-20
  • SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码
    目录为什么要限流限流背景实现限流1、引入依赖2、自定义限流注解3、限流切面4、写一个简单的接口进行测试5、全局异常拦截6、接口测试为什么要限流 系统在设计的时候,我们会有一个系统的预...
    99+
    2022-11-13
  • javascript+html5+css3如何实现自定义弹出窗口效果
    这篇文章主要介绍javascript+html5+css3如何实现自定义弹出窗口效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!效果图:源码:1.demo.jsp<%@&nb...
    99+
    2022-10-19
  • springboot vue接口测试定义编辑功能如何实现
    本文小编为大家详细介绍“springboot vue接口测试定义编辑功能如何实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“springboot vue接口测试定义编辑功能如何实现”文章能帮助大家解决疑惑,下面跟着小...
    99+
    2023-06-30
  • java应用开发之Mybatis通过Mapper代理自定义接口的实现
    如何实现?主要分为以下两步骤 1.通过 Mapper 代理实现⾃定义接口 2.编写与方法相对应的 Mapper.xml 1.自定义接口Account...
    99+
    2022-11-12
  • ASP.NET Core如何使用JWT自定义角色并实现策略授权需要的接口
    ASP.NET Core如何使用JWT自定义角色并实现策略授权需要的接口,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。① 存储角色/用户所能访问的 A...
    99+
    2023-06-26
  • 如何使用Serializable接口来自定义PHP中类的序列化
    目录Serializable接口各种类型的数据进行序列化的结果对象在使用Serializable接口序列化时要注意的地方未定义类的反序列化操作总结关于PHP中的对象序列化这件事儿,之...
    99+
    2022-11-12
  • ASP.NETCore使用JWT自定义角色并实现策略授权需要的接口
    ① 存储角色/用户所能访问的 API 例如 使用 List<ApiPermission> 存储角色的授权 API 列表。 可有可无。 可以把授权访问的...
    99+
    2022-11-12
  • C#快速实现IList非泛型类接口的自定义类作为数据源
    目录一、利用VS的修补程序快速继承IList二、实现必须的成员使用可以绑定数据源的控件我们需要有实现了IList接口的类作为数据源,我们有很多的方法,比如使用ArrayList或者L...
    99+
    2023-02-06
    C# IList数据源
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作