2015-02-13 17 views
6

Utilizzo di un'applicazione ASP.NET 5 (Visual Studio 2015 CTP5) e Microsoft.CodeAnalysis.CSharp.Roslyn - Crea metadatiRiferimento dall'assembly in memoria

Se provo a creare un MetadataReference su un assembly che fa parte della soluzione per passarlo come riferimento a CSharpCompilation.Create, viene visualizzato System.ArgumentException, "Il nome del percorso vuoto non è legale".

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

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

Se controllo la proprietà Location dell'assieme è vuota. Presumo che ciò sia correlato al nuovo modo di compilare le applicazioni in memoria in ASP.NET 5, in modo che l'assembly non sia memorizzato sul disco.

Quindi esiste un modo per passare un riferimento a Roslyn per un assieme senza proprietà Location o al momento non è supportato?

MODIFICA: @JaredPar - @SLaks ha evidenziato esattamente dove fallisce, ma qui è la traccia dello stack completo per informazioni. Sto creando diversi altri MetadataReferences da System. * Prima di questo e non ci sono problemi con nessuno di essi.

System.ArgumentException 
Empty path name is not legal. 
C:\Development\Incubator\net.framework\src\Webfuel.Services.Host\ScriptHelper\ScriptHelper.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:\Development\Incubator\net.framework\src\Webfuel.Services.Host\ScriptHelper\ScriptHelper.cs:line 88 
at Webfuel.Services.Host.ScriptHelper.<>c__DisplayClass0.<CompileTemplate>b__3(String source) in C:\Development\Incubator\net.framework\src\Webfuel.Services.Host\ScriptHelper\ScriptHelper.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:\Development\Incubator\net.framework\src\Webfuel.Services.Host\ScriptHelper\ScriptHelper.cs:line 69 
at Webfuel.Services.Host.SandboxContext.<ExecuteTemplateAsync>d__1.MoveNext() in C:\Development\Incubator\net.framework\src\Webfuel.Services.Host\SandboxContext.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:\Development\Incubator\net.framework\src\Webfuel.Services.Host\SandboxHost.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:\Development\Incubator\net.framework\src\Webfuel.Services.Sandbox\SandboxService.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:\Development\Incubator\net.framework\src\Webfuel.Services.Server\ServerService.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:\Development\Incubator\net.framework\src\Webfuel.Services.Server\ServerService.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:\Development\Incubator\net.framework\src\Webfuel.App\Startup.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() 
+0

È possibile aggiungere la traccia dello stack completo dell'errore? Ciò aiuterà a capire perché questo è fallito. – JaredPar

+0

@JaredPar: http://source.roslyn.io/#Microsoft.CodeAnalysis/MetadataReference/MetadataReference.cs, 297 – SLaks

risposta

3

E 'stato un po', ma ho fatto avere una risposta su questo repository github Roslyn così vi posterò in caso qualcuno trova questa domanda:

ASP.NET 5 ha un'API per questo. Si può fare quello che fa Razor https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs#L132

Questo avveniva nel giro Beta1 di Asp.Net 5 quindi potrebbe essere necessario tweaking, ma il principio è sempre lo stesso - seguire l'API che Asp.Net si utilizza tramite la IAssemblyLoadContextAccessor cui l'iniettore di servizio provvederà.

grazie a David Fowler

UPDATE: La risposta è stata per ASP.NET 5 Beta1. L'API è cambiata molto, e Core 1.0 invece di utilizzare IAssemblyLoadContextAccessor, è possibile accedere AssemblyLoadContext da parte del membro static:

System.Runtime.Loader.AssemblyLoadContext.Default 

e si può quindi chiamare LoadFromStream per caricare un assembly da un'immagine binaria. Ecco uno schizzo molto approssimativa del codice che uso con alcuni pezzi irrilevanti hacked fuori:

 // 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); 

Questo non dovrebbe funzionare così com'è, ma solo dare un'idea dei passi principali.

Anche il problema con la generazione di riferimenti ai metadati da un assembly solo in memoria non esiste più poiché questi non esistono più in Core 1.0, quindi ogni Assembly ha una proprietà Location. Quindi ottenere questi riferimenti è fondamentalmente lo stesso processo di ASP.net 4:

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

La tua domanda non è chiara.

Se nella memoria sono presenti i byte di un assieme compilato, chiamare MetadataReference.CreateFromImage().

Se si desidera aggiungere un riferimento a un progetto Roslyn nello stesso spazio di lavoro, chiamare Compilation.ToMetadataReference().

+1

Non ho i byte. Ho solo un riferimento all'assembly (cioè un riferimento a un oggetto System.Reflection.Assembly). Ma l'assembly non ha alcuna proprietà Location (è vuoto). –

+0

Che tipo di assemblaggio è? Da dove viene? – SLaks

+0

È in un'applicazione ASP.NET 5 (il nuovo sistema di progetto in VS2015). Ho appena capito tramite typeof (). Assemblaggio. Il mio pensiero è che, poiché il nuovo sistema di compilazione non scrive sul disco, questo è ciò che lo infrange. Ho provato a impostare il flag "Produce output on build" sulle impostazioni del progetto, ma non è stato di alcun aiuto. –