In this blog i'm only explaining the important aspects when reading using EWS API. I read from a child folder from root mailbox. Use WellKnownFolderName.Root it will show all folders of my Inbox.Then using web services i call the 3rd party tool and pass the information read from the specific mail box. Below i'm showing only the flow of the process but this will help you to figure our the code level commands.
public static void RunProcess()
{
DateTime dateTime = DateTime.Now;
service.Credentials = new NetworkCredential(Settings.Default.EmailAddress, Settings.Default.EmailPassword);
if (Settings.Default.ExchangeUseAutodiscover == true)
{
if (isDebugEnabled)
{
logger.Debug("Finding Autodiscover URL.");
}
service.AutodiscoverUrl(Settings.Default.EmailAddress, RedirectionCallback);
}
else
{
service.Url = new System.Uri(Settings.Default.ExchangeWebServicesEndpoint);
}
if (isDebugEnabled)
{
logger.Debug(String.Format("EWS Endpoint: {0}", service.Url));
}
BindMailboxFolders();
ProcessEmail();
}
static bool RedirectionCallback(string url)
{
return url.ToLower().StartsWith("https://");
}
static void BindMailboxFolders()
{
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, view);
foreach (Folder folder in findFolderResults)
{
if (folder.DisplayName.Equals(Settings.Default.CaseCreatedMailFolderName))
caseCreatedMailFolder = Folder.Bind(service, folder.Id);
if (folder.DisplayName.Equals(Settings.Default.ErrorMailFolderName))
errorMailFolder = Folder.Bind(service, folder.Id);
if (folder.DisplayName.Equals(Settings.Default.UnknownMailFolderName))
unknownMailFolder = Folder.Bind(service, folder.Id);
}
}
static void ProcessEmail()
{
PropertySet emailPropertySet = new PropertySet(BasePropertySet.FirstClassProperties, EmailMessageSchema.IsRead);
emailPropertySet.RequestedBodyType = BodyType.Text;
ItemView itemView = new ItemView(1000);
itemView.PropertySet = emailPropertySet;
//Get unread email only
SearchFilter filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> findEmailResults = service.FindItems(WellKnownFolderName.Inbox, filter, itemView);
int emailCount = 1;
Dictionary<int, Dictionary<string, string>> emails = new Dictionary<int, Dictionary<string, string>>();
foreach (EmailMessage email in findEmailResults.Items.Where(i => i is EmailMessage))
{
email.Load(emailPropertySet);
EmailData emailData = new EmailData();
emailData.fromAddress = email.From.ToString();
emailData.sent = email.DateTimeSent.ToString();
emailData.toAddress = email.DisplayTo.ToString();
emailData.mailSubject = email.Subject.ToString();
if (isDebugEnabled)
{
logger.Debug("-----------------------------------------------");
logger.Debug("From: " + email.LastModifiedName);
logger.Debug("To: " + email.DisplayTo);
logger.Debug("CC: " + email.DisplayCc);
logger.Debug("Subject: " + email.Subject);
logger.Debug("-----------------------------------------------");
}
emails.Add(emailCount, new Dictionary<string, string>());
email.Body.ToString().Split('\n');
foreach (string line in email.Body.ToString().Split('\n'))
{
if (Regex.IsMatch(line, "^.*:{1}.*$"))
{
//Split only on first occurance of ":"
string[] values = line.Split(new[] { ":" }, 2, StringSplitOptions.None);
emails[emailCount].Add(values[0].Trim(), values[1].Trim());
if (isDebugEnabled)
{
logger.Debug(values[0].Trim() + " - " + values[1].Trim());
}
}
}
//Attempt to create case with web services here, then move into folder based on result of web services call
// Get the Dictionary for the current email
Dictionary<string, string> emailDictionary = emails[1];
bool dataComplete = VerifyEmailProperties(emailData, emailDictionary);
// Get the process to create the Case for
Process process = processFactory.getProcess(emailData);
// Create Case in 3rd party system by calling it's web service
try
{
createCase.processRequest(process);
//Mark as read and move to appropriate folder
email.IsRead = true;
email.Update(ConflictResolutionMode.AutoResolve);
if (isDebugEnabled)
{
logger.Debug("MARKED AS READ...");
}
email.Move(caseCreatedMailFolder.Id);
if (isDebugEnabled)
{
logger.Debug("MOVED TO FOLDER...");
}
emailData = null;
}
catch (Exception e)
{
email.IsRead = true;
email.Update(ConflictResolutionMode.AutoResolve);
if (isErrorEnabled)
{
logger.Error("Failed to Process...MARKED AS READ..." + Environment.NewLine
+ emailData.ToString() + Environment.NewLine + e.InnerException.StackTrace);
}
}
emailData = null;
emailCount++;
}
}
Sunday, 25 November 2018
Wednesday, 21 November 2018
How to send email from a trigger when a record is inserted
Setting up a trigger using sp_send_dbmail is easier than you think. If you have set up your SQL server to send out emails then it's matter of setting up your email template in the trigger. Have a look at below trigger i have created.
In this trigger i have first create email body querying from a database query. Then i embed it and send to the recipient that is again queried out from the DB.
I believe this trigger will save your time :)
USE [Database Name]
GO
/****** Object: Trigger [dbo].[NotificationEmail] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[NotificationEmail]
ON [dbo].[logEvents]
AFTER INSERT
AS
--Initiation
declare @email varchar(200), @ID varchar(12), @emailBody varchar(500), @emailSubject varchar(150)
--Select email and note
select @email = A.EMAIL, @ID = A.ID
from <DB TABLE> A
--Create email strings
set @emailBody = 'A new note has been added to ' + @ID + ', which has triggered an email to ' + @email
+ char(13) + char(10) + char(10) +
+'As this ID has been assigned to you, please review the updated information.'+char(10) + char(10)
+'Thank You'
set @emailSubject = 'New note added to ' + @ID
if @email is not null
begin
--Send email
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'emails',
@recipients = @email,
--@recipients = 'sarasidias@test.com',
@body = @emailBody,
@subject = @emailSubject
end
Tuesday, 21 August 2018
C#: Read from a spreadsheet/Excel
In my previous post i have mentioned about reading from CSV. In this i'm going to share the method i use to read from excel.
Reference:
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
Method:
public void ReadExcel(string excelPath)
{
private static Microsoft.Office.Interop.Excel.Application appExcel;
Microsoft.Office.Interop.Excel.Workbook theWorkbook;
Microsoft.Office.Interop.Excel.Sheets objSheets;
Microsoft.Office.Interop.Excel.Worksheet objWorkSheet;
Microsoft.Office.Interop.Excel.Range range;
string[] strArray;
try
{
appExcel = new Microsoft.Office.Interop.Excel.Application();
if (appExcel != null)
{
theWorkbook = appExcel.Workbooks.Open(excelPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
objSheets = theWorkbook.Worksheets;
objWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)objSheets.get_Item(1);
for (int i = 2; i <= 11; i++)
{
range = objWorkSheet.get_Range("A" + i.ToString(), "I" + i.ToString());
System.Array myValues = (System.Array)range.Cells.get_Value(Type.Missing);
strArray = myValues.OfType<object>().Select(o => o.ToString()).ToArray();
StartSearching(strArray);
}
}
else
{
//clean up stuffs
theWorkbook.Close(false, Type.Missing, Type.Missing);
Marshal.ReleaseComObject(theWorkbook);
appExcel.Quit();
Marshal.FinalReleaseComObject(appExcel);
}
}
catch (Exception ex)
{
_log.ErrorFormat("There was an error reported Read Excel! {0} \n\n", ex.Message, ex.StackTrace);
}
_log.DebugFormat("ReadExcel Completed");
}
Reference:
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
Method:
public void ReadExcel(string excelPath)
{
private static Microsoft.Office.Interop.Excel.Application appExcel;
Microsoft.Office.Interop.Excel.Workbook theWorkbook;
Microsoft.Office.Interop.Excel.Sheets objSheets;
Microsoft.Office.Interop.Excel.Worksheet objWorkSheet;
Microsoft.Office.Interop.Excel.Range range;
string[] strArray;
try
{
appExcel = new Microsoft.Office.Interop.Excel.Application();
if (appExcel != null)
{
theWorkbook = appExcel.Workbooks.Open(excelPath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
objSheets = theWorkbook.Worksheets;
objWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)objSheets.get_Item(1);
for (int i = 2; i <= 11; i++)
{
range = objWorkSheet.get_Range("A" + i.ToString(), "I" + i.ToString());
System.Array myValues = (System.Array)range.Cells.get_Value(Type.Missing);
strArray = myValues.OfType<object>().Select(o => o.ToString()).ToArray();
StartSearching(strArray);
}
}
else
{
//clean up stuffs
theWorkbook.Close(false, Type.Missing, Type.Missing);
Marshal.ReleaseComObject(theWorkbook);
appExcel.Quit();
Marshal.FinalReleaseComObject(appExcel);
}
}
catch (Exception ex)
{
_log.ErrorFormat("There was an error reported Read Excel! {0} \n\n", ex.Message, ex.StackTrace);
}
_log.DebugFormat("ReadExcel Completed");
}
C#: Read from CSV
I'm writing this post thinking how easy it is to read and write to a file for a developer, however if you happen to write a piece of code to read from CSV i bet you take little longer. This is what happened to me. So i thought it's a good move to add this to my blog so i can refer this method anytime.
If you think this helps you, make use of it whenever you want it.
Reference:
using System.IO;
Method to read from CSV:
public string[,] readCSV(string filePath)
{
try
{
string fileData = System.IO.File.ReadAllText(filePath);
// Split into lines.
fileData = fileData.Replace('\n', '\r');
string[] lines = fileData.Split(new Char[] { '\r' }, StringSplitOptions.RemoveEmptyEntries);
// See how many rows and columns there are.
int totalRows = lines.Length;
int totalCols = lines[0].Split(',').Length;
// Allocate the data array.
string[,] resultVals = new string[totalRows, totalCols];
//populate the array with data
for (int row = 0; row < totalRows; row++)
{
string[] line_r = lines[row].Split(',');
for (int col = 0; col < totalCols; col++)
{
resultVals[row, col] = line_r[col];
}
}
return resultVals;
}
catch (Exception ex)
{
_log.ErrorFormat("There was an error reported! {0} \n\n", ex.Message, ex.StackTrace);
return null;
}
}
Method that use the string array:
private void StartSearching(string[,] strArray)
{
try
{
for (int i = 1; i < strArray.GetLength(0); i++)
{
Narnum = strArray[i,0].ToString().TrimEnd().ToLower();
EmpName = strArray[i,1].ToString().Trim();
PreferredName = strArray[i,2].ToString().TrimEnd();
Firstname = strArray[i,3].ToString().TrimEnd();
Surname = strArray[i,4].ToString().TrimEnd();
Position = strArray[i,5].ToString().TrimEnd();
Department = strArray[i,6].ToString().TrimEnd();
Manager = strArray[i,7].ToString().TrimEnd();
Division = strArray[i,8].ToString().TrimEnd();
Validate(Narnum, EmpName, Position, PreferredName, Surname, Firstname, Manager, Division);
}
}
catch (Exception ex)
{
_log.ErrorFormat("There was an error reported! {0} \n\n", ex.Message, ex.StackTrace);
}
}
C#: Convert names to proper case
I have come across situations where some names or surnames have a character and managing casing is the important task. So i developed a simple method to convert the names to proper case in exceptional cases.
Ex: O'Brien , Tucky-Knight, Van Van, Nra (Nanette)
My method below identify the special character and make the next letter to upper case.
public string ConvertToProperNameCase(string input)
{
char[] chars = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input.ToLower()).ToCharArray();
for (int i = 0; i + 1 < chars.Length; i++)
{
if ((chars[i].Equals('\'')) || (chars[i].Equals('-')) || (chars[i].Equals('(')) || (chars[i].Equals(' ')))
{
chars[i + 1] = Char.ToUpper(chars[i + 1]);
}
}
return new string(chars);
}
Ex: O'Brien , Tucky-Knight, Van Van, Nra (Nanette)
My method below identify the special character and make the next letter to upper case.
public string ConvertToProperNameCase(string input)
{
char[] chars = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input.ToLower()).ToCharArray();
for (int i = 0; i + 1 < chars.Length; i++)
{
if ((chars[i].Equals('\'')) || (chars[i].Equals('-')) || (chars[i].Equals('(')) || (chars[i].Equals(' ')))
{
chars[i + 1] = Char.ToUpper(chars[i + 1]);
}
}
return new string(chars);
}
Monday, 28 May 2018
Visualize work in progress(WIP) at any given point of time in Power BI
It
is a very common requirement to visualize the WIP or sales at any given point
of time in Power BI. This task sound really simple but it needs extensive DAX
effort to summaries this details.
A
simple example.
Incident No
|
Incident Open Date
|
Incident Closed Date
|
2018 Jan
|
2018 Feb
|
2018 Mar
|
1ABC
|
01/01/2018
|
02/02/2018
|
1
|
1
|
0
|
2ABC
|
01/01/2018
|
30/01/2018
|
1
|
0
|
0
|
3ABC
|
15/01/2018
|
15/03/2018
|
1
|
1
|
1
|
4ABC
|
06/02/2018
|
|
0
|
1
|
1
|
Total
|
3
|
3
|
2
|
To
do this task, first create the DATE table which has Year and Month columns.
In
your data table you use to measure the WIP create a measure like below:
Measure
=
CALCULATE(
DISTINCTCOUNT(Workload[INCIDENTNO]),
GENERATE(VALUES(Dates[TIMELINE_DATE]),
FILTER(Workload,CONTAINS(
DATESBETWEEN(Dates[TIMELINE_DATE],Workload[CREATED_DATE],Workload[CLOSED_DATE]),
Dates[TIMELINE_DATE],Dates[TIMELINE_DATE])
)
)
)
****Most
importantly this measure works only when your Workload table has NO
relationship with Dates table. ****
CALCULATE(<expression>,<filter1>,<filter2>…)
DISTINCTCOUNT(<column>)
GENERATE(<table1>, <table2>)
VALUES(<TableNameOrColumnName>)
FILTER(<table>,<filter>)
CONTAINS(<table>, <columnName>, <value>[, <columnName>, <value>]…)
DATESBETWEEN(<dates>,<start_date>,<end_date>)
Wednesday, 9 May 2018
Add/Remove SQL DB instance in SQL Server
There may be situations that you need to add a new DB instance to one of your production DB's or remove an instance with the purpose of relocation DB's.
Adding and instance or removing an instance is very straight forward if you follow the installation set up wizard. Also you can use below links to refer for knowledge.
Remove:
https://docs.microsoft.com/en-us/sql/sql-server/install/uninstall-an-existing-instance-of-sql-server-setup?view=sql-server-2017
Add feature:
https://docs.microsoft.com/en-us/sql/database-engine/install-windows/add-features-to-an-instance-of-sql-server-setup?view=sql-server-2017
However most expensive question is whether the DB server need a restart after adding or removing an instance. What is the knocked on effect on production DB server. I have done this many times in my life and you can add or remove an instance without a DB restart. There is no impact to the other instances on the SQL server. However i would recommend taking a snapshot before performing any action to mitigate any risks.
Hope this answers!
Adding and instance or removing an instance is very straight forward if you follow the installation set up wizard. Also you can use below links to refer for knowledge.
Remove:
https://docs.microsoft.com/en-us/sql/sql-server/install/uninstall-an-existing-instance-of-sql-server-setup?view=sql-server-2017
Add feature:
https://docs.microsoft.com/en-us/sql/database-engine/install-windows/add-features-to-an-instance-of-sql-server-setup?view=sql-server-2017
However most expensive question is whether the DB server need a restart after adding or removing an instance. What is the knocked on effect on production DB server. I have done this many times in my life and you can add or remove an instance without a DB restart. There is no impact to the other instances on the SQL server. However i would recommend taking a snapshot before performing any action to mitigate any risks.
Hope this answers!
Dateadd command in SQL
This is very much straight forward but easily forgettable. "dateadd" command is a very useful command in queries. That's why i thought of adding this to my blog.
Ex:
select dateadd(week,-3,getdate());
select dateadd(day,-21,getdate());
Ex:
select * from dbo.tblMembership
where ValidTill >dateadd(week,-3,getdate());
How to find which tables have specific column names in SQL Server
There are times you are required to find a specific column name and what tables are linked up with similar column names. This is easier with third party tools available however if your organisation does not support any third party tool you might think this is more like a manual work. Of course not! Below is the query to get you there. Try and see :)
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%avail%'
ORDER BY schema_name, table_name;
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%avail%'
ORDER BY schema_name, table_name;
Creating a user and grant read access to table level in SQL server
There are some occasions that you need to give limited permissions such as limiting permission in table level. Let say if you grant DB level rad access this permission cascade down to entire DB. However what if you want to grant read access only to few tables? Below i describe an easy way to create a SQL user or windows login and grant table level read access permission.
Launch
SQL server management studio.
To
create a new user collapse Security -> Right click on User -> Select New
user. This way you can create a SQL User account
If
you need to give access to domain user select the Windows authentication and
follow the next steps.
Go
to server roles and make sure Public user role has been granted
Go
to User Mapping and select the DB and make sure Public Role membership has been
selected
Click
Ok to complete the user creation.
Open
a new Query window and choose your DB and run the below query.
Template:
GRANT SELECT ON
"dbo"."tablename1" TO
"<domain>\<username>"
GRANT SELECT ON "dbo"." Tablename2" TO "<domain>\<username>"
GRANT SELECT ON "dbo"." tablename1" TO "<SQL username>"
GRANT SELECT ON "dbo"." Tablename2" TO "<domain>\<username>"
GRANT SELECT ON "dbo"." tablename1" TO "<SQL username>"
GRANT SELECT ON
"dbo"." Tablename2" TO "<SQL username>"
Example:
GRANT SELECT ON "dbo"."Account" TO "sqlusername"
GRANT SELECT ON "dbo"."Branch" TO "sqlusername"
GRANT SELECT ON "dbo"."Business"
TO "sqlusername"
To see how the
permissions are now showing, go to DB and collapse Security, then expand Users.
Select the user you created then right click and select Properties. If you go
to Securables it will show you the granted permission like below.
Subscribe to:
Posts (Atom)