List Item multiple users permissions programmatically (sharepoint) - c#

I've looked around and haven't found a solution yet. I have picked up code snippets here and there to find a solution.
I have a Doc Library called "Document Collaboration" with the field "Assigned To". This is a People/Groups field. These people will be able to work on a specific document(list item permission). Now, at first, they will have hidden permissions(they cant see it), but when added to the doc, they will see it and be able to contribute it, also they will get an email notification. I have attached the full code below.
So, I don't get any errors, when I go through VS10 debug. But it doesn't send any email or doesn't set the permissions. What's wrong?
using System;
using System.IO;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
namespace ARDT.Notifications
{
/// <summary>
/// List Item Events
/// </summary>
public class Notifications : SPItemEventReceiver
{
/// <summary>
/// An item was checked in
/// </summary>
public override void ItemCheckedIn(SPItemEventProperties properties)
{
SPSite site = new SPSite("http://sp2010dev/ardt");
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Document Collaboration"];
SPListItem listItem = properties.ListItem;
SPUser userName = null;
String toAddress = null;
//EMail initializations
bool appendHtmlTag = false;
bool htmlEncode = false;
string subject = "Subject";
string message = "Message text";
//get usernames
string[] userNameArray = listItem.Fields["Assigned to"].ToString().Split(';');
for (int i = 0; i <= userNameArray.Length - 1; i++)
{
userName = web.AllUsers[userNameArray[i]];
toAddress = userName.Email;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//EMAIL USER
bool result = SPUtility.SendEmail(web, appendHtmlTag, htmlEncode, toAddress, subject, message);
//PERMISSIONS
//remove permissions first
web.AllowUnsafeUpdates = true;
listItem.BreakRoleInheritance(false);
SPRoleAssignmentCollection raCollection = listItem.RoleAssignments;
//remove exisiting permissions one by one
for (int a = raCollection.Count - 1; i > -0; i--)
{
raCollection.Remove(a);
}
//grant permissions for specific list item
SPRoleDefinition roleDefintion = web.RoleDefinitions.GetByType(SPRoleType.Contributor);
SPRoleAssignment roleAssignment = new SPRoleAssignment(userName);
roleAssignment.RoleDefinitionBindings.Add(roleDefintion);
listItem.RoleAssignments.Add(roleAssignment);
listItem.Update();
});
}
}
base.ItemCheckedIn(properties);
}
}
}

nope, I made the simple mistake of putting it under checked in instead of updated, there's also a work around for the function being run multiple times when it updates, just make a column called "updateContributors" in your list and default value True/Yes
Here's the code/no time to explain, but pretty commented, good luck:
using System;
using System.IO;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
//Debugging includes
using System.Diagnostics;
namespace ARDT.Notifications
{
/// <summary>
/// List Item Events
/// </summary>
public class Notifications : SPItemEventReceiver
{
/// <summary>
/// An item was updated
/// </summary>
public override void ItemUpdated(SPItemEventProperties properties)
{
if (properties.ListItem["updateContributors"].ToString().Equals("True"))
{
//work around so it goes through it only once instead of everytime the item is updated
properties.ListItem["updateContributors"] = "False";
SPSite site = new SPSite("http://sp2010dev/ardt/");
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Document Collaboration"];
SPListItem listItem = properties.ListItem;
SPUser userName = null;
String toAddress = null;
//EMail initializations
bool appendHtmlTag = false;
bool htmlEncode = false;
string subject = "You have been assigned to a Document";
string message = "Test Message";
//get usernames
string tempFieldValue = listItem["Assigned To"].ToString();
string[] userNameArray = listItem["Assigned To"].ToString().Split(';');
//remove permissions first
web.AllowUnsafeUpdates = true;
listItem.BreakRoleInheritance(false);
SPRoleAssignmentCollection raCollection = listItem.RoleAssignments;
//remove exisiting permissions one by one
for (int a = raCollection.Count - 1; a >= 0; a--)
{
raCollection.Remove(a);
}
for (int i = 1; i < userNameArray.Length; i++)
{
tempFieldValue = userNameArray[i].Replace("#", "");
userName = web.AllUsers[tempFieldValue];
toAddress = userName.Email;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//EMAIL USER
bool result = SPUtility.SendEmail(web, appendHtmlTag, htmlEncode, toAddress, subject, message);
//PERMISSIONS
//grant permissions for specific list item
SPRoleDefinition roleDefintion = web.RoleDefinitions.GetByType(SPRoleType.Contributor);
SPRoleAssignment roleAssignment = new SPRoleAssignment(userName);
roleAssignment.RoleDefinitionBindings.Add(roleDefintion);
listItem.RoleAssignments.Add(roleAssignment);
listItem.Update();
});
i++;
}
}
//base.ItemUpdated(properties);
//after final update has been done return true
properties.ListItem["updateContributors"] = "True";
}
}
}
}

One of the problems you have in your code - you create the SPWeb object in current execution context, but then try to send mail using SPSecurity.RunWithElevatedPrivileges. You should never open the web with one account and then use it in another. You have to re-create the context in RunWithElevatedPrivileges block as it can be seen in this example.

Related

thumbnailPhoto not getting in case of Global Catalog

I have created a AD forest that search for a user across all domains in the forest using its global catalog connection string.
I am trying to get thumbnailPhoto of AD user using c# code. But I did not get thumbnailPhoto property in result object even though it exist in AD.
I had verified the thumbnailPhoto prop in AD using powershell. Also I have verified it by getting using LDAP connection string. It both case I got the byte array.
Below is the code to get user and its properties and _configuration.GlobalCatalog returns the Global catalog connections string which is in format (GC://domain-name).
public Task<ProfileImage> GetProfileImageByEmail(string email)
{
var filterQuery = ("mail=" + email);
return Task.FromResult(GetProfileImageFromAD(filterQuery));
}
private ProfileImage GetProfileImageFromAD(string filterQuery)
{
var result = GetADUserDetails(filterQuery);
if (result == null)
return null;
if (result.Properties.Contains("thumbnailPhoto"))
{
var imageBytes = result.Properties["thumbnailPhoto"][0] as byte[];
if (imageBytes != null)
{
return new ProfileImage
{
Content = new MemoryStream(imageBytes),
ContentType = "image/jpeg"
};
}
}
return null;
}
private SearchResult GetADUserDetails(string filterQuery)
{
using (var userBinding = new DirectoryEntry(_configuration.GlobalCatalog))
{
using (DirectorySearcher adSearch = new DirectorySearcher(userBinding))
{
adSearch.ReferralChasing = ReferralChasingOption.All;
adSearch.Filter = filterQuery;
adSearch.PropertiesToLoad.Add("mail");
adSearch.PropertiesToLoad.Add("sn");
adSearch.PropertiesToLoad.Add("givenName");
adSearch.PropertiesToLoad.Add("thumbnailPhoto");
return adSearch.FindOne();
}
}
}
Any help is appreciated.
Update:
On a domain controller open ADSIEdit, connect to Schema Naming Context, find attribute CN=Picture,CN=Schema,CN=Configuration... and go to it's properties. Verify that isMemberOfPartialAttributeSet is set to TRUE

C# - Connect to Outlook 2010 Mailbox to take Xls Files

I had a a c# script that connects to an OFFICE 365 mailbox and then take any emails with an xls file and puts it in a shared folder. Problem is now the OFFICE 365 mailbox has becomes an Outlook 2010 on premises mailbox, and the script has stopped working.
My questions is what Service URL and service credentials do I use, Is it the same syntax or do I need a new way of connecting in the script ?
OLD script
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Exchange.WebServices.Data;
namespace ST_0710846949654fbd84606ec3011bd081.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
/*
The execution engine calls this method when the task executes.
To access the object model, use the Dts property. Connections, variables, events,
and logging features are available as members of the Dts property as shown in the following examples.
To reference a variable, call Dts.Variables["MyCaseSensitiveVariableName"].Value;
To post a log entry, call Dts.Log("This is my log text", 999, null);
To fire an event, call Dts.Events.FireInformation(99, "test", "hit the help message", "", 0, true);
To use the connections collection use something like the following:
ConnectionManager cm = Dts.Connections.Add("OLEDB");
cm.ConnectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;Provider=SQLNCLI10;Integrated Security=SSPI;Auto Translate=False;";
Before returning from this method, set the value of Dts.TaskResult to indicate success or failure.
To open Help, press F1.
*/
public void Main()
{
ExchangeService service = new ExchangeService();
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Credentials = new WebCredentials("xxreturns#xxxxxxxxxxxx.co.uk", "PasswordXXXXXXXXX", "mail.xxxxxxxxxxxxxxx.co.uk");
service.Url = new Uri("https://mail.xxxxxxxxxxx.co.uk/owa");
// Variable population
string FileName1 = null;
string attSaveLocation = Dts.Variables["User::attSaveLocation"].Value.ToString();
string destfold = Dts.Variables["User::destFolder"].Value.ToString();
string emailFrom = Dts.Variables["User::emailFrom"].Value.ToString();
string filetype = Dts.Variables["User::filetype"].Value.ToString();
//find items in the email folder
FindItemsResults<Item> foundItems =
service.FindItems(WellKnownFolderName.Inbox, new ItemView(600)); //can limit how many results are pulled
foreach (Item item in foundItems)
{
string tmpitemid;
string processed = null;
tmpitemid = item.Id.ToString();
if (item is EmailMessage)
{
// Bind to an existing message item, requesting its Id property (using the tmpitemid) plus its attachments collection.
EmailMessage foundEmail = EmailMessage.Bind(service, new ItemId(tmpitemid), new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments));
EmailMessage foundEmail2 = (EmailMessage)item;
FindFoldersResults findResults = service.FindFolders(WellKnownFolderName.Inbox, new FolderView(10));
//get the from e-mail address for exchange addresses
string fromaddress = null;
NameResolutionCollection nd = service.ResolveName(foundEmail2.From.Address);
foreach (NameResolution nm in nd)
{
if (nm.Mailbox.RoutingType == "SMTP")
{
fromaddress = nm.Mailbox.Address.ToLower();
}
else
{
fromaddress = foundEmail2.From.Address.ToString().ToLower();
}
}
//for other addresses
if (fromaddress == null)
{
fromaddress = foundEmail2.From.Address.ToString().ToLower();
}
//if the email address is like the parameter
if (fromaddress.Contains(emailFrom))
{
//process attachments
foreach (Attachment attachment in foundEmail.Attachments)
{
if (attachment is FileAttachment)
{
FileAttachment fileAttachment = attachment as FileAttachment;
FileName1 = attSaveLocation + fileAttachment.Name;
if (fileAttachment.Name.Contains(filetype))
{
fileAttachment.Load(FileName1);
processed = "Y";
}
}
}
if (processed == "Y")
{
// Get all the folders in the message's root folder.
Folder rootfolder = Folder.Bind(service, WellKnownFolderName.Inbox);
rootfolder.Load();
foreach (Folder folder in rootfolder.FindFolders(new FolderView(100)))
{
if (folder.DisplayName == destfold)
{
foundEmail2.Move(folder.Id);
}
}
}
}
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
}
}
Not sure if this works for Outlook 2010, but perhaps this link can help you:
https://msdn.microsoft.com/en-us/office/office365/api/mail-rest-operations

LDAP: How to get list of users from a specific group using C#?

So I'm new to LDAP, and I'm having trouble finding a solid resource.
I'm able to make the connection, but I'm a little lost as to how to get a list of users from a specific group. Could someone help get me started getting a list of users from a specific group?
Assuming you're talking about Active Directory as your LDAP store, and if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
// if found....
if (group != null)
{
// iterate over members
foreach (Principal p in group.GetMembers())
{
Console.WriteLine("{0}: {1}", p.StructuralObjectClass, p.DisplayName);
// do whatever you need to do to those members
}
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Library to be used for this: System.DirectoryServices
This code will get samaccountname and mail of all users in provided group-email and also from nested groups.
using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AD_LDAP
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Group Email: ");
string groupEmail = Console.ReadLine();
List<ADUser> members = getGroupMembers.MembersInGroup(groupEmail);
if (members != null && members.Count > 0)
{
Console.WriteLine(Environment.NewLine + "Total Users: " + members.Count + Environment.NewLine);
Console.WriteLine("*********************** Users in group ************************" + Environment.NewLine);
Console.WriteLine("Users-Id" + "\t\t" + "Email Address" + Environment.NewLine);
foreach (ADUser item in members)
{
Console.WriteLine(item.UserId + "\t\t\t" + item.EmailAddress);
}
}
else
{
if (members == null)
Console.WriteLine("Invalid group email!");
else
Console.WriteLine("Group email has no members");
}
Console.ReadLine();
}
}
class ADUser
{
public string UserId { get; set; }
public string EmailAddress { get; set; }
}
class getGroupMembers
{
/// <summary>
/// searchedGroups will contain all groups already searched, in order to
/// prevent endless loops when there are circular structured in the groups.
/// </summary>
static Hashtable searchedGroups = null;
/// <summary>
/// "MembersInGroup" will return all users in the group passed in as a parameter
/// The function will recursively search all nested groups.
/// Remark: if there are multiple groups with the same name, this function will just use the first one it finds.
/// </summary>
/// <param name="strGroupEmail">Email of the group, which the users should be retrieved from</param>
/// <returns>ArrayList containing the emails of all users in this group and any nested groups</returns>
static public List<ADUser> MembersInGroup(string strGroupEmail)
{
List<ADUser> groupMembers = null;
searchedGroups = new Hashtable();
// find group
DirectorySearcher searchGroup = new DirectorySearcher("LDAP://DC=,DC=com");
searchGroup.Filter = ("mail=" + strGroupEmail);
SearchResult result = searchGroup.FindOne();
if (result != null && Convert.ToString(result.Properties["objectclass"][1]) == "group")
{
DirectorySearcher search = new DirectorySearcher("LDAP://DC=Your Domain Network,DC=com");
search.Filter = String.Format("(&(objectCategory=group)(cn={0}))", Convert.ToString(result.Properties["samaccountname"][0]));
search.PropertiesToLoad.Add("distinguishedName");
SearchResult sru = null;
try
{
sru = search.FindOne();
DirectoryEntry group = sru.GetDirectoryEntry();
groupMembers = getUsersInGroup(group.Properties["distinguishedName"].Value.ToString());
}
catch { }
}
return groupMembers;
}
/// <summary>
/// getUsersInGroup will return all users in the group passed in as a parameter
/// The function will recursively search all nested groups.
/// </summary>
/// <param name="strGroupDN">"distinguishedName" of the group, which the users should be retrieved from</param>
/// <returns>ArrayList containing the email of all users in this group and any nested groups</returns>
private static List<ADUser> getUsersInGroup(string strGroupDN)
{
List<ADUser> groupMembers = new List<ADUser>();
searchedGroups.Add(strGroupDN, strGroupDN);
// find all users in this group
DirectorySearcher ds = new DirectorySearcher("LDAP://DC=Your Domain Network,DC=com");
ds.Filter = String.Format("(&(memberOf={0})(objectClass=person))", strGroupDN);
ds.PropertiesToLoad.Add("distinguishedName");
ds.PropertiesToLoad.Add("samaccountname");
ds.PropertiesToLoad.Add("mail");
foreach (SearchResult sr in ds.FindAll())
{
if (sr.Properties["mail"].Count > 0)
groupMembers.Add(new ADUser { UserId = sr.Properties["samaccountname"][0].ToString(), EmailAddress = sr.Properties["mail"][0].ToString() });
}
// get nested groups
ArrayList al = getNestedGroups(strGroupDN);
foreach (object g in al)
{
if (!searchedGroups.ContainsKey(g)) // only if we haven't searched this group before - avoid endless loops
{
// get members in nested group
List<ADUser> ml = getUsersInGroup(g as string);
// add them to result list
foreach (ADUser s in ml)
{
groupMembers.Add(s);
}
}
}
return groupMembers;
}
/// <summary>
/// getNestedGroups will return an array with the "distinguishedName" of all groups contained
/// in the group that was passed in as a parameter
/// </summary>
/// <param name="strGroupDN">"distinguishedName" of the group, which the nested groups should be retrieved from</param>
/// <returns>ArrayList containing the "distinguishedName" of each group contained in the group apssed in asa parameter</returns>
private static ArrayList getNestedGroups(string strGroupDN)
{
ArrayList groupMembers = new ArrayList();
// find all nested groups in this group
DirectorySearcher ds = new DirectorySearcher("LDAP://DC=Your Domain Network,DC=com");
ds.Filter = String.Format("(&(memberOf={0})(objectClass=group))", strGroupDN);
ds.PropertiesToLoad.Add("distinguishedName");
foreach (SearchResult sr in ds.FindAll())
{
groupMembers.Add(sr.Properties["distinguishedName"][0].ToString());
}
return groupMembers;
}
}
}
I wrote my code in this way to get the user details but I had an error 'System.DirectoryServices.AccountManagement.PrincipalServerDownException' occurred in System.DirectoryServices.AccountManagement.dll but was not handled in user code. I am just new to .net.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
namespace WebApplication2
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
// if found....
if (group != null)
{
// iterate over members
foreach (Principal p in group.GetMembers())
{
Console.WriteLine("{0}: {1}", p.StructuralObjectClass, p.DisplayName);
// do whatever you need to do to those members
}
}
}
}
}
}

System.ServiceModel.Channels.MessageHeader Error

I'm trying to get the following to work on my machine but I get an error (Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader')
using System;
using System.IO;
using System.Reflection;
namespace com.companyname.business
{
/// <summary>
/// Summary description for SessionCreateRQClient.
/// </summary>
class SessionCreateRQClient
{
/// <summary>
/// The main entry point.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
// Set user information, including security credentials and the IPCC.
string username = "user";
string password = "password";
string ipcc = "IPCC";
string domain = "DEFAULT";
string temp = Environment.GetEnvironmentVariable("tmp"); // Get temp directory
string PropsFileName = temp + "/session.properties"; // Define dir and file name
DateTime dt = DateTime.UtcNow;
string tstamp = dt.ToString("s") + "Z";
//Create the message header and provide the conversation ID.
MessageHeader msgHeader = new MessageHeader();
msgHeader.ConversationId = "TestSession"; // Set the ConversationId
From from = new From();
PartyId fromPartyId = new PartyId();
PartyId[] fromPartyIdArr = new PartyId[1];
fromPartyId.Value = "WebServiceClient";
fromPartyIdArr[0] = fromPartyId;
from.PartyId = fromPartyIdArr;
msgHeader.From = from;
To to = new To();
PartyId toPartyId = new PartyId();
PartyId[] toPartyIdArr = new PartyId[1];
toPartyId.Value = "WebServiceSupplier";
toPartyIdArr[0] = toPartyId;
to.PartyId = toPartyIdArr;
msgHeader.To = to;
//Add the value for eb:CPAId, which is the IPCC.
//Add the value for the action code of this Web service, SessionCreateRQ.
msgHeader.CPAId = ipcc;
msgHeader.Action = "SessionCreateRQ";
Service service = new Service();
service.Value = "SessionCreate";
msgHeader.Service = service;
MessageData msgData = new MessageData();
msgData.MessageId = "mid:20001209-133003-2333#clientofsabre.com1";
msgData.Timestamp = tstamp;
msgHeader.MessageData = msgData;
Security security = new Security();
SecurityUsernameToken securityUserToken = new SecurityUsernameToken();
securityUserToken.Username = username;
securityUserToken.Password = password;
securityUserToken.Organization = ipcc;
securityUserToken.Domain = domain;
security.UsernameToken = securityUserToken;
SessionCreateRQ req = new SessionCreateRQ();
SessionCreateRQPOS pos = new SessionCreateRQPOS();
SessionCreateRQPOSSource source = new SessionCreateRQPOSSource();
source.PseudoCityCode = ipcc;
pos.Source = source;
req.POS = pos;
SessionCreateRQService serviceObj = new SessionCreateRQService();
serviceObj.MessageHeaderValue = msgHeader;
serviceObj.SecurityValue = security;
SessionCreateRS resp = serviceObj.SessionCreateRQ(req); // Send the request
if (resp.Errors != null && resp.Errors.Error != null)
{
Console.WriteLine("Error : " + resp.Errors.Error.ErrorInfo.Message);
}
else
{
msgHeader = serviceObj.MessageHeaderValue;
security = serviceObj.SecurityValue;
Console.WriteLine("**********************************************");
Console.WriteLine("Response of SessionCreateRQ service");
Console.WriteLine("BinarySecurityToken returned : " + security.BinarySecurityToken);
Console.WriteLine("**********************************************");
string ConvIdLine = "convid="+msgHeader.ConversationId; // ConversationId to a string
string TokenLine = "securitytoken="+security.BinarySecurityToken; // BinarySecurityToken to a string
string ipccLine = "ipcc="+ipcc; // IPCC to a string
File.Delete(PropsFileName); // Clean up
TextWriter tw = new StreamWriter(PropsFileName); // Create & open the file
tw.WriteLine(DateTime.Now); // Write the date for reference
tw.WriteLine(TokenLine); // Write the BinarySecurityToken
tw.WriteLine(ConvIdLine); // Write the ConversationId
tw.WriteLine(ipccLine); // Write the IPCC
tw.Close();
//Console.Read();
}
}
catch(Exception e)
{
Console.WriteLine("Exception Message : " + e.Message );
Console.WriteLine("Exception Stack Trace : " + e.StackTrace);
Console.Read();
}
}
}
}
I have added the reference System.ServiceModel and the lines:
using System.ServiceModel;
using System.ServiceModel.Channels;
but I continue to get that error when trying to compile --
Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader'
I am using Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
Professional Edition
Is there another reference I have to add? Or a dll to move over?
I wonder was the code above written for Framework 2.0 only?
Thanks for your help.
The error message is correct, you cannot create an instance of that class, it is declared abstract.
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messageheader.aspx
See if the static method MessageHeader.CreateHeader will work for you. Note there is several overloads, so pick the best one for you.

Extract Exchange 2007 Public Calendar Appointments using Exchange Web Services API

We have a public calendar for our company set up in an Exchange 2007 Public Folder. I am able to retrieve my personal calendar appointments for the current day using the code below. I have searched high and low online and I cannot find one example of someone retrieving calendar information from a Public Folder calendar.
It seems like it should be doable, but I cannot for the life of me get it working. How can I modify the code below to access the calendar? I am not interested in creating any appointments through asp.net, just retrieving a simple list. I am open to any other suggestions as well. Thanks.
ADDED BOUNTY
- I can't be the only person that ever needed to do this. Let's get this problem solved for future generations.
UPDATED AGAIN DUE TO IGNORANCE
- I failed to mention that the project I am working on is .NET 2.0 (very important don't you think?).
* ADDED MY CODE SOLUTION BELOW *
- I have replaced my original code example with the code that ended up working. Many thanks to Oleg for providing the code to find the public folder, which was the hardest part.. I have modified the code using the example from here http://msexchangeteam.com/archive/2009/04/21/451126.aspx to use the simpler FindAppointments method.
This simple example returns an html string with the appointments, but you can use it as a base to customize as needed. You can see our back and forth under his answer below.
using System;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace ExchangePublicFolders
{
public class Program
{
public static FolderId FindPublicFolder(ExchangeService myService, FolderId baseFolderId,
string folderName)
{
FolderView folderView = new FolderView(10, 0);
folderView.OffsetBasePoint = OffsetBasePoint.Beginning;
folderView.PropertySet = new PropertySet(FolderSchema.DisplayName, FolderSchema.Id);
FindFoldersResults folderResults;
do
{
folderResults = myService.FindFolders(baseFolderId, folderView);
foreach (Folder folder in folderResults)
if (String.Compare(folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0)
return folder.Id;
if (folderResults.NextPageOffset.HasValue)
folderView.Offset = folderResults.NextPageOffset.Value;
}
while (folderResults.MoreAvailable);
return null;
}
public static string MyTest()
{
ExchangeService myService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
myService.Credentials = new NetworkCredential("USERNAME", "PASSWORD", "DOMAIN");
myService.Url = new Uri("https://MAILSERVER/ews/exchange.asmx");
Folder myPublicFoldersRoot = Folder.Bind(myService, WellKnownFolderName.PublicFoldersRoot);
string myPublicFolderPath = #"PUBLIC_FOLDER_CALENDAR_NAME";
string[] folderPath = myPublicFolderPath.Split('\\');
FolderId fId = myPublicFoldersRoot.Id;
foreach (string subFolderName in folderPath)
{
fId = Program.FindPublicFolder(myService, fId, subFolderName);
if (fId == null)
{
return string.Format("ERROR: Can't find public folder {0}", myPublicFolderPath);
}
}
Folder folderFound = Folder.Bind(myService, fId);
if (String.Compare(folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0)
{
return string.Format("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath);
}
CalendarFolder AK_Calendar = CalendarFolder.Bind(myService, fId, BasePropertySet.FirstClassProperties);
FindItemsResults<Appointment> AK_appointments = AK_Calendar.FindAppointments(new CalendarView(DateTime.Now,DateTime.Now.AddDays(1)));
string rString = string.Empty;
foreach (Appointment AK_appoint in AK_appointments)
{
rString += string.Format("Subject: {0}<br />Date: {1}<br /><br />", AK_appoint.Subject, AK_appoint.Start);
}
return rString;
}
}
}
Like promised here is a code example. I used the Microsoft Exchange Web Services (EWS) Managed API 1.0 and recommend you to do the same. The most comments I included in the code
using System;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace ExchangePublicFolders {
class Program {
static FolderId FindPublicFolder (ExchangeService myService, FolderId baseFolderId,
string folderName) {
// We will search using paging. We will use page size 10
FolderView folderView = new FolderView (10,0);
folderView.OffsetBasePoint = OffsetBasePoint.Beginning;
// we will need only DisplayName and Id of every folder
// se we'll reduce the property set to the properties
folderView.PropertySet = new PropertySet (FolderSchema.DisplayName,
FolderSchema.Id);
FindFoldersResults folderResults;
do {
folderResults = myService.FindFolders (baseFolderId, folderView);
foreach (Folder folder in folderResults)
if (String.Compare (folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0)
return folder.Id;
if (folderResults.NextPageOffset.HasValue)
// go to the next page
folderView.Offset = folderResults.NextPageOffset.Value;
}
while (folderResults.MoreAvailable);
return null;
}
static void MyTest () {
// IMPORTANT: ExchangeService is NOT thread safe, so one should create an instance of
// ExchangeService whenever one needs it.
ExchangeService myService = new ExchangeService (ExchangeVersion.Exchange2007_SP1);
myService.Credentials = new NetworkCredential ("MyUser#corp.local", "myPassword00");
myService.Url = new Uri ("http://mailwebsvc-t.services.local/ews/exchange.asmx");
// next line is very practical during development phase or for debugging
myService.TraceEnabled = true;
Folder myPublicFoldersRoot = Folder.Bind (myService, WellKnownFolderName.PublicFoldersRoot);
string myPublicFolderPath = #"OK soft GmbH (DE)\Gruppenpostfächer\_Template - Gruppenpostfach\_Template - Kalender";
string[] folderPath = myPublicFolderPath.Split('\\');
FolderId fId = myPublicFoldersRoot.Id;
foreach (string subFolderName in folderPath) {
fId = FindPublicFolder (myService, fId, subFolderName);
if (fId == null) {
Console.WriteLine ("ERROR: Can't find public folder {0}", myPublicFolderPath);
return;
}
}
// verify that we found
Folder folderFound = Folder.Bind (myService, fId);
if (String.Compare (folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0) {
Console.WriteLine ("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath);
return;
}
CalendarFolder myPublicFolder = CalendarFolder.Bind (myService,
//WellKnownFolderName.Calendar,
fId,
PropertySet.FirstClassProperties);
if (myPublicFolder.TotalCount == 0) {
Console.WriteLine ("Warning: Public folder {0} has no appointment. We try to create one.", myPublicFolderPath);
Appointment app = new Appointment (myService);
app.Subject = "Writing a code example";
app.Start = new DateTime (2010, 9, 9);
app.End = new DateTime (2010, 9, 10);
app.RequiredAttendees.Add ("oleg.kiriljuk#ok-soft-gmbh.com");
app.Culture = "de-DE";
app.Save (myPublicFolder.Id, SendInvitationsMode.SendToNone);
}
// We will search using paging. We will use page size 10
ItemView viewCalendar = new ItemView (10);
// we can include all properties which we need in the view
// If we comment the next line then ALL properties will be
// read from the server. We can see there in the debug output
viewCalendar.PropertySet = new PropertySet (ItemSchema.Subject);
viewCalendar.Offset = 0;
viewCalendar.OffsetBasePoint = OffsetBasePoint.Beginning;
viewCalendar.OrderBy.Add (ContactSchema.DateTimeCreated, SortDirection.Descending);
FindItemsResults<Item> findResultsCalendar;
do {
findResultsCalendar = myPublicFolder.FindItems (viewCalendar);
foreach (Item item in findResultsCalendar) {
if (item is Appointment) {
Appointment appoint = item as Appointment;
Console.WriteLine ("Subject: \"{0}\"", appoint.Subject);
}
}
if (findResultsCalendar.NextPageOffset.HasValue)
// go to the next page
viewCalendar.Offset = findResultsCalendar.NextPageOffset.Value;
}
while (findResultsCalendar.MoreAvailable);
}
static void Main (string[] args) {
MyTest();
}
}
}
You should update the string myPublicFolderPath to the value with your public calender folder. I set myService.TraceEnabled = true which produce long output with debug information. You should of cause remove the line for production.
UPDATED: Some additional links you could find in Create new calendar system support in Exchange OWA. If you not yet seen the videos and you want to use Exchange Web Services I would recommend you to watch there. It could save your time in the future.
I did similar thing for Exchange 2003, but using WebDAV Search method (http://msdn.microsoft.com/en-us/library/aa143053%28v=EXCHG.65%29.aspx).
http://geekswithblogs.net/cskardon/archive/2008/12/01/hunting-those-elusive-public-folders-using-exchange-web-services-part.aspx may help.

Categories

Resources