MVC Api 的跨项目路由

现有Momoda.Api项目,由于团队所有人在此项目下开发,导致耦合度太高,现从此接口项目中拆分出多个子项目从而避免对Momda.Api的改动导致“爆炸”
MVCApi的跨项目路由和MVC有解决方式有点不同
第一步:
首先在Momoda下创建域创建好之后把生成的YZCAreaRegistration文件移动到Areas目录下YZC目录外,然后排除YZC文件夹,像这样:
第二步:
创建一个新的MVCApi叫 YZC.WebAi,在资源管理器中用 YZC.WebAi文件夹下的内容替换掉Areas下的YZC域文件夹中的内容,并且只留下Controllers,Views和Models三个文件夹,其他的config和Global等都删除
第三步:
右键LYL解决方案添加现有项目在YZC域下找到工程文件 ( \LYL\Momoda.Api\Areas)
这样就把Momoda.Api下的YZC域给拆分出来,开发过程中只关注YZC.WebApi即可,目录结构如下图:
第四步:
更改YZCAreaRegistration域路由文件。
Api路由文件的更改是否和MVC跨域路由一样添加context.MapRoute方法的最后一个命名空间参数就能解决呢?答案当然没有那么简单。。。。。哈哈哈哈
我们现验证以下是否按照MVC跨项目路由的解决方案也同样适用于Api。
更改父API项目的域路由文件:
1 public override void RegisterArea(AreaRegistrationContext context)
2         {
3             context.MapRoute(
4                 "YZC_default",
5                 "YZC/{controller}/{action}/{id}",
6                 new { action = "Index", id = UrlParameter.Optional },
7                 new string[] { "YZC.Controllers" }//添加域项目的控制层命名空间
8             );
9         }
在子api项目中添加controller:
 1 {
 2     public class ChildrenController : ApiController
 3     {  
 4 #region 跨项目路由测试
 5         [HttpGet]
 6         public string Test()
 7         {
 8             return "小良哥";
 9         }
10         #endregion
11     }
12 }
浏览器中测试结果:
没有路由到,表明MVC域的处理和Api域的处理是不同的
解决方案:
在父ApiMomoda.Api下的App_Start中新增叫CustomHttpControllerSelector的类并且继承DefaultHttpControllerSelector
代码如下:
 1 /// <summary>
 2     /// 自定义区域类
 3     /// </summary>
 4     public class CustomHttpControllerSelector: DefaultHttpControllerSelector
 5     {
 6         private const string NamespaceRouteVariableName = namespaceName";
 7 //namespaceName之后要用到
 8         //private const string AreaRouteVariableName = "area";
 9         private readonly HttpConfiguration _configuration;
10         private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerCache;
11 
12         public CustomHttpControllerSelector(HttpConfiguration configuration)
13             : base(configuration)
14         {
15             _configuration = configuration;
16 
17             _apiControllerCache = new Lazy<ConcurrentDictionary<string, Type>>(
18                 new Func<ConcurrentDictionary<string, Type>>(InitializeApiControllerCache));
19         }
20 
21 
22         private ConcurrentDictionary<string, Type> InitializeApiControllerCache()
23         {
24             IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver();
25             var types = this._configuration.Services.GetHttpControllerTypeResolver()
26                 .GetControllerTypes(assembliesResolver).ToDictionary(t => t.FullName, t => t);
27 
28             return new ConcurrentDictionary<string, Type>(types);
29         }
30 
31         public IEnumerable<string> GetControllerFullName(HttpRequestMessage request, string controllerName)
32         {
33             object namespaceName;
34             var data = request.GetRouteData();
35             IEnumerable<string> keys = _apiControllerCache.Value.ToDictionary<KeyValuePair<string, Type>, string, Type>(t => t.Key,
36                     t => t.Value, StringComparer.OrdinalIgnoreCase).Keys.ToList();
37 
38             if (!data.Values.TryGetValue(NamespaceRouteVariableName, out namespaceName))
39             {
40                 return from k in keys
41                        where k.EndsWith(string.Format(".{0}{1}", controllerName,
42                        DefaultHttpControllerSelector.ControllerSuffix), StringComparison.OrdinalIgnoreCase)
43                        select k;
44             }
45 
46             string[] namespaces = (string[])namespaceName;
47             return from n in namespaces
48                    join k in keys on string.Format("{0}.{1}{2}", n, controllerName,
49                    DefaultHttpControllerSelector.ControllerSuffix).ToLower() equals k.ToLower()
50                    select k;
51         }
52 
53 
54         public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
55         {
56             Type type;
57             if (request == null)
58             {
59                 throw new ArgumentNullException("request");
60             }
61 
62             string controllerName = this.GetControllerName(request);
63             if (string.IsNullOrEmpty(controllerName))
64             {
65                 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
66                     string.Format("No route providing a controller name was found to match request URI '{0}'",
67                     new object[] { request.RequestUri })));
68             }
69 
70             IEnumerable<string> fullNames = GetControllerFullName(request, controllerName);
71             if (fullNames.Count() == 0)
72             {
73                 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
74                         string.Format("No route providing a controller name was found to match request URI '{0}'",
75                         new object[] { request.RequestUri })));
76             }
77 
78             if (!this._apiControllerCache.Value.TryGetValue(fullNames.First(), out type))
79             {
80                 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
81                         string.Format("No route providing a controller name was found to match request URI '{0}'",
82                         new object[] { request.RequestUri })));
83             }
84 
85             return new HttpControllerDescriptor(_configuration, controllerName, type);
86         }
87     }
View Code
更改父API项目的域路由文件为:
 1 namespace Momoda.Api
 2 {
 3     public class YZCAreaRegistration : AreaRegistration
 4     {
 5         public override string AreaName//域名称
 6         {
 7             get
 8             {
 9                 return "YZC";
10             }
11         }
12         public override void RegisterArea(AreaRegistrationContext context)
13         {
14             context.Routes.MapHttpRoute(
15                   name: this.AreaName + "_default",
16                   routeTemplate: "api/" + this.AreaName + "/{controller}/{action}/{id}",
17                   defaults: new
18            {
19           id = RouteParameter.Optional,
20           namespaceName = new string[] { string.Format("{0}.Controllers",this.AreaName) }
21  //namespaceName名称要CustomHttpControllerSelector中NamespaceRouteVariableName的值一致
22           }
23               );  
24         }
25     }
26 }
这样就完成了吗?没有!!!必须把域YZC.WebApi生成路径设置为Momoda.Api的bin文件下
测试结果:
成功!
域名称可加可不加同样成功
17:57:11,嘿嘿,下班啦
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2016-11-03 17:59  Leon_Chaunce  阅读(1093)  评论(0编辑  收藏  举报