Sending email through http with LinkedResource property - c#

I am trying to compose a email that has a body with a embedded image using LinkedResource. When I try to Post it to our api that connects to the smtp I get this exception:
System.AggregateException: InvalidOperationException: Timeouts are not supported on this stream.
JsonSerializationException: Error getting value 'ReadTimeout' on 'System.IO.FileStream'.
This is my code what do I need to change to make this work.
class Program
{
static void Main(string[] args)
{
Mailer();
}
public static void Mailer()
{
var imageOne = new LinkedResource("PumpkinSpice.jpg", "image/jpeg");
imageOne.ContentId = "psl";
var imageLink = $"<img src=\"cid:{imageOne.ContentId}\"/>";
var listOfResources = new List<LinkedResource> {imageOne};
var email = new MailInfo()
{
ToAddresses = "mcjibbles#foo.com",
CcAddresses = "jibbles#bar.com",
BccAddresses = null,
Subject = "test email",
Body = "Email body" + imageLink,
Resources = listOfResources,
IsHtml = true
};
using (var client = CreateClient())
{
client.PostAsJsonAsync($"api/email", email).Wait();
}
}
private static HttpClient CreateClient()
{
return new HttpClient(new HttpClientHandler { UseDefaultCredentials = true })
{
BaseAddress = new Uri("http://fakesite.com/")
};
}
}
class MailInfo
{
public string ToAddresses { get; set; }
public string CcAddresses { get; set; }
public string BccAddresses { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public bool IsHtml { get; set; }
public List<LinkedResource> Resources { get; set; }
}
Api Code
public class EmailController : ApiController
{
[HttpPost]
public void SendEmail(EmailInformation information)
{
using (var message = new MailMessage())
{
message.Subject = information.Subject;
var toAddresses = SplitAddresses(information.ToAddresses);
foreach (var address in toAddresses)
{
message.To.Add(new MailAddress(address));
}
message.IsBodyHtml = information.IsHtml;
message.Body = information.Body;
using (var htmlView = AlternateView.CreateAlternateViewFromString(message.Body, null, "text/html"))
{
foreach (var resource in information.Resources)
{
htmlView.LinkedResources.Add(resource);
}
using (var client = new SmtpClient(WebConfigurationManager.AppSettings["Smtp"]))
{
message.From = information.FromAddress;
client.Send(message);
}
}
}
}
public class EmailInformation
{
public string ToAddresses { get; set; }
public string FromAddress { get; set; }
public string CcAddresses { get; set; }
public string BccAddresses { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public bool IsHtml { get; set; }
public List<LinkedResource> Resources { get; set; }
}
}

Related

Getting Http Error Code 411 : Length Required

When I am trying to upload a file using following code I am receiving Length Required error. Please note that if I am uploading a TEXT file then I don't see any issues. But when I upload WORD or PDF I am seeing the error. FYI, I am able to see to Content-Length in my request header in both occasions. Any help would be much appreciated.
internal static class CreateFile
{
private static string _Server = "MyServer.com";
private static string _Database = "ACTIVE";
internal static async Task<string> CreateFileInFolder(string _AuthToken, string _FolderId, string _FileLocation)
{
// Force TLS 1.2 instead of the default value.
ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//folder creation URI
string _FileCreateUri = $"https://{_Server}/api/v2/customers/1/libraries/{_Database}/folders/{_FolderId}/documents";
FileInfo _FileDetails = new (_FileLocation);
string _Result = "";
FileRoot _FileRoot = new()
{
doc_profile = new FileProfile()
{
author = "ADMIN",
comment = "New Import",
default_security = "private",
name = _FileDetails.Name,
custom1 = "Test",
custom2 = "Test",
custom17 = "12345",
access = "full_access",
database = _Database,
size = _FileDetails.Length,
#class = "DOC",
type = "ACROBAT",
type_description = "",
wstype = "document"
},
audit = new FileAudit()
{
comments = "Test Import"
},
keep_locked = false,
warnings_for_required_and_disabled_fields = true
};
byte[] _FileBytes = File.ReadAllBytes(_FileDetails.FullName);
string _Boundary = $"----------{DateTime.Now.Ticks:x}";
MultipartFormDataContent _MultipartFormDataContent = new(_Boundary)
{
{
JsonContent.Create(_FileRoot), "profile"
},
{
new StreamContent(new MemoryStream(_FileBytes), _FileBytes.Length), "file"
}
};
_MultipartFormDataContent.Headers.Remove("Content-Type");
_MultipartFormDataContent.Headers.TryAddWithoutValidation("Content-Type", $"multipart/form-data; boundary={_Boundary}");
using (HttpClient _HttpClient = new())
{
//include authentication token in request header
_HttpClient.DefaultRequestHeaders.Add("X-Auth-Token", _AuthToken);
using (HttpResponseMessage _HttpResMsg = await _HttpClient.PostAsync(_FileCreateUri, _MultipartFormDataContent))
{
if (_HttpResMsg.StatusCode == HttpStatusCode.Created)
{
_Result = _HttpResMsg.Content.ReadAsStringAsync().Result;
}
}
}
//MessageBox.Show($"Json profile newly created folder: {_HttpResMsg.Content.ReadAsStringAsync().Result}", "New Folder Profile", MessageBoxButton.OK);
return _Result;
}
public class FileAudit
{
public string comments { get; set; }
}
public class FileProfile
{
public string author { get; set; }
public string access { get; set; }
public string comment { get; set; }
public string #class { get; set; }
public string database { get; set; }
public string default_security { get; set; }
public string name { get; set; }
public long size { get; set; }
public string type { get; set; }
public string type_description { get; set; }
public string wstype { get; set; }
public string custom1 { get; set; }
public string custom2 { get; set; }
public string custom17 { get; set; }
}
public class FileRoot
{
public FileProfile doc_profile { get; set; }
public FileAudit audit { get; set; }
public bool keep_locked { get; set; }
public bool warnings_for_required_and_disabled_fields { get; set; }
}
}
Tried to use HttpRequestMessage by setting Content-Length but again able to upload TEXT files but not WORD or PDF files.

Reading and writting on appsettings.json

I am trying to read and write a value on appsettings.json.It is called Refreshed_Token. I have found something on internet and it was very well explained as an example but i get only one error. Can you please guys help me thank you very much.
Worker.cs
public async Task request_refresh_token()
{
var client = new RestClient("https://accounts.zoho.eu/oauth/v2/token?grant_type=authorization_code&client_id=" +_config.Value.Zoho_Client_Id+ "&client_secret=" +_config.Value.Zoho_Client_Secret+ "&code=" +_config.Value.Zoho_Code);
var request = new RestRequest();
request.AddHeader("Cookie", "xxx; xxx; iamcsr=xxx");
RestResponse response = await client.PostAsync(request);
var result = JObject.Parse(response.Content);
var refresh_token = result["refresh_token"].Value<string>();
update_appsettings_json(refresh_token);
}
public void update_appsettings_json(string refresh_token)
{
var appSettingsPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "appsettings.json");
var json = File.ReadAllText(appSettingsPath);
var jsonSettings = new JsonSerializerSettings();
jsonSettings.Converters.Add(new ExpandoObjectConverter());
jsonSettings.Converters.Add(new StringEnumConverter());
dynamic config = JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(json, jsonSettings);
config.Config.Zoho_Code = Zoho_Refreshed_Token.refresh_token;
var newJson = JsonConvert.SerializeObject(config, Formatting.Indented, jsonSettings);
File.WriteAllText(appSettingsPath, newJson);
}
appsetting.json file :
{
"Config": {
"LeadCustomerId": "4096",
"URL": "example.com",
"Token": "xxx",
"Contact_Custom_Id": "11249",
"Opportunity_Custom_Id": "11261",
"Account_Custom_Id": "13397",
"Task_Custom_Id": "16876",
"Call_Custom_Id": "17033",
"Meeting_Custom_Id": "17098",
"Zoho_Client_Id": "xxx",
"Zoho_Client_Secret": "xxx",
"Zoho_Code": "xxx",
"Zoho_Refreshed_Token": ""
}
}
Config.cd file is:
public class Config
{
public string LeadCustomerId { get; set; }
public string WeclappURL { get; set; }
public string Weclapp_Token { get; set; }
public string Contact_Custom_Id { get; set; }
public string Opportunity_Custom_Id { get; set; }
public string Account_Custom_Id { get; set; }
public string Task_Custom_Id { get; set; }
public string Call_Custom_Id { get; set; }
public string Meeting_Custom_Id { get; set; }
public string Zoho_Client_Id { get; set; }
public string Zoho_Client_Secret { get; set; }
public string Zoho_Code { get; set; }
public string Zoho_Refreshed_Token { get; set; }
}
The error i get is this: The Zoho_Refreshed_Token does not exist in the current context
Thank you for your time!

NUnit/Selenium/C# test gives "System.Exception : The test case source could not be found." error

Getting error message from the title above. Test itself does not get to this line >> public void IdentityTenantCreation(AccountInfo acct). Any idea why this is happening and how to fix it? Otherwards does not go into LoginData class at all.
public class AccountInfo
{
public string REGION { get; set; }
public string USER { get; set; }
public string PASSWORD { get; set; }
public string ACCTNAME { get; set; }
public string ACCTCONTACT { get; set; }
}
public class LoginData
{
public static IEnumerable<AccountInfo> GetLoginData
{
get
{
AccountInfo acctInformation = new();
var dataSheet = ExcelHelpers.ReadDataSheet("Login");
foreach (var keys in dataSheet[0].Keys)
{
string flag = dataSheet[0][keys][1].colValue;
if (flag[0].ToString().ToUpper() == "Y")
{
acctInformation = new()
{
REGION = dataSheet[0][keys][0].colValue,
USER = dataSheet[0][keys][2].colValue,
PASSWORD = dataSheet[0][keys][3].colValue,
ACCTNAME = dataSheet[0][keys][4].colValue,
ACCTCONTACT = dataSheet[0][keys][5].colValue
};
}
}
yield return acctInformation;
}
}
}
[Test]
[TestCaseSource(typeof(LoginData), "GetData")]
public void IdentityTenantCreation(AccountInfo acct)
{
LogIntoSF(acct.USER, acct.PASSWORD);
SwitchToClassicDash();
.......
}

PropertyInfo List is null when using reflection with generics

I am using a method to try and iterate through an object to get all of the object's properties, some of which are lists of objects.
This all works except for the part where I check for objects within the initial object's properties. If it finds a list of objects I want it to iterate through them.
Annoyingly, I'm getting null on my list of whatever type.
I'm now getting an error in VS because pt isn't instantiated, but it would be at run time.
Below is the if statement I'm using to try and catch whatever object/List is being parsed.
Am I going the right (roundabout) way or doing this or is this completely wrong?
Problematic Code - if statement null list:
public static string DeconstructLists<T>(T obj, string body)
{
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || property.PropertyType == typeof(bool))
body += property.Name + " = " + property.GetValue(obj, null) + Environment.NewLine;
else
{
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
//null list exception
var list = (IEnumerable)property.GetValue(obj, null);
foreach (var item in list)
{
DeconstructLists(item, body);
}
// stack overflow exception
//var props = property.PropertyType.GetGenericArguments()[0];
//foreach (var p in props.GetProperties())
//{
// DeconstructLists(p, body);
//}
}
}
}
return body;
}
Post create method:
public ActionResult Create(Company cmp)
{
if (ModelState.IsValid)
{
db.companys.Add(cmp);
db.SaveChanges();
// send email
SendEmail(cmp);
return RedirectToAction("Thankyou", "Home", new { form="ASN" });
}
return View(cmp);
}
Send email method:
public static void SendEmail(Company cm)
{
string _body = "";
string _subject = "ASN Form Request";
_body = DeconstructLists<Company>(cm, _body);
using (SmtpClient msgClient = new SmtpClient())
{
msgClient.EnableSsl = false;
msgClient.DeliveryMethod = SmtpDeliveryMethod.Network;
msgClient.UseDefaultCredentials = false;
msgClient.Credentials = new NetworkCredential
{
UserName = "",
Password = ""
};
msgClient.Host = "";
msgClient.Port = 0;
using (MailMessage msg = new MailMessage())
{
msg.To.Add(""); // to add
msg.From = new MailAddress("");// from add
msg.Subject = _subject;
msg.Body = _body;
// preparing the message to be sent
msgClient.Send(msg);
}
}
}
Class objects:
public class Company
{
public int companyId { get; set; }
public string name { get; set; }
public string telephone { get; set; }
public string regNumber { get; set; }
public virtual IList<Asn> asns { get; set; }
public virtual IList<Contact> contacts { get; set; }
}
public class Contact
{
public int contactId { get; set; }
public int companyId { get; set; }
public Company company { get; set; }
public string name { get; set; }
public string telephone { get; set; }
}
public class Asn
{
public int asnId { get; set; }
public int companyId { get; set; }
public Company company { get; set; }
public bool userBehalf { get; set; }
public bool something { get; set; }
}
If it finds a list of objects I want it to iterate through them.
You don't need a list for iteration, the minimum iteratable type is IEnumerable. In fact your if statement is checking just that
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
// ...
}
So why not just using inside
var list = (IEnumerable)property.GetValue(obj, null);
foreach (var item in list)
{
DeconstructLists(item, body);
}
EDIT: See this, it works, then see why yours does not:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Tests
{
class Test
{
static void Main(string[] args)
{
var company = new Company
{
companyId = 1,
name = "ACME",
};
company.asns = new List<Asn>
{
new Asn { asnId = 1, companyId = company.companyId, company = company },
new Asn { asnId = 2, companyId = company.companyId, company = company },
};
company.contacts = new List<Contact>
{
new Contact { contactId = 1, companyId = company.companyId, company = company, name = "Contact1" },
new Contact { contactId = 2, companyId = company.companyId, company = company, name = "Contact2" }
};
var body = DeconstructLists(company, "");
}
public static string DeconstructLists<T>(T obj, string body)
{
var type = obj.GetType();
var properties = type.GetProperties();
foreach (var property in properties)
{
if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || property.PropertyType == typeof(bool))
body += property.Name + " = " + property.GetValue(obj, null) + Environment.NewLine;
else
{
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
body = body + property.Name + ": {" + Environment.NewLine;
var list = (IEnumerable)property.GetValue(obj, null);
foreach (var item in list)
{
body = body + item.GetType().Name + ": {" + DeconstructLists(item, "") + "}" + Environment.NewLine;
}
body = body + "}" + Environment.NewLine;
}
}
}
return body;
}
}
public class Company
{
public int companyId { get; set; }
public string name { get; set; }
public string telephone { get; set; }
public string regNumber { get; set; }
public virtual IList<Asn> asns { get; set; }
public virtual IList<Contact> contacts { get; set; }
}
public class Contact
{
public int contactId { get; set; }
public int companyId { get; set; }
public Company company { get; set; }
public string name { get; set; }
public string telephone { get; set; }
}
public class Asn
{
public int asnId { get; set; }
public int companyId { get; set; }
public Company company { get; set; }
public bool userBehalf { get; set; }
public bool something { get; set; }
}
}
Maybe you could try something like this in your if statement ?
var genericType = property.PropertyType.GetGenericArguments()[0];
foreach (var prop in genericType.GetProperties())
{
DeconstructLists(prop, body);
}
This topic may also help you: How to get the type of T from a member of a generic class or method?

c# POST json not working as expected?

I have this example python script that im trying to convert to c# using newtonsoft :
import urllib
import urllib2
import json
url = 'http://server.net/fcgi/scrut_fcgi.fcgi'
report_details = {
'reportTypeLang' : 'conversations',
'reportDirections' : {
'selected' : 'inbound'
},
'times' : {
'dateRange' : 'Last5Minutes'
},
'filters' : {
'sdfDips_0' : 'in_AC10033A_AC10033A-410'
},
'dataGranularity' : {
'selected' : 'auto'
}
}
data_i_need = {
'inbound' : {
'table' : {
'query_limit' : {
'offset' : 0,
'max_num_rows' : 1
}
}
},
'outbound' : {
'table' : {
'query_limit' : {
'offset' : 0,
'max_num_rows' : 1
}
}
}
}
data = {
'rm' : 'report_api',
'action' : 'get',
'rpt_json' : json.dumps( report_details ),
'data_requested' : json.dumps( data_i_need )
}
data = urllib.urlencode( data )
req = urllib2.Request( url, data )
response = urllib2.urlopen( req )
report = response.read()
report_obj = json.loads( report )
so far with some help i have the following c# code but it does not return any data like the python version just errors as if the request is incorrect:
class Program
{
static void Main(string[] args)
{
ReportDirections reportDirections = new ReportDirections();
reportDirections.selected = "inbound";
Times Times = new Times();
Times.dateRange = "Last5Minutes";
Filters Filters = new Filters();
Filters.sdfDips_0 = "in_AC10033A_AC10033A-410";
DataGranularity DataGranularity = new DataGranularity();
DataGranularity.selected = "auto";
ReportDetails ReportDetails = new ReportDetails();
ReportDetails.reportTypeLang = "conversations";
ReportDetails.reportDirections = reportDirections;
ReportDetails.times = Times;
ReportDetails.filters = Filters;
ReportDetails.dataGranularity = DataGranularity;
//
QueryLimit QueryLimit = new QueryLimit();
QueryLimit.offset = 0;
QueryLimit.max_num_rows = 1;
QueryLimit2 QueryLimit2 = new QueryLimit2();
QueryLimit2.offset = 0;
QueryLimit2.max_num_rows = 1;
Table Table = new Table();
Table.query_limit = QueryLimit;
Table2 Table2 = new Table2();
Table2.query_limit = QueryLimit2;
Inbound Inbound = new Inbound();
Inbound.table = Table;
Outbound Outbound = new Outbound();
Outbound.table = Table2;
DataINeed DataINeed = new DataINeed();
DataINeed.inbound = Inbound;
DataINeed.outbound = Outbound;
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://server.bobo.net/fcgi/scrut_fcgi.fcgi");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
var serializer = new Newtonsoft.Json.JsonSerializer();
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
using (var tw = new Newtonsoft.Json.JsonTextWriter(streamWriter))
{
serializer.Serialize(tw,
new
{
action = "get",
rm = "report_api",
data_requested = DataINeed,
rpt_json = ReportDetails
});
}
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
Console.WriteLine(responseText);
}
}
}
public class tw
{
public string rm { get; set; }
public string action { get; set; }
public string rpt_json { get; set; }
public string data_requested { get; set; }
}
public class DataINeed
{
public Inbound inbound { get; set; }
public Outbound outbound { get; set; }
}
public class Inbound
{
public Table table { get; set; }
}
public class Outbound
{
public Table2 table { get; set; }
}
public class Table
{
public QueryLimit query_limit { get; set; }
}
public class Table2
{
public QueryLimit2 query_limit { get; set; }
}
public class QueryLimit
{
public int offset { get; set; }
public int max_num_rows { get; set; }
}
public class QueryLimit2
{
public int offset { get; set; }
public int max_num_rows { get; set; }
}
public class ReportDetails
{
public string reportTypeLang { get; set; }
public ReportDirections reportDirections { get; set; }
public Times times { get; set; }
public Filters filters { get; set; }
public DataGranularity dataGranularity { get; set; }
}
public class ReportDirections
{
public string selected { get; set; }
}
public class Times
{
public string dateRange { get; set; }
}
public class Filters
{
public string sdfDips_0 { get; set; }
}
public class DataGranularity
{
public string selected { get; set; }
}
public class bob
{
}
does this look like the correct way to POST the json request or does something look wrong?
Thanks
Try this..
using System.Net;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
ReportDirections reportDirections = new ReportDirections();
reportDirections.selected = "inbound";
Times Times = new Times();
Times.dateRange = "Last5Minutes";
Filters Filters = new Filters();
Filters.sdfDips_0 = "in_AC10033A_AC10033A-410";
DataGranularity DataGranularity = new DataGranularity();
DataGranularity.selected = "auto";
ReportDetails ReportDetails = new ReportDetails();
ReportDetails.reportTypeLang = "conversations";
ReportDetails.reportDirections = reportDirections;
ReportDetails.times = Times;
ReportDetails.filters = Filters;
ReportDetails.dataGranularity = DataGranularity;
//
QueryLimit QueryLimit = new QueryLimit();
QueryLimit.offset = 0;
QueryLimit.max_num_rows = 1;
QueryLimit2 QueryLimit2 = new QueryLimit2();
QueryLimit2.offset = 0;
QueryLimit2.max_num_rows = 1;
Table Table = new Table();
Table.query_limit = QueryLimit;
Table2 Table2 = new Table2();
Table2.query_limit = QueryLimit2;
Inbound Inbound = new Inbound();
Inbound.table = Table;
Outbound Outbound = new Outbound();
Outbound.table = Table2;
DataINeed DataINeed = new DataINeed();
DataINeed.inbound = Inbound;
DataINeed.outbound = Outbound;
WebClient _webClient = new WebClient();
_webClient.Headers.Add("Content-Type", "application/json");
string data_requested = HttpUtility.UrlEncode(JsonConvert.SerializeObject(DataINeed));
string rpt_json = HttpUtility.UrlEncode(JsonConvert.SerializeObject(ReportDetails));
string data = "action=get&rm=report_api&data_requested=" + data_requested + "&rpt_json="+rpt_json;
string address = "http://server/fcgi/scrut_fcgi.fcgi";
var responseText = Encoding.Default.GetString(_webClient.UploadData(address, "POST", Encoding.Default.GetBytes(data)));
Console.WriteLine(responseText);
}
}
public class tw
{
public string rm { get; set; }
public string action { get; set; }
public string rpt_json { get; set; }
public string data_requested { get; set; }
}
public class DataINeed
{
public Inbound inbound { get; set; }
public Outbound outbound { get; set; }
}
public class Inbound
{
public Table table { get; set; }
}
public class Outbound
{
public Table2 table { get; set; }
}
public class Table
{
public QueryLimit query_limit { get; set; }
}
public class Table2
{
public QueryLimit2 query_limit { get; set; }
}
public class QueryLimit
{
public int offset { get; set; }
public int max_num_rows { get; set; }
}
public class QueryLimit2
{
public int offset { get; set; }
public int max_num_rows { get; set; }
}
public class ReportDetails
{
public string reportTypeLang { get; set; }
public ReportDirections reportDirections { get; set; }
public Times times { get; set; }
public Filters filters { get; set; }
public DataGranularity dataGranularity { get; set; }
}
public class ReportDirections
{
public string selected { get; set; }
}
public class Times
{
public string dateRange { get; set; }
}
public class Filters
{
public string sdfDips_0 { get; set; }
}
public class DataGranularity
{
public string selected { get; set; }
}
public class bob
{
}
managed to get it working by changing the content-type to :
_webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
i was debugging with charles and the python version was posting a json formated form, changed the c# content type to match and now works a treat
Many Thanks for your code and help.

Categories

Resources