首页 > 代码库 > MVC Api 的跨项目路由
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 =http://www.mamicode.com/ 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 }
更改父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,嘿嘿,下班啦
MVC Api 的跨项目路由
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。