Accessing Shared Contacts with EWS Managed API (Exchange 2010) - c#

I'm currently working on a project where I need to get Information from shared contacts (name, mailadress, etc) to compare multiple shared folders and find duplicate entries.
I'm coding in Visual Studio 2015. The program is just a console Application that creates an excel sheet, where the duplicate contacts are marked.
The Exchange Server is 2010 SP1.
The contacts are shared via E-Mail.
I have no problem to get acces to my own contacts. But I can't get to the folders that are shared to me.
I tried to follow this Guide.
But unfortunately this line gives me a nullpointer exception.
NameResolutionCollection ncCol = service.ResolveName(lnLegDN, ResolveNameSearchLocation.DirectoryOnly, true);
if (ncCol.Count > 0)
And further on I don't really understand what this part is supposed to to anyways, so I can't really fix it. It's my first time working with the EWS Managed API.
After changing the code I am able to get acces to the contacts folder from another mailbox. But that is not the folder that is shared to me.
So my question is, how can I get a contactsfolder that is named "CheckForDuplicates" for example. Is there a way?
Here is the code I changed in the above example. I'm getting the name of the mail box owner and than look for their contacts. After that I call a routine that gets the needed information from all contacts within that folder.
foreach (Item itItem in fiResults.Items)
{
object WlinkStoreEntryId = null;
if (itItem.TryGetProperty(PidTagWlinkStoreEntryId, out WlinkStoreEntryId))
{
string lookup = itItem.Subject;
string[] lookupArr = lookup.Trim().Split(new Char[] {'-'});
NameResolutionCollection ncCol = service.ResolveName(lookupArr[0], ResolveNameSearchLocation.DirectoryOnly, true);
if (ncCol.Count > 0)
{
try
{
Console.WriteLine(itItem.Subject);
FolderId SharedContactsId = new FolderId(WellKnownFolderName.Contacts, ncCol[0].Mailbox.Address);
Folder SharedContactFolder = Folder.Bind(service, SharedContactsId);
rtList.Add(ncCol[0].Mailbox.Address, SharedContactFolder);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
}
}

I found the solution.
And it's way easier than expected.
I realized that I should look for Folders in the WellKnownFolderName.Root and not in WellKnownFolderName.Contacts.
Because the WellKnownFolderName.Contacts is reserved for the Contacts-Folder. And not like I thought for all contactfolders.
FolderId sharedRootFolderid = new FolderId(WellKnownFolderName.Root, ncCol[0].Mailbox.Address);
FolderView sharedFolderView = new FolderView(1000);
sharedFolderView .PropertySet = new PropertySet(BasePropertySet.IdOnly);
sharedFolderView .PropertySet.Add(FolderSchema.DisplayName);
sharedFolderView .Traversal = FolderTraversal.Deep;
SearchFilter testSearchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "CheckForDuplicates");
FindFoldersResults sharedContacts = service.FindFolders(sharedRootFolderid , testSearchFilter, sharedFolderView);
And that's already it.

Related

How do I check if folder and sub folder exist in Outlook using EWS Web Service & C#

I'm very new to C# development.
I'm trying to check and create a folder/ sub-folder exist in Outlook Mailbox using Exchange Web Service.
Folder Structure
MAIN_folder
Sub Folder-1
Sub Folder-2
Sub Folder-3
Implementation
public void checkFolderExistOrNot( String folder_name)
{
FolderView fv = new FolderView(100);
var findFoldersResults = exchangeService.FindFolders(
WellKnownFolderName.Inbox,
new SearchFilter.SearchFilterCollection(
LogicalOperator.Or,
new SearchFilter.ContainsSubstring(FolderSchema.DisplayName, folder_name)),
fv);
foreach (var folder in findFoldersResults)
{
if (folder is Folder)
{
if (folder.DisplayName == folder_name)
{
archiveFolderID = folder.Id;
}
}
}
//if archive folder not found create and assign the variable to the folderID
if (archiveFolderID == null)
{
Folder folder = new Folder(exchangeService);
folder.DisplayName = folder_name;
folder.Save(WellKnownFolderName.Inbox);
archiveFolderID = folder.Id;
}
}
checkFolderExistOrNot(MAIN_folder)
checkFolderExistOrNot(MAIN_folder.Sub Folder-1)
checkFolderExistOrNot(MAIN_folder.Sub Folder-2)
checkFolderExistOrNot(MAIN_folder.Sub Folder-3)
But this is only creating the Main folder under the inbox. It would be greatly appreciated if someone could help me to identify what is missing in my implementation.
Thanks in Advance.
The only way to tell if a folder exists is to search for it with your search because you don't specify the traversal in the Folderview it will always be shallow. If you specify a deep traversal in
FolderView fv = new FolderView(100);
fv.Traversal = FolderTraversal.Deep;
You should then be able to find the parent folder you want to create a new subfolder on. Your logic should work okay as long as you don't have any name clashes a different folder levels. Otherwise what I do is this Exchange Web Service FolderId for a folder created by user or Get to an Exchange folder by path using EWS
Have you given Microsoft Graph a look?
You can basically use it for anything in Microsoft 365. With you you can also achieve your goal.
You will need to create a GraphServiceClient and with it you can do the following to check if a folder exists:
string user = "emailAddressOfTheUser";
var parentFolderRequest = graphClient.Users[user].MailFolders.Inbox.ChildFolders
.Request()
.Filter($"startsWith(displayName, 'parentFolderName')");
var parentMailFolder = await parentFolderRequest.GetAsync(cancellationToken);
Once you have the parent folder you can get it's ID and once you know that you can search it for child folders:
var parentMailFolderID = parentMailFolder.First().Id;
var childFolderRequest = graphClient.Users[user].MailFolders[parentMailFolderID].ChildFolders
.Request()
.Filter($"startsWith(displayName, 'childFolderName')");
var childMailFolder = await parentFolderRequest.GetAsync(cancellationToken);
If the childMailFolder.Count > 0 then the folder exists, if not you create the child folder:
var childFolder = new MailFolder
{
DisplayName = "childFolderName",
IsHidden = false
};
await graphClient.Users[graphUser.Id]
.MailFolders[parentMailFolderID].ChildFolders
.Request()
.AddAsync(childFolder );

Why I can't insert a file into a SharePoint list via code? It goes into exception, seems that the access is denied

I am very new in SharePoint (I am using SharePoint 2013) and I am experiencing a strange problem. This is very strange because in another section of my application it works fine (in another subsite).
So basically into SharePoint I have a SharePoint list named Protocollo.
My code contains the following lines that add a document (a file) into a subfolder of the previous SharePoint List:
internal static int InsertItem(Dictionary<string, object> prot, Documento doc, bool assignVisibility, bool newItem)
{
int state = 0;
SPListItem item = null;
UOR currUOR = null;
List<UOR> path = new List<UOR>();
SPWeb web = SPContext.Current.Web;
string siglaAOO = web.Properties["sigla_aoo"];
DBConnection dbConfig = ArxeiaProtocollo.Util.ProtUtils.InitializeDBConnection();
dbConfig.Database = siglaAOO;
string username = web.CurrentUser.LoginName;
try
{
SPList list = web.Lists["Protocollo"];
web.AllowUnsafeUpdates = true;
SPFolderCollection folders = list.RootFolder.SubFolders;
SPFolder annoFolder;
DateTime dateProt = Convert.ToDateTime(prot["Data protocollo"]);
try
{
annoFolder = folders[dateProt.Year.ToString()];
}
catch
{
annoFolder = folders.Add(dateProt.Year.ToString());
}
SPFolder meseFolder;
try
{
meseFolder = annoFolder.SubFolders[dateProt.Month.ToString("D2")];
}
catch
{
meseFolder = annoFolder.SubFolders.Add(dateProt.Month.ToString("D2"));
}
SPFolder dayFolder;
try
{
dayFolder = meseFolder.SubFolders[dateProt.Day.ToString("D2")];
}
catch
{
dayFolder = meseFolder.SubFolders.Add(dateProt.Day.ToString("D2"));
}
SPFile spFile = dayFolder.Files.Add(doc.Nome, doc.File, true);
............................................................
............................................................
............................................................
}
As you can see the previous code retrievce the Protocollo list from the current website allowing updates on it by:
SPList list = web.Lists["Protocollo"];
web.AllowUnsafeUpdates = true;
Then into this list it creates (it doesn't exist) a gerarcic folders structure for year (annoFolder), month (meseFolder) and day (dayFolder).
It works fine, I tried to delete these folder structure from my SharePoint site and performing this method it is created again, infact this is what I obtained:
As you can see it correctly creates this folder structure into my SharePoint list (named Protocollo) into the current website.
Ok finnally my code try to insert a document into the last subfolder (the dayfolder) by:
SPFile spFile = dayFolder.Files.Add(doc.Nome, doc.File, true);
I am passing to the Add() method: the name of the file, the byte array representing the file and the true boolean value.
The problem is that performing this line I obtain the following exception that is not providing information:
{Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
Then in my front end it appears a "denied access" popup window.
The strange thing is that another sites in my SharePoint that uses the same code have no problem. Another strange thing is that manually uploading the file into this location of the list it works fine so I think that it should not be a user permission problem.
Some idea? What can I try to do to solve this strange problem?
SharePoint codes run using the Application Pool user in IIS not the user that you have logged in to SharePoint, so it is common to get an access denied error even when you have access. So I would suggest you check the permission for the AppPool account on the Protocollo library. Or you can use SPSecurity.RunWithElevatedPrivileges if you have trust in the user that will run the code.
Beware of the pitfalls though.
Here is a sample usage:
Guid siteId = SPContext.Current.Site.ID;
Guid webId = SPContext.Current.Web.ID;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteId))
{
using (SPWeb web = site.OpenWeb(webId))
{
// Your code here
}
}
});

C# Outlook ; After creating folder can't move emails

My application is supposed to send some emails to some destination. After that operation I would like to automatically move sent mails to specific folder ( based on the document type that is in the mail attachment ). If the folder doesn't exist then the program has to create it and then move the mail to the newly created folder. The issue is that after I create a new folder and succcesfully move the mail to it for the first time, then when i sent anothe mails that are supposed to be moved to the said folder the program doesn't see the folder. In fact the Folders method doesn't return any folders at all.
frankly, im out of ideas whats wrong.
when checking in the debugger it says that parentFolder.Folders "Enumeration yielded no results"
I am not sure if I should do anything more after creating the folder in the method createFolder ( ie. something like, update folders list... )
here is my code:
public void moveEmails(string itemType, Boolean itemSent, Outlook.MailItem objMail)
{
Outlook.MAPIFolder folderParent = objMail.Parent as Outlook.MAPIFolder;
Outlook.Folders folders;
Boolean notMoved = true;
objMail.UserProperties.Add("TransferredBy", Outlook.OlUserPropertyType.olText, true, Outlook.OlUserPropertyType.olText);
objMail.UserProperties["TransferredBy"].Value = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
objMail.Save();
if (folderParent.Name != "Inbox")
folderParent = digForInbox(folderParent);
folders = folderParent.Folders;
if (!itemSent)
itemType = "NOT DELIVERED";
foreach (Outlook.MAPIFolder folder in folders)
{
if (folder.Name == itemType)
{
objMail.Move(folder);
notMoved = false;
}
}
if (notMoved)
createFolder(itemType,objMail, folderParent);
}
public void createFolder(string itemType, Outlook.MailItem objMail, Outlook.MAPIFolder folderParent)
{
Outlook.MAPIFolder folderNew;
folderNew = folderParent.Folders.Add( itemType, Outlook.OlDefaultFolders.olFolderInbox ) as Outlook.MAPIFolder;
objMail.Move(folderNew);
}
private Outlook.MAPIFolder digForInbox(Outlook.MAPIFolder folder)
{
Boolean isNotInbox = true;
while(isNotInbox)
{
if(folder.Name != "Inbox")
{
folder = folder.Parent as Outlook.MAPIFolder;
}
else
{
isNotInbox = false;
}
}
return folder;
}
I have found the answer to my question:
https://social.msdn.microsoft.com/forums/windows/en-us/180c000c-524a-45dd-88fe-88b470be3597/accessing-subfolders-within-shared-mailbox?forum=outlookdev
the issue was similar to the one in the link. I didnt imagine that because my mailboxes are mainly shared ones that would affect it in any other way than performance (due to connecting to the exchange server )
Posting this as an answer
I'd suggest using the SaveSentMessageFolder property of the MailItem class. It allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent. Also you may find the following articles helpful:
How To: Change an Outlook e-mail message before sending using C# or VB.NET
How To: Create a new folder in Outlook

Replacing a file with a new file of the same name but different content in TFS via C#

i´m currently working on a programm which updates templates on our companies Team Foundation Server. I am having those new templates locally on my disk and want to replace the existing ones on the server. I was trying different approaches and this is my newest version. The problem is that either
the new file is "in use" when accessing it through coding in c#(while not in use when i try to replace it in runtime using the normal explorer).
the replacement is not appearing in the pending changes, the pendingChanges array is initial.
using (var tfs = TeamFoundationServerFactory.GetServer("myserver"))
{
var versionControlServer = tfs.GetService(typeof(VersionControlServer)) as VersionControlServer;
// Create a new workspace for the currently authenticated user.
var workspace = versionControlServer.CreateWorkspace("Temporary Workspace", versionControlServer.AuthorizedUser);
try
{
// Check if a mapping already exists.
var workingFolder = new WorkingFolder("$serverpath", #"c:\tempFolder");
// Create the mapping (if it exists already, it just overides it, that is fine).
workspace.CreateMapping(workingFolder);
workspace.Get(VersionSpec.Latest, GetOptions.GetAll);
string[] paths = new string[1];
paths[0] = "test.pdf";
workspace.PendEdit(paths, RecursionType.Full, null, LockLevel.None);
// Go through the folder structure defined and create it locally, then check in the changes.
CreateFolderStructure(workspace, workingFolder.LocalItem);
// Check in the changes made.
int a = workspace.CheckIn(workspace.GetPendingChanges(), "This is my comment");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Cleanup the workspace.
workspace.Delete();
// Remove the temp folder used.
Directory.Delete(#"C:\tempFolder", true);
}
}
}
static void CreateFolderStructure(Workspace workspace, string initialPath)
{
workspace.PendDelete("$serverpath/test.pdf", RecursionType.None);
File.Copy(#"C:\test\testnew.pdf", #"C:\tempfolder\test", true);
workspace.PendAdd(#"C:\tempfolder\test.pdf");
}
I found a solution to the problem. The workspace which was used by "authorizedUser" was obviously not enough.. I found out that a need a TeamFoundationIdentity to do it. Here is a guide on how to fix the issue.
http://blogs.msdn.com/b/taylaf/archive/2010/03/29/using-tfs-impersonation-with-the-version-control-client-apis.aspx

"There is no working folder mapping" error when accessing TFS

I'm working on an application that can create and add items to TFS.
My files get created correctly and in the correct location, however the Workspace.PendAdd method only works for one specific workspace, other workspaces give me the "There is no working folder mapping" error.
The method I am using is PendAdd(string filepath, bool recursive) so I pass in a directory to be added and would expect to add both the directory and its files as a pending add in TFS.
Both workspaces are identical in everything but name, neither have any files currently checked out and neither contain any files.
From my google searches I have found that there may be an issue when adding files to a workspace mapped to $/ but the workspace I am using is mapped to $/TFSFiles/ and so far nothing else seems likely.
The code for my PendAdd method is :
private IEnumerable<PendingChange> PendAddFileToTfs(string newFilename)
{
var previousPendingChanges = new List<PendingChange>(_selectedWorkspace.GetPendingChanges());
var changesAdded = _selectedWorkspace.PendAdd(Path.GetDirectoryName(newFilename), true);
var pendingAdds = new List<PendingChange>(_selectedWorkspace.GetPendingChanges());
var itemsToCheckIn = pendingAdds.Except(previousPendingChanges);
return itemsToCheckIn;
}
The method fails at the _selectedWorkspace.PendAdd line. I debugged and verified it is the correct local path and correct workspace.
Can someone point me in the right direction here?
EDIT:
The _selectedWorkspace variable is set by the user.
I get a list of all available workspaces via this code:
_workspaces = _versionControl.QueryWorkspaces(null, _versionControl.AuthorizedUser,environment.MachineName);
I then show a list of workspaces in a combobox and allow the user to select one.
This calls this method:
public void SetWorkspace(string workspaceName)
{
_selectedWorkspace = _workspaces.FirstOrDefault(ws => ws.Name.Equals(workspaceName));
}
You need to create a local workspace before you can add pendAdd files to TFS. I am not sure where _selectedWorkspace is coming from but it looks like it is not configured properly. Although I don't have a c# version to hand I do have a version in PowerShell that calls c#... should give you the way to go.
function New-TfsTeamProjectRootFolder {
Param(
[Microsoft.TeamFoundation.Client.TfsTeamProjectCollection] $TfsCollection,
[Microsoft.TeamFoundation.Server.ProjectInfo] $TfsTeamProject,
[String] $GlobalEntryValue
)
$TempWorkspaceName = "Create-TfsTeamSourceFolder"
$TempFolder = "c:\temp\$TempWorkspaceName"
$ServerFolder = "$/$($TfsTeamProject.Name)"
$TfsVersionControl = Get-TfsVersionControlServer $TfsCollection
try {
$workspace = $TfsVersionControl.GetWorkspace($TempFolder )
} catch {
$workspace = $TfsVersionControl.CreateWorkspace($TempWorkspaceName);
$workspace.Map($ServerFolder, $TempFolder);
}
$NewFolder = "$TempFolder\$GlobalEntryValue";
try {
$SourceItem = $TfsVersionControl.GetItem("$ServerFolder/$GlobalEntryValue")
} catch {
New-Item -ItemType Directory -Force -Path $NewFolder;
$workspace.PendAdd($NewFolder, $true);
$pendingChanges = $workspace.GetPendingChanges();
$changesetNumber = $workspace.CheckIn($pendingChanges, "Added folder for '$GlobalEntryValue'");
$SourceItem = $TfsVersionControl.GetItem("$ServerFolder/$GlobalEntryValue")
}
$workspace.Delete()
Return $SourceItem
}
Again I am not sure why your code is not working as I think the issue is in the greater context than we can see in the example above.

Categories

Resources