.Net Client issue "Unable to render template"



  • There seems to be an issue with the function call service.RenderAsync which is returning the following error

    JsReportException: Unable to render template.  <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>Error</title>
    </head>
    <body>
    <pre>Cannot POST /api/api/report</pre>
    </body>
    </html>
    

    Its looks like its adding path 'api' twice even though the call sent is

    ReportingService service = new ReportingService("https://{host}/reporting/api/report");
    

    Removing 'api' from path works and returns the pdf file only when its the root path but for the scenario above where 'reporting' is the root path it fails.



  • The ReportingService constructor parameter accepts url to the jsreport service
    If your jsreport instance runs on https://host/reporting, you should do:

    ReportingService service = new ReportingService("https://host/reporting");
    


  • If I keep just reporting its returns a 404 error

    JsReportException: Unable to render template.  <html>
    <head><title>404 Not Found</title></head>
    <body bgcolor="white">
    <center><h1>404 Not Found</h1></center>
    <hr><center>nginx/1.14.0 (Ubuntu)</center>
    </body>
    </html>
    

    I have 2 enterprise licenses for 2 clients, I had faced the issue before when the path sent was

    ReportingService service = new ReportingService("https://host/api/report");
    

    I ended up sending

    ReportingService service = new ReportingService("https://host/report");
    

    and it worked for that scenario.



  • So you can open https://host/reporting in the browser, see jsreport studio and render template?
    But if you use (new ReportingService(https://host/reporting)).renderAsync you get 404 error?

    The 404 error you shared is from nginx, not jsreport. Are you sure you have the correct settings there?
    What if you invoke jsreport render request using a postman or some other tool?



  • A postman call to the link below returns the pdf file

    https://host/reporting/api/report
    

    The issue is the JsReport .Net Client package, below is the snippet of code

    //ReportingService service = new ReportingService("https://{host}/reporting/api/report");
    ReportingService service = new ReportingService("https://{host}/reporting");
    service.Username = {username};
    service.Password = {password};
    using (var fileStream = File.Create(Server.MapPath("~/temp/") + {reportname}+ ".pdf"))
    {
              var report = service.RenderAsync({jsreport_shortid}, {data}).Result; //Error pops up here
              report.Content.CopyTo(fileStream);
              Response.ContentType = "application/pdf";
              Response.AppendHeader("Content-Disposition", "attachment; filename=" + {reportname} + ".pdf");
              fileStream.Seek(0, SeekOrigin.Begin);
              fileStream.CopyTo(Response.OutputStream);
              Response.Flush();
              Response.Close();
              Response.End();
    }


  • Hmm. Thanks. Nothing comes to my mind, unfortunately. I don't see any reason why the postman should behave differently than the client.

    I would recommend doing the same HTTP post you do from postman but inside c#, and see if it actually works.



  • Hey Jan! Yes attempted HTTP Post in C# replicating postman and it works.



  • Thank you. I guess you use also the .net HttpClient lib?
    Could you check what you do differently, there is no big magic in the jsreport-client code.
    https://github.com/jsreport/jsreport-dotnet-client/blob/master/jsreport.Client/ReportingService.cs#L154



  • Please see below, I replicated most of what was available on the jsreport-dotnet-client git

    public class JsReportHelper
        {
            public TimeSpan? HttpClientTimeout { get; set; }
            public IContractResolver ContractResolverForDataProperty { get; set; }
    
            public async Task<Report> RenderAsync(string templateUri, string templateShortid, JObject jsonData)
            {
                JObject root = new JObject();
                JObject template = new JObject
                {
                    { "shortid", templateShortid }
                };
                root.Add("template", template);
                root.Add("data", jsonData);
                string request = SerializerHelper.SerializeRenderRequest(templateShortid, jsonData.ToString(), ContractResolverForDataProperty);
                CancellationToken ct = default(CancellationToken);
                var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(
                        Encoding.UTF8.GetBytes(String.Format("{0}:{1}", Constants.JsReport_Username, Constants.JsReport_Password))));
                if (HttpClientTimeout != null)
                    client.Timeout = HttpClientTimeout.Value;
                var content = new StringContent(root.ToString(), Encoding.UTF8, "application/json");
                var response = await client.PostAsync(templateUri, content, ct).ConfigureAwait(false);
    
    
                if (response.StatusCode != HttpStatusCode.OK)
                    throw JsReportException.Create("Unable to render template. ", response);
    
                response.EnsureSuccessStatusCode();
    
                return await ReportFromResponse(response).ConfigureAwait(false);
            }
            private static async Task<Report> ReportFromResponse(HttpResponseMessage response)
            {
                var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
                IDictionary<string, string> meta = new Dictionary<string, string>();
                response.Headers.ToList().ForEach(h => meta[h.Key] = h.Value.FirstOrDefault());
                response.Content.Headers.ToList().ForEach(h => meta[h.Key] = h.Value.FirstOrDefault());
                return new ReportHttp()
                {
                    Content = stream,
                    Response = response
                };
            }
        }
    

    This is how I invoke it

    JsReportHelper jsService = new JsReportHelper();
    //item.jsreport_url ("https://{host}/reporting/api/report")
    //item.jsreport_shortid (js report template id)
    //root (JObject)
    var report = jsService.RenderAsync(item.jsreport_url, item.jsreport_shortid, root).Result;
    

    I am not sure why but the error with the original code (see below) still persists.

    ReportingService service = new ReportingService("https://{host}/reporting/api/report");
    //or
    ReportingService service = new ReportingService("https://{host}/reporting");
    


  • It jsreport.Client uses the BaseAddress param for HttpClient. Could you try the same?

    var client = new HttpClient() { BaseAddress = "https://{host}/reporting"};
    var response = await client.PostAsync("api/report", content, ct).ConfigureAwait(false);
    


  • Attempted with jsreport.Client, I get the 404 error.
    0_1617631833210_upload-e50025ee-a230-4c26-901e-66992a1d9097

    Attempted with custom, It downloads the file
    0_1617632531858_upload-7913f5eb-34d4-4892-89a1-672b041decf3

    0_1617633431848_upload-74237df7-03df-4c7c-beb9-7bdf16bcc861

    I bet its something silly on my end but cant for heaven's sake figure it out :'D .

    For now I have gone ahead with the custom implementation. A voice in my head keeps wanting me to figure out the cause of this error :D If you want to get to the bottom of this error as well, I can put in a request for a test user and set up a mirror report and DM you the details.


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.