I'm getting Status Code 405, Method not allowed error when sending email that has an attachment. I'm using HttpClient to post my request to the API rather Microsoft Graph Client. Don't want to have dependency of Microsoft Graph library. My send email without attachment works fine but not with the attachment.
try
{
const string url = "https://graph.microsoft.com/v1.0/users/myemail#outlook.com/sendMail";
var path = "C:\\Attachments\\image1.jpg";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
byte[] bytes = File.ReadAllBytes(path);
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
var email = new Email
{
Message = new Message
{
Subject = "Test subject",
Body = new Body
{
ContentType = "Text",
Content = "message"
},
ToRecipients = new List<Recipients>
{
new Recipients
{
EmailAddress = new EmailAddress
{
Address = "testemail#outlook.com"
}
}
},
Attachments = new List<Attachment>
{
new Attachment
{
Name = "image1.jpg",
ContentBytes = base64String,
ContentType = "image/jpeg"
}
}
}
};
var jsonMessage = JsonConvert.SerializeObject(email);
var content = new StringContent(jsonMessage, Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
response.EnsureSuccessStatusCode();
}
}
catch (HttpRequestException e)
{
Console.WriteLine(e.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Following is the answer if someone else get stuck with same issue
For "Attachment" object, Microsoft Graph need '#odata.type' property with the value of '#microsoft.graph.fileAttachment'
Attachments = new List<Attachment>
{
new Attachment
{
//GraphDataType property name will be changed to #odata.type
GraphDataType = "#microsoft.graph.fileAttachment",
Name = "image1.jpg",
ContentBytes = base64String,
ContentType = "image/jpeg"
}
}
Replace 'GraphDataType' inside Serialized Object with '#odata.type'
var jsonMessage = JsonConvert.SerializeObject(email);
jsonMessage = jsonMessage.Replace("GraphDataType", "#odata.type");
Related
I have this problem. i have to submit a file (or not) to an endpoint on an API of bmc.
the KEY:entry with the VALUE:data_entry.txt is the json to send with the values, as the same of the body.
The attach-z2AF_WIAttachment1 is the file i want to submit. I'm it's always throuwing some error, or headers invalid, or filetype not valid, but in postman is working.
I cant convert to C#.
this is my code so far, or now.
try
{
//authentication
var dict = new Dictionary<string, string>();
dict.Add("username", "applicationUsernameJonDoe");
dict.Add("password", "applicationPassowrdXPTO");
var clientLogin = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, Endpoint_loginITSM) { Content = new FormUrlEncodedContent(dict) };
var res = clientLogin.SendAsync(req); //.Result.ToString();
var body = res.GetAwaiter().GetResult().Content.ReadAsStringAsync();
//pedido de criação de registo
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post
};
request.Headers.Add("Authorization", body.Result.ToString());
if (!string.IsNullOrEmpty(registos.Objeto.fileName))
{
registos.Objeto.Registo.z2AF_WIAttachment1 = registos.Objeto.fileName;
}
string json = JsonConvert.SerializeObject(new { values = registos.Objeto });
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
MemoryStream memoryStream = new MemoryStream();
using (BsonDataWriter writer = new BsonDataWriter(memoryStream))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, registos.Objeto.Registo);
}
var data_entry_bytes = memoryStream.ToArray();
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
ByteArrayContent data_entry_json_content = new ByteArrayContent(data_entry_bytes);
data_entry_json_content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
data_entry_json_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("entry")
{
FileName = "data_entry.txt",
Name = "entry",
};
multiForm.Add(data_entry_json_content);
ByteArrayContent z2AF_WIAttachment1_content = new ByteArrayContent(file_bytes);
z2AF_WIAttachment1_content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
z2AF_WIAttachment1_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attach-z2AF_WIAttachment1")
{
FileName = registos.Objeto.fileName,
Name = "attach-z2AF_WIAttachment1",
};
multiForm.Add(z2AF_WIAttachment1_content);
request.Content = multiForm;
var result = await client.SendAsync(request);
var resBody = result.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _resBody = JsonConvert.DeserializeObject<dynamic>(resBody);
string registoID = _resBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", registoID);
}
}
catch (Exception e)
{
string classname = this.GetType().Name;
CentralLibrary.Services.ErrorLoggingService.ErrorLogsForCore(classname, e, _env.WebRootPath);
return ResponseHandler<string>.Resposta(true, "EXCEPTION : resposta api bit criar registos", e.Message);
}
Here is a better solution.
I had a problem with the last, but for someone who doesnt wnat to use de library RestClient that's the way. But this is working 100% and i have JsonProperty Names for NewtonSoft.Json so this workin with names like
[JsonProperty("z1D Action")]
public string z1D_Action { get; } = "CREATE";
so, my code is, and using an object AbrirRegistosITSM with nested object AbrirRegistosITSM_com_anexo my final solution is
AbrirRegistosITSM _registo = new AbrirRegistosITSM
{
Values = new AbrirRegistosITSM_com_anexo
{
Details = registos.Objeto.Comentario,
Customer_Login = registos.username,
Login_ID = registos.username,
SR_Type_Field_3 = registos.Objeto.Tipologia,
SR_Type_Field_28 = registos.Objeto.Categoria,
z2AF_WIAttachment1 = registos.Objeto.FicheiroNome
}
};
var client = new RestClient(Endpoint_CreateITSM);
string baseFolder = _env.WebRootPath;
string pathDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathDir);
string pathDirFile = Path.Combine(pathDir, registos.Objeto.FicheiroNome);
File.WriteAllBytes(pathDirFile, Convert.FromBase64String(registos.Objeto.FicheiroBase64));
string pathEntryDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathEntryDir);
string patnEntrydirFile = Path.Combine(pathEntryDir, "data_entry.txt");
File.WriteAllText(patnEntrydirFile, JsonConvert.SerializeObject(new { values = _registo.Values }));
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Authorization", token);
request.AddFile("entry", patnEntrydirFile, "application/json");
request.AddFile("attach-z2AF_WIAttachment1", pathDirFile, "application/octet-stream");
var reqbody = JsonConvert.SerializeObject(_registo);
request.AddParameter("application/json", reqbody, ParameterType.RequestBody);
RestResponse response = client.Execute(request);
var respostaBody = response.Content.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"]["Request Number"];
then i return the request number that what i need, but you have a lot of values there. I use NewtonSoft remember that. I dont use JsonSerializer because i wasn't able to save the json property names with spaces with JsonSerializer.
I'm not entirely sure what's going wrong here. It can be a lot of things, but I might be able to get you going. The last couple of weeks I build a HttpClient that sends a file with metadata to a GraphQL endpoint.
Please ensure the following:
I think you are requesting the file through an call. Please store it in a variable as a Byte[] using the ReadAsByteArrayAsync(). Do note decode it or cast it to a string or anything. You'll just corrupt the file.
var response = client.GetAsync(fileUrl);
var downloadedFile = await response.Result.Content.ReadAsByteArrayAsync();
The following code might not work entirely in your case, but should help you get going building the right request, since I'm also sending metadata in my request containing the file extension and some other information. This will most likely send the file to your API without a file extension.
using (var client = new HttpClient())
{
var file = new byte[] { 1, 2, 3 };
var fileToUpload = new ByteArrayContent(file);
var formData = new MultipartFormDataContent
{
{ fileToUpload, "entry", "passInFileExtensionForExample"},
{ fileToUpload, "attach-z2AF_WIAttachment1", "passInFileExtensionForExample" }
};
var response = await client.PostAsync("endpoint", formData);
}
Add the Bearer token using the following code:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
So i've discover the solution for my problem. I'm gonna to submit only one file. I have to submit also the Json body as a file "entry" "data_entry.txt" and for HttpRequestMessage you have to have a content MultipartFormDataContent and here you can add as many files as you have. i have to convert the Json body to a file ( in this case i converted to binary Array) with the name entry, and the name of the file data_entry.txt, but it's what the endpoint needs, so...whatever.
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
MultipartFormDataContent content = new MultipartFormDataContent();
//adicionar ficheiro
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
StreamContent fileContent = new StreamContent(new MemoryStream(file_bytes));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[attach-z2AF_WIAttachment1]",
FileName = registos.Objeto.fileName
};
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
content.Add(fileContent);
//adicionar ficheiro entry
StreamContent entryStreamContent = new StreamContent(new MemoryStream(ObjectToByteArray(registos.Objeto.Registo)));
entryStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[entry]",
FileName = "data_entry.txt"
};
entryStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
content.Add(entryStreamContent);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post,
Content= content
};
request.Headers.Add("Authorization", body.Result.ToString());
string json = JsonConvert.SerializeObject(new { values = registos.Objeto.Registo});
request.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(json));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var resposta = await client.SendAsync(request);
var respostaBody = resposta.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", _registoID);
So this is my solution. and it's working :)
I am trying to upload an image along with some json data inside a MultipartFormDataContent object. But my webapi is not receiving the requests properly for some reason. Initially the api was rejecting the request outright with a 415 response. To fix this I added an xml formatter for multipart/form-data to WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
This seemed to work for the most part, I tested it using ARC and it received all of the parts of the multipart, the only issue was the string content didn't appear in the form,it was in the files but I put that down to the request not being formatted as a StringContent object.
The current issue I am having is that my Xamarin app, when sending the multipart request doesn't seem to be posting anything. When the request hits the API Controller, the content headers are there and everything, but the files and form fields are both empty.
After doing some research it seems that I have to write a custom MediaTypeFormatter but none of the ones I have found seem to be the one I am looking for.
Here is the rest of my code:
Api Controller:
[HttpPost]
public SimpleResponse UploadImage(Image action)
{
SimpleResponse ReturnValue = new SimpleResponse();
try
{
if (HttpContext.Current.Request.Files.AllKeys.Any())
{
var httpPostedFile = HttpContext.Current.Request.Files["uploadedImage"];
var httpPostedFileData = HttpContext.Current.Request.Form["imageDetails"];
if (httpPostedFile != null)
{
MiscFunctions misctools = new MiscFunctions();
string fileName = User.Identity.Name + "_" + misctools.ConvertDateTimeToUnix(DateTime.Now) + ".jpg";
string path = User.Identity.Name + "/" + DateTime.Now.ToString("yyyy-mm-dd");
string fullPath = path + fileName;
UploadedFiles uploadedImageDetails = JsonConvert.DeserializeObject<UploadedFiles>(httpPostedFileData);
Uploaded_Files imageDetails = new Uploaded_Files();
imageDetails.FileName = fileName;
imageDetails.ContentType = "image/jpeg";
imageDetails.DateCreated = DateTime.Now;
imageDetails.UserID = User.Identity.GetUserId();
imageDetails.FullPath = fullPath;
Stream imageStream = httpPostedFile.InputStream;
int imageLength = httpPostedFile.ContentLength;
byte[] image = new byte[imageLength];
imageStream.Read(image, 0, imageLength);
Image_Data imageObject = new Image_Data();
imageObject.Image_Data1 = image;
using (var context = new trackerEntities())
{
context.Image_Data.Add(imageObject);
context.SaveChanges();
imageDetails.MediaID = imageObject.ImageID;
context.Uploaded_Files.Add(imageDetails);
context.SaveChanges();
}
ReturnValue.Success = true;
ReturnValue.Message = "success";
ReturnValue.ID = imageDetails.ID;
}
}
else
{
ReturnValue.Success = false;
ReturnValue.Message = "Empty Request";
ReturnValue.ID = 0;
}
}
catch(Exception ex)
{
ReturnValue.Success = false;
ReturnValue.Message = ex.Message;
ReturnValue.ID = 0;
}
return ReturnValue;
}
Xamarin App Web Request:
public async Task<SimpleResponse> UploadImage(ImageUpload action)
{
SimpleResponse ReturnValue = new SimpleResponse();
NSUserDefaults GlobalVar = NSUserDefaults.StandardUserDefaults;
string token = GlobalVar.StringForKey("token");
TaskCompletionSource<SimpleResponse> tcs = new TaskCompletionSource<SimpleResponse>();
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Add("Accept", "application/xml");
using (var httpContent = new MultipartFormDataContent())
{
ByteArrayContent baContent = new ByteArrayContent(action.Image.Data);
baContent.Headers.ContentType = new MediaTypeHeaderValue("Image/Jpeg");
string jsonString = JsonConvert.SerializeObject(action.UploadFiles);
StringContent stringContent = new StringContent(jsonString);
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (HttpResponseMessage httpResponse = await httpClient.PostAsync(new Uri("http://10.0.0.89/api/Location/UploadImage"), httpContent))
{
string returnData = httpResponse.Content.ReadAsStringAsync().Result;
SimpleResponse jsondoc = JsonConvert.DeserializeObject<SimpleResponse>(returnData);
ReturnValue.ID = jsondoc.ID;
ReturnValue.Message = jsondoc.Message;
ReturnValue.Success = jsondoc.Success;
}
}
}
}
catch(WebException ex)
{
ReturnValue.Success = false;
if (ex.Status == WebExceptionStatus.Timeout)
{
ReturnValue.Message = "Request timed out.";
}
else
{
ReturnValue.Message = "Error";
}
tcs.SetResult(ReturnValue);
}
catch (Exception e)
{
ReturnValue.Success = false;
ReturnValue.Message = "Something went wrong";
tcs.SetResult(ReturnValue);
}
return ReturnValue;
}
You are not adding the parts to the content before trying to send it
//...code removed for brevity
httpContent.Add(baContent, "uploadedImage");
httpContent.Add(stringContent, "imageDetails");
//...send content
On the server side you can check this answer
Http MultipartFormDataContent
on how to read the incoming multi-part request
try
{
var jsonData = "{your json"}";
var content = new MultipartFormDataContent();
content.Add(new StringContent(jsonData.ToString()), "jsonData");
try
{
//Checking picture exists for upload or not using a bool variable
if (isPicture)
{
content.Add(new StreamContent(_mediaFile.GetStream()), "\"file\"", $"\"{_mediaFile.Path}\"");
}
else
{
//If no picture for upload
content.Add(new StreamContent(null), "file");
}
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine("Exception:>" + exc);
}
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(new Uri("Your rest uri"), content);
if (response.IsSuccessStatusCode)
{
//Do your stuff
}
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("Exception:>" + e);
}
Where _mediaFile is the file selected from gallery or camera.
https://forums.xamarin.com/discussion/105805/photo-json-in-xamarin-post-webservice#latest
I am trying to ReplyAll to email with Outlook 365 API. Following this tutorial. As per tutorial to ReplyAll we just need to input Commnet but when I try to do that it's giving Bad Request error -
"error": {
"code": "ErrorInvalidRecipients",
"message": "At least one recipient isn't valid., A message can't be sent because it contains no recipients."
}
I am trying to do this with below method.
public string EmailReplyAll(AuthenticationResult result, string uriString, string msgBody)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uriString);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
EmailReplyAll replyAll = new EmailReplyAll();
replyAll.MsgBody = msgBody;
var jsonData = JsonConvert.SerializeObject(msgBody);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = httpClient.PostAsync(request.ToString(),content).Result;
if (!response.IsSuccessStatusCode)
throw new WebException(response.StatusCode.ToString() + ": " + response.ReasonPhrase);
uriString = response.Content.ReadAsStringAsync().Result;
return uriString;
}
Could someone please point me where I am doing wrong. I'm trying this with WPF.
Here is what I figured out and working for me.
EmailReplyAll class
public class EmailReplyAll
{
public string Comment { get; set; }
}
The URI string -
var uriString = String.Format(CultureInfo.InvariantCulture, "{0}api/{1}/me/messages/{2}/replyall", graphApiEndpoint, graphApiVersion, emailId);
//emailId is id of email e.g - AAMkADBjMGZiZGFACAAC8Emr9AAA=
EmailReplyAll method -
public string EmailReplyAll(AuthenticationResult result, string uriString, string msgBody)
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
EmailReplyAll replyAll = new EmailReplyAll();
replyAll.Comment = msgBody;
var jsonData = JsonConvert.SerializeObject(replyAll);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = httpClient.PostAsync(uriString, content).Result;
var apiResult = response.Content.ReadAsStringAsync().Result;
}
catch (Exception exception)
{
return "Error";
}
return apiResult;
}
I am trying to implement Mail Chimp's new API with my ASP.NET C# website so when a user enters their email address into an input box it will be added to my mailchimp list automatically. I have tried various other methods however none of these have worked.
I have tried a Web Client which threw a 405 Cannot use that Method response and a HttpClient which threw an error on the starred GetStringAsync method call because its not a task.
My code so far is detailed below:
public bool BatchSubscribe(IEnumerable<MailChimpSubscriberModel> newSubscribers)
{
if (string.IsNullOrEmpty(_defaultListId)) throw new ArgumentNullException(Res.Resource.MailChimpIntegrationNoListId);
if (string.IsNullOrEmpty(_apiKey)) throw new ArgumentNullException(Res.Resource.MailChimpIntegrationNoApiKey);
foreach (MailChimpSubscriberModel subscriber in newSubscribers)
{
string url = "https://" + _dataPoint + ".api.mailchimp.com/3.0/lists/" + _defaultListId + "/";
Subscriber member = new Subscriber();
member.email = subscriber.Email;
member.subscribed = "subscribed";
string jsonString = new JavaScriptSerializer().Serialize(member);
//using (WebClient client = new WebClient())
//{
// client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
// client.Headers[HttpRequestHeader.Authorization] = new AuthenticationHeaderValue("Basic", _apiKey).ToString();
// string HtmlResult = client.(url, jsonString);
// return true;
//}
using (var http = new HttpClient())
{
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", _apiKey);
string content = await http.**GetStringAsync**(#"https://us11.api.mailchimp.com/3.0/lists");
Console.WriteLine(content);
}
}
return false;
}
I'm a bit late to this question, but as it took me half a day to figure it out, here there is my answer, so it can help others. I'm using MailChimp 3.0:
private void subscribeAddress()
{
string apiKey = "APIKEY-usX"; //your API KEY created by you.
string dataCenter = "usX";
string listID = "listID"; //The ListID of the list you want to use.
SubscribeClassCreatedByMe subscribeRequest = new SubscribeClassCreatedByMe
{
email_address = "somebodys#email.com",
status = "subscribed"
};
subscribeRequest.merge_fields = new MergeFieldClassCreatedByMe();
subscribeRequest.merge_fields.FNAME = "YourName";
subscribeRequest.merge_fields.LNAME = "YourSurname";
using (HttpClient client = new HttpClient())
{
var uri = "https://" + dataCenter + ".api.mailchimp.com/";
var endpoint = "3.0/lists/" + listID + "/members";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", apiKey);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri(uri);
//NOTE: To avoid the method being 'async' we access to '.Result'
HttpResponseMessage response = client.PostAsJsonAsync(endpoint, subscribeRequest).Result;//PostAsJsonAsync method serializes an object to
//JSON and then sends the JSON payload in a POST request
//StatusCode == 200
// -> Status == "subscribed" -> Is on the list now
// -> Status == "unsubscribed" -> this address used to be on the list, but is not anymore
// -> Status == "pending" -> This address requested to be added with double-opt-in but hasn't confirmed yet
// -> Status == "cleaned" -> This address bounced and has been removed from the list
//StatusCode == 404
if ((response.IsSuccessStatusCode))
{
//Your code here
}
}
}
Here there are the classes SubscribeClassCreatedByMe and MergeFieldClassCreatedByMe
namespace Subscriber
{
public class SubscribeClassCreatedByMe
{
public string email_address { get; set; }
public string status { get; set; }
public MergeFieldClassCreatedByMe merge_fields { get; set; }
}
}
namespace Subscriber
{
public class MergeFieldClassCreatedByMe
{
public string FNAME { get; set; }
public string LNAME { get; set; }
}
}
Well, I hope this help!!
401 isn't "cannot use that method" it's "Unauthorized". You've got an authentication error. From the looks of things, you're not quite doing basic auth the right way. Check out this example for the details you're missing.
PS: the response that comes back from APIv3 is usually pretty helpful, so you should always make sure to look at that whole response, not just the status code.
It works if you change auth to these lines:
String username = "abc"; //anything
String password = apiKey; //your apikey
String encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", encoded);
Below code snippet is should work on .NET Core 2.1 using Mailchimp API V3.0:
string url = #"https://" + mailchimpInstance + ".api.mailchimp.com/3.0/lists/" + ListId + "/members";
var info = new Info() { email_address = "example#gmail.com", status = "subscribed" };
var infoJson = JsonConvert.SerializeObject(info);
using (var client = new HttpClient())
{
var uri = "https://" + mailchimpInstance + ".api.mailchimp.com/";
var endpoint = "3.0/lists/" + ListId + "/members";
try
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",ApiKey);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri(uri);
var content = new StringContent(infoJson.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(endpoint, content);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine("Response from server -> " + responseString);
return Ok();
Add into References MailChimp.Net.dll
than you can define an interface like
IMailChimpManager manager = new MailChimpManager(ConfigurationManager.AppSettings["MailChimpApiKey"].ToString());
than you can add or update your client in your MailChimp list
Member m = await manager.Members.AddOrUpdateAsync(ConfigurationManager.AppSettings["MailChimpListId"].ToString(), new Member { EmailAddress = _email, EmailType = "html", Status = Status.Pending});
m = await manager.Members.AddOrUpdateAsync(ConfigurationManager.AppSettings["MailChimpListId"].ToString(), new Member { EmailAddress = _email, EmailType = "html", Status = Status.Subscribed });
It is very simple.. I think...
I am writing a Web API service where I want to accept a file (image) and a serialized object (JSON) that contains key information about the image. Not having issues with the image part but when I add string content containing the deserialized object I am having issues in trying to determine which is which and act accordingly.
The client code looks like:
HttpClient client = new HttpClient();
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StreamContent(File.Open("c:\\MyImages\\Image00.jpg", FileMode.Open)), "image_file", "Image00.jpg");
ImageKeys ik = new ImageKeys { ImageId = "12345", Timestamp = DateTime.Now.ToString() };
JavaScriptSerializer js = new JavaScriptSerializer();
if (ik != null)
{
content.Add(new StringContent(js.Serialize(ik), Encoding.UTF8, "application/json"), "image_keys");
}
string uri = "http://localhost/MyAPI/api/MyQuery/TransferFile";
var request = new HttpRequestMessage()
{
RequestUri = new Uri(uri),
Method = HttpMethod.Post
};
request.Content = content;
string responseStr = "";
try
{
HttpResponseMessage result = client.SendAsync(request).Result;
string resultContent = string.Format("{0}:{1}", result.StatusCode, result.ReasonPhrase);
//
// Handle the response
//
responseStr = resultContent;
}
catch (Exception ex)
{
responseStr = ex.Message;
}
listBox1.Items.Add(responseStr);
So I include the image file first followed by a serialized object as StringContent. On the server side I am using the following code to parse the message.
HttpRequestMessage request = this.Request;
HttpResponseMessage ret = new HttpResponseMessage();
//
// Verify that this is an HTML Form file upload request
//
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = "c:\\tmp\\uploads";
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
//
// Create a stream provider for setting up output streams that saves the output under c:\tmp\uploads
// If you want full control over how the stream is saved then derive from MultipartFormDataStreamProvider
// and override what you need.
//
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider(root);
try
{
await request.Content.ReadAsMultipartAsync(streamProvider);
foreach (var file in streamProvider.Contents)
{
if (file.Headers.ContentDisposition.Name == "image_file")
{
FileInfo finfo = new FileInfo(streamProvider.FileData.First().LocalFileName);
string destFile = Path.Combine(root, streamProvider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", ""));
//
// File.Move cannot deal with duplicate files
// Ensure that the target does not exist.
//
if (File.Exists(destFile))
{
File.Delete(destFile);
}
File.Move(finfo.FullName, destFile);
}
else if (file.Headers.ContentDisposition.Name == "image_keys")
{
// deserialize key class
string str = file.ReadAsStringAsync().Result;
JavaScriptSerializer js = new JavaScriptSerializer();
ImageKeys ik = js.Deserialize<ImageKeys>(str);
}
}
ret.StatusCode = HttpStatusCode.OK;
ret.Content = new StringContent("File uploaded.");
}
catch (Exception ex)
{
ret.StatusCode = HttpStatusCode.UnsupportedMediaType;
ret.Content = new StringContent("File upload failed.");
}
return ret;
The foreach loop tries to process each item in the multipart content as a file but I want to treat the various content types separately but it is not clear to me how they are delineated.
Thanks
You can cast Content to MultipartFormDataContent and iterate thru it. Based on content type you can read it as a file or string. Example for string content type:
var dataContents = request.Content as MultipartFormDataContent;
foreach (var dataContent in dataContents)
{
var name = dataContent.Headers.ContentDisposition.Name;
var value = dataContent.ReadAsStringAsync().Result;
...
}