欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

AreaHttpControllerSelector 对 Web Api 实现 Area 路由控制

程序员文章站 2022-04-10 15:32:44
结合此文章:http://www.cnblogs.com/wuhuacong/p/5828038.html ......

结合此文章:

using system;
using system.collections.concurrent;
using system.collections.generic;
using system.globalization;
using system.linq;
using system.net.http;
using system.reflection;
using system.web.http;
using system.web.http.controllers;
using system.web.http.dispatcher;
using system.web.http.routing;

namespace pemsoft.web.appserver
{
    /// <summary>
    /// area路由控制,如url中含{action}则通过area查找控制器,不存在{area}或找不到控制器则按默认规则再找一次
    /// 作者:ifu25
    /// 日期:2017/07/08
    /// 参考:http://www.jianshu.com/p/8242215cd8c0 、 http://www.cnblogs.com/silicon-fado/p/3571938.html
    /// </summary>
    public class areahttpcontrollerselector : defaulthttpcontrollerselector
    {
        #region 变量

        /// <summary>
        /// area名称
        /// </summary>
        private const string _arearoutevariablename = "area";

        private readonly httpconfiguration _configuration;

        private dictionary<string, type> _apicontrollertypes;

        /// <summary>
        /// 所有api控制器集合
        /// </summary>
        private dictionary<string, type> apicontrollertypes
        {
            get { return _apicontrollertypes ?? (_apicontrollertypes = getcontrollertypes()); }
        }

        #endregion

        /// <summary>
        /// 构造
        /// </summary>
        public areahttpcontrollerselector(httpconfiguration configuration) : base(configuration)
        {
            _configuration = configuration;
        }

        /// <summary>
        /// 覆写父类的选择控制器方法,通过此方法实现根据area查找控制器
        /// </summary>
        public override httpcontrollerdescriptor selectcontroller(httprequestmessage request)
        {
            //选通过area查找控制器,找不到则忽略area再找一次
            return getapicontroller(request) ?? base.selectcontroller(request);
        }

        #region 内部方法

        /// <summary>
        /// 获取所有控制器
        /// </summary>
        private static dictionary<string, type> getcontrollertypes()
        {
            var assemblies = appdomain.currentdomain.getassemblies();

            var types = assemblies.selectmany(a => a.gettypes().where(t => !t.isabstract && t.name.endswith(controllersuffix) && typeof(ihttpcontroller).isassignablefrom(t)))
                .todictionary(t => t.fullname, t => t);

            return types;
        }

        /// <summary>
        /// 为给定的httprequestmessage选择带area的控制器,没有area则返回null
        /// </summary>
        private httpcontrollerdescriptor getapicontroller(httprequestmessage request)
        {
            var controllername = base.getcontrollername(request);

            var areaname = getareaname(request);
            if (string.isnullorempty(areaname))
            {
                return null;
            }

            var type = getcontrollertypebyarea(areaname, controllername);
            if (type == null)
            {
                return null;
            }

            return new httpcontrollerdescriptor(_configuration, controllername, type);
        }

        /// <summary>
        /// 从httprequestmessage获取area,没有指定area则返回null
        /// </summary>
        private static string getareaname(httprequestmessage request)
        {
            var data = request.getroutedata();

            if (!data.values.containskey(_arearoutevariablename))
            {
                return null;
            }

            return data.values[_arearoutevariablename].tostring().tolower();
        }

        /// <summary>
        /// 获取指定area下的控制器
        /// </summary>
        /// <param name="areaname">area名称</param>
        /// <param name="controllername">控制器名称</param>
        private type getcontrollertypebyarea(string areaname, string controllername)
        {
            var areanametofind = string.format(".{0}.", areaname.tolower());
            var controllernametofind = string.format(".{0}{1}", controllername, controllersuffix);

            return apicontrollertypes.where(t => t.key.tolower().contains(areanametofind) && t.key.endswith(controllernametofind, stringcomparison.ordinalignorecase))
                    .select(t => t.value).firstordefault();
        }

        #endregion
    }
}