sendgrid / sendgrid-csharp

The Official Twilio SendGrid C#, .NetStandard, .NetCore API Library
https://sendgrid.com
MIT License
1.08k stars 584 forks source link

Feature request: Don't use dynamic #303

Closed onionhammer closed 7 years ago

onionhammer commented 8 years ago

Dynamic defeats the purpose and removes any advantages of a statically typed language. There is no compile time error checking, and there is no way to explore the API with autocomplete, you just have to know sg.client.mail.send.post(requestBody), which is kind of crazy.

Also it relies on the DLR, which is much slower than normal compiled/jitted C# code.

thinkingserious commented 8 years ago

Thanks @onionhammer!

Currently, our goal is to hide the implementation details through helpers. Here is our first try, but we have already received a ton of awesome feedback on how to improve: https://github.com/sendgrid/sendgrid-csharp/tree/master/SendGrid/SendGrid/Helpers/Mail).

Also, we want you to be able to pass in your desired HTTP client, this is why we removed it from the core of this library.

All that said, we've heard very compelling arguments ( thanks for adding another :) ) why we should ditch the reflection. So we will leave this ticket open and add it to our backlog. It can rise with additional +1s, comments or a pull request with a signed CLA.

ryanelian commented 8 years ago

I agree with @onionhammer. It wasn't immediately clear that the email sender method is asynchronous due to the lack of Intellisense.

In addition, the library should be written using C# Coding Convention. (e.g. instead of .client.mail.send.post, should be .Client.Mail.Send.Post instead!)

Also, we want you to be able to pass in your desired HTTP client, this is why we removed it from the core of this library.

I rather have the library statically typed than sacrificing static typing for plug-ability.

But let's say we want to implement that feature, we can design it like this instead:

public interface IHttpClientMapper
{
    Task PostAsync(object parameter1, object parameter2, object parameter3);
}

// Allow developer to implement their own mapper using the interface defined above,
// then set a static property containing a HTTP mapper for use by all SendGridApiClient instances!
SendGridApiClient.HttpClientMapper = new MyHttpClientMapper()

This way, the library is extensible without sacrificing static typing.

add it to our backlog

IMHO this should be a high priority issue, not a backlog. But hey, I don't run the company. :smile:

thinkingserious commented 8 years ago

Hello @ryanelian,

Thanks for the feedback! I've added your vote to the issue.

With regards to the Async issue, we have: https://github.com/sendgrid/sendgrid-csharp/issues/200 (added your vote to that)

Intellisense should work once we get that integrated into the Mail Helper.

Regarding method naming conventions, we have: https://github.com/sendgrid/sendgrid-csharp/issues/239 (added your vote to that)

I believe we are using the proper naming conventions in the helper which will eventually hide the underlying HTTP client.

I like your suggestion for the IHttpClientMapper. We will revisit when it comes time to execute these changes.

It may be that we ditch the dependency to our dynamic client in favor of a static one.

Regarding the "backlog", I'm using that as a generic term to signify that it's something we will definitely execute as soon as we can. The priority is determined by a multitude of factors beyond what I described previously. I can say the priority on this is steadily rising and I'm looking forward to working on it again. We have a great deal of awesome feedback on this subject.

Thanks again!

Corillian commented 8 years ago

Please add my vote, I couldn't agree more that using dynamic makes the API clunky and unnecessarily difficult to use. There are so many levels of indirection within the client just to send an email and without intellisense you're forced to look at the source code to see what's going on. That's how I ended up here in the first place because I have no idea what the hell a response.StatusCode is, your documentation doesn't tell me, and now I have to dig through your code just to verify my suspicion that it's an integer status code from the web request since it could also be the .NET framework's strongly typed enumeration for HTTP status codes or something completely different. Pretty ridiculous.

Static typing is your friend and interfaces exist to hide implementations. I honestly can't think of a single good reason to use dynamic other than for consuming JSON objects, which is still dubious if the format of the JSON object never changes, as well as how ASP.NET uses it for ViewBag.

saliehendricks commented 8 years ago

+1

Eirenarch commented 8 years ago

I hope this release is some bad joke. Dynamic all the way? Conventions that go against the C# conventions (camelCase methods and properties)? It looks like someone let JS devs work on a C# library with no prior C# experience. Or maybe the library is autogenerated from swagger or something?

thinkingserious commented 8 years ago

Thanks everyone for all the +1's!

This is now scheduled to be the next C# issue we'll tackle when I return on Monday, followed by enabling support for .NET Core (during that process we will look into providing binaries for 4.5.X and 4.6.X.)

Before we begin writing code for the rewrite, I will collect all the feedback from here and other threads and start a new thread (I'll ping all of you here on that thread) where I'll outline the new approach. If you have the time, your feedback will again be appreciated at that point.

We REALLY appreciate your patience and support on this. The constructive criticism we have received on this has been awesome.

Please note that our scheduling could change, depending on what new issues arise until then. In any case, this has become near the top of our backlog, so it will get done soon.

@Corillian,

In the new version, we will move to using the framework's enumeration. The dependency on the dynamic HTTP client will be removed.

@Eirenarch,

Yes, the majority of this library is auto-generated from our Swagger definition. It was a shortcut to allow the support for the v3 Web API endpoints across all our libraries as a MVP in a short timeframe. The plan was to listen, then iterate accordingly. We will continue to listen and iterate, so please keep the feedback coming :)

Eirenarch commented 8 years ago

Honestly giving us a swagger generated library is kind of insulting. We know how to call rest services. Either provide statically typed API that prevents errors and provides good developer experience by virtue of having proper types and methods or tell us to call your REST services directly.

onionhammer commented 8 years ago

@Eirenarch I don't think this a very productive direction to take this issue discussion.

@thinkingserious Thanks for the good news - looking forward to your next updates

thinkingserious commented 8 years ago

@Eirenarch,

That is the idea behind the helpers. What you are asking for is the same thing we wish to deliver, we just need some time to get there. Thanks again for helping validate and pushing us forward.

Also, I forgot to mention that we built the original code and automation tools ourselves so that once we do get it right we can scale across all our libraries. We did look at using existing Swagger auto-generating tools, but decided that in the end that would not serve our end goals.

thinkingserious commented 8 years ago

Thanks for the kind words @onionhammer. I'm really excited about the next steps!

saliehendricks commented 8 years ago

Great to hear this is underway. Also very glad to hear about 4.5.0 libs being supported. I just forked and compiled for 4.5 today and was annoyed that I needed to do that for no apparent reason.

On 18 August 2016 at 22:05, Elmer Thomas notifications@github.com wrote:

Thanks for the kind words @onionhammer https://github.com/onionhammer. I'm really excited about the next steps!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/sendgrid/sendgrid-csharp/issues/303#issuecomment-240840078, or mute the thread https://github.com/notifications/unsubscribe-auth/ABvuwmKSJCNhHPdBIO9KuuBZMIvXhUbfks5qhLsHgaJpZM4JjMem .

thinkingserious commented 8 years ago

@saliehendricks ouch :(

We've heard that pain far too often, I can't wait to get that fixed too!

That said, we are planning to only officially support 4.5.2+ because those are the versions that Microsoft still supports.

May I ask why you are using 4.5.0? I'm asking to learn if we should indeed provide those dlls also. Thanks!

saliehendricks commented 8 years ago

We have a code base targeting 4.5.0 and a production environment upgrade to 4.5.2 would require site down time. Further to that we have been a bit lazy about updating frameworks. Risk vs Reward and all that.

Based on the libraries code I can't really see the need for it to target 4.5.2 when 4.5 is completely sufficient and has wider reach with full compat with 4.5+ and 4.6 +. I obviously have no idea about your plans going forward.

thinkingserious commented 8 years ago

Great feedback @saliehendricks! I'll ping you when it comes time to implement this.

thinkingserious commented 8 years ago

Hello everyone,

Just a quick update. It looks like I'll get back to this ticket a bit later in the week.

When I returned today, I found that several other issues bumped this one down a few notches.

I can't wait!

thinkingserious commented 8 years ago

Hello Everyone,

I should not be making any time commitments :(

Our backlog is completely dynamic and while this issue is still in the top ten, it's not possible for me to give an exact day when this pops up next on the list.

I'm sending this update to let everyone know that will get done and it's high priority. I just can pin down the exact date.

Thanks for your continued patience.

That said, please feel welcome to start directing the conversation with additional feedback. We will work on this collaboratively.

Jericho commented 8 years ago

@thinkingserious Just want to remind you that several months ago I rewrote the entire SendGrid C# library and added the following features:

Unfortunately, my PR was closed without being merged. I'm guessing what I wrote didn't align with your "everything must be dynamic" architecture ;-) Since you seem to be reconsidering your architecture, feel free to take whatever you think is helpful from my branch.

thinkingserious commented 8 years ago

@Jericho,

I'll be definitely pinging you when the time comes to implement. Thanks for following up!

Eirenarch commented 8 years ago

@Jericho I am also interested in hand-written statically typed library and honestly if SendGrid deprecate the current one that works with the v2 API (I think) I'd rather write my own. So I might be willing to help (but no commitment)

JohnMcAvinue commented 8 years ago

Completely agree about not using dynamic. I'm reverting to version 7 because 8 is simply too difficult to use and has been a regressive step in my opinion

thinkingserious commented 8 years ago

Thanks for the vote @JohnMcAvinue!

scottdock commented 8 years ago

@thinkingserious Thank you so much for listening to the community and responding. We appreciate it! Will keep watching for the update!

thinkingserious commented 8 years ago

Thank you for the positive support @scottdock! We appreciate it!

I've added your vote.

brendonwm commented 8 years ago

+1

thinkingserious commented 8 years ago

I think the people on this thread are going to be key in next iteration of this library. If you have a moment, please check this out: https://github.com/sendgrid/sendgrid-csharp/issues/317

We are looking forward to working with you all to help make the next iteration of this library awesome.

HeyJoel commented 8 years ago

+1

cyotek commented 8 years ago

As you seem to have a voting system for priority, please consider my vote for going back to a statically typed API sooner rather than later. I've just upgraded one of my core projects to the latest version only to find the API completely different. Reworking that shouldn't be a problem, but the abhorrent nature of dynamic means firstly, I haven't a clue how to use the new API without digging through the docs (and oddly enough needing to read the docs to learn how to use a SMTP client of all things seems abnormal) and secondly because as I change the send mail implementation so infrequently, the next time I need to revisit it to add some new feature, I'll have forgotten how it works and will need to hunt it down all over again.

I'd also echo the comments about using "proper" .NET naming conventions, but at the end of the day, this is of less importance (to me) as long as the API is self documenting and will catch compile time syntax issues.

thinkingserious commented 8 years ago

@cyotek,

Thanks for adding your voice! The detailed feedback is greatly appreciated.

It is definitely our intent to hide all of that low level implementation, we just have not quite gotten there yet on our roadmap. But thanks to great feedback like yours (and your added vote), we will get there sooner!

We hope that the Mail Helper will solve the issue you have identified about needing to dig through the docs to figure out basic functionality.

Along with removing dynamic dependencies, we will be enhancing the Mail Helper portion of the library shortly. You can check that project out here. Please let us know if you have any feedback on that as well :)

With Best Regards,

Elmer

jason-persson commented 8 years ago

Some quick feedback, after some internal discussion our company won't be updating to V3 API until a static API is provided for C#. So +1 from us.

thinkingserious commented 8 years ago

Thanks @jason-persson,

Vote added.

thinkingserious commented 8 years ago

Hello everyone,

To get this party started, we will begin here: https://github.com/sendgrid/sendgrid-csharp/issues/344

thinkingserious commented 8 years ago

In this branch I'll be removing the dynamic functionality and merging into the v9beta branch when complete

I'm using the v9beta branch to group all the breaking changes described in these projects.

abergs commented 8 years ago

YES, Have my Vote! This is the most confusing piece of .NET code I've ever used. I seriously think I might be better off just hand crafting the requests. Glad your actively working on this!! 👍

Would you say the new branch is kind of usable yet?

@Jericho How do I use your lib instead? Would you recommend using it?

thinkingserious commented 8 years ago

Hi @abergs,

Thanks for your vote!

It's not quite ready and I would not recommend it for production as it's in flux right now.

You can follow along here and if you have any ideas, suggestions or feedback we would love to hear from you.

We are also implementing the other v3beta items here before releasing.

Jericho commented 8 years ago

@abergs I created a library based on the strongly typed code I wrote and I called it StrongGrid. Here's an example that demonstrates how to send emails using my library:

var from = new MailAddress("test@example.com", "John Smith");
var to1 = new MailAddress("recipient1@mailinator.com", "Recipient1");
var to2 = new MailAddress("recipient2@mailinator.com", "Recipient2");
var subject = "Hello World!";
var textContent = new MailContent("text/plain", "Hello world!");
var htmlContent = new MailContent("text/html", "<html><body>Hello <b><i>world!</i></b><br/><a href=\"http://microsoft.com\">Microsoft's web site</a></body></html>");
var personalizations = new[]
{
    new MailPersonalization
    {
        To = new[] { to1 },
        Subject = "Dear friend"
    },
    new MailPersonalization
    {
        To = new[] {to2 },
        Subject = "Dear customer"
    }
};
var mailSettings = new MailSettings
{
    Footer = new FooterSettings
    {
        Enabled = true,
        Html = "<p>This email was sent with the help of the <b>StrongGrid</b> library</p>",
        Text = "This email was sent with the help of the StrongGrid library"
    }
};
var trackingSettings = new TrackingSettings
{
    ClickTracking = new ClickTrackingSettings
    {
        EnabledInHtmlContent = true,
        EnabledInTextContent = true
    },
    OpenTracking = new OpenTrackingSettings { Enabled = true },
    GoogleAnalytics = new GoogleAnalyticsSettings { Enabled = false },
    SubscriptionTracking = new SubscriptionTrackingSettings { Enabled = false }
};
client.Mail.SendAsync(personalizations, subject, new[] { textContent, htmlContent }, from,
    mailSettings: mailSettings,
    trackingSettings: trackingSettings
).Wait();

My library also has convenient methods that simplify sending emails. Here's the simplified way to send a single email to a single recipient:

client.Mail.SendToSingleRecipientAsync(to, from, subject, htmlContent, textContent).Wait();

and here's the simplified way to send the same email to multiple recipients:

var recipients = new[] { to1, to2, to3 };
client.Mail.SendToMultipleRecipientsAsync(recipients, from, subject, htmlContent, textContent).Wait();

At the moment my library allows you to send emails and I am also in the process of releasing my code for all other resources in SendGrid's v3 API (e.g.: lists, contacts, subscription groups, api keys, templates, categories, etc.).

You can find my library on nuget and the code on GitHub.

bbbford commented 8 years ago

+1

kirajhpang commented 8 years ago

+1 for remove dynamic.

Recently my production is losing email via v2 due to unknown reason, maybe is related to DDos Attack last week. So I do a urgent migrate from v2 endpoint to v3. Now, I able to send out my mails, but somehow on some cases I cannot be reproduce error email via sandbox, that's why I might need status code on response to give me more detail. Here come dynamic problem.

Looking forward for new release. Good Job guys!

goalie7960 commented 8 years ago

👍

thinkingserious commented 7 years ago

This fix (Remove Dynamic Dependency) has been merged into the v9beta branch: https://github.com/sendgrid/sendgrid-csharp/tree/v9beta

We are now moving to part 2 of 3 of this refactor: [v9beta] ASP.Net 4.5 to Core 1.0 Compatibility

Part 3 is: [v9beta] Mail Helper Enhancement (v3 mail/send)

Though I'm closing this issue, please free to continue the conversation here.

Thanks again for all the support and patience!

isaacabraham commented 7 years ago

Any plans for when this might be released? Currently the use of dynamic makes it difficult to use SendGrid from F#.

thinkingserious commented 7 years ago

Hi @isaacabraham,

We are pushing to get the beta released to Nuget within the next few weeks.

In the mean time, @Jericho's StrongGrid is a great solution.