toddams / RazorLight

Template engine based on Microsoft's Razor parsing engine for .NET Core
Apache License 2.0
1.51k stars 259 forks source link

RazorLight + Azure Functions v3 Working Now #306

Closed mrlund closed 4 years ago

mrlund commented 4 years ago

Can't contribute much additional information to the title, but I've been struggling with rendering razor on azure functions for a while, and suddenly managed to get it working today.

I can't claim credit, but I assume that its a combination of platform and package updates that allows it to work now. Since I've seen many others struggle with this I thought I'd file an issue to let people know that it's possible now.

The catch is that I can't point to why it suddenly started working. I first tried all the tricks in the book, without luck, but suddenly it started working and even a simple repro is working nicely. It's probably just a combination of things wrong in my real project ¯_(ツ)_/¯

Here's the very simple (basically out of the box) version that actually works when deployed to an Azure Function v3: https://github.com/mrlund/razorlight-azure-functions-v3-test

P.S: In my real world app I have a custom RazorLightProject implementation that loads the templates (and layouts) from blob storage, and that works fine too, so it's not just this simplified version above.

toddams commented 4 years ago

I'm glad to hear you managed to get RazorLight working on Azure, which is, probably, not such a rare use case. But a lack of details of the "fix" makes this issue not as useful as it could be. If, eventually, you find out what exactly makes it work - feel free to submit your PR, community will appreciate your help :)

sgolomedov commented 4 years ago

Provided sample works fine, but be careful with updating dependencies - with Microsoft.NET.Sdk.Functions starting with version 3.0.4. RazorLight fail to find dependent assembly (Microsoft.AspNetCore.Razor.Language).

jzabroski commented 4 years ago

@sgolomedov As I'm not familiar with Azure Functions at all, would you mind putting together a repro I can run in a sandbox? It would be very helpful towards #299 - I simply don't have the bandwidth to learn how to put together an Azure Functions sample to understand and debug the issues.

At minimum, can you provide the stack trace which should include which version of the dependent assembly its trying to find? That would be hepful on top of your clue about v3.0.4.

Put another way, are you saying if you fork https://github.com/mrlund/razorlight-azure-functions-v3-test and update ONE dependency (Microsoft.NET.Sdk.Functions) to 3.0.4 it all breaks?

rzubek commented 4 years ago

I'm not the OP but I can confirm this, since I've just been trying this as well.

The sample code you mention (by mrlund) works great with the specified package versions.

But as soon as you upgrade microsoft.net.sdk.functions to latest stable (3.0.6 in my case) it starts throwing runtime exceptions:

[4/18/2020 2:34:30 AM] C# HTTP trigger function processed a request.
[4/18/2020 2:34:30 AM] Executed 'RenderTemplate' (Failed, Id=30aa818d-9018-4013-98aa-45ab45b80eaf)
[4/18/2020 2:34:30 AM] System.Private.CoreLib: Exception while executing function: RenderTemplate. RazorLight: Could not load file or assembly 'Microsoft.AspNetCore.Razor.Language, Version=3.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.

I tried a variety of versions, and sdk versions 3.0.1-3.0.3 work correctly. But sdk packages from 3.0.4 through the latest 3.0.6 cause RazorLight to throw the above error.

I'm not seeing an obvious way to get a stack trace, but the last few lines of the log output prior to the error are:

'func.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Rob\AppData\Local\AzureFunctionsTools\Releases\3.4.1\cli_x64\Microsoft.IdentityModel.Protocols.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'func.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Rob\AppData\Local\AzureFunctionsTools\Releases\3.4.1\cli_x64\Microsoft.Azure.WebJobs.Logging.dll'. Symbols loaded.
'func.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Rob\AppData\Local\AzureFunctionsTools\Releases\3.4.1\cli_x64\Microsoft.AspNetCore.WebUtilities.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'func.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Rob\Documents\Visual Studio 2019\Projects\TestProject\TestProject\bin\Debug\netcoreapp3.0\bin\RazorLight.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'func.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Rob\AppData\Local\AzureFunctionsTools\Releases\3.4.1\cli_x64\Microsoft.AspNetCore.Razor.Language.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Exception thrown: 'System.IO.FileNotFoundException' in TestProject.dll

Hope this helps!

jzabroski commented 4 years ago

@rzubek Is func.exe something I can run locally? Basically, I don't have time to learn all of Azure Functions but if someone can explain to me step-by-step how to repro the issue on a local machine, I can probably debug this.

rzubek commented 4 years ago

@jzabroski Yes, you can run it locally! Here's a good doc on how to get set up in VS2019: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio

Just the first three sections are enough to test locally.

In my testing I created a new Functions project like described in that tutorial, and then replaced the body of the cs file with code from mrlund's project, and added RazorLight from nuget (the latest preview beta version). That's enough to repro.

jzabroski commented 4 years ago

@rzubek Thank you very much. Very helpful.

Just the first three sections are enough to test locally.

Note to self:

Section 1: Prerequisites Section 2: Create a function app project Section 3: Run the Function Locally

rzubek commented 4 years ago

@jzabroski Good news - the problem with azure functions v3 is on their end, and there's a work-around.

The newer versions of the functions SDK are cleaning out DLLs too eagerly, and until that's fixed in the SDK, it can be prevented by adding this to .csproj.

  <PropertyGroup>
    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
  </PropertyGroup>

Confirmed that this works for RazorLight as well. For future reference, they're tracking it here: https://github.com/Azure/azure-functions-host/issues/5894

jzabroski commented 4 years ago

Awesome, thank you @rzubek for amazing diligence and for sharing your findings. You are a gentleman and a scholar.

fhucko commented 4 years ago

I tried everything, including unofficial beta package, and nothing works. I use Core 3.1 azure function, launched locally. With unofficial beta i get this error: System.TypeLoadException: 'Method 'CommonGetSpecialTypeMember' in type 'Microsoft.CodeAnalysis.CSharp.CSharpCompilation' from assembly 'Microsoft.CodeAnalysis.CSharp, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not have an implementation.'

jzabroski commented 4 years ago

@hogan Have you tried a simple repro in Azure Functions vs your full blown solution? When you say "I tried everything", did you try the solution described by @rzubek above?

I can't really help someone who posts a random exception message. There's just zero hope of me figuring out what your problem is.

I realize you're probably frustrated, but if you don't document what "trying everything" covers, it doesn't really help - it just adds confusion.

fhucko commented 4 years ago

@jzabroski now I have tried to create new azure function project wih2.0.0-beta7 and example code from readme. I have tried both string rendering, and custom razorlight project. I did tests in this order:

Conclusion: With freshly created azure function v3, example code and SetOperatingAssembly, it works, even in Azure cloud! :)

I am still trying to figure out why it does not work in my full blown solution, but overall I am happy that it works in clean project.

The issue with my full blown solution seems to be in my template code. So I consider RazorLight a well working library. Cool :)

jzabroski commented 4 years ago

@hogan Thanks for all that information. Stephen Cleary pointed out to me that much of Azure Functions problems likely come from two areas:

  1. Azure Functions runs the latest runtime for your given FUNCTIONS_EXTENSION_VERSION. Therefore, if you are not also using dependencies bound to the latest Azure Functions version, you might end up with strange failures.
  2. On top of this is the problem @rzubek reported, where Azure Functions SDK tries to Clean your Build output of "Runtime Dependencies" via RemoveRuntimeDependencies task. The hack is to set a private flag that is really only intended for use by the Azure Functions SDK:
    <PropertyGroup>
      <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
    </PropertyGroup>

Based on my reading, Microsoft.NET.Sdk.Functions is a bit magical. It does a lot of interesting code generation at compile time, like generating a function.json file for each azure function.

DanielClausen commented 4 years ago

@hogan Were you ever able to resolve the error in your existing project? I'm getting the Method 'CommonGetSpecialTypeMember' in type 'Microsoft.CodeAnalysis.CSharp.CSharpCompilation' exception when trying to add RazorLight to my Azure Function 3.1 project. I have a unit test that is able to compile my template and get the correct output so I currently don't think it is a template problem.

jzabroski commented 4 years ago

@DanielClausen what version of func.exe

EDIT: I also see Azure Functions is now on 3.1

DanielClausen commented 4 years ago

@jzabroski Function Runtime Version: 3.0.13901.0

jzabroski commented 4 years ago

so func.exe is 3.0.13901.0 but SDK is 3.1?

DanielClausen commented 4 years ago

Yes, that would be correct, version 3.x is intended with Core 3.1: https://docs.microsoft.com/en-us/azure/azure-functions/functions-versions

jzabroski commented 4 years ago

Sorry to be nitpicky, but youre actually using:

func.exe version 3.0.13901.0 .net core runtime version 3.1.?.? azure functions sdk version ? can't be 3.1 since nuget says 3.0.9 is latest https://www.nuget.org/packages/Microsoft.NET.Sdk.Functions/

jzabroski commented 4 years ago

This is incredibly critical to get right to troubleshoot a problem. THe massive tree of dependencies is enormous. Can't search in the wrong haystack for a needle.

DanielClausen commented 4 years ago

It's fine my apologies for not being clear, I didn't catch on you were asking about the SDK version. In my defense it's past 5 on a Friday and weekend brain is taking over.

func.exe version 3.0.13901.0 .net core runtime version 3.1.302 Microsoft.NET.Sdk.Functions version 3.0.8

jzabroski commented 4 years ago

Hey man, It's OK, on Monday, please try 3.0.9. That would probably be the lazy brain way to push past this issue.

DanielClausen commented 4 years ago

@jzabroski I've got it working! Based on a blog where someone claimed to have RazorLight working with Functions V2 I was using the RazorLight.Unofficial 2.0.0-beta1.3. I switched over to RazorLog 2.0.0-beta9 and now it works. In hindsight I should have tried that sooner. I also tried upgrading to 3.0.9 and that didn't make a difference.

Hopefully, this information can help anyone else that might stumble into this issue. The assistance was much appreciated @jzabroski !

jzabroski commented 4 years ago

@DanielClausen I really appreciate that. It's been a long journey herding cats among people who use unofficial RazorLight packages and getting people onto the main line, but it's starting to come back into the fold.