Roslyn-создание MetadataReference из сборки в памяти

работа над ASP.NET 5 приложение (Visual Studio 2015 CTP5) и Microsoft.CodeAnalysis.Используется CSharp.

Если я попытаюсь создать MetadataReference для сборки, которая является частью решения, чтобы передать ее как ссылку на CSharpCompilation.Создаю, получаю систему.Исключение ArgumentException, "пустое имя пути не допускается".

// Throws exception
MetadataReference.CreateFromAssembly(typeof(this).Assembly);

// Doesn't throw exception
MetadataReference.CreateFromAssembly(typeof(Object).Assembly);

Если я проверяю свойство Location сборки, оно пусто. Я предполагаю, что это связано с новым способом составления заявок в памяти в ASP.NET 5, так что сборка не хранится на диске.

Итак, есть ли способ передать ссылку на Roslyn для сборки без свойства Location или это в настоящее время не поддерживается?

изменить: @JaredPar - @SLaks выделил точно, где он терпит неудачу, но вот полная трассировка стека для информации. Я создаю несколько других MetadataReferences из System.* сборки до этого и нет никаких проблем ни с одной из них.

System.ArgumentException
Empty path name is not legal.
C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostScriptHelperScriptHelper.cs
Line 86:  
Line 87:              // Compile the code
Line 88:              var compilation = CSharpCompilation.Create(
Line 89:                  assemblyName,
Line 90:                  options: new CSharpCompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary),
 at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, Win32Native.SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 
at System.IO.File.OpenRead(String path) 
at Microsoft.CodeAnalysis.InternalUtilities.FileStreamLightUp.OpenFileStream(String path) 
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssembly(Assembly assembly, MetadataReferenceProperties properties, DocumentationProvider documentation) 
at Microsoft.CodeAnalysis.MetadataReference.CreateFromAssembly(Assembly assembly) 
at Webfuel.Services.Host.ScriptHelper.CompileScriptImpl(String source) in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostScriptHelperScriptHelper.cs:line 88 
at Webfuel.Services.Host.ScriptHelper.<>c__DisplayClass0.<CompileTemplate>b__3(String source) in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostScriptHelperScriptHelper.cs:line 71 
at System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) 
at Webfuel.Services.Host.ScriptHelper.CompileTemplate(String template) in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostScriptHelperScriptHelper.cs:line 69 
at Webfuel.Services.Host.SandboxContext.<ExecuteTemplateAsync>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostSandboxContext.cs:line 176 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult() 
at Webfuel.Services.Host.SandboxHost.<ExecuteTemplateAsync>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.HostSandboxHost.cs:line 39 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult() 
at Webfuel.Services.Sandbox.SandboxService.<ExecuteTemplateAsync>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.SandboxSandboxService.cs:line 47 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult() 
at Webfuel.Services.Server.ServerService.<ProcessContentRequestAsync>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.ServerServerService.cs:line 179 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult() 
at Webfuel.Services.Server.ServerService.<ProcessRequestAsync>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.Services.ServerServerService.cs:line 73 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter<TResult>.GetResult() 
at Webfuel.App.ServerMiddleware.<Invoke>d__1.MoveNext() in C:DevelopmentIncubatornet.frameworksrcWebfuel.AppStartup.cs:line 89 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.RequestContainer.ContainerMiddleware.<Invoke>d__1.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.KlrHttpApplication.<ProcessRequestAsyncImpl>d__1.MoveNext() 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at Microsoft.AspNet.Loader.IIS.HttpApplicationBase.<InvokeProcessRequestAsyncImpl>d__1.MoveNext()

2 ответов


прошло некоторое время, но я получил ответ на этот вопрос в репозитории GitHub Roslyn, поэтому я опубликую его, если кто-то найдет этот вопрос:

ASP.NET 5 имеет API для этого. Ты можешь делать то, что делает бритва.https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs#L132

Это было в районе Beta1 Asp.Net 5 поэтому может потребоваться настройка, но принцип все тот же-следуйте API, который Asp.Net сам по себе использует через IAssemblyLoadContextAccessor которое инжектор обслуживания обеспечит.

спасибо Дэвиду Фаулеру

UPDATE: этот ответ был для ASP.NET 5 Beta1. API сильно изменился, и в Core 1.0 вместо использования IAssemblyLoadContextAccessor вы можете получить доступ к AssemblyLoadContext из статического члена:

System.Runtime.Loader.AssemblyLoadContext.Default

и затем вы можете вызвать LoadFromStream для загрузки сборки из двоичного изображения. Вот очень грубый набросок кода, который я использую с некоторыми ненужными битами, взломанными out:

        // Give the assembly a unique name
        var assemblyName = "Gen" + Guid.NewGuid().ToString().Replace("-", "") + ".dll";

        // Build the syntax tree
        var syntaxTree = CSharpSyntaxTree.ParseText(source);

        // Compile the code
        var compilation = CSharpCompilation.Create(
            assemblyName,
            options: new CSharpCompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary),
            syntaxTrees: new List<SyntaxTree> { syntaxTree },
            references: GetMetadataReferences());

        // Emit the image of this assembly 
        byte[] image = null;
        using (var ms = new MemoryStream())
        {
            var emitResult = compilation.Emit(ms);
            if (!emitResult.Success)
            {
                throw new InvalidOperationException();
            }
            image = ms.ToArray();
        }

        Assembly assembly = null;

        // NETCORE
        using (var stream = new MemoryStream(image))
            assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromStream(stream);

это не должно работать как есть, но просто дать представление об основных шагах.

также проблема с созданием ссылок на метаданные из сборки только в памяти больше не существует, поскольку они больше не существуют в Core 1.0, поэтому каждая сборка имеет свойство Location. Таким образом, получение этих ссылок-это в основном тот же процесс, что и в ASP.net 4:

MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName(assemblyName)).Location);

Ваш вопрос неясен.

Если у вас есть байты скомпилированной сборки в памяти, вызовите MetadataReference.CreateFromImage().

Если вы хотите добавить ссылку на проект Roslyn в той же рабочей области, вызовите Compilation.ToMetadataReference().