diff options
author | brandonmwest <brawest@gmail.com> | 2013-07-29 12:51:31 -0700 |
---|---|---|
committer | brandonmwest <brawest@gmail.com> | 2013-07-29 12:51:31 -0700 |
commit | 8313c8bab44bef9fde57ac2e22f994427d8d83bd (patch) | |
tree | 1c8c5550dab4b2c6fd62ae9698c5ecaaa2d8f5a0 /SendGrid/SendGridMail/Transport/Web.cs | |
parent | 2a1b360b89ac07fab5e4a377f380bd563dfa5f7e (diff) | |
parent | 072cd3ebf52417a275b5180cd1e6841ca4aa86df (diff) | |
download | sendgrid-csharp-8313c8bab44bef9fde57ac2e22f994427d8d83bd.zip sendgrid-csharp-8313c8bab44bef9fde57ac2e22f994427d8d83bd.tar.gz sendgrid-csharp-8313c8bab44bef9fde57ac2e22f994427d8d83bd.tar.bz2 |
Merge pull request #33 from sendgrid/bw-net45
Remove RestSharp, refactor to System.Net.Http.HttpClient
Diffstat (limited to 'SendGrid/SendGridMail/Transport/Web.cs')
-rw-r--r-- | SendGrid/SendGridMail/Transport/Web.cs | 366 |
1 files changed, 192 insertions, 174 deletions
diff --git a/SendGrid/SendGridMail/Transport/Web.cs b/SendGrid/SendGridMail/Transport/Web.cs index 6ff89d5..2e32f47 100644 --- a/SendGrid/SendGridMail/Transport/Web.cs +++ b/SendGrid/SendGridMail/Transport/Web.cs @@ -1,175 +1,193 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; +using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http.Headers;
using System.Xml;
-using RestSharp; - -namespace SendGridMail.Transport -{ - public class Web : ITransport - { - #region Properties - //TODO: Make this configurable - public const String BaseURl = "sendgrid.com/api/"; - public const String Endpoint = "mail.send"; - public const String JsonFormat = "json"; - public const String XmlFormat = "xml"; - - private readonly NetworkCredential _credentials; - private readonly bool Https; - #endregion - - /// <summary> - /// Factory method for Web transport of sendgrid messages - /// </summary> - /// <param name="credentials">SendGrid credentials for sending mail messages</param> - /// <param name="https">Use https?</param> - /// <returns>New instance of the transport mechanism</returns> - public static Web GetInstance(NetworkCredential credentials, bool https = true) - { - return new Web(credentials, https); - } - - /// <summary> - /// Creates a new Web interface for sending mail. Preference is using the Factory method. - /// </summary> - /// <param name="credentials">SendGrid user parameters</param> - /// <param name="https">Use https?</param> - internal Web(NetworkCredential credentials, bool https = true) - { - Https = https; - _credentials = credentials; - } - - /// <summary> - /// Delivers a message over SendGrid's Web interface - /// </summary> - /// <param name="message"></param> - public void Deliver(ISendGrid message) - { - var client = Https ? new RestClient("https://" + BaseURl) : new RestClient("http://" + BaseURl); - var request = new RestRequest(Endpoint + ".xml", Method.POST); - AttachFormParams(message, request); - AttachFiles(message, request); - var response = client.Execute(request); - CheckForErrors(response); - } - - #region Support Methods - private void AttachFormParams(ISendGrid message, RestRequest request) - { - var formParams = FetchFormParams(message); - formParams.ForEach(kvp => request.AddParameter(kvp.Key, kvp.Value)); - } - - private void AttachFiles (ISendGrid message, RestRequest request) - { - //TODO: think the files are being sent in the POST data... but we need to add them as params as well - - var files = FetchFileBodies (message); - files.ForEach (kvp => request.AddFile ("files[" + Path.GetFileName (kvp.Key) + "]", kvp.Value.FullName)); - - var streamingFiles = FetchStreamingFileBodies(message); - foreach (KeyValuePair<string, MemoryStream> file in streamingFiles) { - var name = file.Key; - var stream = file.Value; - var writer = new Action<Stream>( - delegate(Stream s) - { - stream.CopyTo(s); - } - ); - - request.AddFile("files[" + name + "]", writer, name); - } - } - - private void CheckForErrors (IRestResponse response) - { - //transport error - if (response.ResponseStatus == ResponseStatus.Error) { - throw new Exception(response.ErrorMessage); - } - - //TODO: check for HTTP errors... don't throw exceptions just pass info along? - var content = response.Content; - var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)); - - using (var reader = XmlReader.Create(stream)) - { - while (reader.Read()) - { - if (reader.IsStartElement()) - { - switch (reader.Name) - { - case "result": - break; - case "message": // success - bool errors = reader.ReadToNextSibling("errors"); - if (errors) - throw new ProtocolViolationException(content); - else - return; - case "error": // failure - throw new ProtocolViolationException(content); - default: - throw new ArgumentException("Unknown element: " + reader.Name); - } - } - } - } - } - - internal List<KeyValuePair<String, String>> FetchFormParams(ISendGrid message) - { - var result = new List<KeyValuePair<string, string>>() - { - new KeyValuePair<String, String>("api_user", _credentials.UserName), - new KeyValuePair<String, String>("api_key", _credentials.Password), - new KeyValuePair<String, String>("headers", message.Headers.Count == 0 ? null : Utils.SerializeDictionary(message.Headers)), - new KeyValuePair<String, String>("replyto", message.ReplyTo.Length == 0 ? null : message.ReplyTo.ToList().First().Address), - new KeyValuePair<String, String>("from", message.From.Address), - new KeyValuePair<String, String>("fromname", message.From.DisplayName), - new KeyValuePair<String, String>("subject", message.Subject), - new KeyValuePair<String, String>("text", message.Text), - new KeyValuePair<String, String>("html", message.Html), - new KeyValuePair<String, String>("x-smtpapi", message.Header.AsJson()) - }; - if(message.To != null) - { - result = result.Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("to[]", a.Address))) - .Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("toname[]", a.DisplayName))) - .ToList(); - } - if(message.Bcc != null) - { - result = result.Concat(message.Bcc.ToList().Select(a => new KeyValuePair<String, String>("bcc[]", a.Address))) - .ToList(); - } - if(message.Cc != null) - { - result = result.Concat(message.Cc.ToList().Select(a => new KeyValuePair<String, String>("cc[]", a.Address))) - .ToList(); - } - return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList(); - } - - internal List<KeyValuePair<String, MemoryStream>> FetchStreamingFileBodies(ISendGrid message) - { - return message.StreamedAttachments.Select(kvp => kvp).ToList(); - } - - internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message) - { - if(message.Attachments == null) - return new List<KeyValuePair<string, FileInfo>>(); - return message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList(); - } - - #endregion - } -} +using System.Net.Http;
+
+namespace SendGridMail.Transport
+{
+ public class Web : ITransport
+ {
+ #region Properties
+ //TODO: Make this configurable
+ public const String BaseUrl = "sendgrid.com/api/";
+ public const String Endpoint = "/api/mail.send";
+ public const String JsonFormat = "json";
+ public const String XmlFormat = "xml";
+
+ private readonly NetworkCredential _credentials;
+ private readonly bool _https;
+ #endregion
+
+ /// <summary>
+ /// Factory method for Web transport of sendgrid messages
+ /// </summary>
+ /// <param name="credentials">SendGrid credentials for sending mail messages</param>
+ /// <param name="https">Use https?</param>
+ /// <returns>New instance of the transport mechanism</returns>
+ public static Web GetInstance(NetworkCredential credentials, bool https = true)
+ {
+ return new Web(credentials, https);
+ }
+
+ /// <summary>
+ /// Creates a new Web interface for sending mail. Preference is using the Factory method.
+ /// </summary>
+ /// <param name="credentials">SendGrid user parameters</param>
+ /// <param name="https">Use https?</param>
+ internal Web(NetworkCredential credentials, bool https = true)
+ {
+ _https = https;
+ _credentials = credentials;
+ }
+
+ /// <summary>
+ /// Delivers a message over SendGrid's Web interface
+ /// </summary>
+ /// <param name="message"></param>
+ public void Deliver(ISendGrid message)
+ {
+ var client = new HttpClient
+ {
+ BaseAddress = _https ? new Uri("https://" + BaseUrl) : new Uri("http://" + BaseUrl)
+ };
+
+ var content = new MultipartFormDataContent();
+ AttachFormParams(message, content);
+ AttachFiles(message, content);
+ var response = client.PostAsync(Endpoint + ".xml", content).Result;
+ CheckForErrors(response);
+ }
+
+ #region Support Methods
+ private void AttachFormParams(ISendGrid message, MultipartFormDataContent content)
+ {
+ var formParams = FetchFormParams(message);
+ foreach (var keyValuePair in formParams)
+ {
+ content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
+ }
+ }
+
+ private void AttachFiles(ISendGrid message, MultipartFormDataContent content)
+ {
+ var files = FetchFileBodies (message);
+ foreach (var file in files)
+ {
+ var fs = new FileStream(file.Key, FileMode.Open, FileAccess.Read);
+ var fileContent = new StreamContent(fs);
+
+ fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
+ {
+ Name = "files[" + Path.GetFileName(file.Key) + "]",
+ FileName = Path.GetFileName(file.Key)
+ };
+
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
+ content.Add(fileContent);
+ }
+
+ var streamingFiles = FetchStreamingFileBodies(message);
+ foreach (KeyValuePair<string, MemoryStream> file in streamingFiles) {
+ var name = file.Key;
+ var stream = file.Value;
+ var fileContent = new StreamContent(stream);
+
+ fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
+ {
+ Name = "files[" + Path.GetFileName(file.Key) + "]",
+ FileName = Path.GetFileName(file.Key)
+ };
+
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
+ content.Add(fileContent);
+ }
+ }
+
+ private void CheckForErrors (HttpResponseMessage response)
+ {
+ //transport error
+ if (response.StatusCode != HttpStatusCode.OK) {
+ throw new Exception(response.ReasonPhrase);
+ }
+
+ //TODO: check for HTTP errors... don't throw exceptions just pass info along?
+ var content = response.Content.ReadAsStreamAsync().Result;
+
+ using (var reader = XmlReader.Create(content))
+ {
+ while (reader.Read())
+ {
+ if (reader.IsStartElement())
+ {
+ switch (reader.Name)
+ {
+ case "result":
+ break;
+ case "message": // success
+ bool errors = reader.ReadToNextSibling("errors");
+ if (errors)
+ throw new ProtocolViolationException();
+ return;
+ case "error": // failure
+ throw new ProtocolViolationException();
+ default:
+ throw new ArgumentException("Unknown element: " + reader.Name);
+ }
+ }
+ }
+ }
+ }
+
+ internal List<KeyValuePair<String, String>> FetchFormParams(ISendGrid message)
+ {
+ var result = new List<KeyValuePair<string, string>>
+ {
+ new KeyValuePair<String, String>("api_user", _credentials.UserName),
+ new KeyValuePair<String, String>("api_key", _credentials.Password),
+ new KeyValuePair<String, String>("headers", message.Headers.Count == 0 ? null : Utils.SerializeDictionary(message.Headers)),
+ new KeyValuePair<String, String>("replyto", message.ReplyTo.Length == 0 ? null : message.ReplyTo.ToList().First().Address),
+ new KeyValuePair<String, String>("from", message.From.Address),
+ new KeyValuePair<String, String>("fromname", message.From.DisplayName),
+ new KeyValuePair<String, String>("subject", message.Subject),
+ new KeyValuePair<String, String>("text", message.Text),
+ new KeyValuePair<String, String>("html", message.Html),
+ new KeyValuePair<String, String>("x-smtpapi", message.Header.AsJson())
+ };
+ if(message.To != null)
+ {
+ result = result.Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("to[]", a.Address)))
+ .Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("toname[]", a.DisplayName)))
+ .ToList();
+ }
+ if(message.Bcc != null)
+ {
+ result = result.Concat(message.Bcc.ToList().Select(a => new KeyValuePair<String, String>("bcc[]", a.Address)))
+ .ToList();
+ }
+ if(message.Cc != null)
+ {
+ result = result.Concat(message.Cc.ToList().Select(a => new KeyValuePair<String, String>("cc[]", a.Address)))
+ .ToList();
+ }
+ return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList();
+ }
+
+ internal List<KeyValuePair<String, MemoryStream>> FetchStreamingFileBodies(ISendGrid message)
+ {
+ return message.StreamedAttachments.Select(kvp => kvp).ToList();
+ }
+
+ internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message)
+ {
+ if(message.Attachments == null)
+ return new List<KeyValuePair<string, FileInfo>>();
+ return message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList();
+ }
+
+ #endregion
+ }
+}
|