首页 > 编程语言 >ASP.NET Web API]如何Host定义在独立程序集中的Controller

ASP.NET Web API]如何Host定义在独立程序集中的Controller

时间:2023-04-10 23:12:29浏览次数:52  
标签:Web ASP return 程序 class Controller HttpController new public

原文:https://www.cnblogs.com/artech/p/custom-assembly-resolver.html

通过《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方法执行的结果。

标签:Web,ASP,return,程序,class,Controller,HttpController,new,public
From: https://www.cnblogs.com/bruce1992/p/17304675.html

相关文章

  • ASP.NET Core MVC 从入门到精通之接化发(二)
    随着技术的发展,ASP.NETCoreMVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NETCoreMVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生,或其他想从事ASP.NETCoreMVC系统开发的人员。 经过前两篇文章的讲解,初步了解ASP.NETCor......
  • ctfshow web入门 sql注入 171-175
    171-175同属无过滤绕过(并未对sql语句过滤,仅对查询结果过滤)重点:1、了解万能密码2、了解sql语句中字符串函数3、了解备份功能(导入/导出数据)4、蚁剑如何连接数据库web171$sql="selectusername,passwordfromuserwhereusername!='flag'andid=......
  • 常见webeshell工具流量分析
    中国菜刀虚拟机使用仅主机模式,开启apache服务,使用wireshark对此网卡进行抓包  追踪http数据流  base64解码得出<?php@ini_set("display_errors","0");@set_time_limit(0);if(PHP_VERSION<'5.3.0'){@set_magic_quotes_runtime(0);};echo("X@Y&qu......
  • SIP视频监控 / webrtc视频会议接入GB28181国标平台
     截图使用的是知乎视频 实现思路:1.使用国标代理网关,建立sip号码与gb28181设备号,通道号之间的对照表,实现gb28181网关功能(设备注册,目录查询,心跳,直播拉流,Bye,设备注销),参:GB28181国标代理-CHHC-博客园(cnblogs.com)2.直播拉流时,可通过调用sip系统/视频会议系统提供发送RTP......
  • WebAssembly 助力云原生:APISIX 如何借助 Wasm 插件实现扩展功能?
    本文将介绍Wasm,以及ApacheAPISIX如何实现Wasm功能。作者朱欣欣,API7.ai技术工程师原文链接什么是WasmWasm是WebAssembly的缩写。WebAssembly/Wasm是一个基于堆栈的虚拟机设计的指令格式。在Wasm未出现之前,浏览器中只能支持运行Javascript语言。当Wasm出现......
  • SpringMVC怎么实现web端上传超大文件
    ​ 一、功能性需求与非功能性需求要求操作便利,一次选择多个文件和文件夹进行上传;支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传。刷新页面后继续传输。关闭浏览器后保留进度信息。支持文件夹批量上传下载,服务器端保留文件夹层级结构,服务......
  • 前端怎么实现web端上传超大文件
    ​ASP.NET上传文件用FileUpLoad就可以,但是对文件夹的操作却不能用FileUpLoad来实现。下面这个示例便是使用ASP.NET来实现上传文件夹并对文件夹进行压缩以及解压。ASP.NET页面设计:TextBox和Button按钮。​编辑TextBox中需要自己受到输入文件夹的路径(包含文件夹),通过Button实......
  • Webpack中手动实现Loader与Plugin
    Loaderloader是一个转换器,用于对源代码进行转换。工作流程webpack.config.js里配置了一个模块的Loader;2.遇到相应模块文件时,触发了该模块的loader;3.loader接受了一个表示该模块文件内容的source;4.loader使用webapck提供的一系列api对source进行转换,......
  • 解决WebService部署时出现的“未能创建类型...”错误
       这几天正在学习WebService,但是在部署时老是出现“未能创建类型...”的错误,在IIS7.0下折腾了半天,终于成功部署,现将经验向大家奉上。   首先必须先在IIS在创建一个虚拟目录(这个就不用多说了吧),如果这个时候直接在浏览器里调用WebService就会出现......
  • 第9章 使用MVC为移动和客户端应用程序创建Web API(ASP.NET Core in Action, 2nd Editio
    本章包括创建WebAPI控制器以向客户端返回JSON使用属性路由自定义URL使用内容协商生成响应使用[ApiController]属性应用通用约定在前五章中,您已经完成了服务器端渲染ASP.NETCore应用程序的每一层,使用RazorPages将HTML渲染到浏览器。在本章中,您将看到对ASP.NETCore应用程......