问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

如何Host定义在独立程序集中的Controller

发布网友 发布时间:2022-05-30 21:57

我来回答

1个回答

热心网友 时间:2023-11-23 12:08

通过《ASP.NET Web API的Controller是如何被创建的?》的介绍我们知道默认ASP.NET Web API在Self Host寄宿模式下用于解析程序集的AssembliesResolver是一个DefaultAssembliesResolver对象,它只会提供当前应用程序域已经加载的程序集。如果我们将HttpController定义在非寄宿程序所在的程序集中(实际上在采用Self Host寄宿模式下,我们基本上都会选择在独立的项目定义HttpController类型),即使我们将它们部属在宿主程序运行的目录中,宿主程序启动的时候也不会主动去加载这些程序集。由于当前应用程序域中并不曾加载这些程序集,HttpController类型解析将会失败,HttpController的激活自然就无法实现。[本文已经同步到《How ASP.NET Web API Works?》]
我们可以通过一个简单的实例来证实这个问题。我们在一个解决方案中定义了如右图所示的4个项目,其中Foo、Bar和Baz为类库项目,相应的HttpController类型就定义在这3个项目之中。Hosting是一个作为宿主的控制台程序,它具有对上述3个项目的引用。我们分别在项目Foo、Bar和Baz中定义了三个继承自ApiController的HttpController类型FooController、BarController和BazController。如下面的代码片断所示,我们在这3个HttpController类型中定义了唯一的Action方法Get并让它返回当前HttpController类型的AssemblyQualifiedName。
1: public class FooController : ApiController
2: {
3: public string Get()
4: {
5: return this.GetType().AssemblyQualifiedName;
6: }
7: }
8:
9: public class BarController : ApiController
10: {
11: public string Get()
12: {
13: return this.GetType().AssemblyQualifiedName;
14: }
15: }
16:
17: public class BarController : ApiController
18: {
19: public string Get()
20: {
21: return this.GetType().AssemblyQualifiedName;
22: }
23: }

我们在作为宿主的Hosting程序中利用如下的代码以Self Host模式实现了针对Web API的寄宿。我们针对基地址“http://127.0.0.1:3721”创建了一个HttpSelfHostServer,在开启之前我们注册了一个URL模板为“api/{controller}/{id}”的路由。
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: Uri baseAddress = new Uri("http://127.0.0.1:3721");
6: using (HttpSelfHostServer httpServer = new HttpSelfHostServer(new HttpSelfHostConfiguration(baseAddress)))
7: {
8: httpServer.Configuration.Routes.MapHttpRoute(
9: name : "DefaultApi",
10: routeTemplate : "api/{controller}/{id}",
11: defaults : new { id = RouteParameter.Optional });
12:
13: httpServer.OpenAsync().Wait();
14: Console.Read();
15: }
16: }
17: }

在启动宿主程序后,我们试图通过浏览器对分别定义在FooController、BarController和BazController中的Action方法Get发起调用,不幸的是我们会得到如图4-4所示的结果。从显示在浏览器中的消息我们很清楚问题的症结所在:根据路由解析得到HttpController名称并不能得到匹配的类型。

导致上述这个问题的原因我们在上面已经分析过了:默认注册的DefaultAssembliesResolver仅仅提供当前应用程序域加载的程序集。我们可以通过自定义的AssembliesResolver来解决这个问题。我们的解决思路是让需要预先加载的程序集可配置,具体来说可以采用具有如下结构的配置来设置需要预先加载的程序集。
1: <configuration>
2: <configSections>
3: <section name="preLoadedAssemblies"
4: type="Hosting.PreLoadedAssembliesSettings, Hosting"/>
5: </configSections>
6: <preLoadedAssemblies>
7: <add assemblyName ="Foo.dll"/>
8: <add assemblyName ="Bar.dll"/>
9: <add assemblyName ="Baz.dll"/>
10: </preLoadedAssemblies>
11: </configuration>

在创建自定义的AssembliesResolver之前我们先得为这段配置定义相应的配置节和配置元素类型。相关的类型(PreLoadedAssembliesSettings、AssemblyElementCollection和AssemblyElement)定义如下所示,由于配置结构比较简单,在这里我们不对它们作详细介绍了。
1: public class PreLoadedAssembliesSettings: ConfigurationSection
2: {
3: [ConfigurationProperty("", IsDefaultCollection = true)]
4: public AssemblyElementCollection AssemblyNames
5: {
6: get { return (AssemblyElementCollection)this[""]; }
7: }
8:
9: public static PreLoadedAssembliesSettings GetSection()
10: {
11: return ConfigurationManager.GetSection("preLoadedAssemblies")
12: as PreLoadedAssembliesSettings;
13: }
14: }
15:
16: public class AssemblyElementCollection : ConfigurationElementCollection
17: {
18: protected override ConfigurationElement CreateNewElement()
19: {
20: return new AssemblyElement();
21: }
22: protected override object GetElementKey(ConfigurationElement element)
23: {
24: AssemblyElement serviceTypeElement = (AssemblyElement)element;
25: return serviceTypeElement.AssemblyName;
26: }
27: }
28:
29: public class AssemblyElement : ConfigurationElement
30: {
31: [ConfigurationProperty("assemblyName", IsRequired = true)]
32: public string AssemblyName
33: {
34: get { return (string)this["assemblyName"]; }
35: set { this["assemblyName"] = value; }
36: }
37: }

由于我们自定义的AssembliesResolver是对现有DefaultAssembliesResolver的扩展(尽管其程序集提供机制仅仅通过一句代码来实现),我们将类型命名为ExtendedDefaultAssembliesResolver。如下面的代码片断所示,ExtendedDefaultAssembliesResolver继承自DefaultAssembliesResolver,在重写的GetAssemblies方法中我们先通过分析上述的配置并主动加载尚未加载的程序集,然后调用基类的同名方法来提供最终的程序集。
1: public class ExtendedDefaultAssembliesResolver : DefaultAssembliesResolver
2: {
3: public override ICollection<Assembly> GetAssemblies()
4: {
5: PreLoadedAssembliesSettings settings = PreLoadedAssembliesSettings.GetSection();
6: if (null != settings)
7: {
8: foreach (AssemblyElement element in settings.AssemblyNames)
9: {
10: AssemblyName assemblyName = AssemblyName.GetAssemblyName(element.AssemblyName);
11: if(!AppDomain.CurrentDomain.GetAssemblies().Any(assembly=>AssemblyName.ReferenceMatchesDefinition(assembly.GetName(),assemblyName)))
12: {
13: AppDomain.CurrentDomain.Load(assemblyName);
14: }
15: }
16: }
17: return base.GetAssemblies();
18: }
19: }

我们在作为宿主的Hosting程序中利用如下的代码将一个ExtendedDefaultAssembliesResolver对象注册到当前HttpConfiguration的ServicesContainer上。
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: Uri baseAddress = new Uri("http://127.0.0.1:3721");
6: using (HttpSelfHostServer httpServer = new HttpSelfHostServer(new HttpSelfHostConfiguration(baseAddress)))
7: {
8: httpServer.Configuration.Services.Replace(typeof(IAssembliesResolver),new ExtendedDefaultAssembliesResolver());
9: //其他操作
10: }
11: }
12: }

重新启动宿主程序后再次在浏览器输入对应的地址来访问分别定义在FooController、BarController和BazController中的Action方法Get,我们会得到如下图所示的输出结果,这正是目标Action方法执行的结果。

转载仅供参考,版权属于原作者。祝你愉快,满意请采纳哦
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
为什么电脑上的word界面变小为什么WORD里面的页面变的很小怎么设置回来... AHA拯救心脏救命术(Basic Life Support,BLS) 基础生命的基本顺序 机械制图第一视角与第三视角的区别 明日之后野外感染者据点都在什么地方 感染就聚集点位置分享 明日之后 明日之后哪些地图有强力感染者? 《明日之后》野外感染者据点一览 明日之后野外感染者据点去哪找 妙洁提醒你注意:保鲜膜有些不能加热 有些不能包肉 C盘里文件的修改日期是不是就代表那天我用过电脑,我是上午用的,可文件... 恶性肿瘤是否是癌症 httpclient能不能自己设置hosts-CSDN论坛 检查了1个多月终于出了结果,恶性肿瘤算是得癌症吗 恶性肿瘤是癌症吗? 虚拟机有两个网卡一个设成了自定义(Host-only),但另一个怎么无法设成桥接?很郁闷 恶性肿瘤一定是癌症吗? 恶性肿瘤是不是癌症,怎么治疗? 癌症可以称为恶性肿瘤吗? win0笔记本麦克风没声音怎么设置 为什么win0插入耳机没有声音 我只知道一句歌词,,求歌曲名 我只知道几句歌词,求歌名 我就不明白了? 我知道了~是什么意思 我只知道一件事,那就是什么都不知道 那个歌词为什么后面我就知道了唱得快那是什么歌 谁知道这是什么歌? 我就知道其中一句歌词! 百度一下我就知道什么了? 填空:看到―――,我就知道春天来了 你刚开口我就知道了是什么时态? 恶性肿瘤算不算癌症 癌症和恶性肿瘤有区别吗?什么药可以治疗癌症? 恶性肿瘤和癌症是一回事吗 怎么算的?? 请问怎么计算 怎么算。 国龙碳汇真实现状?是不是骗局? 初三化学好的进来 碳氢化合物,81.7%C(质量),怎么求化学式 初中化学碳这部分的复习指导,视频,笔记,习题 都行,急。。。。好再加100分 化学方程式接龙 人财两得是什么生肖 人财两得怎么样 北京人财两得咨询有限公司怎么样? 人财两空的反义词 西游记的白龙马扮演者是不是沈腾 沈腾出演过西游记吗 沈腾的表演功底扎实、爆发力很强,会成为下一个“星爷”吗? 欢乐喜剧人扮演西游记妖怪 哪些影视剧中,拍摄时因为演员的自娱自乐,而最终成了经典?