Hi team,
My solution is composed by two projects:
- Client-Side (DevExtreme)
- Server-Side (Web Report Designer)
My requirement is to pass certain information from session context provided by login process (in client-side) and retrieve it in the CustomReportStorageWebExtension (in server-side) in order to pass that information as parameters to report.
I done this in a prototype based on MVC with Web Report Designer, all integrated in a unique project, and all works fine, you can see the code attached.
But now, I have one solution composed by two projects running in differents domains, and the solution I described above does not working (I think, the reason is due the CORS scenario).
How I can accomplish that requirement in this architecture?
Login Process code:
C# [HttpPost]
public JsonResult OpenSesionUser(string nombreUsuario, string idNivel)
{
try
{
if (idNivel != "")
{
USUARIOS usuario = SessionContext.Current._usuario;
NivelUsuarioVM nivelUsuario = NivelUsuarioDAO.GetByUsuarioIdNivelId(usuario, idNivel);
if (!NullOrEmptyValidator.IsEmptyEntity(nivelUsuario))
{
NivelRepository repo = new NivelRepository();
repo.ValidarAccesibilidad(nivelUsuario);
if (!usuario.NIVEL_DEFECTO.Equals(idNivel))
UsuarioDAO.UpdateNivelDefecto(usuario, idNivel);
SessionContext.Current._nivelUsuario = nivelUsuario;
//Pass object nivelUsuario to context HTTP used by Web Report Designer
if (Session["_NivelUsuario"] == null)
{
Session["_NivelUsuario"] = nivelUsuario.COD_NIVEL;
Session["_NombreNivel"] = nivelUsuario.DESCRIPCION_NIVEL;
}
///////////////////////////////////////////////////////////////////////////////////
SesionDAO.Create(new SESIONES() { IP = IP.GetIpCliente(), ID_NIVEL_USUARIO = nivelUsuario.ID });
FormsAuthentication.SetAuthCookie(nombreUsuario, false);
}
//Translator.GetAllTraducciones();
}
return new OkRequest("ok");
}
catch (iSGCASExceptions ex)
{...}
}
CustomReportStorageWebExtension code:
C#public override byte[] GetData(string url)
{
// Get the report's layout from report's storage
using (var session = SessionFactory.Create())
{
var reportEntity = session.GetObjectByKey<CATALOGO_REPORTES>(url);
XtraReport report = new XtraReport();
using (MemoryStream ms = new MemoryStream(reportEntity.LAYOUT))
{
report.LoadLayoutFromXml(ms);
}
try
{
report.Parameters["Id_Nivel"].Value = HttpContext.Current.Session["_NivelUsuario"];
report.Parameters["Nombre_Nivel"].Value = HttpContext.Current.Session["_NombreNivel"];
}
catch {
...
};
using (MemoryStream ms = new MemoryStream())
{
report.SaveLayoutToXml(ms);
reportEntity.LAYOUT = ms.ToArray();
}
session.CommitChanges();
return reportEntity.LAYOUT;
}
}
Regards,
Oscar
Hi Oscar,
>>I think, the reason is due the CORS scenario
CORS can be indeed the cause of the issue here. Since you named it, can you clarify if you allow cross-origin requests? The following tutorial mentions this requirement: Report Designer Server-Side Configuration (ASP.NET MVC). Checking the network log and returned error codes can also be beneficial and give some clues: Reporting Application Diagnostics.
Note: you're using OAuth authentication and CORS, you're also expected to handle the preflight request. For more details about this, please check the following thread where I discussed a similar issue in the case of WebDocumentViewer: Report parameter input type.
Let me know if you find anything.
Regards,
Yaroslav
Thanks Yaroslav,
I enabled all directives and implementations in order to get access to server without success.
As workaround, I installed the CORS-Anywhere plug-in for Firefox and Chrome and it worked very well.
As final solution, I will include the original code of CORS-Anywhere project inside my solution, which I can download from GitHub.
That plug-in allows all requests to get access in server (bypassing all CORS rules), and the requests are no refused when I trying get cross resources, all requests are ending with status 200.
With the plug-in CORS-Anywhere all is working perfect, the one issue I'm facing is can't get the values from session context when I preparing the call to Web Report Designer, so, the report can't execute correctly because the parameters have no valid values.
Basicly, I'm looking for something that allow to share the session between applications in CORS scenarios.
Have you some approach for accomplish the requirement?
Regards,
Oscar
Hi Oscar,
>>As final solution, I will include the original code of CORS-Anywhere project inside my solution, which I can download from GitHub.
I'm not sure if I understand the idea. Provided that you're working on a web project, how would including the source code of the browser extension help here? From my understanding, in order for this to work you need to install the extension on all client computers, which may be not desired or even possible. I suggest that we work together on solving this issue and implementing a proper CORS support that would not require any extension. As I mentioned, the first troubleshooting step here is to inspect the network log and returned error codes. Open the browser's developer tools (F12) and switch to the "Network" tab. Reproduce the issue. Then, right click the Network tab and save the profiling results into HTTP Archive format (*.har) file. Share this file for review.
>>Basicly, I'm looking for something that allow to share the session between applications in CORS scenarios.
I'd like to know more about your solution architecture prior to suggestion any particular solution. You mentioned that you have a separate DevExtreme project which represents the front end of your web site. But DevExtreme is only a collection of widgets. How do you actually deliver the HTML content to the user?
Regards,
Yaroslav
Hi Yaroslav,
I'll try explain your observations:
We sell one solution per customer "on-premise" and its "perimeter security" is very hard. Anyway, I agree with you, the ideal is implementing CORS rules in the right way, without need of any other "third-party" software.
About CORS-Anywhere plug-in, I included now because I need to solve problems related with CORS and I'm not an expert in these subjects.
No doubt you have the reason, that could not be the best solution, but, until I have more knowledge and experience, that could be a workaround.
The technical challenge is to implement CORS rules considering the main project include the Login process and the session must be shared for the secondary project.
In this case, I thanks your offering of support.
The requirement assigned to me was "include a reportability functionality" for the original system a.k.a. iSGCAS which implements all functionality for data management using DevExtreme, jQuery and Ajax based in a MVC design pattern.
The restrictions were:
In that case, an independent project to Reportabilidad was the right choice.
Reportabilidad implements all functionality to create and serve the reports created, which lives inside a database, in order to avoid modify the MVC architecture.
From here derives the need of pass some session's data to reporting.
I hope I have clarified your concerns and, please, feel free to inquiry further details.
Best regards,
Oscar
Thank you for the clarification, Oscar. The situation is clear to me now with the exception of one question: "What is the type of your original project?" That is, right now you have two projects. One project is the ASP.NET MVC project with controllers that will process all report-related requests. But what is the type of the "iSGCAS "project? You mentioned that it uses "the MVC pattern". Does this mean that it is also an ASP.NET MVC application? Do you have two ASP.NET MVC applications now? Usually, sharing the same identity of a logged in user between multiple web applications implies the usage of a shared authentication server. That's what we called the Single sign-on (SSO) feature, but its implementation is not related to any particular UI component and goes beyond the scope of our support services.
Regards,
Yaroslav
Thanks Yaroslav,
The answer to your question: Yes, as shown in attached image of the previuos message, we have two web applications with separated responsibilities: one for data management (that's the original project) and another one for preparation and presentation of reportings, both MVC pattern.
I'm very clear about the situation and, I think I can solve the problem using an iframe or something like that to pass the parameter.
Anyway, thanks a lot Yaroslav.
Best regards,
Oscar
Maybe, my approach was wrong…
Reading more, there is a class, ASPxClientReportDesigner, which have the method AddParameterType… could you guide me in order to set and use in an whole example, from client to server?
Thanks in advance,
Oscar
Oscar,
I confirm that this method exists at the
ASPxClientReportDesigner
level. This API is used to create a new parameter type the user can choose when creating a new parameter via the "Add New Parameter" dialog. A sample project can be found in the answer here: add support for stored procedures using sql time data type parameters to mvc report designer. There, a custom editor is used to edit a parameter of theSystem.TimeSpan
type (which the user sees as "Time" in the drop-down window).I should mention though that I don't quite understand how a custom report parameter can help either with the CORS or SSO implementation. These are two application-level features that do not rely on any particular visual component.
Would you please clarify? Am I missing anything here?
Hi Yaroslav,
Actually, in essence what I need is a way to pass some values from client to inside of report component (as parameters) in order to complete the report's underlying query.
That's all.
I'm not pretending implementing CORS neither SSO, just to pass two simple parameters.
In the process to achieve that, I applied different approaches which conducted to my to facing CORS and SSO, but these never have been my goal.
You know all details about our solution.
There is some way to accomplish that?
In the attached figure I show you what I need.
Considering another approach, Is there a way to pass the parameters in the url?, how I can do that?, this is my code:
$.ajax({ url: pathUrl + '/Disennador', contentType: 'application/html; charset=utf-8', crossDomain: true, method: 'GET', dataType: 'html', success: function (result) { document.write(result); const host = 'http://localhost:12000/', reportUrl = reportUrl, designerOptions = { reportUrl: reportUrl, requestOptions: { host: host, getDesignerModelAction: "/ReportDesigner/GetReportDesignerModel", getLocalizationAction: "/ReportDesigner/GetLocalization" }, callbacks: { CustomizeMenuActions: function (s, e) { var exitAction = e.GetById(DevExpress.Reporting.Designer.Actions.ActionId.Exit); if (exitAction) exitAction.visible = true; } } } setTimeout(function () { ko.applyBindings({ designerOptions }); }, 2000); }, error: (function (xhr, status) { //alert(status); }) })
Ther
Thanks in advance,
Regards,
Oscar
Oscar,
>>In the attached figure I show you what I need.
The attached screenshot illustrates the built-in "Parameters" panel that is a part of the WebDocumentViewer interface. Any parameters that you type there will be automatically propagated to the underlying report. This functionality works out of the box and does not require any extra handing.
>>what I need is a way to pass some values from client to inside of report component (as parameters)
Since you're using the client-side integration approach, you open a report from the storage by defining the
reportUrl
variable. You never operate with the XtraReport instance in C# code, it's about JavaScript. In other words, there is no direct way of passing values from the client to the server using theXtraReport.Parameters
collection. Of course, the above "Parameters" panel is the exception here.What kind of information do you wish to pass? Are we still talking about session context provided by the login process? This information is usually passed in the HTML request header, not as a report parameter. An example would be a bearer token, which is a cryptic string generated by the server in response to a login request. We use jQuery AJAX to communicate with the server, and we allow patching these requests using the following client-side setting:
DevExpress.Analytics.Utils.ajaxSetup.ajaxSettings
. You can see how this property is used in this GitHub example: Web Document Viewer - How to export documents in an application with token-based authentication.It should be also mentioned that the built-in ASP.NET authentication mechanism uses cookies and not tokens. An attempt to share a cookie would be nothing but an attempt to implement the SSO experience: Share Cookie Across Sub Domain In ASP.NET.
Regards,
Yaroslav
Thanks Yaroslav.
The kind of data I need to pass are not related with session context. These are no sensitive.
I need populate that two parameters without user intervention, directly from client.
I'm using
to connect with the server, but I can't figure where add the parameters I need to send to reporting.
Regards,
Oscar
Hi Yaroslav,
Reading a lot, a found this question from Manish Gupta 13, https://supportcenter.devexpress.com/ticket/details/t618828 who facing exactly the same situation as me.
I'll apply their approach in order to achieve my goal.
If you have something to update or complete, please, do it.
Regards,
Oscar
>>The kind of data I need to pass are not related with session. These are no sensitive.
So, what are these parameters and how do you intended to use them further? Note that Web End-User Report Designer will reveal all parameters to the user regardless of their visibility, there's no way of hiding a certain parameter from the UI. I'm asking this question as you specifically mentioned that you'd like to complete this task "without user intervention".
>>If you have something to update or complete, please, do it.
What you found is a possible solution, but it will only work for the report that you open by default in code, not for the report that the users opens through the built-in "Open" dialog.
Thanks Yaroslav,
I sorry by didn't be clear about the use scenario of web report designer.
Here I go to clarify the "use scenario":
Our customer have two roles for use this tool:
The designer, who have permision to create and and assign the report to users whom will consume this reports (final consumer role). Obviously the designer have full permisions to see and modify the parameters. In fact, the designer is the owner and responsible's user of these reports.
The final consumer, who have permision only to see the the reports and its data. The parameters what I need are required to complete the underlying query, and this parameters will be hidden for the final consumer. This must be passed by code without final consumer's intervention.
The list of reports is managed by a form which is out of the web report designer.
So, the final consumer never, but never will see the web report designer in action, they just will use the web report viewer.
I hope this is clear for you now.
Regards,
Oscar
you say:
You never operate with the XtraReport instance in C# code, it's about JavaScript. In other words, there is no direct way of passing values from the client to the server using the XtraReport.Parameters collection
So, could you guide me in a way to accomplish that?
please, it's urgent…
Regards,
Oscar