Generating StiNetCoreViewer from the server and sending as s

Stimulsoft Reports.NET discussion
MichalCh
Posts: 17
Joined: Fri Sep 22, 2017 7:37 am

Generating StiNetCoreViewer from the server and sending as s

Post 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
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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.
MichalCh
Posts: 17
Joined: Fri Sep 22, 2017 7:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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.
MichalCh
Posts: 17
Joined: Fri Sep 22, 2017 7:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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
    }
})
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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.
MichalCh
Posts: 17
Joined: Fri Sep 22, 2017 7:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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
Vladimir
Posts: 1462
Joined: Fri Apr 13, 2007 4:05 am
Location: Earth

Re: Generating StiNetCoreViewer from the server and sending

Post 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.
MichalCh
Posts: 17
Joined: Fri Sep 22, 2017 7:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Generating StiNetCoreViewer from the server and sending

Post 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.
Post Reply