Toh*_*hid 7 asp.net-web-api asp.net-web-api-routing asp.net-web-api2
我正在尝试设计模块化Web API应用程序(它不是MVC应用程序!),其中管理员角色的用户可以在不重新启动ASP.NET应用程序的情况下添加或删除模块.
ApiController.因此,主Web API项目中唯一的控制器是:
[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);
}
}
Run Code Online (Sandbox Code Playgroud)
ModuleService.TryLoad()通过使用简单地查找并将程序集加载到应用程序域AppDomain.CurrentDomain.Load().这部分运作良好.
Configuration.MapHttpAttributeRoutes()没有引起任何错误,但它打破了整个路由系统.在该行之后,任何路由尝试都会导致此错误:
该对象尚未初始化.确保在所有其他初始化代码之后在应用程序的启动代码中调用HttpConfiguration.EnsureInitialized().
我添加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
}
Run Code Online (Sandbox Code Playgroud)
然后我们应该扩展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);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,我们必须用我们的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();
}
}
Run Code Online (Sandbox Code Playgroud)
如果有人对我如何实现它感兴趣ModuleService,我可以将代码上传到GitHub.
以下是GitHub中的完整源代码:https://github.com/tohidazizi/modular-web-api-poc
| 归档时间: |
|
| 查看次数: |
3795 次 |
| 最近记录: |