Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call data portal operation methods explicitly #4359

Open
rockfordlhotka opened this issue Dec 3, 2024 · 5 comments
Open

Call data portal operation methods explicitly #4359

rockfordlhotka opened this issue Dec 3, 2024 · 5 comments

Comments

@rockfordlhotka
Copy link
Member

rockfordlhotka commented Dec 3, 2024

Today, data portal operation methods are private and are called dynamically by the data portal. They are identified by attributes such as Fetch or Update.

This is a problem because AOT will optimize these methods out of the codebase. It is also a problem because Visual Studio grays out the code, thinking it is never invoked.

Using a code generator, it might be possible to explicitly invoke these methods. Here are my initial thoughts on how such a thing might work.

  1. A generator can look at the code and identify all data portal operation methods
  2. The generator can create an interface that includes all the methods, and code to implement the interface explicitly - invoking the actual methods
  3. The server-side data portal can be changed to detect this interface, and if it exists, to use the interface for invoking methods instead of invoking the private methods (which may provide slight performance improvement)

For example:

    public partial class PersonEdit : BusinessBase<PersonEdit>
    {
        public static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(nameof(Name));
        public string Name
        {
            get => GetProperty(NameProperty);
            set => SetProperty(NameProperty, value);
        }

        [Fetch]
        private void Fetch(string name)
        {
            LoadProperty(NameProperty, name);
        }
    }

    // generated code:

    public interface IPersonEditOperations
    {
        void Fetch(string name);
    }

    public partial class PersonEdit : IPersonEditOperations
    {
        void IPersonEditOperations.Fetch(string name) => Fetch(name);
    }
@JasonBock
Copy link
Contributor

"and code to implement the interface implicitly" - I think you meant "explicitly".

What would be the trigger for the SG? The existence of the DP attribute(s) on the method within the type?

@JasonBock
Copy link
Contributor

BTW you'd want to have a check to make sure the name you generate, IPersonEditOperations in this case, does not collide with an existing type name in scope. And I guarantee you'll need to do this, because someone, somewhere, has created a I{MyBOTypeName}Operations type in their code that'll break you ;).

@Chicagoan2016
Copy link
Contributor

First time I saw PersonEdit as partial class.

@michaelcsikos
Copy link

Is the explicit interface implementation only to make it look like the method is used?

@rockfordlhotka
Copy link
Member Author

Is the explicit interface implementation only to make it look like the method is used?

At a minimum, yes. This causes AOT and VS to think that the method is viable.

However, I am hopeful that we can go beyond this point and optimize the invocation of the operation methods by generating client-side extension methods that "know" which overload to invoke.

The idea goes like this:

  1. Generate a server-side interface where each method overload has a unique name, and delegates to the appropriate private operation method
  2. Generate client-side extension methods for IDataPortal<T> with strongly-typed methods for each operation method - increasing quality of client-side code with typing (@StefanOssendorf has a generator that already does this)
  3. On the client, each of those extension methods "knows" the overload that needs to be invoked, and so it can pass the unique name of the method on the interface to the server
  4. On the server, the data portal can use the unique operation method name from the client to invoke that method on the interface, which then invokes your private operation method

The only place reflection is needed would be step 4, and even there it would be a direct invocation instead of the overload scanning and scoring that exists currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

4 participants