Add 2 parameters to Email Template Body - c#

I have a email template and i have bind 1 parameter to it(this.OrderCode) and it's working .So now i need to bind another one.
Email Template Like Below,
string OrderTemplate="<p><%=this.OrderCode%></p><p><%=this.ReferredTo%></p>";
tempValues comes like below,
[0]this.OrderCode
[1]ODR5000
[2]this.ReferredTo
[3]Janez Smithson
Using below code i need to show both of above values.In here only shows 1st value only(ODR5000)
public string EmailTemplate(string OrderTemplate, params string[] tempValues)
{
string templatebody = string.Empty;
try
{
templatebody = OrderTemplate;
for (var i = 0; i < tempValues.Length; i++)
{
templatebody= templatebody.Replace("<%={0}%>".FormatWith(tempValues[i]), tempValues++);
}
}
catch (Exception ex)
{
throw ex;
Log4NetLogger.Log(ex);
}
return templatebody;
}

I have pretty similar function for that.
for (int i = 0; i < tempValues.Length; i++)
{
var pattern = string.Format(#"(\[{0}\])", i);
templatebody = Regex.Replace(templatebody, pattern, tempValues[i].ToString());
}

Related

C# Why does adding objects to my List<> replace all other items?

I am trying to read input from the console and create objects of my own datatype Word and add them to a List. However everytime I add a new one all previous ones get replaced.
The Loop:
while (!QuitInput(wordInput.ToLower()))
{
...handle invalid input...
else
{
try
{
ReadWordFromConsole(languages[0], languages[1], wordInput);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
wordInput = Console.ReadLine().Trim(' ', ';');
}
The Method:
private static void ReadWordFromConsole(string language1, string language2, string input)
{
var splitInput = input.Split(';');
for (int i = 0; i < splitInput.Length; i++)
splitInput[i] = splitInput[i].Trim(' ');
if (splitInput.Length < 2)
{
if (!input.Contains(';'))
throw new ArgumentException("Separate with ';'");
throw new ArgumentException("Invalid input. 'h' for help.");
}
var translationList = new List<string>();
for (int i = 1; i < splitInput.Length; i++)
translationList.Add(splitInput[i]);
var word = new Word(language1, language2, splitInput[0], translationList);
_loadedWords.Add(word);
}
Word class:
private static string _language;
public Word(string language, string translationLanguage, string text, List<string> translations)
{
Language = language;
TranslationLanguage = translationLanguage;
Text = text;
Translations = translations;
}
public string Language
{
get
{
return _language;
}
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("Language cannot be empty");
_language = value;
}
}
...
The global list declared in the same class as ReadWordFromConsole:
private static List<Word> _loadedWords = new List<Word>();
When researching I discovered some posts saying that you cannot use the same instance of the object in the loop. But am I not creating a new one every time ReadWordFromConsole is called?
What would I have to change in order for it to work and not replace previous words?
With a static field as backing store of a property
private static string _language;
even if it is an instance property, you are effectively having just a single location where all your Word instances store/get their Language.
Solution: just remove that static.

Assigning instance variables obtained through reflection in generic method

I have data in tab-separated values (TSV) text files that I want to read and (eventually) store in database tables. With the TSV files, each line contains one record, but in one file the record can have 2 fields, in another file 4 fields, etc. I wrote working code to handle the 2-field records, but I thought this might be a good case for a generic method (or two) rather than writing new methods for each kind of record. However, I have not been able to code this because of 2 problems: I can't create a new object for holding the record data, and I don't know how to use reflection to generically fill the instance variables of my objects.
I looked at several other similar posts, including Datatable to object by using reflection and linq
Below is the code that works (this is in Windows, if that matters) and also the code that doesn't work.
public class TSVFile
{
public class TSVRec
{
public string item1;
public string item2;
}
private string fileName = "";
public TSVFile(string _fileName)
{
fileName = _fileName;
}
public TSVRec GetTSVRec(string Line)
{
TSVRec rec = new TSVRec();
try
{
string[] fields = Line.Split(new char[1] { '\t' });
rec.item1 = fields[0];
rec.item2 = fields[1];
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Bad import data on line: " +
Line + "\n" + ex.Message, "Error",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
}
return rec;
}
public List<TSVRec> ImportTSVRec()
{
List<TSVRec> loadedData = new List<TSVRec>();
using (StreamReader sr = File.OpenText(fileName))
{
string Line = null;
while ((Line = sr.ReadLine()) != null)
{
loadedData.Add(GetTSVRec(Line));
}
}
return loadedData;
}
// *** Attempted generic methods ***
public T GetRec<T>(string Line)
{
T rec = new T(); // compile error!
Type t = typeof(T);
FieldInfo[] instanceVars = t.GetFields();
string[] fields = Line.Split(new char[1] { '\t' });
for (int i = 0; i < instanceVars.Length - 1; i++)
{
rec. ??? = fields[i]; // how do I finish this line???
}
return rec;
}
public List<T> Import<T>(Type t)
{
List<T> loadedData = new List<T>();
using (StreamReader sr = File.OpenText(fileName))
{
string Line = null;
while ((Line = sr.ReadLine()) != null)
{
loadedData.Add(GetRec<T>(Line));
}
}
return loadedData;
}
}
I saw the line
T rec = new T();
in the above-mentioned post, but it doesn't work for me...
I would appreciate any suggestions for how to make this work, if possible. I want to learn more about using reflection with generics, so I don't only want to understand how, but also why.
I wish #EdPlunkett had posted his suggestion as an answer, rather than a comment, so I could mark it as the answer...
To summarize: to do what I want to do, there is no need for "Assigning instance variables obtained through reflection in generic method". In fact, I can have a generic solution without using a generic method:
public class GenRec
{
public List<string> items = new List<string>();
}
public GenRec GetRec(string Line)
{
GenRec rec = new GenRec();
try
{
string[] fields = Line.Split(new char[1] { '\t' });
for (int i = 0; i < fields.Length; i++)
rec.items.Add(fields[i]);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Bad import data on line: " + Line + "\n" + ex.Message, "Error",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
}
return rec;
}
public List<GenRec> Import()
{
List<GenRec> loadedData = new List<GenRec>();
using (StreamReader sr = File.OpenText(fileName))
{
string Line = null;
while ((Line = sr.ReadLine()) != null)
loadedData.Add(GetRec(Line));
}
return loadedData;
}
I just tested this, and it works like a charm!
Of course, this isn't helping me to learn how to write generic methods or use reflection, but I'll take it...

Automatic null values in database if textbox is empty

I want to have null values in my table when the user has left the textbox empty. I'm doing this with a array and a for loop:
private void AddQuestion()
{
string [] checkinput= new string[] { txtBxQuestionCat.Text, txBxQuestion.Text };
string[] countinput= new string[2];
if (String.IsNullOrEmpty(txtBxQuestionCat.Text) && String.IsNullOrEmpty(txBxQuestion.Text))
{
ExceptiesException ex = new ExceptiesException("error");
throw ex;
}
for (int i = 0; i < countinput.Length; i++)
{
if (checkinput[i] == "")
{
countinput[i] = null;
}
}
try
{
qa = new HR5DataSetTableAdapters.QueriesTableAdapter();
qa.AddQuestion(countinput[0], countinput[1]);
hR5DataSetQuestionTableAdapter.Fill(hR5DataSet.question);
questionViewSource1.View.MoveCurrentToLast();
MessageBox.Show("add complete");
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
}
This should be working, but when I'm adding a questioncat and a question and load it into my datagrid, the new questioncat and question has not added to the database, only a new QuestionId. I think it is because I say countinput[i] = null, but I don't know how I could also say that the values need to be null if de textboxes are empty.
You don't need the countinput variable. Alter the for loop after the "both empty" check to
for (int i = 0; i < checkinput.Length; i++)
if (checkinput[i] == "")
checkinput[i] = null;
and then add the question with
qa.AddQuestion(checkinput[0], checkinput[1]);
Currently you are always entering null values, and ignoring the user input.

"RPC Server is unavailable" when exporting Outlook contacts to CSV

I am exporting Outlook contacts with a custom form to CSV from a specific Contacts folder. This folder is not the default location. It is a large folder with almost 7,000 contacts. This is a shared mailbox in Office 365, but we can't use the Outlook or Graph APIs because of the custom data.
My code below works fine, except that after iterating through 200-800 contacts, I get this error: "RPC Server is unavailable. (Exception from HRESULT: 0x800706BA)."
I also tried exporting the folder to a .pst and accessing that folder on my local machine. The result is essentially the same. UPDATE: I've been watching Outlook.exe in the task manager, and it steadily increases its memory consumption to around 300MB before crashing. I've tried the same code on a laptop running Office 2010, and I get an "Out of Memory" error.
I get the error whether Outlook is open or closed, but closing Outlook during program operation will immediately trigger this error. Outlook either starts (or restarts) following this error. I've read a number of SO posts and articles related to this error, but I'm not sure exactly what's going on. Any help is appreciated.
UPDATE: Code has been updated to use for loops instead of foreach loops per Dmitry Streblechenko's suggestion.
using System;
using Microsoft.Office.Interop.Outlook;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace OutlookContacts
{
class Program
{
static void Main(string[] args)
{
var encoding = Encoding.UTF8;
string csvPath = #"myCSVPath";
Application outlook = new Application();
NameSpace ns = outlook.GetNamespace("MAPI");
MAPIFolder sharedContacts;
string recipientName = "myEmail#myDomain";
StringBuilder headerRow = new StringBuilder();
Recipient recip = ns.CreateRecipient(recipientName);
StreamWriter writer = new StreamWriter(csvPath, false, encoding);
recip.Resolve();
if (recip.Resolved)
{
try
{
//EntryID and StoreID of my folder
sharedContacts =
ns.GetFolderFromID(
"myEntryID",
"myStoreID"
);
Items contacts = sharedContacts.Items;
//Writing header row
ContactItem first = contacts.GetFirst();
var properties = first.ItemProperties;
for(int i = 0; i < properties.Count; i++)
{
try
{
headerRow.Append(string.Format("\"{0}\",", properties[i].Name));
}
catch (System.Exception ex)
{
headerRow.Append(string.Format("{0},", ex.Message));
}
}
headerRow.AppendLine(Environment.NewLine);
WriteToCSV(writer, headerRow);
Console.WriteLine("Header row written;");
Marshal.ReleaseComObject(properties);
Marshal.ReleaseComObject(first);
//Writing Records
for (int i = 1; i <= contacts.Count; i++)
{
object o = contacts[i];
if (o is ContactItem)
{
ContactItem contact = (ContactItem)o;
if (contact != null)
{
Console.Write(contact.FullName);
StringBuilder dataRow = new StringBuilder();
ItemProperties contactProps = contact.ItemProperties;
for (int j = 0; j < contactProps.Count; j++)
{
ItemProperty property = contactProps[j];
try
{
if (property.Value == null)
{
string value = "null,";
dataRow.Append(value);
}
//else if (property.Name == "Attachments")
//{
// //Attachment file names
// string attachment = "";
// for (int k = 1; k < contact.Attachments.Count; k++)
// {
// attachment = (string.Format("\"{0}\"; ", contact.Attachments[k].FileName));
// dataRow.Append(attachment);
// }
// dataRow.Append(",");
//}
else
{
string value = property.Value.ToString();
value = value.Replace("\r\n\r\n\r\n", "\r\n")
.Replace("\r\n\r\n", "\r\n")
.Replace("\"", "'");
value = (string.Format("\"{0}\",", value));
dataRow.Append(value);
}
}
catch (System.Exception ex)
{
string value = string.Format("{0}: {1},", property.Name, ex.Message);
dataRow.Append(value);
}
Marshal.ReleaseComObject(property);
}
dataRow.Append(Environment.NewLine);
WriteToCSV(writer, dataRow);
Marshal.ReleaseComObject(contactProps);
Marshal.ReleaseComObject(contact);
}
Marshal.ReleaseComObject(o);
counter++;
Console.WriteLine(": Written " + counter);
}
}
}
catch (System.Exception ex)
{
Console.WriteLine(dataRow.ToString(), ex.Message);
Console.ReadKey();
}
}
}
static void WriteToCSV(StreamWriter writer, StringBuilder row)
{
var data = row.ToString();
writer.WriteAsync(data);
}
}
}
Looks like you are running out of RPC channels. You need to avoid using foreach loops (they tend to keep all collection members referenced until the loop exits) and explicitly release all COM objects are soon as you are done with them.
Off the top of my head:
for(int i = 1; i <= contacts.Count; i++)
{
obejct o = contacts[i];
ContactItem contact = o as ContactItem;
if (o != null)
{
ItemProperties properties = contact.ItemProperties;
StringBuilder newLine = new StringBuilder();
for (int j = 1; j <= properties.Count; j++)
{
ItemProperty property = properties[j];
var value = "";
if (property.Value == null)
{
value = "null,";
Console.WriteLine(value);
newLine.Append(value);
}
else
{
value = property.Value.ToString() + ",";
newLine.Append(value);
}
Marshal.ReleaseComObject(property);
}
newLine.Append(Environment.NewLine);
WriteToCSV(writer, newLine);
Marshal.ReleaseComObject(properties);
Marshal.ReleaseComObject(contact);
}
Marshal.ReleaseComObject(o);
}

Is it possible to keep running nunit scripts even if error occurs

I have a test which reads input from csv file and executes all test based on input in a loop and also write back results in same file for each row executed. Problem is it is failing to run the whole input data even if error occurs in single input data. Is it possible to keep running the tests even if one of the input data failed.
Please guide.
Thanks
Code
[Test, Category(TestConstants.DataCategoryName)]
public void GenerateTestData_Book()
{
string csv_file_path = GetAppSettingsEntry("CSVResourcesPath", true);
DataTable csvData = GetDataFromCSVFile(csv_file_path);
for (int i = 0; i < csvData.Rows.Count; i++)
{
var request = TestData.Helper.GetBooks<RequestedBook>(csvData.Rows[i][0]);
string errors = string.Empty;
if (response.HasErrors())
{
errors = string.Join(Environment.NewLine, response.ResponseInfos.GetErrors().Select(x => x.Code + " " + x.Text));
UpdateColumnInCSVFile(csv_file_path,error, errors, Convert.ToString(csvData.Rows[i][0]));
}
else
{
// Save Book id in file
UpdateColumnInCSVFile(csv_file_path, Reference, Convert.ToString(response.Book.Bookid), Convert.ToString(csvData.Rows[i][0]));
}
}
}
}
You should just put a try-catch inside your for loop.
If you want the test to fail on error you could store a bool declared before the loop and make a assert.isTrue after the loop.
Something like this:
public void GenerateTestData_Book()
{
string csv_file_path = GetAppSettingsEntry("CSVResourcesPath", true);
DataTable csvData = GetDataFromCSVFile(csv_file_path);
bool hasError = false;
for (int i = 0; i < csvData.Rows.Count; i++)
{
try
{
//do your stuff here....
}
catch (System.Exception)
{
hasError = true;
}
}
Assert.IsFalse(hasError);
}

Categories

Resources