m31coding / M31.FluentAPI

Generate fluent builders for your C# classes with ease.
MIT License
99 stars 5 forks source link

async methods #34

Open mikej0 opened 1 month ago

mikej0 commented 1 month ago

Hello,

I haven't seen a mention of this in the docs.

I'm working with fluent interfaces that call an API, so the last method call in a chain will fire off the request. When I work on the classes manually, I usually have a Send() method which just calls it's neighbour SendAsync() synchronously, so I have the option. If it can't yet, is it possible to detect method signatures with async in it and have it return the Task<IInterface> instead of only the IInterface? Or is there already a way I should be approaching this?

Good work though - looks like this will save me a massive amount of time!

Thanks,

Mike

m31coding commented 1 month ago

Hi @mikej0 ,

Thank you very much for this request. async is not yet supportet, there is currently no way to make the builder return a task. However, it should be feasible to implement this in the final builder step. I'll look into adding this feature soon

Best regards, Kevin

m31coding commented 4 weeks ago

Hi @mikej0,

I was looking into this issue and noticed that using an async FluentMethod in combination with FluentReturn in the last step is already working. I have updated the HttpRequest example and added an async usage example to Program.cs. I believe the current possibilities already cover most use cases. Please let me know if you have any questions.

Best regards, Kevin

mikej0 commented 3 weeks ago

Hi Kevin,

Just had a look, and I think the issue is that I want to be able to continue with the fluent api. Looking at the example, it appears that the async method would be the last. I can't see that it's possible to have it return the interface?

So for example, assuming I have an API that allows me to post a new user. The request will return the full record, which now has an ID as well. I can capture that in the same fluent class, so that I could continue editing the object and put an update.

Something like:

var user = await UserAPI.WithName(...).CreateAsync(); //user now has an id from the api call.

//Assuming they later change their name
await user.WithName(...).UpdateAsync(); //update uses the id

If that's already possible and I've misunderstood, that would be great.

Cheers,

Mike

mikej0 commented 3 weeks ago

I've also just realised it might have difficulty re-using the same method name.

This fluent api I've just described would also need WithName(...) to be able to have two uses in the fluent interface., or is there a workaround?

For example, in my mind, this would be ideal:

[FluentAPI]
public class User {

    private int? Id {get; set;}

    [FluentMember(0)]
    [FluentMember(2)] // Can't do this at the moment;
    public string Name {get; private set;}

    [FluentMember(1)]
    [FluentContinueWith(2)]
    public async Task CreateAsync() { //Needs to return Task<IUser...>?
        // Send API call
        this.Id = response.Id;
    }

    [FluentMember(3)]
    [FluentContinueWith(2)]
    public async Task UpdateAsync() { //Needs to return Task<IUser...>?
        // Send API call.
    }
}

One workaround would be that WithName(...) allows both Create and Update after it, but that would remove some of the protection of having a fluent interface.

What do you think?

Thanks,

Mike