.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 onhttps://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 theBaseAddress
param forHttpClient
. 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.
Attempted with custom, It downloads the file
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.