gpt4 book ai didi

asp.net-web-api - 模块化 ASP.NET Web API : how to add/remove route at run time to a Web API

转载 作者:行者123 更新时间:2023-12-04 11:49:04 26 4
gpt4 key购买 nike

我正在尝试设计一个模块化 Web API 应用程序(它不是 MVC 应用程序!),其中管理员角色的用户可以在不重新启动 ASP.NET 应用程序的情况下添加或删除模块。

  • 模块:每个模块都是一个程序集(.dll 文件),其中包含至少一个派生自 ApiController 的类.
  • 路由基于 Attribute Routing in ASP.NET Web API 2
  • 模块(组件)的生产不在此问题的范围内。
  • 模块(汇编文件)被复制到项目根目录中的 `~/plugins/文件夹中/从中删除。这个过程也不在这个问题的范围内。
  • 主要的 ASP.NET Web API 项目基本上只有一个 Controller 来管理(添加/删除)模块。其他 Controller 将作为模块添加。

  • 所以主 Web API 项目中唯一的 Controller 是:

    [RoutePrefix("api/modules")]
    public class ModulesController : ApiController
    {
    private ModuleService _moduleService = new ModuleService();

    // GET: api/Modules
    [Route]
    public IEnumerable<string> Get()
    {
    return _moduleService.Get().Select(a => a.FullName);
    }

    // POST: api/Modules/{moduleName}
    [Route("{id}")]
    public void Post(string id)
    {
    Assembly _assembly;
    var result = _moduleService.TryLoad(id, out _assembly);

    if(!result) throw new Exception("problem loading " + id);

    // Refresh routs or add the new rout
    Configuration.Routes.Clear();
    Configuration.MapHttpAttributeRoutes();
    // ^ it does not work :(
    }

    // DELETE: api/Modules/{moduleName}
    [Route("{id}")]
    public void Delete(string id)
    {
    _moduleService.Remove(id);
    }
    }
    ModuleService.TryLoad()只需使用 AppDomain.CurrentDomain.Load() 查找程序集并将其加载到应用程序域中即可。 .这部分运作良好。
    Configuration.MapHttpAttributeRoutes()不会引发任何错误,但会破坏整个路由系统。在该行之后,任何路由尝试都会导致此错误:

    The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.



    我添加了 HttpConfiguration.EnsureInitialized()到代码,但它没有解决问题(同样的错误)。

    问题
  • 这种设计有意义吗?它会起作用吗?
  • 如何向路由集合添加新路由或完全刷新路由集合?
  • 最佳答案

    我解决了。

    首先,感谢 @Aleksey L. ,对 ModuleController 稍作改动(添加 Configuration.Initializer(Configuration) ):

    [RoutePrefix("api/modules")]
    public class ModulesController : ApiController
    {
    private ModuleService _moduleService = new ModuleService();

    // Other codes

    public void Post(string id)
    {
    _moduleService.Load(id);

    Configuration.Routes.Clear();
    Configuration.MapHttpAttributeRoutes();
    Configuration.Initializer(Configuration);
    }

    // Other codes
    }

    那么我们应该扩展 DefaultHttpControllerSelector :

    public class ModularHttpControllerSelector : DefaultHttpControllerSelector
    {
    private readonly HttpConfiguration _configuration;

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

    public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
    {
    var result = base.GetControllerMapping();
    AddPluginsControllerMapping(ref result);
    return result;
    }

    private void AddPluginsControllerMapping(ref IDictionary<string, HttpControllerDescriptor> controllerMappings)
    {
    var custom_settings = _getControllerMapping();

    foreach (var item in custom_settings)
    {
    if (controllerMappings.ContainsKey(item.Key))
    controllerMappings[item.Key] = item.Value;
    else
    controllerMappings.Add(item.Key, item.Value);
    }
    }

    private ConcurrentDictionary<string, HttpControllerDescriptor> _getControllerMapping()
    {
    var result = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
    var duplicateControllers = new HashSet<string>();
    Dictionary<string, ILookup<string, Type>> controllerTypeGroups = GetControllerTypeGroups();

    foreach (KeyValuePair<string, ILookup<string, Type>> controllerTypeGroup in controllerTypeGroups)
    {
    string controllerName = controllerTypeGroup.Key;

    foreach (IGrouping<string, Type> controllerTypesGroupedByNs in controllerTypeGroup.Value)
    {
    foreach (Type controllerType in controllerTypesGroupedByNs)
    {
    if (result.Keys.Contains(controllerName))
    {
    duplicateControllers.Add(controllerName);
    break;
    }
    else
    {
    result.TryAdd(controllerName, new HttpControllerDescriptor(_configuration, controllerName, controllerType));
    }
    }
    }
    }

    foreach (string duplicateController in duplicateControllers)
    {
    HttpControllerDescriptor descriptor;
    result.TryRemove(duplicateController, out descriptor);
    }

    return result;
    }

    private Dictionary<string, ILookup<string, Type>> GetControllerTypeGroups()
    {
    IAssembliesResolver assembliesResolver = new DefaultAssembliesResolver(); //was: _configuration.Services.GetAssembliesResolver();
    IHttpControllerTypeResolver controllersResolver = new DefaultHttpControllerTypeResolver(); //was: _configuration.Services.GetHttpControllerTypeResolver();

    ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
    var groupedByName = controllerTypes.GroupBy(
    t => t.Name.Substring(0, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length),
    StringComparer.OrdinalIgnoreCase);

    return groupedByName.ToDictionary(
    g => g.Key,
    g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
    StringComparer.OrdinalIgnoreCase);
    }
    }

    当然,我们必须用我们的 HttpControllerSelector 替换默认的 HttpControllerSelector,在 App_start\WebApiConfig.cs :

    public static class WebApiConfig
    {
    public static void Register(HttpConfiguration config)
    {
    GlobalConfiguration.Configuration.Services.Replace(
    typeof(System.Web.Http.Dispatcher.IHttpControllerSelector),
    new ModularHttpControllerSelector(config));

    config.MapHttpAttributeRoutes();
    }
    }

    如果有人对我如何实现 ModuleService 感兴趣,我可以将代码上传到GitHub。

    以下是 GitHub 中的完整源代码: https://github.com/tohidazizi/modular-web-api-poc

    关于asp.net-web-api - 模块化 ASP.NET Web API : how to add/remove route at run time to a Web API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39088765/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com