Page 1 of 2

Generating StiNetCoreViewer from the server and sending as s

Posted: Tue Oct 24, 2017 10:17 am
by MichalCh
Hello,

I'm trying to generate StiNetCoreViewer, parse it to string and send it back to the client. Unfortunately I'm having a small issue and I do not know what I'm doing wrong here

The Index View:

Code: Select all

@using Stimulsoft.Report.NetCore;
@{
    ViewData["Title"] = "Home Page";
}
<br />
<p>hello world</p>
@Html.Stimulsoft().StiNetCoreViewer("NetCoreViewer1", new StiNetCoreViewerOptions()
{
    Actions =
    {
        GetReportData = "GetReport",
        ViewerEvent = "ViewerEvent"
    }
})
Here is the simple action which should generate the view and send back as string
The exception is being thrown in Index.cshtml when intializing Html.Stimulsoft()... and it is being invoked
by await view.RenderAsync(viewContext);

Code: Select all

        private ActionContext GetActionContext(IServiceProvider serviceProvider)
        {
            var httpContext = new DefaultHttpContext
            {
                RequestServices = serviceProvider
            };

            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }

        [HttpGet]
        public async Task<IActionResult> GetReportView(
            [FromServices] IRazorViewEngine razorViewEngine,
            [FromServices] IServiceProvider serviceProvider,
            [FromServices] ITempDataProvider tempDataProvider)
        {
            var reportView = GetReportView(); // This method returns just a class with .Data property as generated report with byte[] type

            ViewBag.Data = reportView.Data;

                var name = "Index";

                var actionContext = GetActionContext(serviceProvider);
                var viewEngineResult = razorViewEngine.FindView(actionContext, name, false);

                if (!viewEngineResult.Success)
                {
                    throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
                }

                var view = viewEngineResult.View;

                using (var output = new StringWriter())
                {
                    var viewContext = new ViewContext(
                        actionContext,
                        view,
                        new ViewDataDictionary<TModel>(
                            metadataProvider: new EmptyModelMetadataProvider(),
                            modelState: new ModelStateDictionary())
                        {
                            Model = null
                        },
                        new TempDataDictionary(
                            actionContext.HttpContext,
                            tempDataProvider),
                        output,
                        new HtmlHelperOptions());

                    await view.RenderAsync(viewContext);

                    result = output.ToString();
            }

            var contentResult = new ContentResult
            {
                Content = result,
                ContentType = "text/html"
            };

            return contentResult;
        }
The methods GetReport() and ViewerEvent() are also in the same controller but they are not being invoked at all

Code: Select all

        public IActionResult GetReport()
        {
            IActionResult result = null;

            try
            {
                result = StiNetCoreViewer.GetReportDataResult(this, ViewBag.Data);
            }
            catch(Exception ex)
            {
                var msg = ex.Message;
                var data = ex.Data;
            }

            return result;
        }

        public IActionResult ViewerEvent()
        {
            IActionResult result = null;

            try
            {
                result = StiNetCoreViewer.ViewerEventResult(this);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                var data = ex.Data;
            }

            return result;
        }
If I delete @Html.Stimulsoft().StiNetCoreViewer... from View, Hello World is being displayed properly
The exception which is being thrown:

Code: Select all

[12:12:39 ERR] Unhandled ArgumentOutOfRangeException at WebApi.Controllers.ReportController.GetReportView (WebApi)
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
   at System.ThrowHelper.ThrowArgumentOutOfRange_IndexException()
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Stimulsoft.Report.NetCore.StiRequestParamsHelper.GetRequestUrl(ViewContext viewContext, String controller, Boolean relativeUrls, Boolean passQueryParams) in D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report.NetCore\Helpers\StiRequestParamsHelper.cs:line 200
   at Stimulsoft.Report.NetCore.StiNetCoreViewer.Render() in D:\Stimulsoft\Stimulsoft.Reports\Stimulsoft.Report.NetCore\Viewer\StiNetCoreViewer.Render.cs:line 77
   at AspNetCore._Views_Shared_Index_cshtml.<ExecuteAsync>d__0.MoveNext() in C:\backend-report-server\backend-report-server\ReportServer.WebApi\Views\Shared\Index.cshtml:line 7
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.<RenderPageCoreAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.<RenderPageAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.<RenderAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ReportServer.WebApi.Controllers.ReportController.<GetReportView>d__3.MoveNext() in C:\backend-report-server\backend-report-server\ReportServer.WebApi\Controllers\ReportController.cs:line 115
--- End of stack trace from previous location where exception was thrown ---
It looks like Stimulsoft.Report.NetCore\Helpers\StiRequestParamsHelper.cs:line 200 requires some sort of list or sth but I can't find any documentation about that.
Can you be of any help?

Cheers

Re: Generating StiNetCoreViewer from the server and sending

Posted: Tue Oct 24, 2017 2:02 pm
by Alex K.
Hello,

This is due to the fact that the component analyzes the current RouteData for calling the necessary actions. Send to the viewer the RouteData from the current controller, for example:

Code: Select all

return new ActionContext(httpContext, /*new RouteData()*/ this.RouteData, new ActionDescriptor());
Thank you.

Re: Generating StiNetCoreViewer from the server and sending

Posted: Tue Oct 24, 2017 2:43 pm
by MichalCh
Hello,

Unfortunately passing this.RouteData did not fix the issue, same error occurs. I've tried to pass current this.HttpContext as well later on <- still the same issue with line 200 in StiRequestParamsHelper

Cheers

Re: Generating StiNetCoreViewer from the server and sending

Posted: Tue Oct 24, 2017 4:26 pm
by Alex K.
Hello,

We couldn't reproduce this issue on our samples.
Please send us a sample project which reproduces the issue for analysis.

Thank you.

Re: Generating StiNetCoreViewer from the server and sending

Posted: Wed Oct 25, 2017 2:13 pm
by MichalCh
Hello,

When I took out the controller and action to brand new project I've discovered the issue. There are calls being made from front-end to actions ViewerEvent() and GetReport() and our Infrastructure is blocking those calls.

Is there a way to pass to that view generated in the back-end StiNetCoreViewer.GetReportDataResult(this, reportData); and StiNetCoreViewer.ViewerEventResult(this); instead of making them as an "Actions" in StiNetCoreViewerOptions?
Actions =
{
GetReportData = "GetReport",
ViewerEvent = "ViewerEvent"
}


so that Index.cshtml would look like

Code: Select all

@using Stimulsoft.Report.NetCore;
@{
    ViewData["Title"] = "Home Page";
}
<br />
<p>hello world</p>
@Html.Stimulsoft().StiNetCoreViewer("NetCoreViewer1", new StiNetCoreViewerOptions()
{
    Model =
    {
        ReportData = @ViewBag.ReportData,
        ViewerEvent = @ViewBag.ViewerEvent
    }
})

Re: Generating StiNetCoreViewer from the server and sending

Posted: Fri Oct 27, 2017 7:34 am
by Alex K.
Hello.

You can specify controller which will use for the viewer requests:

Code: Select all

        Server =
        {
            Controller = "ViewerController",
...
Also, with JavaScript code you can change URL mask for all requests:

Code: Select all

<script>
    jsNetCoreViewer1.options.requestUrl = "/Home/{action}";
    jsNetCoreViewer1.options.requestAbsoluteUrl = "http://localhost:4000/Home/{action}";
</script>
jsNetCoreViewer1 - variable of JavaSctipt, js + viewer component id
{action} - mandatory part of string, it will be changed on the action's name of the viewer.

Thank you.

Re: Generating StiNetCoreViewer from the server and sending

Posted: Fri Oct 27, 2017 10:15 am
by MichalCh
Hello,

Great, can I get some sort of documentation about jsNetCoreViewer? And perhaps jsNetCoreDesigner since it is exactly the same problem there.

The reason I'm asking is we'll need to add extra headers for get requests.

But just out of curiosity isn't there a private field/array in js where I can just assign data from the server directly? Since I'm assuming the get is getting the response and parsing it into private fields so we can send it right away from the Index() action and to not make another GETs

Cheers

Re: Generating StiNetCoreViewer from the server and sending

Posted: Fri Oct 27, 2017 1:22 pm
by Vladimir
Hello,

Unfortunately there is no documentation on JavaScript objects, because this is the source code of the product, and the changes are more "hacks" than the regular features, and may stop working in the next versions. At this time, you can try to overload the method of sending requests, and pass additional POST parameters. Send additional headers will not work, this requires a revision of the code of the product.

Code: Select all

<script>
    _http = jsNetCoreViewer1.http;
    jsNetCoreViewer1.http = function (params, callback, action) {
        params["MyParamName"] = "MyParamValue";
        _http(params, callback, action);
    }
</script>
Thank you.

Re: Generating StiNetCoreViewer from the server and sending

Posted: Wed Nov 01, 2017 8:54 am
by MichalCh
Hello,

I've extracted the ViewerEvent(), DesignerEvent() and GetReport() into seperate controller StmController

Code: Select all

[Route("stm")]
    public class StmController : Controller
    {
        [HttpGet]
        [Route("getreport", Name = "GetReport")]
        [ProducesResponseType(typeof(string), 200)]
        public IActionResult GetReport()
        {
            IActionResult result = null;

            try
            {
                result = StiNetCoreViewer.GetReportDataResult(this, ViewBag.Data);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                var data = ex.Data;
            }

            return result;
        }

        [HttpGet]
        [Route("viewerevent", Name = "ViewerEvent")]
        [ProducesResponseType(typeof(string), 200)]
        public IActionResult ViewerEvent()
        {
            IActionResult result = null;

            try
            {
                result = StiNetCoreViewer.ViewerEventResult(this);
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                var data = ex.Data;
            }

            return result;
        }

        [Route("designerevent", Name = "DesignerEvent")]
        [ProducesResponseType(typeof(string), 200)]
        public IActionResult DesignerEvent()
        {
            return StiNetCoreDesigner.DesignerEventResult(this);
        }
    }
from the demo project I've found out that this link is the first which is being requested

Code: Select all

http://localhost:50502/Home/DesignerEvent?stinetcore_component=Designer&stinetcore_action=Resource&stinetcore_data=office2013.whiteblue&version=2017.1.11
So I've checked if the response is the same from my new extracted controller and it is!

Code: Select all

http://localhost:5104/Stm/DesignerEvent?stinetcore_component=Designer&stinetcore_action=Resource&stinetcore_data=office2013.whiteblue&version=2017.1.11
So the only thing left was to "redirect" actions/controller from Views to issue Get to another controller. I've tried all three options provided by you guys, seperately and all together.
The same error still occurs and the endpoints are not being hit. I've set up breakpoints on the start of the methods from StmController and on get request from the browser using the link above the breakpoint is being hit but by using the view it isn't. But the breakpoint in the view on line 13th is hit

Code: Select all

@using Stimulsoft.Report.NetCore;
@{
    ViewData["Title"] = "Home Page";
}
<br />
<p>hello world</p>

<script>
    jsNetCoreViewer1.options.requestUrl = "/stm/{action}";
    jsNetCoreViewer1.options.requestAbsoluteUrl = "http://localhost:5104/stm/{action}";
</script>

@Html.Stimulsoft().StiNetCoreViewer("NetCoreViewer1", new StiNetCoreViewerOptions()
{
    Server =
    {
            Controller = "StmController"
    },

    Actions =
    {
        GetReportData = "GetReport",
        ViewerEvent = "ViewerEvent"
    }
})
What else am I missing?

Cheers

Re: Generating StiNetCoreViewer from the server and sending

Posted: Wed Nov 01, 2017 10:25 am
by Alex K.
Hello,

Please try to change option:
Controller = "StmController"
on:
Controller = "Stm"
that option uses directly in URL request.

Also, if you set this option, the controller name must be replaced in JavaScript options, there is no need to set it additionally.
If it did not help, please send us a sample project for analysis.

Also, all JavaScript code should be added after initialization of the component.

Thank you.