使用.NET Core在运行时构建动态控制器

时间:2017-08-08 19:20:32

标签: asp.net-mvc asp.net-core-mvc

我想要一个Web服务,允许您动态添加/修改控制器代码而无需重新编译。

我已经找到了使用DefaultHttpControllerSelector执行此操作的方法,但这在.NET核心中不起作用。我也发现使用IApplicationModelConvention做类似的事情,但这只允许你在启动时添加新的控制器。使用DefaultHttpControllerSelector,您无需重新编译即可完成所有操作。 (以下示例来自https://www.strathweb.com/2013/03/leveraging-roslyn-to-author-asp-net-web-api-without-recompiling/

public class NoCacheSelector : DefaultHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
private const string Controllers = @"C:UsersFilipDocumentsVisual Studio 2012ProjectsMvcApplication6MvcApplication6Controllers";
private const string Models = @"C:UsersFilipDocumentsVisual Studio 2012ProjectsMvcApplication6MvcApplication6Models";

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

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
    var controllers = Directory.GetFiles(Controllers);
    var models = Directory.GetFiles(Models);
    var metadataReferences = controllers.Select(i => SyntaxTree.ParseFile(i)).Union(models.Select(i => SyntaxTree.ParseFile(i)));

    var compiledCode = Compilation.Create(
        outputName: "controllersAndModels.dll",
        options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
        syntaxTrees: metadataReferences,
        references: new[] { 
            new MetadataFileReference(typeof(object).Assembly.Location), 
            new MetadataFileReference(typeof(Enumerable).Assembly.Location), 
            new MetadataFileReference(typeof(ApiController).Assembly.Location), 
     });

    Assembly assembly;
    using (var stream = new MemoryStream())
    {
        compiledCode.Emit(stream);
        assembly = Assembly.Load(stream.GetBuffer());
    }

    var types = assembly.GetTypes();
    var matchedTypes = types.Where(i => typeof(IHttpController).IsAssignableFrom(i)).ToList();

    var controllerName = base.GetControllerName(request);
    var matchedController = matchedTypes.FirstOrDefault(i => i.Name.ToLower() == controllerName.ToLower() + "controller");

    return new HttpControllerDescriptor(_configuration, controllerName, matchedController);
}
}

0 个答案:

没有答案