Search code examples
c#asp.net-corerotativa

Rotativa.Netcore works locally but not after deployment


I am using the latest Rotativa.NetCore assembly in a ASP.NET Core 2.1.1 project. The NuGet (https://www.nuget.org/packages/Rotativa.AspNetCore v. 1.0.6) does not work on deployment (win2016) but works locally (win10).

IIS on deployment gives 404 and the error log (stdout) shows this:

fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.Exception
   at Rotativa.AspNetCore.WkhtmlDriver.Convert(String wkhtmlPath, String switches, String html, String wkhtmlExe)
   at Rotativa.AspNetCore.WkhtmltopdfDriver.ConvertHtml(String wkhtmltopdfPath, String switches, String html)
   at Rotativa.AspNetCore.ViewAsPdf.CallTheDriver(ActionContext context)
   at Rotativa.AspNetCore.AsResultBase.BuildFile(ActionContext context)
   at Rotativa.AspNetCore.AsResultBase.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

Here is 'myproject' source

public IActionResult DownloadCertificate(int id)
{
    var model = getData(id);
    return new ViewAsPdf("PdfCertificate", model)
    {
        WkhtmlPath = "", // set the path to the Rotativa .exe files. works locally but not on deployment. 
        FileName = "Cert.pdf"
    };
}

I have tried changing WkhtmlPath to "..\\Rotativa\\" but no luck.

Troubleshooting I found this: https://stackoverflow.com/a/48166956/560784 - apparently Rotativa is compiled against .NET Core 1.0:

There's code to update Rotativa.NetCore from .Net Core 1 to .Net Core 2.0 here: https://github.com/aaxelm/Rotativa.NetCore/pull/1/files?diff=split

So, I downloaded the Rotativa source and updated to .NET core 2.0 accordingly, referenced the new assembly. Problem persists.

I have checked permssions as well. Rotativa folder gives IIS_IUSRS execute permissions (running ApplicationPoolIdentity).

What am I missing?

My local folder structure:

c:\inetpub\myproject\myproject.dll + web.config and what not. c:\inetpub\myproject\Rotativa{wkhtmltoimage.exe, wkhtmltopdf.exe, wkhtmltox.dll}

My deployed folder structure:

c:\inetpub\sites\myproject\myproject.dll + web.config and what not. c:\inetpub\sites\myproject\wwwroot\ (static files) c:\inetpub\sites\myproject\Rotativa{wkhtmltoimage.exe, wkhtmltopdf.exe, wkhtmltox.dll}


Solution

  • It turns out I needed to install Microsoft Visual C++ Redistributable 2017 (x86) - download here: https://visualstudio.microsoft.com/vs/older-downloads/ or https://visualstudio.microsoft.com/downloads/

    1. I reverted to the official nuget (for easier future maintenance) https://www.nuget.org/packages/Rotativa.AspNetCore v. 1.0.6
    2. I added RotativaConfiguration.Setup(env, "..\\Rotativa\\"); to Startup.cs
    3. My final code looks like this:

    Code:

    public IActionResult DownloadCertificate(int id)
    {
        var model = getData(id);
        return new ViewAsPdf("PdfCertificate", model)
        {
             FileName = "Cert.pdf"
        };
    }