Background / Context
I am currently working on a project to create a set of design-time tools (leveraging the Studio API SDK) to improve the developer experience in Studio. This project should be publicly available here: GitHub - yashbrahmbhatt/LazyFramework.DX: Supercharge your UiPath development experience with LazyFramework.DX! This package uses the power of UiPath's Studio SDK to provide delightful design-time tools for developers. Let’s be real: debugging and managing configuration files can be painful. LazyFramework.DX aims to make your life easier, and dare we say, fun!.
So far, I’d say it’s still in the PoC phase as there’s only 1 service/module that is created and even that doesn’t have all of the functionality I intend to support (AKA use at your own risk). Also I wrote most of it this weekend, so definitely IMMENSE amounts of cleanup and optimization is still required before I’d be satisfied with it.
If you’re just looking to help me and don’t care about what this project aims to achieve, scroll to the last header section titled ‘THE PROBLEM’.
The Vision
There were really only 2 modules that I had in mind when starting this project, maybe 2.5:
AutoConfig (named ‘Athena’)
- Summary: Reads your excel or json config file and maps the values to a C# class. The idea is fuck Generics like Dictionaries that we have all been victims of. No longer would we need to double check what the key value in the config was. No longer would we update/write a config key in our xamls only to be englightened after 10 mins of testing that “The given key ‘{key}’ was not present in the Dictionary”. This was made possible with the 23.10 release with the introduction of Coded Workflows, and more importantly Coded Source Files. Since UiPath implemented a service in Studio that compiles .cs files and reflects their classes into the current AppDomain (or something like that, idk .NET), we are able to remove our dependency on generics. The two main generics I was looking to target were Config variables and QueueItem.SpecificContent or Data variables.
Here are some screenshots for what that looks like currently on a REFramework templated project:
- Config.xlsx
- AutoGenerated Config Files
Base Class - To minimize the effort for adoption, I needed to implement a constructor that uses the output of the REFramework’s InitAllSettings workflow, so every Config class needs to be able to be initialized from an Excel/Dictionary<string, object>
Class(es) based on Config settings
*I know the category attribute doesn’t do anything useful since attributes are generally for the runtime, this will be updated to XML comments for each member based on the descriptions set in the config after I solve the major issue below.
File Watcher (named ‘Odin’)
- Summary: A service internal to this package that lets the other modules subscribe to file system events and act accordingly. Currently, Athena uses it, and all planned modules all plan on using it.
Logger (named ‘Hermes’)
- Summary: Since this project can’t log to Studio’s output window, I had to create another window for the logs of specifically this extension.
AutoDoc (Name TBD, thinking of Seshat or Nabu)
- Summary: Reads your XAML files and automatically generates documentation about that workflow in the form of markdown (other output types can probably be supported in the future) in real time. Although not a part of the current source code, I think I’ve proven it out as it’s a workflow/folder I inject into all of my projects and it’s worked really well so far.
It started off as UiPath Workflows for parsing .xaml files and the project.json but compiled code source files have so much faster execution, so I converted it. I’m talking like 5 mins → 40s kinds of optimization from what I assume is just a compilation vs reflection difference.
Whenever it is run, the root ‘Documentation’ folder gets deleted and repopulated with markdown files that represent all the workflows.
* MD files don’t show up in the project panel
These markdown files then become useful when connected with a GIT Provider like AzDO or GitHub, where you are able to create Wiki’s from a folder in a branch of your repo and navigate through them as documentation.
Project MD file:
Workflow MD file:
All of the information is right there in the .xaml files, and like all developers, I hate rewriting it out myself when its within the code already. So I thought I could automate that translation.
This could be extended significantly to support all sorts of outputs like MSWord, PDF, etc.
2.5 Multi-‘Project’ Projects
- Summary: This one I’ve done 0 implementation on and is the most subjective to personal preference, so thats why its a .5. Ever since multiple entry points were supported by UiPath (I don’t even remember how long ago they did that), I’ve wanted to host multiple UiPath projects (including libraries, test projects, etc.) within 1 Studio instance. I can’t really justify it as well as the previous points, but this seems like a useful tool to be able to use. Especially when RPA implementers are getting more sophisticated with CI/CD pipelines. The idea being that you have a folder structure like this:
- Main Project (Where this service would run)
- Library 1
- Library1.project.json
- Project 2
- Entry Point 1
- Entry Point 2
- Project2.project.json
- Test Project 3
- Entry Point 3
- Project3.project.json
- Entry Point 3
- Library 1
- project.json
We want to be able to compile each of those projects differently, but it would tremendously help the developer experience to be able to modify them without additional Studio instances or managing inter-dependencies between the projects. Unfortunately, UiPath instaces are bound to a single project.json. The workaround I was thinking of was:
- Hook Into UiPath’s Project Template feed
- Set up a Project Initialization function that takes the template and creates an ‘instance’ of it in your project as a folder inside of root.
- Since we have a FileWatcher instance already initialized for the other modules, this module can also subscribe for file changes and update every project.json accordingly in real time.
- This, combined with the UiPath CLI, would allow you to automatically segregate different projects for build/release, while maintaining a simplified and consolidated dev environment.
Again, this isn’t fully thought out yet and may never be implemented, but that was the idea; essentially providing a .sln or solution level support within UiPath Studio.
THE PROBLEM
- Summary - If you use the package as it currently is, you will get this error whenever you compile the project. This includes at design-time when you’re trying to debug your code. This problem makes the entire project useless, as without the ability to debug workflows with Studio, the other functionalities are meaningless or get overshadowed by this problem.
I believe the root of this problem is some sort of coordination between:
- The target framework
- The dependencies
- How Studio works
This entire project heavily leverages the UiPath Studio Activities SDK (SDK - Studio Activities SDK). As part of the requirements to use that SDK and the implementation that UiPath recommends for it, we need to be able resolve the following types, which are not included in the UiPath Studio Activities SDK:
This project currently targets net6.0-windows, net7.0-windows, and net8.0-windows since those are the targets of the last few versions of UiPath Studio and those targets don’t allow you to import the System.Activities assembly from .NET since System.Activities is not compatible with them.
The only way to resolve those types that I’ve found is to use the UiPath.Workflow package (available here: GitHub - UiPath/CoreWF: WF runtime ported to work on .NET 6) and/or its derivative like System.Activities.Metadata as a dependency.
I believe the reason that we get that error during compilation when the LazyFramework.DX package is added as a dependency is due the how I think that UiPath Studio works. I believe it works by reflecting particular methods of particular classes, and so when it tries to do this when the LazyFramework.DX package is installed, it resolves the System.Activities.Activity class to the class defined in the UiPath.Activities.Metadata dependency instead of the default assembly included with Studio. UiPath.Activities.Metadata’s implementation of the Activity class doesn’t have a constructor that works with the way UiPath Studio’s ActivityFactory works, and so we see the error message in the screenshot above.
I’ve tried trying to create an ‘extern alias’ for the System.Activities.Metadata package, but that doesn’t seem to work . Anyways, this is a long enough post as it is, please leave a comment if you have any ideas to help resolve this or if you think that the functionalities this project aims to provide sound like something you would use OR if you have ideas for any other functionality you would like to see at design-time.
ANY HELP WOULD BE GREATLY APPRECIATED <3
Thanks,
Yash Brahmbhatt