Unplanned
Last Updated: 03 Dec 2024 14:31 by ADMIN
Scheduled for 2025 Q1
Ian
Created on: 24 Oct 2024 14:36
Type: Feature Request
1
Customize Telerik via code

Currently, to customize the report engine, for example to add some custom user functions, we have to either use the app config or provide a IConfiguration to ReportProcessor constructor, which seems to set a static field for all reports, and on top of that we have to provide a whole assembly (which will load ALL non-private static methods, I did try to use typereferences instead of assemblyReferences, but that doesn't seem to work for custom functions).

Meanwhile all we needed was to expose a handful of functions. Our current workaround is to have a whole assembly dedicated to that.

It'd good to be able to:

- Specify either a single class or individual methods through the library API (e.g. reportProcessor.AddCustomFunction("name", (arg) => ...); or reportProcessor.AddCustomFunctions(typeof(MyCustomFunctions);)
- Avoid using static state (it limits how the library can be used and, more importantly, tested)
- Maybe have a way to provide a Service Provider, that Telerik library would use to create services/classes and pull IConfiguration from, especially those we provide, that way the custom functions could use services from our application, rather than using all static methods.

 

Thank you,

4 comments
ADMIN
Ivan Hristov
Posted on: 03 Dec 2024 14:31

Hello Ian,

First, I'd like to ensure you that your feedback is always appreciated, since it represents real-life scenarios we might have omitted when researching the behavior of a feature, or underestimated the importance of a fix. We monitor closely the items in our feedback portal and take them into account during the product planning iterations.

Now up to your comments on my previous post:

1) I have already logged in our backlog the first item we discussed - to provide a way to easily filter out the types and methods in an assembly, effectively showing in designer applications only the ones that match a certain criteria, instead of adding all by default and filter out the specifically marked ones.

2) As for extending the application configuration with custom assemblies, in our 2024 Q3 we've introduced a neat feature: you can register assemblies in Standalone Report Designer without leaving the application and modifying the application configuration file: In the Options view there's a UI to navigate to your assemblies and pick one or more files. The designer will register them in its own config file and load the assemblies in the app domain so they will be at your disposal without restarting the Standalone Designer. I believe this feature would make it a bit easier for the teams, which are getting started with Report Designer and have to go through documentation to see how to set it up.

3) I'm glad you confirmed that the idea of extending the engine, allowing to pass a custom implementation of UserFunctionsProvider, would cover your scenarios. We regard this as the fastest feasible way of delivering such customization without breaking some existing functionality. I have logged this user story in our backlog and scheduled it for planning.

Thank you again for the constructive discussion - it's always a pleasure to have one. We will update this thread as soon as some of the functionalities we talked about, changes its development status. This way you'll be informed about the development and deployment progress.

Regards,
Ivan Hristov
Progress Telerik

Ian
Posted on: 26 Nov 2024 19:56

Hey Ivan,

 

Thank you for listening to our feedback,

 

This is something we can improve by introducing some behavioral change, which will load only the types and methods decorated with some attribute instead of pulling all the available types in the referenced assemblies.

That would be great, I can see how that could be an annoyance for other teams/customers trying to upgrade, so for us allowing to enable the more strict behavior with an option would also work.

 

 

I like the idea of extending the ReportProcessor with custom functions programmatically, but we're yet to determine how to provide good design-time support for reports using such functions. We're currently having such problems where the reports behave differently when being designed [...] and when rendered in client's app [...] Registering the assembly that contains the class MyCustomFunctions in the Designer's config file seems the logical choice, but in this case, you should take care to keep the assembly deployed in the Designer folder in sync with the latest changes in your MyCustomFunctions class. Another approach might be to have one assembly with no or minimal implementation registered in Designer, and the actual implementation referenced in your app, but this again might cause confusion among users who do not understand how the Reporting configuration is resolved.

 

I see how that would be a challenge, but indeed either the configuration or registering an assembly with interfaces sounds like great solutions to me, especially the latter. Keeping them in sync is already something one would need to do today (and can be accomplished as part of our own application build process), and people would already need to read the documentation to know how to register them today, so I’d imagine (and this coming from a place of ignorance on the issues other teams face when getting started) that if the documentation on, say, AddCustomFunctions would reference how to setup the Designer, to be able to see those functions, should cover that.

 

 

We're using static classes and methods for user functions precisely because we would like to have more deterministic behavior. Also, if we leave the instantiation of those classes to the user, we might run into hard-to-investigate concurrency problems and memory leaks.

 

I understand, DI can have some gnarly errors, especially with complex dependencies, but static instances that need to reference local instances/services would also have concurrency and memory leak issues, in our experience DI has been proving a better approach that allows cleaner and more testable code.

 

 

The idea of having a custom UserFunctionsProvider is worth investigating. We already have a similar concept with the custom IResourceResolver - a class that allows you to handle yourself the resources (data, images, etc.) resolved during reports processing. I believe an implementation that allows you to pass your own implementation using DI would solve the problems you're currently having?

 

Yes, our use case would definitely be covered if I can give my own instantiated service implementing an interface or abstraction to resolve or provide those functions.

 

 

Ultimately for us, being able to provide either the Service Provider or the already instantiated service (regardless if it's one with the methods or an interface that resolves those methods) would greatly improve the efficiency and experience of integrating your library.

For the Designer, being able to provide an assembly with just the interfaces would be a perfect solution, or maybe also specify a UserFunctionsProvider that can return the supported functions (name, namespace, arguments, …), and it would be up to us to provide a class/implementation that just returns the specifications that is in sync with the one that the software that actually runs those (and again, keeping that in sync across software sounds like our responsibility, not yours, IMHO).

 

 

Thank you again for reaching out, I’m happy to answer any more questions or provide some simplified examples of what we are doing (if you reach me by e-mail).

ADMIN
Ivan Hristov
Posted on: 25 Nov 2024 16:32

Hi Ian!

 

My name is Ivan Hristov and I'm the engineering manager of Telerik Reporting. I'd like to thank you for the suggestions of improving the 'user functions' feature in our product. We have discussed internally your suggestions and agreed that the current implementation can be extended to fit scenarios like yours. I'd like to ask you a few questions to confirm I've understood correctly the scenario.

 

First, your assumption that the IConfiguration is set as a static field accessible throughout the app lifetime, is correct. By design, we want to have a single instance of the Reporting configuration that can be accessed not only by the processing engine, but also from the design-time classes used in Standalone Report Designer and Visual Studio Report Designer. In previous versions of Telerik Reporting this configuration was set in the application configuration file, which was read only once, hence there was no need to modify it at runtime. The constructor overload for the ReportProcessor was added a few years ago with the introduction of .NET Core support.

As for the loading of all non-private static methods, they can be filtered using the Function attribute and its IsVisible property. I understand that to make it work properly, one should decorate all the methods in the assembly with this attribute. This is something we can improve by introducing some behavioral change, which will load only the types and methods decorated with some attribute instead of pulling all the available types in the referenced assemblies.

 

I like the idea of extending the ReportProcessor with custom functions programmatically, but we're yet to determine how to provide good design-time support for reports using such functions. We're currently having such problems where the reports behave differently when being designed (i.e. working with IConfiguration from app config file) and when rendered in client's app, where the IConfiguration might be totally different. It will be helpful to share your opinion on this subject - how do you think the Report Designer should behave in such a scenario? Registering the assembly that contains the class MyCustomFunctions in the Designer's config file seems the logical choice, but in this case, you should take care to keep the assembly deployed in the Designer folder in sync with the latest changes in your MyCustomFunctions class. Another approach might be to have one assembly with no or minimal implementation registered in Designer, and the actual implementation referenced in your app, but this again might cause confusion among users who do not understand how the Reporting configuration is resolved.

 

As for the static state, we're currently supporting instance classes for user functions, as long as they have a parameterless constructor. However, instance methods are not supported. We're using static classes and methods for user functions precisely because we would like to have more deterministic behavior. Also, if we leave the instantiation of those classes to the user, we might run into hard-to-investigate concurrency problems and memory leaks.

 

The idea of having a custom UserFunctionsProvider is worth investigating. We already have a similar concept with the custom IResourceResolver - a class that allows you to handle yourself the resources (data, images, etc.) resolved during reports processing. I believe an implementation that allows you to pass your own implementation using DI would solve the problems you're currently having?

 

In order to proceed with this discussion and better understand the requirements, I'd like to ask you to elaborate further and provide some guidance on how you would like to have such feature implemented, having in mind the details I provided above. Your input is very valuable to us, since user functions are integral part of Reporting engine, and we want to make sure its refactoring will bring the most value to our clients.

 

Thanks in advance,


Ivan Hristov
Progress Telerik

Stay tuned by visiting our roadmap and feedback portal pages, enjoy a smooth take-off with our Getting Started resources, or visit the free self-paced technical training at https://learn.telerik.com/.
ADMIN
Todor
Posted on: 31 Oct 2024 13:11

Hello Ian,

Thank you for this input.

The suggested feature would indeed be beneficial for our users and we are already considering the introduction of runtime code compilation in the processing workflow of our reports. We would take into account your ideas as well. The ServiceProvider seems very promising.

We still need to investigate and discuss the potential security issue related to the feature. We will update the thread after a discussion within the team. 

Regards,
Todor
Progress Telerik

Stay tuned by visiting our roadmap and feedback portal pages, enjoy a smooth take-off with our Getting Started resources, or visit the free self-paced technical training at https://learn.telerik.com/.