I have created Reporting Projects which are RestService, and ReportLibrary. These two projects will be integrated with another project. The problem is Reporting Project can't get httpcontext that send from another project. I tried to figure out the problem and i found that it was success to receive the httpcontext in RestService(as image Success001, Success002) but ReportLibrary cannot(as image Failed001, Failed002). You can see example images that attach with this post.
Has anyone found this? or any suggestion?
Thank you
17 Answers, 1 is accepted
Please check HttpContext.Current.User is not available in the data-retrieval method executed by an ObjectDataSource component.
In general, we copy the current context on processing the report, but this does not include the whole object. The current context is available in the Reporting REST Service's methods, the report's constructor and events, but not in the process handling the data-retrieval via data source components.
In order to provide you more accurate suggestions, please elaborate on the usage of the current context in the report.
Regards,
Stef
Telerik by Progress
You indicate that the current context is available in the reports constructor, but this does not appear to be consistently true.
We have an application which uses javascript to add reports to the page. When the report is opened, the report constructor is called (at least) three times. The first two times HttpContext.Current.User has a value. The third time, it does not. I just tested the previous version and all three times, the HttpContext.Current.User had a value.
From a security perspective, we need the report to be able to independently verify the user identity as opposed to receiving as a parameter. The way we solve this is by using Ninject DI to inject HttpContext.Current.User as an IPrincipal into all the different layers that need to know the user's identity. This also prevents the need from having to manually pass user name thru application layers that have no direct need for the identity.
For the report data sources, we were able to make this work in version 10.2.16.1025 of Telerik Reporting by manually using DependencyResolver to instantiate the data sources in the report constructor. (Technically, we use an extension method and reflection to minimize the coding impact for each report)
var
obj = DependencyResolver.Current.GetService((Type)objectDataSource.DataSource);
objectDataSource.DataSource = obj;
Additionally, we told Ninject to use a copy of the user identity instead of the real identity as this was sufficient for our needs and overcame an issue when the HttpContext User was disposed before the object data sources used it.
Kernel.Bind<IPrincipal>()
.ToMethod(x =>
new
GenericPrincipal(
new
GenericIdentity(HttpContext.Current.User.Identity.Name),
null
))
.InRequestScope();
Unfortunately, something appears the have changed between our original version and version 11.0.17.222 such that the third call to constructor the report no longer has access to HttpContext.Current.User so we are no unable to upgrade without completely re-architecting how we pass user identity through the application layers.
- Using dependency injection in the object data source layer behind reports
- Accessing the user identity in the object data source layer (by use of dependency injection)
First the dependency injection...
1. Create an extension method (and helper function) to manually instantiate objet data sources using DI:
public
static
void
InjectDependencies(
this
Telerik.Reporting.Report report)
{
// Inject dependencies on the report data source if necessary
// There can be multiple data source in the report
// Use reflection to find out all the data sources and inject dependencies
BindingFlags bindFlags = BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic;
Type reportType = report.GetType();
FieldInfo[] fieldInfo = reportType.GetFields(bindFlags);
foreach
(var field
in
fieldInfo)
{
if
(field.FieldType ==
typeof
(ObjectDataSource))
{
(field.GetValue(report)
as
ObjectDataSource).InjectDependencies();
}
}
}
public
static
void
InjectDependencies(
this
ObjectDataSource objectDataSource)
{
if
(objectDataSource !=
null
&& objectDataSource.DataSource
is
Type)
{
var obj = DependencyResolver.Current.GetService((Type)objectDataSource.DataSource);
objectDataSource.DataSource = obj;
}
}
2. Call the extension method in the constructor for all reports.
public
partial
class
R0201 : Telerik.Reporting.Report
{
public
R0201()
{
InitializeComponent();
this
.InjectDependencies();
}
}
Now that DI is working, we can resolve the issue of getting the user identity using dependency, using:
- A GenericPrinicpal when HttpContext.Current.User is available to handle situations in which the User object is disposed by ASP.NET before it is used.
- A cookie to fill in when HttpContext.Current.User is not available (with some logic to try to protect against spoofing).
1. First a method to generic an IPrincipal object that can be injected in the object data source layer (note that the function parameter only exists to make this method friendly to Ninject). This method also performs all cookie maintenance and is therefore standalone:
private
static
IPrincipal GetIPrincipal(Ninject.Activation.IContext ctx)
{
var contextUserName = HttpContext.Current.User?.Identity?.Name;
var cookieUserName = HttpContext.Current.Request.Cookies[USERNAME_COOKIENAME]?.Value;
if
(contextUserName !=
null
)
{
if
(cookieUserName !=
null
&& cookieUserName != contextUserName)
throw
new
Exception(
"Username mismatch"
);
HttpContext.Current.Response.Cookies.Add(
new
HttpCookie(USERNAME_COOKIENAME, contextUserName));
return
new
GenericPrincipal(
new
GenericIdentity(contextUserName),
null
);
}
else
if
(cookieUserName !=
null
)
{
return
new
GenericPrincipal(
new
GenericIdentity(cookieUserName),
null
);
}
throw
new
Exception(
"Can't determine user name"
);
}
2. Next, set up the injection (Ninject specific):
Kernel.Bind<IPrincipal>()
.ToMethod(GetIPrincipal)
.InRequestScope();
Thank you for the provided information. We will appreciate it, if you have chance to submit it in a project as a Case Study.
Beside the selected approach, you can use a custom resolver in which you can create an instance of your report via custom report constructor accepting the current context. The custom resolver will have to return an InstanceReportSource.
About the reported problem, we can confirm the current context is lost on the third call to the Reporting REST Service's resolver. Also before and now in time, the current context is not available in events and data-retrieval methods executed by data source components (is not available during the report processing).
The reason is that on requesting the document (GetDocument request to the service) we send the server-side ReportSource to an internal ReportProcessor, and the creation of the report and its processing happen in a separate context. Our developers will research how to copy the original context in the newly created context where the report is processed.
Your Telerik points are updated to thank you for bringing the issue to our attention.
Regards,
Stef
Telerik by Progress
The fix is not scheduled for a release yet and there is no exact ETA. We will re-discuss the priority of the issue and I will post an update in this thread.
In general, the changed behavior can be seen in versions newer than v10.2.16.1219.
Please use the approach suggested by Gregory Petrites, or the approach based on Telerik Reporting - a custom resolver where you can instantiate the report and pass custom information like the current context in it.
Thank you for your understanding.
Regards,
Stef
Progress Telerik
The impact of the changes which will follow is still evaluated and a fix can be expected at earliest for R3 2017 in the middle of September.
Having the above into account, our recommendation is to switch to a custom resolver allowing you to pass the needed information in the report.
Thank you for your understanding.
Regards,
Stef
Progress Telerik
Hi Stef,
Is changes were made in R3 2017 or it`ll be implemented in next version?
The changes were introduced in R3 2017 release (11.2.17.913) - release notes.
Regards,
Katia
Progress Telerik
Could it be that this bug is again present in the current R2 2018 Release (2018.2.516.545) ?
My HttpContext.Current is always null the third time the resolve method is being called.
Could it be that this bug is again present in the current R2 2018 Release (2018.2.516.545) ?
My HttpContext.Current is always null the third time the resolve method is being called.
[/quote]
We have the same problem
@Telerik:
Is there an ETA for when this will be fixed?
Starting with Telerik Reporting R1 2018 SP3 (12.0.18.416) the System.Web.HttpContext.Current is NOT available in the report rendering thread. To access the current user context use the Telerik.Reporting.Processing.UserIdentity.Current static property.
The purpose of this change is to allow the rendering engine to use a dedicated rendering thread queue with configurable count which will significantly improve product's performance.
Regards,
Todor
Progress Telerik
I thought I would throw in a solution for our situation. Accessing the UserIdentity didn't help, the Context was null there as well. What we were after was a replacement for HttpContext.Current.Server.MapPath("~/") and this did the trick.
Replaced:
appPath = HttpContext.Current.Server.MapPath("~/");
with:
appPath = System.Web.Hosting.HostingEnvironment.MapPath("~/");
The Context of UserIdentity should be created before using, if it is needed (i.e. to carry information from HttpContext to the report engine).
You can save items from the HttpContext to the UserIdentity by overriding the GetUserIdentity() method in the ReportsController, and adding the needed items to the UserIdentity.Context property:
protected
override
UserIdentity GetUserIdentity()
{
var identity =
base
.GetUserIdentity();
identity.Context =
new
System.Collections.Concurrent.ConcurrentDictionary<
string
,
object
>();
identity.Context[
"appPath"
] = System.Web.HttpContext.Current.Server.MapPath(
"~/"
);
// More user items can be added to identity.Context here
return
identity;
}
The appPath can then be taken as UserIdentity.Current.Context["appPath"], for example:
var appPath = UserIdentity.Current.Context[
"appPath"
];
Regards,
Todor
Progress Telerik
Hello Todor,
After Telerik Reporting R1 2018 SP3 (12.0.18.416) upgrade, I am not able to run two different REST Services one after other.
Below are my two services.
REST Service 1
=======================================================================
static ReportsController()
{
var appPath = HttpContext.Current.Server.MapPath("~/");
var reportsPath = Path.Combine(appPath, "Reports");
var resolver = new ReportFileResolver(reportsPath)
.AddFallbackResolver(new ReportTypeResolver());
configurationInstance = new ReportServiceConfiguration
{
HostAppId = "Html5AppRep",
Storage = new Telerik.Reporting.Cache.MsSqlServerStorage("Data Source=tfssrv12\\dbtrideo;Failover Partner=824269-DB4;Initial Catalog=TrideoReports;Integrated Security=True;Connection Timeout=600"),
ReportResolver = resolver,
ClientSessionTimeout = 15,
};
}
REST Service 2
=======================================================================
static ADHOCReportController()
{
//Setup the ReportServiceConfiguration
configurationInstance = new ReportServiceConfiguration
{
HostAppId = "Html5App",
Storage = new Telerik.Reporting.Cache.MsSqlServerStorage("Data Source=tfssrv12\\dbtrideo;Failover Partner=824269-DB4;Initial Catalog=TrideoNewReports;Integrated Security=True;Connection Timeout=600"),
ReportResolver = new MyResolver(),//resolver,
ClientSessionTimeout = 15,
};
}
=======================================================================
These both REST Services are resides in a project and i was able to run both services at any time.
But After upgrade, After login in my application, First If i run the REST Service1 then i am not able to run Rest Service 2.
Or After login, First if i run the REST Service2 then i am not able to run REST Service 1.
Attached is a fiddler log in which the first report was successful, but the second report has stopped at "0 Pages loaded so far..." and its not delivering report.
What changes do i need to handle for both services according to new upgrade. I manage the same HostAppID name is also not solved this issue.
Please help
Hello Todor ,
After Telerik Reporting R1 2018 SP3 (12.0.18.416) upgrade, i am not able to execute 2 REST Services one after other.
These 2 REST Services are in single Project and after logged in in application only any one REST Service is delivering report.
Below are 2 Services
REST Service 1
====================================================================
static ADHOCReportController()
{
//Setup the ReportServiceConfiguration
configurationInstance = new ReportServiceConfiguration
{
HostAppId = "Html5App",
Storage = new Telerik.Reporting.Cache.MsSqlServerStorage("Data Source=tfssrv12\\dbtrideo;Failover Partner=824269-DB4;Initial Catalog=TrideoNewReports;Integrated Security=True;Connection Timeout=600"),
ReportResolver = new MyResolver(),//resolver,
ClientSessionTimeout = 15,
};
}
REST Service 2
=================================================================
static ReportsController()
{
var appPath = HttpContext.Current.Server.MapPath("~/");
var reportsPath = Path.Combine(appPath, "Reports");
var resolver = new ReportFileResolver(reportsPath)
.AddFallbackResolver(new ReportTypeResolver());
configurationInstance = new ReportServiceConfiguration
{
HostAppId = "Html5AppRep",
Storage = new Telerik.Reporting.Cache.MsSqlServerStorage("Data Source=tfssrv12\\dbtrideo;Failover Partner=824269-DB4;Initial Catalog=TrideoReports;Integrated Security=True;Connection Timeout=600"),
ReportResolver = resolver,
ClientSessionTimeout = 15,
};
}
I tried with Same HostAppID for both services also but did not worked. After Telerik Reporting R1 2018 SP3 (12.0.18.416) upgrade what are code changes do we need to handle to execute both services simultaneously.
After logged in in application, he first service report execution successfully, and when run the second rest service the report is stopped at "0 pages loaded so far..." and report not delivered.
Please help
I noticed that you have already opened a support ticket (#1177104) where you have asked similar questions. I suggest to continue the discussion there as it is not directly related to the topic of this forum thread.
Regards,
Todor
Progress Telerik