zoukankan      html  css  js  c++  java
  • 在WebAPI中自动创建Controller

    在MIS系统中,大部分的操作都是基本的CRUD,并且这样的Controller非常多。

    为了复用代码,我们常常写一个泛型的基类。

        public class EntityController<T> : ApiController
        {
            public IQueryable<T> GetAll()
            {
                ...
            }

            public T Get(int id)
            {
                ...
            }

            public T Put(int id, Ink ink)
            {
                ...
            }

            public T Post(Ink ink)
            {
                ...
            }

            public void Delete(int id)
            {
                ...
            }
        }

    当增加一种类型的时候,我们需要手动增加一个子类:

        public class InkController : EntityController<Ink>
        {
        }

        public class PenController : EntityController<Pen>
        {
        }

    当实体模型比较多的时候仍然就存在繁琐和难以维护的问题。因此我们也需要一种自动创建的机制,

    要实现自动创建Controller,首先得把现在这种静态创建Controller的方式改成动态创建的方式。在WebAPI中,我们可以通过替换IHttpControllerSelector来实现动态创建Controller。

    首先我们实现自己的IHttpControllerSelector

        public class MyControllerSelector : DefaultHttpControllerSelector
        {
            private readonly HttpConfiguration _configuration;

            public MyControllerSelector(HttpConfiguration configuration)
                : base(configuration)
            {
                _configuration = configuration;
            }

            public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                var controllerName = base.GetControllerName(request);
                return new HttpControllerDescriptor(_configuration, controllerName, typeof(Controllers.EntityController<Ink>));
            }
        }

    然后在初始化函数中注册我们的ControllerSelector

    public static class WebApiConfig
    {
    public static void Register(HttpConfiguration config)
    {
                // Web API configuration and services
                
    GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(GlobalConfiguration.Configuration));

                // Web API routes
                config.MapHttpAttributeRoutes();
                ……
    }
    }

    这样一来,即使没有子类InkController,我们同样可以特化泛型控制器EntityController<Ink>实现同样的效果。

    到这一步后,还存在一个问题:ControllerSelector只能根据HttpRequest获取ControllerName,并不知道其对应的Model,不知道该如何特化EntityController。解决这个问题的常见的方式就是维护一张Controller名称和实体类型的映射表:

        public class MyControllerSelector : DefaultHttpControllerSelector
        {
            static Dictionary<string, Type> _entityMap;
            static MyControllerSelector()
            {
                _entityMap = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);

                _entityMap["Ink"] = typeof(Ink);
                _entityMap["Pen"] = typeof(Pen);
            }

            private readonly HttpConfiguration _configuration;

            public MyControllerSelector(HttpConfiguration configuration)
                : base(configuration)
            {
                _configuration = configuration;
            }


            public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                var controllerName = base.GetControllerName(request);

                Type entityType = null;
                if (!_entityMap.TryGetValue(controllerName.ToLower(), out entityType))
                {
                    return base.SelectController(request);
                }

                return new HttpControllerDescriptor(_configuration, controllerName, typeof(Controllers.EntityController<>).MakeGenericType(entityType));
            }
        }

    虽然这样做本身没有什么问题。这种手动维护Controller列表的方式仍然无法达到自动创建Controller的要求,因此我们还需要一种自动生成这种映射表的机制。这里我仍然是采用同前文一样的Attribute+反射的方式。

    首先写一个ControllerAttribute,

        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
        public class ControllerAttribute : Attribute
        {
            public string Name { get; private set; }

            public ControllerAttribute(string name)
            {
                this.Name = name;
            }
        }

    然后,在数据模型中标记该Attribute

        [Controller("Pen")]
        public class Pen

     

        [Controller("Ink")]
        public class Ink

    最后,根据反射建立Controller名称和类型的关联关系

        static Dictionary<string, Type> _entityMap;
        static MyControllerSelector()
        {
            var assembly = typeof(MyControllerSelector).Assembly;

            var entityTypes = from type in assembly.GetTypes()
                                let controllerAtt = type.GetCustomAttribute<ControllerAttribute>()
                                where controllerAtt != null
                                select new { Type = type, ControllerName = controllerAtt.Name };

            _entityMap = entityTypes.ToDictionary(i => i.ControllerName, i => i.Type, StringComparer.OrdinalIgnoreCase);
        }

    这样基本上就可以用了。最后顺手做一下优化,减少的HttpControllerDescriptor创建操作,最终版本的ControllerSelector如下。

        public class MyControllerSelector : DefaultHttpControllerSelector
        {
            private Dictionary<string, HttpControllerDescriptor> _controllerMap;

            public MyControllerSelector(HttpConfiguration configuration)
                : base(configuration)
            {
                var entityTypes = from type in typeof(MyControllerSelector).Assembly.GetTypes()
                                 let controllerAtt = type.GetCustomAttribute<ControllerAttribute>()
                                 where controllerAtt != null
                                 select new { Type = type, ControllerName = controllerAtt.Name };

                _controllerMap = entityTypes.ToDictionary(
                                    i => i.ControllerName,
                                    i => new HttpControllerDescriptor(configuration, i.ControllerName,
                                            typeof(Controllers.EntityController<>).MakeGenericType(i.Type)),
                                    StringComparer.OrdinalIgnoreCase);
            }

            public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                HttpControllerDescriptor controllerDescriptor = null;
                if (!_controllerMap.TryGetValue(base.GetControllerName(request), out controllerDescriptor))
                {
                    return base.SelectController(request);
                }
                else
                {
                    return controllerDescriptor;
                }
            }
        }

  • 相关阅读:
    Hbase 0.98集群搭建的详细步骤
    java使用Apache POI操作excel文件
    linux下用非root用户重启导致ssh无法连接的问题
    solr update
    solr(一)
    libreoffice
    git
    hbase基本操作
    http://webapp.docx4java.org/OnlineDemo/PartsList.html
    git
  • 原文地址:https://www.cnblogs.com/TianFang/p/5185866.html
Copyright © 2011-2022 走看看