Updating SPFile properties using SPFile.Update() - c#

I'm trying to update SPFile properties.
Here is my code:
using (SPSite oSite = new SPSite(sFileURL))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
oWeb.AllowUnsafeUpdates = true;
oFile = oWeb.GetFile(sFileURL);
foreach (XmlNode xNode in oXmlDoc.FirstChild.ChildNodes)
{
oFile.Item.Properties[xNode.Name] = xNode.InnerText;
string itemmm =oFile.Item.Properties[xNode.Name].ToString();
}
oFile.Update();
oWeb.AllowUnsafeUpdates = false;
}
}
The problem is that when I check the file properties in SharePoint I don't see the changes I have made.
I was trying to add AllowUnsafeUpdates = true but it didn't solve the problem.
What else can I do?

In fact, you don't modify SPFile instance, but the associated SPItem. Hence calling SPFile.Update() does nothing. It's better to work with the SPItem instance directly:
SPItem item = oFile.Item;
item.Properties[xNode.Name] = xNode.InnerText;
item.Update();
Also, AllowUnsafeUpdates property is not relevant to your situation. Do not alter it.

Your code is lacking all checks which is to be done before actual update.
using (SPSite oSite = new SPSite(sFileURL))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
oWeb.AllowUnsafeUpdates = true;
SPFile oFile = oWeb.GetFile(sFileURL);
if (oFile == null)
{
return false;
}
SPListItem item = oFile.GetListItem();
if (item.File.Level == SPFileLevel.Checkout)
{
item.File.UndoCheckOut();
}
if (item.File.Level != SPFileLevel.Checkout)
{
item.File.CheckOut();
}
item["Your Column name"] = "Value";
item.SystemUpdate(false);
item.File.CheckIn("SystemCheckedin");
item.File.Publish("SystemPublished");
oWeb.AllowUnsafeUpdates = false;
}
}

Related

Get Outlook Appointments including recurring ones using EWS

I have implemented an SSIS Package getting all appoinments from a particular shared outlook calendar.
What I noticed is that the recurring ones are NOT returned because they are a kind of virtual. Only the Master of them will give me the ability to get also the recurring ones.
Looking at my code, do you have any suggestions how I can retrieve also the recurring ones?
I'm just a little stuck and any hint is highly appreciated!
#region Namespaces
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Microsoft.Exchange.WebServices.Data;
#endregion
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
string sharedCalendarID;
static FolderId FindPublicFolder(ExchangeService myService, FolderId baseFolderId, string folderName)
{
// search using paging.
FolderView folderView = new FolderView(10, 0);
folderView.OffsetBasePoint = OffsetBasePoint.Beginning;
// need only DisplayName and Id of every folder
// 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;
}
public override void CreateNewOutputRows()
{
// IMPORTANT: ExchangeService is NOT thread safe, so one should create an instance of
// ExchangeService whenever one needs it.
ExchangeService myService = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
myService.Credentials = new NetworkCredential("username", "password");
myService.Url = new Uri("https://......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 = #"CHI\WIED PFL Agenda";
string[] folderPath = myPublicFolderPath.Split('\\');
FolderId fId = myPublicFoldersRoot.Id;
foreach (string subFolderName in folderPath)
{
fId = FindPublicFolder(myService, fId, subFolderName);
if (fId == null)
{
// No Calendar found
return;
}
}
// verify
Folder folderFound = Folder.Bind(myService, fId);
if (String.Compare(folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) == 0)
{
sharedCalendarID = fId.ToString(); ;
}
else
return;
CalendarFolder myPublicFolder = CalendarFolder.Bind(myService,
//WellKnownFolderName.Calendar,
fId,
PropertySet.FirstClassProperties);
// search using paging. page size 10
ItemView viewCalendar = new ItemView(10);
// include all properties which we need in the view
// comment the next line then ALL properties will be read from the server.
//viewCalendar.PropertySet = new PropertySet(ItemSchema.Subject, ItemSchema.Id);
viewCalendar.Offset = 0;
viewCalendar.OffsetBasePoint = OffsetBasePoint.Beginning;
viewCalendar.OrderBy.Add(ContactSchema.DateTimeCreated, SortDirection.Descending);
FindItemsResults<Item> findResultsCalendar;
do
{
//SearchFilter searchFilter = new SearchFilter.IsGreaterThan(AppointmentSchema.Start, DateTime.Today);
var searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And,
new SearchFilter.IsEqualTo(ItemSchema.ItemClass, "IPM.Appointment"),
new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, DateTime.Now),
new SearchFilter.IsLessThan(AppointmentSchema.Start, DateTime.Now.AddDays(4)));
findResultsCalendar = myPublicFolder.FindItems(searchFilter, viewCalendar);
//get additional properties for each item returned by view, do this as view cannot return a lot of useful stuff like attendees
ServiceResponseCollection<ServiceResponse> addProperties =
myService.LoadPropertiesForItems(from Item item in findResultsCalendar select item,
new PropertySet(
BasePropertySet.IdOnly,
AppointmentSchema.Body,
AppointmentSchema.Subject,
AppointmentSchema.Start,
AppointmentSchema.End,
AppointmentSchema.IsRecurring,
AppointmentSchema.AppointmentType
));
List<Appointment> additionalProperties = new List<Appointment>(addProperties.Count);
if (addProperties != null)
{
foreach (ServiceResponse currentResponce in addProperties)
{
additionalProperties.Add(((Appointment)((GetItemResponse)currentResponce).Item));
}
}
foreach (Item item in findResultsCalendar)
{
Appointment appt = item as Appointment;
if (item is Appointment || appt.AppointmentType == AppointmentType.RecurringMaster)
{
Appointment currentAppointmentAddProps = null;
currentAppointmentAddProps = additionalProperties.Find(
delegate(Appointment arg)
{
return arg.Id == item.Id;
}
);
//convert to int wether the Appointment is recurring or not
int isRecurring = currentAppointmentAddProps.IsRecurring ? 1 : 0;
Appointment appoint = item as Appointment;
OutputRecordSetBuffer.AddRow();
OutputRecordSetBuffer.ActualEndDate = currentAppointmentAddProps.End;
OutputRecordSetBuffer.ActualStartDate = currentAppointmentAddProps.Start;
OutputRecordSetBuffer.Subject = appoint.Subject;
OutputRecordSetBuffer.EntryID = Guid.NewGuid();
//OutputRecordSetBuffer.Detail = appoint.Body.ToString();
//OutputRecordSetBuffer.CalendarID = fId.ToString();
//OutputRecordSetBuffer.AppointmentID = appoint.Id.ToString();
OutputRecordSetBuffer.CalendarID = sharedCalendarID;
OutputRecordSetBuffer.AppointmentID = Guid.NewGuid();
OutputRecordSetBuffer.IsRecurring = isRecurring;
}
}
if (findResultsCalendar.NextPageOffset.HasValue)
// go to the next page
viewCalendar.Offset = findResultsCalendar.NextPageOffset.Value;
}
while (findResultsCalendar.MoreAvailable);
}
}
I have solved my issue on my own :)
Instead of using the ItemView class, I used the CalendarView class.
CalendarView expands also the recurring appointments, thats it :)

How to retrieve list items from SharePoint 2013

At work we had to move from SharePoint 2010 to 2013 and my code for retrieving list items doesn't work anymore. Here is my code for SP 2010:
com.mycompany.intranet.Lists listService = new com.mycompany.intranet.Lists();
listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
listService.Url = "url";
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
string listName = cbxMailDistributionList.SelectedValue.ToString();
string viewName = "";
string rowLimit = "0";
System.Xml.XmlElement query = xmlDoc.CreateElement("Query");
System.Xml.XmlElement viewFields = xmlDoc.CreateElement("ViewFields");
System.Xml.XmlElement queryOptions = xmlDoc.CreateElement("QueryOptions");
viewFields.InnerXml = "<FieldRef Name='Title' />";
System.Xml.XmlNode nodeListItems =
listService.GetListItems(listName, viewName, query, viewFields, rowLimit, queryOptions, null);
xmlDoc.LoadXml(nodeListItems.InnerXml);
xlNodeList rows = xmlDoc.GetElementsByTagName("z:row");
List<string> recipients = new List<string>();
foreach (XmlNode attribute in rows)
{
if(attribute.Attributes["ows_Title"].Value == null){}
else {
if (recipients.Contains(attribute.Attributes["ows_Title"].Value)){}
else {
recipients.Add(attribute.Attributes["ows_Title"].Value);
}
}
}
recipients.Sort();
distributionList = recipients;
Can you please help me to get it working with a SharePoint 2013 list again?
URL has already been updated but i get the following error: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=DE-DE&k=k(EHNullReference);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)&rd=true
But the list has no empty fields.
listName
is the ID of the list element.
Please help.
Thanks in advance!
Finally it works again with this code:
List<string> recipients = new List<string>();
string siteURL = #"myurl/";
ClientContext cc = new ClientContext(siteURL);
cc.Credentials = System.Net.CredentialCache.DefaultCredentials;
Web web = cc.Web;
List list = web.Lists.GetById(new Guid(cbxMailDistributionList.SelectedValue.ToString()));
CamlQuery caml = new CamlQuery();
ListItemCollection items = list.GetItems(caml);
cc.Load<List>(list);
cc.Load<ListItemCollection>(items);
cc.ExecuteQuery();
foreach (Microsoft.SharePoint.Client.ListItem item in items)
{
if(item.FieldValues["Title"] == null) { }
else
{
if (recipients.Contains(item.FieldValues["Title"].ToString())) { }
else
{
recipients.Add(item.FieldValues["Title"].ToString());
}
}
}
recipients.Sort();
distributionList = recipients;
}
else
{
distributionList = null;
}
New day, new luck. Sorry for the prematurely posting of this question. I should have slept on it for a night. ;)
BR

How to get Sharepoint List using c#

How to get fields values from a particular list item.In my case i want to get all form fileds of Workplan list.Actually i want to get Workplan all list item and insert to sharepoint 2013 associated database.
I try the following code.
string strUrl = "http://example.com/default.aspx";
using (SPSite site = new SPSite(strUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[52];
SPQuery myquery = new SPQuery();
myquery.Query = "";
SPListItemCollection items = list.GetItems(myquery);
foreach (SPListItem item in items)
{
if (item != null)
{
var Name = item.ListItems.Fields.List;
Console.WriteLine("Name is :" + Name);
}
}
}
}
This is the easiest way I can think of using Server Object Model:
string strUrl = "http://example.com";
using(SPSite oSite = new SPSite(strUrl))
{
using(SPWeb oWeb = oSite.OpenWeb())
{
SPList list = oWeb.Lists["Workplan"];
foreach(SPField field in list.Fields)
{
Console.WriteLine(field.Title);
}
}
}
Btw, as for your site-URL "http://example.com/default.aspx" it is enough to do it like "http://example.com".
For more information on Sharepoint I recommend using this site in the future.
using (SPSite site = new SPSite("URL")
{
using (SPWeb web = site.OpenWeb("sitecollection/subsite"))
{
//to get specific list type
string listUrl = "/sites/sitecollection/subsite/Lists/Announcements";
SPList list = web.GetList(listUrl);
Console.WriteLine("List URL: {0}", list.RootFolder.ServerRelativeUrl);
}
}
//To get all lists from spweb use this:
SPSite oSiteCollection = SPContext.Current.Site;
using(SPWebCollection collWebs = oSiteCollection.AllWebs)
{
foreach (SPWeb oWebsite in collWebs)
{
SPListCollection collSiteLists = oWebsite.Lists;
foreach (SPList oList in collSiteLists)
{
//get your each list here
}
oWebsite.Dispose();
}
}

GetGroups method in system.DirectoryServices.AccountManagement does seem to refresh

Essentially what I'm trying to do is add a computer/user to a group. After I add the object to the group, I want to query the groups of the object to see what they have.
It seems that the GetGroups method doesn't update fast enough. My test always seems to fail. If I put some breakpoints in VS, it will run if I wait enough.
I'm new to playing with the AccounManagement namespace (I've used the pre .net 3.5 code alot). I guess I could loop through the code a few times but I'm seeing if other people have suggestions for this.
I've done the following unit test
[Test]
public void Check()
{
string distinguishedName = "ComputerDistinguishedName";
string groupDN = "GroupDistinguished name";
// Remove the identity from the group so it does crashes if it's already part of it.
GroupCtrl.RemoveIdentityFromGroup(groupDN, distinguishedName);
using (var ctx = new PrincipalContext(ContextType.Domain))
{
var group = GroupPrincipal.FindByIdentity(ctx, groupDN);
Console.WriteLine(group.Members.Count);
if (!group.Members.Contains(ctx, IdentityType.DistinguishedName, distinguishedName))
{
group.Members.Add(ctx, IdentityType.DistinguishedName, distinguishedName);
group.Save();
}
foreach (var item in group.Members)
{
Console.WriteLine(item.DistinguishedName);
}
Console.WriteLine(group.Members.Count);
}
var isMemberOf = false;
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
var found = Principal.FindByIdentity(ctx, IdentityType.DistinguishedName, distinguishedName);
if (found != null)
{
Console.WriteLine(found.DistinguishedName);
foreach (var item in found.GetGroups())
{
Console.WriteLine(item.DistinguishedName);
if (item.DistinguishedName == groupDN)
{
isMemberOf = true;
}
}
}
Assert.AreEqual(true, isMemberOf);
}
// Reset our group membership to run the test again.
GroupCtrl.RemoveIdentityFromGroup(groupDN, distinguishedName);
}
Edit 1:
So I tried two different approaches
1 -
I tried getting the getUnderlyingObject and then looping through the memberOf properties (same result)
2 -
I avoided the AccountManagement code and used a DirectorySearcher and looped through the memberOf property and it comes up every time. Sighh
So I changed my code to the following. The old way of checking memberOf with DirectorySearch works everytime. I was hoping to use only use the AccountManagement class for this project. I wonder if future version of the class will be better.
[Test]
public void Check()
{
//var test = new Constructor();
var test = new AdContextObject();
string distinguishedName = "ComputerDistinguishedName";
string groupDN = "GroupDistinguished name";
// Remove the identity from the group so it does crashes if it's already part of it.
GroupCtrl.RemoveIdentityFromGroup(groupDN, distinguishedName);
using (var ctx = test.GetContext())
{
var group = GroupPrincipal.FindByIdentity(ctx, groupDN);
Console.WriteLine(group.Members.Count);
if (!group.Members.Contains(ctx, IdentityType.DistinguishedName, distinguishedName))
{
Console.WriteLine("addGroup");
group.Members.Add(ctx, IdentityType.DistinguishedName, distinguishedName);
group.Save();
}
foreach (var item in group.Members)
{
Console.WriteLine(item.DistinguishedName);
}
Console.WriteLine(group.Members.Count);
}
DirectoryEntry de = new DirectoryEntry();
de.Path = "LdapSource";
DirectorySearcher ser = new DirectorySearcher(de);
ser.Filter = "(&(ObjectCategory=computer)(name=ComputerName))";
ser.PropertiesToLoad.Add("name");
ser.PropertiesToLoad.Add("memberOf");
var returnValue = ser.FindAll();
var isMemberOf = false;
foreach (SearchResult res in returnValue)
{
var memberOf = GetMultiValue(res, "MemberOf");
foreach (var item in memberOf)
{
Console.WriteLine(item);
if (item.Equals(groupDN, StringComparison.OrdinalIgnoreCase))
{
isMemberOf = true;
}
}
}
Assert.AreEqual(true, isMemberOf);
Console.WriteLine("old way worked fine");
isMemberOf = false;
using (PrincipalContext ctx = test.GetContext())
{
var found = Principal.FindByIdentity(ctx, IdentityType.DistinguishedName, distinguishedName);
if (found != null)
{
foreach (var item in found.GetGroups())
{
Console.WriteLine(item.DistinguishedName);
if (item.DistinguishedName.Equals(groupDN, StringComparison.OrdinalIgnoreCase))
{
isMemberOf = true;
}
}
}
Assert.AreEqual(true, isMemberOf);
}
// Reset our group membership to run the test again.
GroupCtrl.RemoveIdentityFromGroup(groupDN, distinguishedName);
}
public static string[] GetMultiValue(SearchResult result, string fieldName)
{
string[] returnValue = null;
if (result != null)
{
if (result.Properties.Contains(fieldName))
{
ResultPropertyValueCollection propertyValue = result.Properties[fieldName];
if (propertyValue != null)
{
if (propertyValue.Count > 1)
{
string[] valueArray = new string[propertyValue.Count];
for (int i = 0; i < propertyValue.Count; i++)
{
string valStr = propertyValue[i].ToString();
valueArray[i] = valStr;
}
returnValue = valueArray;
}
else if (propertyValue.Count == 1)
{
string[] tempString = new string[] { propertyValue[0].ToString() };
returnValue = tempString;
}
else
{
string[] tempString = new string[] { };
returnValue = tempString;
}
}
}
}
return returnValue;
}
public class AdContextObject
{
public PrincipalContext GetContext()
{
return new PrincipalContext(ContextType.Domain, "domainStuff", "MoreDomainStuff");
}
}

Programatically select and bind Sharepoint list items

I have some code to bind SharePoint list items to text boxes. But I only got the code to bind one item. My list contains two columns (ID and Name):
*ID Name*
1 Steven
2 Joe
3 Henry
This code picks out the Name field from the first item (that means my textbox will show "Steven":
try
{
SPQuery query = new SPQuery();
query.Query = "";
query.ViewFields = "";
query.RowLimit = 100;
using (SPSite site = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists.TryGetList("Employee List");
if (list != null)
{
if (list.GetItems(query).GetDataTable() != null)
{
DataTableReader rdr = list.GetItems(query).GetDataTable().CreateDataReader();
if (rdr.Read())
{
TextBox1.Text = rdr["Name"].ToString();
rdr.Close();
}
}
}
}
}
}
How to select the rest of them names? I was thinking about an if-statement to check if field = ID (1, 2, 3) etc. but couldn't find out anything.
Use a while loop and it should loop through all the "Name" values.
if (list.GetItems(query).GetDataTable() != null)
{
using (DataTableReader rdr = list.GetItems(query).GetDataTable().CreateDataReader())
{
while (rdr.Read())
{
TextBox1.Text = rdr["Name"].ToString();
}
}
}
Addtionally you should be using a using statement to ensure that Dispose() and Close() are both called on the DataTableReader.

Categories